[platform] JNI layer for http uploader class

This commit is contained in:
Arsentiy Milchakov 2018-02-01 19:18:07 +03:00 committed by Roman Kuznetsov
parent 68d332b783
commit 2f11131c9f
8 changed files with 160 additions and 50 deletions

View file

@ -20,13 +20,13 @@ jclass g_bookmarkClazz;
jclass g_myTrackerClazz;
jclass g_httpClientClazz;
jclass g_httpParamsClazz;
jclass g_httpHeaderClazz;
jclass g_platformSocketClazz;
jclass g_utilsClazz;
jclass g_bannerClazz;
jclass g_ratingClazz;
jclass g_arrayListClazz;
jclass g_loggerFactoryClazz;
jclass g_keyValueClazz;
jclass g_httpUploaderClazz;
extern "C"
{
@ -44,12 +44,13 @@ JNI_OnLoad(JavaVM * jvm, void *)
g_myTrackerClazz = jni::GetGlobalClassRef(env, "com/my/tracker/MyTracker");
g_httpClientClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient");
g_httpParamsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient$Params");
g_httpHeaderClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient$HttpHeader");
g_platformSocketClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/location/PlatformSocket");
g_utilsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/Utils");
g_bannerClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/ads/Banner");
g_ratingClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/ugc/UGC$Rating");
g_loggerFactoryClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/log/LoggerFactory");
g_keyValueClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/KeyValue");
g_httpUploaderClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpUploader");
return JNI_VERSION_1_6;
}
@ -65,12 +66,13 @@ JNI_OnUnload(JavaVM *, void *)
env->DeleteGlobalRef(g_myTrackerClazz);
env->DeleteGlobalRef(g_httpClientClazz);
env->DeleteGlobalRef(g_httpParamsClazz);
env->DeleteGlobalRef(g_httpHeaderClazz);
env->DeleteGlobalRef(g_platformSocketClazz);
env->DeleteGlobalRef(g_utilsClazz);
env->DeleteGlobalRef(g_bannerClazz);
env->DeleteGlobalRef(g_ratingClazz);
env->DeleteGlobalRef(g_loggerFactoryClazz);
env->DeleteGlobalRef(g_keyValueClazz);
env->DeleteGlobalRef(g_httpUploaderClazz);
}
} // extern "C"
@ -286,4 +288,30 @@ void DumpDalvikReferenceTables()
env->CallStaticVoidMethod(vm_class, dump_mid);
env->DeleteLocalRef(vm_class);
}
jobject ToKeyValue(JNIEnv * env, std::pair<std::string, std::string> src)
{
static jmethodID const PairInit = jni::GetConstructorID(
env, g_keyValueClazz, "(Ljava/lang/String;Ljava/lang/String;)V");
jni::TScopedLocalRef key(env, jni::ToJavaString(env, src.first));
jni::TScopedLocalRef value(env, jni::ToJavaString(env, src.second));
return env->NewObject(g_keyValueClazz, PairInit, key.get(), value.get());
}
std::pair<std::string, std::string> ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings)
{
static jfieldID const keyId = env->GetFieldID(g_keyValueClazz, "key",
"Ljava/lang/String;");
static jfieldID const valueId = env->GetFieldID(g_keyValueClazz, "value",
"Ljava/lang/String;");
jni::ScopedLocalRef<jstring> const key(
env, static_cast<jstring>(env->GetObjectField(pairOfStrings, keyId)));
jni::ScopedLocalRef<jstring> const value(
env, static_cast<jstring>(env->GetObjectField(pairOfStrings, valueId)));
return { jni::ToNativeString(env, key.get()), jni::ToNativeString(env, value.get()) };
}
} // namespace jni

View file

@ -10,6 +10,7 @@
#include <memory>
#include <string>
#include <utility>
extern jclass g_mapObjectClazz;
extern jclass g_featureIdClazz;
@ -17,12 +18,13 @@ extern jclass g_bookmarkClazz;
extern jclass g_myTrackerClazz;
extern jclass g_httpClientClazz;
extern jclass g_httpParamsClazz;
extern jclass g_httpHeaderClazz;
extern jclass g_platformSocketClazz;
extern jclass g_utilsClazz;
extern jclass g_bannerClazz;
extern jclass g_ratingClazz;
extern jclass g_loggerFactoryClazz;
extern jclass g_keyValueClazz;
extern jclass g_httpUploaderClazz;
namespace jni
{
@ -90,4 +92,28 @@ jobjectArray ToJavaArray(JNIEnv * env, jclass clazz, TContainer const & src, TTo
jobjectArray ToJavaStringArray(JNIEnv * env, std::vector<std::string> const & src);
void DumpDalvikReferenceTables();
jobject ToKeyValue(JNIEnv * env, std::pair<std::string, std::string> src);
template <typename Container>
jobjectArray ToKeyValueArray(JNIEnv * env, Container const & src)
{
return jni::ToJavaArray(env, g_keyValueClazz, src,
std::bind(&ToKeyValue, std::placeholders::_1, std::placeholders::_2));
}
std::pair<std::string, std::string> ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings);
template <typename OutputIt>
void ToNativekeyValueContainer(JNIEnv * env, jobjectArray src, OutputIt it)
{
int const length = env->GetArrayLength(src);
for (size_t i = 0; i < length; ++i)
{
jni::ScopedLocalRef<jobject> const arrayItem(env, env->GetObjectArrayElement(src, i));
*it = ToNativeKeyValue(env, arrayItem.get());
++it;
}
}
} // namespace jni

