void StorageReferenceInternal::FutureCallback()

in storage/src/android/storage_reference_android.cc [225:339]


void StorageReferenceInternal::FutureCallback(JNIEnv* env, jobject result,
                                              util::FutureResult result_code,
                                              const char* status_message,
                                              void* callback_data) {
  FutureCallbackData* data =
      reinterpret_cast<FutureCallbackData*>(callback_data);
  if (data == nullptr) {
    util::CheckAndClearJniExceptions(env);
    return;
  }

  if (result_code != util::kFutureResultSuccess) {
    // Failed, so the result is a StorageException.
    std::string message;
    Error code =
        (result_code == util::kFutureResultCancelled)
            ? kErrorCancelled
            : data->storage->ErrorFromJavaStorageException(result, &message);
    LogDebug("FutureCallback: Completing a Future with an error (%d).", code);
    if (data->func == kStorageReferenceFnPutFile ||
        data->func == kStorageReferenceFnPutBytes ||
        data->func == kStorageReferenceFnGetMetadata ||
        data->func == kStorageReferenceFnUpdateMetadata) {
      // If it's a Future<Metadata> that failed, ensure that an invalid metadata
      // is returned.
      data->impl->CompleteWithResult(data->handle, code, message.c_str(),
                                     Metadata(nullptr));
    } else {
      data->impl->Complete(data->handle, code, message.c_str());
    }
  } else if (result && env->IsInstanceOf(result, util::string::GetClass())) {
    LogDebug("FutureCallback: Completing a Future from a String.");
    // Complete a Future<std::string> from a Java String object.
    data->impl->CompleteWithResult<std::string>(
        data->handle, kErrorNone, status_message,
        util::JStringToString(env, result));
  } else if (result && env->IsInstanceOf(result, util::uri::GetClass())) {
    LogDebug("FutureCallback: Completing a Future from a URI.");
    // Complete a Future<std::string> from a Java URI object.
    data->impl->CompleteWithResult<std::string>(
        data->handle, kErrorNone, status_message,
        util::JniUriToString(env, env->NewLocalRef(result)));
  } else if (result &&
             env->IsInstanceOf(
                 result, stream_download_task_task_snapshot::GetClass()) &&
             data->dest != nullptr) {
    // Complete a Future<size_t>. We have previously also copied
    // bytes from a Java byte[] array via CppByteDownloader.
    LogDebug("FutureCallback: Completing a Future from a byte array.");
    jlong num_bytes = env->CallLongMethod(
        result, stream_download_task_task_snapshot::GetMethodId(
                    stream_download_task_task_snapshot::kGetBytesTransferred));
    data->impl->Complete<size_t>(
        data->handle, kErrorNone, status_message,
        [num_bytes](size_t* size) { *size = num_bytes; });
  } else if (result &&
             env->IsInstanceOf(result, storage_metadata::GetClass())) {
    // Complete a Future<Metadata> from a Java StorageMetadata object.
    LogDebug("FutureCallback: Completing a Future from a StorageMetadata.");
    data->impl->Complete<Metadata>(
        data->handle, kErrorNone, status_message,
        [data, result](Metadata* metadata) {
          *metadata = Metadata(new MetadataInternal(data->storage, result));
        });
  } else if (result &&
             env->IsInstanceOf(result, upload_task_task_snapshot::GetClass())) {
    LogDebug("FutureCallback: Completing a Future from an UploadTask.");
    // Complete a Future<Metadata> from a Java UploadTask.TaskSnapshot.
    jobject metadata_obj = env->CallObjectMethod(
        result, upload_task_task_snapshot::GetMethodId(
                    upload_task_task_snapshot::kGetMetadata));
    data->impl->Complete<Metadata>(data->handle, kErrorNone, status_message,
                                   [data, metadata_obj](Metadata* metadata) {
                                     *metadata = Metadata(new MetadataInternal(
                                         data->storage, metadata_obj));
                                   });
    env->DeleteLocalRef(metadata_obj);
  } else if (result &&
             env->IsInstanceOf(result,
                               file_download_task_task_snapshot::GetClass())) {
    LogDebug("FutureCallback: Completing a Future from a FileDownloadTask.");
    // Complete a Future<size_t> from a Java FileDownloadTask.TaskSnapshot.
    jlong bytes = env->CallLongMethod(
        result, file_download_task_task_snapshot::GetMethodId(
                    file_download_task_task_snapshot::kGetBytesTransferred));
    data->impl->Complete<size_t>(data->handle, kErrorNone, status_message,
                                 [bytes](size_t* size) { *size = bytes; });
  } else {
    LogDebug("FutureCallback: Completing a Future from a default result.");
    // Unknown or null result type, treat this as a Future<void> and just
    // return success.
    data->impl->Complete(data->handle, kErrorNone, status_message);
  }
  if (data->listener != nullptr) {
    env->CallVoidMethod(data->listener,
                        cpp_storage_listener::GetMethodId(
                            cpp_storage_listener::kDiscardPointers));
    env->DeleteGlobalRef(data->listener);
  }
  if (data->cpp_byte_downloader != nullptr) {
    env->CallVoidMethod(data->cpp_byte_downloader,
                        cpp_byte_downloader::GetMethodId(
                            cpp_byte_downloader::kDiscardPointers));
    env->DeleteGlobalRef(data->cpp_byte_downloader);
  }
  if (data->cpp_byte_uploader != nullptr) {
    env->CallVoidMethod(
        data->cpp_byte_uploader,
        cpp_byte_uploader::GetMethodId(cpp_byte_uploader::kDiscardPointers));
    env->DeleteGlobalRef(data->cpp_byte_uploader);
  }
  delete data;

  util::CheckAndClearJniExceptions(env);
}