void JniLogSystemCallback::operator()(AdblockPlus::LogSystem::LogLevel logLevel,
    const std::string& message, const std::string& source)
{
  JNIEnvAcquire env(GetJavaVM());

  jmethodID method = env->GetMethodID(
      *JniLocalReference<jclass>(*env,
          env->GetObjectClass(GetCallbackObject())),
      "logCallback",
      "(" TYP("LogSystem$LogLevel") "Ljava/lang/String;Ljava/lang/String;)V");

  // TODO: Set log level from Java and handle it here (to reduce C++->Java calls)

  if (method)
  {
    const char* enumName = 0;

    switch (logLevel)
    {
    default:
    case AdblockPlus::LogSystem::LOG_LEVEL_TRACE:
      enumName = "TRACE";
      break;
    case AdblockPlus::LogSystem::LOG_LEVEL_LOG:
      enumName = "LOG";
      break;
    case AdblockPlus::LogSystem::LOG_LEVEL_INFO:
      enumName = "INFO";
      break;
    case AdblockPlus::LogSystem::LOG_LEVEL_WARN:
      enumName = "WARN";
      break;
    case AdblockPlus::LogSystem::LOG_LEVEL_ERROR:
      enumName = "ERROR";
      break;
    }

    jclass enumClass = logLevelClass->Get();
    if (enumClass)
    {
      jfieldID enumField = env->GetStaticFieldID(enumClass, enumName,
          TYP("LogSystem$LogLevel"));
      JniLocalReference<jobject> jLogLevel(*env,
          env->GetStaticObjectField(enumClass, enumField));

      JniLocalReference<jstring> jMessage(*env,
          env->NewStringUTF(message.c_str()));
      JniLocalReference<jstring> jSource(*env,
          env->NewStringUTF(source.c_str()));

      env->CallVoidMethod(GetCallbackObject(), method, *jLogLevel, *jMessage,
          *jSource);
    }

    CheckAndLogJavaException(*env);
  }
}
void JniUpdaterCallback::Callback(const std::string& arg)
{
  JNIEnvAcquire env(GetJavaVM());

  jclass clazz = env->GetObjectClass(GetCallbackObject());
  jmethodID method = env->GetMethodID(clazz, "updateCallback", "(Ljava/lang/String;)V");

  if (method)
  {
    jstring jArg = env->NewStringUTF(arg.c_str());
    env->CallVoidMethod(GetCallbackObject(), method, jArg);
  }

  CheckAndLogJavaException(*env);
}
void JniFilterChangeCallback::Callback(const std::string& arg, const AdblockPlus::JsValuePtr jsValue)
{
  JNIEnvAcquire env(GetJavaVM());

  jclass clazz = env->GetObjectClass(GetCallbackObject());
  jmethodID method = env->GetMethodID(clazz, "filterChangeCallback", "(Ljava/lang/String;" TYP("JsValue") ")V");

  if (method)
  {
    jstring jArg = env->NewStringUTF(arg.c_str());
    jobject jJsValue = NewJniJsValue(*env, jsValue, jsValueClass->Get());
    env->CallVoidMethod(GetCallbackObject(), method, jArg, jJsValue);
  }

  CheckAndLogJavaException(*env);
}
void JniUpdateCheckDoneCallback::Callback(const std::string& arg)
{
  JNIEnvAcquire env(GetJavaVM());

  jmethodID method = env->GetMethodID(
      *JniLocalReference<jclass>(*env,
          env->GetObjectClass(GetCallbackObject())),
      "updateCheckDoneCallback",
      "(Ljava/lang/String;)V");

  if (method)
  {
    JniLocalReference<jstring> jArg(*env, env->NewStringUTF(arg.c_str()));
    env->CallVoidMethod(GetCallbackObject(), method, *jArg);
  }

  CheckAndLogJavaException(*env);
}