View file

@ -1,12 +1,44 @@
#include <jni.h>
#include "com/mapswithme/core/jni_helper.hpp"
#include "com/mapswithme/core/ScopedEnv.hpp"
#include "com/mapswithme/core/ScopedLocalRef.hpp"
#include "platform/http_uploader.hpp"
#include "base/assert.hpp"
#include <cstdint>
#include <functional>
namespace platform
{
void HttpUploader::Upload() const
{
// Dummy implementation.
CHECK(m_callback, ());
auto env = jni::GetEnv();
CHECK(env, ());
static jmethodID const httpUploaderConstructor =
jni::GetConstructorID(env, g_httpUploaderClazz, "(Ljava/lang/String;Ljava/lang/String;"
"[Lcom/mapswithme/util/KeyValue;"
"[Lcom/mapswithme/util/KeyValue;"
"Ljava/lang/String;Ljava/lang/String;)V");
jni::ScopedLocalRef<jstring> const method(env, jni::ToJavaString(env, m_method));
jni::ScopedLocalRef<jstring> const url(env, jni::ToJavaString(env, m_url));
jni::ScopedLocalRef<jobjectArray> const params(env, jni::ToKeyValueArray(env, m_params));
jni::ScopedLocalRef<jobjectArray> const headers(env, jni::ToKeyValueArray(env, m_headers));
jni::ScopedLocalRef<jstring> const fileKey(env, jni::ToJavaString(env, m_fileKey));
jni::ScopedLocalRef<jstring> const filePath(env, jni::ToJavaString(env, m_filePath));
jni::ScopedLocalRef<jobject> const httpUploaderObject(
env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(),
params.get(), headers.get(), fileKey.get(), filePath.get()));
static jmethodID const uploadId = jni::GetMethodID(env, httpUploaderObject, "upload", "()I");
m_callback(env->CallIntMethod(httpUploaderObject, uploadId), "dummy");
}
} // namespace platform

View file

@ -34,6 +34,7 @@ SOFTWARE.
#include "base/logging.hpp"
#include <string>
#include <iterator>
#include <unordered_map>
DECLARE_EXCEPTION(JniException, RootException);
@ -103,22 +104,12 @@ void SetHeaders(ScopedEnv & env, jobject const params,
if (headers.empty())
return;
static jmethodID const headerInit = jni::GetConstructorID(
env.get(), g_httpHeaderClazz, "(Ljava/lang/String;Ljava/lang/String;)V");
static jmethodID const setHeaders = env->GetMethodID(
g_httpParamsClazz, "setHeaders", "([Lcom/mapswithme/util/HttpClient$HttpHeader;)V");
g_httpParamsClazz, "setHeaders", "([Lcom/mapswithme/util/KeyValue;)V");
RethrowOnJniException(env);
using HeaderPair = std::unordered_map<std::string, std::string>::value_type;
auto headerFunc = [](JNIEnv * env, HeaderPair const & item)
{
jni::TScopedLocalRef first(env, jni::ToJavaString(env, item.first));
jni::TScopedLocalRef second(env, jni::ToJavaString(env, item.second));
return env->NewObject(g_httpHeaderClazz, headerInit, first.get(), second.get());
};
jni::TScopedLocalObjectArrayRef jHeaders(env.get(), jni::ToJavaArray(env.get(), g_httpHeaderClazz,
headers, headerFunc));
jni::TScopedLocalObjectArrayRef jHeaders(env.get(), jni::ToKeyValueArray(env.get(), headers));
env->CallVoidMethod(params, setHeaders, jHeaders.get());
RethrowOnJniException(env);
}
@ -127,8 +118,6 @@ void LoadHeaders(ScopedEnv & env, jobject const params, std::unordered_map<std::
{
static jmethodID const getHeaders =
env->GetMethodID(g_httpParamsClazz, "getHeaders", "()[Ljava/lang/Object;");
static jfieldID const keyId = env->GetFieldID(g_httpHeaderClazz, "key", "Ljava/lang/String;");
static jfieldID const valueId = env->GetFieldID(g_httpHeaderClazz, "value", "Ljava/lang/String;");
jni::ScopedLocalRef<jobjectArray> const headersArray(
env.get(), static_cast<jobjectArray>(env->CallObjectMethod(params, getHeaders)));
@ -136,20 +125,8 @@ void LoadHeaders(ScopedEnv & env, jobject const params, std::unordered_map<std::
RethrowOnJniException(env);
headers.clear();
int const length = env->GetArrayLength(headersArray.get());
for (size_t i = 0; i < length; ++i)
{
jni::ScopedLocalRef<jobject> const headerEntry(
env.get(), env->GetObjectArrayElement(headersArray.get(), i));
jni::ToNativekeyValueContainer(env.get(), headersArray, std::inserter(headers, headers.end()));
jni::ScopedLocalRef<jstring> const key(
env.get(), static_cast<jstring>(env->GetObjectField(headerEntry.get(), keyId)));
jni::ScopedLocalRef<jstring> const value(
env.get(), static_cast<jstring>(env->GetObjectField(headerEntry.get(), valueId)));
headers.emplace(jni::ToNativeString(env.get(), key.get()),
jni::ToNativeString(env.get(), value.get()));
}
RethrowOnJniException(env);
}

View file

@ -97,7 +97,7 @@ public final class HttpClient
if (!TextUtils.isEmpty(p.cookies))
connection.setRequestProperty("Cookie", p.cookies);
for (HttpHeader header : p.headers)
for (KeyValue header : p.headers)
{
connection.setRequestProperty(header.key, header.value);
}
@ -163,14 +163,14 @@ public final class HttpClient
if (header.getKey() == null || header.getValue() == null)
continue;
p.headers.add(new HttpHeader(header.getKey().toLowerCase(), TextUtils.join(", ", header.getValue())));
p.headers.add(new KeyValue(header.getKey().toLowerCase(), TextUtils.join(", ", header.getValue())));
}
}
else
{
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
if (cookies != null)
p.headers.add(new HttpHeader("Set-Cookie", TextUtils.join(", ", cookies)));
p.headers.add(new KeyValue("Set-Cookie", TextUtils.join(", ", cookies)));
}
OutputStream ostream;
@ -244,21 +244,9 @@ public final class HttpClient
return url.replaceAll("(token|password|key)=([^&]+)", "***");
}
private static class HttpHeader
{
HttpHeader(@NonNull String key, @NonNull String value)
{
this.key = key;
this.value = value;
}
public String key;
public String value;
}
private static class Params
{
public void setHeaders(@NonNull HttpHeader[] array)
public void setHeaders(@NonNull KeyValue[] array)
{
headers = new ArrayList<>(Arrays.asList(array));
}
@ -282,7 +270,7 @@ public final class HttpClient
// Received data is stored here if not null or in data otherwise.
String outputFilePath;
String cookies;
ArrayList<HttpHeader> headers = new ArrayList<>();
ArrayList<KeyValue> headers = new ArrayList<>();
int httpResponseCode = -1;
boolean followRedirects = true;
boolean loadHeaders;

View file

@ -0,0 +1,41 @@
package com.mapswithme.util;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
final class HttpUploader
{
@NonNull
private final String mMethod;
@NonNull
private final String mUrl;
@NonNull
private final ArrayList<KeyValue> mParams;
@NonNull
private final ArrayList<KeyValue> mHeaders;
@NonNull
private final String mFileKey;
@NonNull
private final String mFilePath;
@SuppressWarnings("unused")
private HttpUploader(@NonNull String method, @NonNull String url, @NonNull KeyValue[] params,
@NonNull KeyValue[] headers, @NonNull String fileKey, @NonNull String filePath)
{
mMethod = method;
mUrl = url;
mParams = new ArrayList<>(Arrays.asList(params));
mHeaders = new ArrayList<>(Arrays.asList(headers));
mFileKey = fileKey;
mFilePath = filePath;
}
@SuppressWarnings("unused")
private int upload()
{
// Dummy. Error code 200 - Http OK.
return 200;
}
}

View file

@ -0,0 +1,17 @@
package com.mapswithme.util;
import android.support.annotation.NonNull;
final class KeyValue
{
KeyValue(@NonNull String key, @NonNull String value)
{
this.key = key;
this.value = value;
}
@NonNull
public final String key;
@NonNull
public final String value;
}

View file

@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <functional>
#include <map>
#include <string>