You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2013/05/26 18:57:34 UTC

[09/28] git commit: Improved library for using JVM/JNI and updated uses (in tests).

Improved library for using JVM/JNI and updated uses (in tests).

Review: https://reviews.apache.org/r/11270


Project: http://git-wip-us.apache.org/repos/asf/incubator-mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mesos/commit/233edea2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mesos/tree/233edea2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mesos/diff/233edea2

Branch: refs/heads/master
Commit: 233edea23871302be582ddba340cfc6c7c68ef30
Parents: 07c44ce
Author: Benjamin Hindman <be...@twitter.com>
Authored: Thu May 2 09:29:32 2013 -0700
Committer: Benjamin Hindman <be...@twitter.com>
Committed: Fri May 24 22:05:05 2013 -0700

----------------------------------------------------------------------
 src/Makefile.am                     |   18 +-
 src/jvm/java/io.hpp                 |   36 ++
 src/jvm/java/lang.hpp               |   31 ++
 src/jvm/java/net.hpp                |   26 +
 src/jvm/jvm.cpp                     |  767 ++++++++++++++++++------------
 src/jvm/jvm.hpp                     |  367 ++++++++++-----
 src/jvm/org/apache/log4j.cpp        |   16 +
 src/jvm/org/apache/log4j.hpp        |   69 +++
 src/jvm/org/apache/zookeeper.hpp    |  168 +++++++
 src/tests/zookeeper_test.cpp        |   72 +--
 src/tests/zookeeper_test.hpp        |   12 +-
 src/tests/zookeeper_test_server.cpp |  201 ++------
 src/tests/zookeeper_test_server.hpp |   55 +--
 13 files changed, 1131 insertions(+), 707 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 5ed3423..fe31707 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -552,14 +552,24 @@ CLEANFILES += $(MESOS_SOURCES_JAR)
 # main libmesos.so.
 noinst_LTLIBRARIES += libjava.la
 
-libjava_la_SOURCES = java/jni/convert.cpp java/jni/construct.cpp	\
+libjava_la_SOURCES =							\
+	java/jni/convert.cpp						\
+	java/jni/convert.hpp						\
+	java/jni/construct.cpp						\
+	java/jni/construct.hpp						\
 	java/jni/org_apache_mesos_Log.cpp				\
 	java/jni/org_apache_mesos_MesosSchedulerDriver.cpp		\
 	java/jni/org_apache_mesos_MesosExecutorDriver.cpp		\
 	java/jni/org_apache_mesos_state_Variable.cpp			\
-	java/jni/org_apache_mesos_state_ZooKeeperState.cpp jvm/jvm.cpp
-
-libjava_la_SOURCES += java/jni/convert.hpp java/jni/construct.hpp jvm/jvm.hpp
+	java/jni/org_apache_mesos_state_ZooKeeperState.cpp		\
+	jvm/jvm.cpp							\
+	jvm/jvm.hpp							\
+	jvm/java/io.hpp							\
+	jvm/java/lang.hpp						\
+	jvm/java/net.hpp						\
+	jvm/org/apache/log4j.cpp					\
+	jvm/org/apache/log4j.hpp					\
+	jvm/org/apache/zookeeper.hpp
 
 libjava_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libjava_la_CPPFLAGS += $(JAVA_CPPFLAGS)

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/java/io.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/java/io.hpp b/src/jvm/java/io.hpp
new file mode 100644
index 0000000..fa0c60c
--- /dev/null
+++ b/src/jvm/java/io.hpp
@@ -0,0 +1,36 @@
+#ifndef __JAVA_IO_HPP__
+#define __JAVA_IO_HPP__
+
+#include <jvm/jvm.hpp>
+
+namespace java {
+namespace io {
+
+class File : public Jvm::Object
+{
+public:
+  File(const std::string& pathname)
+  {
+    static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+        Jvm::Class::named("java/io/File")
+        .constructor()
+        .parameter(Jvm::get()->stringClass));
+
+    object = Jvm::get()->invoke(constructor, Jvm::get()->string(pathname));
+  }
+
+  void deleteOnExit()
+  {
+    static Jvm::Method method = Jvm::get()->findMethod(
+        Jvm::Class::named("java/io/File")
+        .method("deleteOnExit")
+        .returns(Jvm::get()->voidClass));
+
+    Jvm::get()->invoke<void>(object, method);
+  }
+};
+
+} // namespace io {
+} // namespace java {
+
+#endif // __JAVA_IO_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/java/lang.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/java/lang.hpp b/src/jvm/java/lang.hpp
new file mode 100644
index 0000000..5eb365d
--- /dev/null
+++ b/src/jvm/java/lang.hpp
@@ -0,0 +1,31 @@
+#ifndef __JAVA_LANG_HPP__
+#define __JAVA_LANG_HPP__
+
+#include <jvm/jvm.hpp>
+
+namespace java {
+namespace lang {
+
+class Throwable : public Jvm::Object
+{
+public:
+  Throwable(const std::string& message)
+  {
+    static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+        Jvm::Class::named("java/lang/Throwable")
+        .constructor()
+        .parameter(Jvm::get()->stringClass));
+
+    object = Jvm::get()->invoke(constructor, Jvm::get()->string(message));
+  }
+
+private:
+  friend void Jvm::check(JNIEnv* env); // For constructing default instances.
+
+  Throwable() {}
+};
+
+} // namespace lang {
+} // namespace java {
+
+#endif // __JAVA_LANG_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/java/net.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/java/net.hpp b/src/jvm/java/net.hpp
new file mode 100644
index 0000000..7816251
--- /dev/null
+++ b/src/jvm/java/net.hpp
@@ -0,0 +1,26 @@
+#ifndef __JAVA_NET_HPP__
+#define __JAVA_NET_HPP__
+
+#include <jvm/jvm.hpp>
+
+namespace java {
+namespace net {
+
+class InetSocketAddress : public Jvm::Object // TODO(benh): Extends SocketAddress.
+{
+public:
+  InetSocketAddress(int port)
+  {
+    static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+        Jvm::Class::named("java/net/InetSocketAddress")
+        .constructor()
+        .parameter(Jvm::get()->intClass));
+
+    object = Jvm::get()->invoke(constructor, port);
+  }
+};
+
+} // namespace net {
+} // namespace java {
+
+#endif // __JAVA_NET_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/jvm.cpp
----------------------------------------------------------------------
diff --git a/src/jvm/jvm.cpp b/src/jvm/jvm.cpp
index a4fb791..d053f59 100644
--- a/src/jvm/jvm.cpp
+++ b/src/jvm/jvm.cpp
@@ -8,571 +8,714 @@
 #include <sstream>
 #include <vector>
 
-#include <stout/hashmap.hpp>
+#include <stout/exit.hpp>
 #include <stout/foreach.hpp>
 
 #include "jvm/jvm.hpp"
 
+#include "jvm/java/lang.hpp"
 
-namespace mesos {
-namespace internal {
 
-jmethodID Jvm::findMethod(const Jvm::JClass& clazz,
-                          const std::string& name,
-                          const Jvm::JClass& returnType,
-                          const std::vector<Jvm::JClass> argTypes,
-                          bool isStatic)
+// Static storage and initialization.
+Jvm* Jvm::instance = NULL;
+
+
+Try<Jvm*> Jvm::create(
+    const std::vector<std::string>& options,
+    JNI::Version version,
+    bool exceptions)
 {
-  std::ostringstream signature;
-  signature << "(";
-  std::vector<Jvm::JClass>::iterator args;
-  foreach (Jvm::JClass type, argTypes) {
-    signature << type.signature();
+  // TODO(benh): Make this thread-safe.
+  if (instance != NULL) {
+    return Error("Java Virtual Machine already created");
   }
-  signature << ")" << returnType.signature();
 
-  LOG(INFO) << "looking up" << (isStatic ? " static " : " ") << "method "
-            << name << signature.str();
-
-  jmethodID id = NULL;
-  if (isStatic) {
-    id = env->GetStaticMethodID(findClass(clazz),
-                                name.c_str(),
-                                signature.str().c_str());
-  } else {
-    id = env->GetMethodID(findClass(clazz),
-                          name.c_str(),
-                          signature.str().c_str());
+  JavaVMInitArgs vmArgs;
+  vmArgs.version = version;
+  vmArgs.ignoreUnrecognized = false;
+
+  JavaVMOption* opts = new JavaVMOption[options.size()];
+  for (size_t i = 0; i < options.size(); i++) {
+    opts[i].optionString = const_cast<char*>(options[i].c_str());
   }
+  vmArgs.nOptions = options.size();
+  vmArgs.options = opts;
 
-  // TODO(John Sirois): consider CHECK -> return Option if re-purposing this
-  // code outside of tests.
-  CHECK(id != NULL);
-  return id;
-}
+  JavaVM* jvm = NULL;
+  JNIEnv* env = NULL;
 
+  int result = JNI_CreateJavaVM(&jvm, JNIENV_CAST(&env), &vmArgs);
 
-Jvm::ConstructorFinder::ConstructorFinder(
-    const Jvm::JClass& _type)
-    : type(_type),
-      parameters() {}
+  if (result == JNI_ERR) {
+    return Error("Failed to create JVM!");
+  }
 
+  delete[] opts;
 
-Jvm::ConstructorFinder&
-Jvm::ConstructorFinder::parameter(const Jvm::JClass& type)
-{
-  parameters.push_back(type);
-  return *this;
+  return instance = new Jvm(jvm, version, exceptions);
 }
 
 
-Jvm::JConstructor Jvm::findConstructor(const ConstructorFinder& signature)
+bool Jvm::created()
 {
-  jmethodID id =
-      findMethod(signature.type,
-                 "<init>",
-                 voidClass,
-                 signature.parameters,
-                 false);
-  return Jvm::JConstructor(signature.type, id);
+  return instance != NULL;
 }
 
 
-Jvm::JConstructor::JConstructor(const JConstructor& other) : clazz(other.clazz),
-                                                             id(other.id) {}
+Jvm* Jvm::get()
+{
+  if (instance == NULL) {
+    create();
+  }
+  return CHECK_NOTNULL(instance);
+}
 
 
-Jvm::JConstructor::JConstructor(const JClass& _clazz,
-                                const jmethodID _id) : clazz(_clazz),
-                                                       id(_id) {}
+Jvm::ConstructorFinder::ConstructorFinder(const Jvm::Class& _clazz)
+  : clazz(_clazz), parameters() {}
 
 
-jobject Jvm::invoke(const JConstructor& ctor, ...)
+Jvm::ConstructorFinder& Jvm::ConstructorFinder::parameter(
+    const Jvm::Class& clazz)
 {
-  va_list args;
-  va_start(args, ctor);
-  jobject result = env->NewObjectV(findClass(ctor.clazz), ctor.id, args);
-  va_end(args);
-  CHECK(result != NULL);
-  return result;
+  parameters.push_back(clazz);
+  return *this;
 }
 
 
+Jvm::Constructor::Constructor(const Constructor& that)
+  : clazz(that.clazz), id(that.id) {}
+
+
+Jvm::Constructor::Constructor(const Class& _clazz, const jmethodID _id)
+  : clazz(_clazz), id(_id) {}
+
+
 Jvm::MethodFinder::MethodFinder(
-    const Jvm::JClass& _clazz,
+    const Jvm::Class& _clazz,
     const std::string& _name)
-    : clazz(_clazz),
-      name(_name),
-      parameters() {}
+  : clazz(_clazz),
+    name(_name),
+    parameters() {}
 
 
-Jvm::MethodFinder& Jvm::MethodFinder::parameter(const JClass& type)
+Jvm::MethodFinder& Jvm::MethodFinder::parameter(const Class& type)
 {
   parameters.push_back(type);
   return *this;
 }
 
 
-Jvm::MethodSignature Jvm::MethodFinder::returns(const JClass& returnType) const
+Jvm::MethodSignature Jvm::MethodFinder::returns(const Class& returnType) const
 {
   return Jvm::MethodSignature(clazz, name, returnType, parameters);
 }
 
 
-Jvm::JMethod Jvm::findMethod(const MethodSignature& signature)
-{
-  jmethodID id = findMethod(signature.clazz,
-                            signature.name,
-                            signature.returnType,
-                            signature.parameters,
-                            false);
-  return Jvm::JMethod(signature.clazz, id);
-}
-
-
-Jvm::JMethod Jvm::findStaticMethod(const MethodSignature& signature)
-{
-  jmethodID id = findMethod(signature.clazz,
-                            signature.name,
-                            signature.returnType,
-                            signature.parameters,
-                            true);
-  return Jvm::JMethod(signature.clazz, id);
-}
+Jvm::MethodSignature::MethodSignature(const MethodSignature& that)
+  : clazz(that.clazz),
+    name(that.name),
+    returnType(that.returnType),
+    parameters(that.parameters) {}
 
 
-Jvm::MethodSignature::MethodSignature(const MethodSignature& other) :
-    clazz(other.clazz),
-    name(other.name),
-    returnType(other.returnType),
-    parameters(other.parameters) {}
-
-
-Jvm::MethodSignature::MethodSignature(const JClass& _clazz,
-                                      const std::string& _name,
-                                      const JClass& _returnType,
-                                      const std::vector<JClass>& _parameters) :
-    clazz(_clazz),
+Jvm::MethodSignature::MethodSignature(
+    const Class& _clazz,
+    const std::string& _name,
+    const Class& _returnType,
+    const std::vector<Class>& _parameters)
+  : clazz(_clazz),
     name(_name),
     returnType(_returnType),
     parameters(_parameters) {}
 
 
-Jvm::JMethod::JMethod(const JMethod& other)
-    : clazz(other.clazz), id(other.id) {}
+Jvm::Method::Method(const Method& that)
+    : clazz(that.clazz), id(that.id) {}
 
 
-Jvm::JMethod::JMethod(const JClass& _clazz, const jmethodID _id)
+Jvm::Method::Method(const Class& _clazz, const jmethodID _id)
     : clazz(_clazz), id(_id) {}
 
 
-template <>
-jobject Jvm::invokeV<jobject>(const jobject receiver,
-                              const jmethodID id,
-                              va_list args)
+const Jvm::Class Jvm::Class::named(const std::string& name)
 {
-  jobject result = env->CallObjectMethodV(receiver, id, args);
-  CHECK(result != NULL);
-  return result;
+  return Jvm::Class(name, false /* NOT a native type. */);
 }
 
 
-template<>
-void Jvm::invokeV<void>(const jobject receiver,
-                        const jmethodID id,
-                        va_list args)
+Jvm::Class::Class(const Class& that)
+  : name(that.name), native(that.native) {}
+
+
+Jvm::Class::Class(const std::string& _name, bool _native)
+  : name(_name), native(_native) {}
+
+
+const Jvm::Class Jvm::Class::arrayOf() const
 {
-  env->CallVoidMethodV(receiver, id, args);
+  return Jvm::Class("[" + name, native);
 }
 
 
-template <>
-bool Jvm::invokeV<bool>(const jobject receiver,
-                        const jmethodID id,
-                        va_list args)
+Jvm::ConstructorFinder Jvm::Class::constructor() const
 {
-  return env->CallBooleanMethodV(receiver, id, args);
+  return Jvm::ConstructorFinder(*this);
 }
 
 
-template <>
-char Jvm::invokeV<char>(const jobject receiver,
-                        const jmethodID id,
-                        va_list args)
+Jvm::MethodFinder Jvm::Class::method(const std::string& name) const
 {
-  return env->CallCharMethodV(receiver, id, args);
+  return Jvm::MethodFinder(*this, name);
 }
 
 
-template <>
-short Jvm::invokeV<short>(const jobject receiver,
-                          const jmethodID id,
-                          va_list args)
+std::string Jvm::Class::signature() const
 {
-  return env->CallShortMethodV(receiver, id, args);
+  return native ? name : "L" + name + ";";
 }
 
 
-template <>
-int Jvm::invokeV<int>(const jobject receiver,
-                      const jmethodID id,
-                      va_list args)
+Jvm::Field::Field(const Field& that)
+  : clazz(that.clazz), id(that.id) {}
+
+
+Jvm::Field::Field(const Class& _clazz, const jfieldID _id)
+    : clazz(_clazz), id(_id) {}
+
+
+Jvm::Env::Env(bool daemon)
+  : env(NULL), detach(false)
 {
-  return env->CallIntMethodV(receiver, id, args);
-}
+  JavaVM* jvm = Jvm::get()->jvm;
 
+  // First check if we are already attached.
+  int result = jvm->GetEnv(JNIENV_CAST(&env), Jvm::get()->version);
 
-template <>
-long Jvm::invokeV<long>(const jobject receiver,
-                        const jmethodID id,
-                        va_list args)
+  // If we're not attached, attach now.
+  if (result == JNI_EDETACHED) {
+    if (daemon) {
+      jvm->AttachCurrentThreadAsDaemon(JNIENV_CAST(&env), NULL);
+    } else {
+      jvm->AttachCurrentThread(JNIENV_CAST(&env), NULL);
+    }
+    detach = true;
+  }
+}
+
+Jvm::Env::~Env()
 {
-  return env->CallLongMethodV(receiver, id, args);
+  if (detach) {
+    Jvm::get()->jvm->DetachCurrentThread();
+  }
 }
 
 
-template <>
-float Jvm::invokeV<float>(const jobject receiver,
-                          const jmethodID id,
-                          va_list args)
+jstring Jvm::string(const std::string& s)
 {
-  return env->CallFloatMethodV(receiver, id, args);
+  Env env;
+  return env->NewStringUTF(s.c_str());
 }
 
 
-template <>
-double Jvm::invokeV<double>(const jobject receiver,
-                            const jmethodID id,
-                            va_list args)
+Jvm::Constructor Jvm::findConstructor(const ConstructorFinder& finder)
 {
-  return env->CallDoubleMethodV(receiver, id, args);
+  jmethodID id = findMethod(
+      finder.clazz,
+      "<init>",
+      voidClass,
+      finder.parameters,
+      false);
+
+  return Jvm::Constructor(finder.clazz, id);
 }
 
 
-template <>
-void Jvm::invoke<void>(const jobject receiver, const JMethod& method, ...)
+Jvm::Method Jvm::findMethod(const MethodSignature& signature)
 {
-  va_list args;
-  va_start(args, method);
-  invokeV<void>(receiver, method.id, args);
-  va_end(args);
+  jmethodID id = findMethod(
+      signature.clazz,
+      signature.name,
+      signature.returnType,
+      signature.parameters,
+      false);
+
+  return Jvm::Method(signature.clazz, id);
 }
 
 
-template <>
-jobject Jvm::invokeStaticV<jobject>(const JClass& receiver,
-                                    const jmethodID id,
-                                    va_list args)
+Jvm::Method Jvm::findStaticMethod(const MethodSignature& signature)
 {
-  jobject result = env->CallStaticObjectMethodV(findClass(receiver), id, args);
-  CHECK(result != NULL);
-  return result;
+  jmethodID id = findMethod(
+      signature.clazz,
+      signature.name,
+      signature.returnType,
+      signature.parameters,
+      true);
+
+  return Jvm::Method(signature.clazz, id);
 }
 
 
-template<>
-void Jvm::invokeStaticV<void>(const JClass& receiver,
-                              const jmethodID id,
-                              va_list args)
+Jvm::Field Jvm::findStaticField(const Class& clazz, const std::string& name)
 {
-  env->CallStaticVoidMethodV(findClass(receiver), id, args);
+  Env env;
+
+  jfieldID id = env->GetStaticFieldID(
+      findClass(clazz),
+      name.c_str(),
+      clazz.signature().c_str());
+
+  check(env);
+
+  return Jvm::Field(clazz, id);
 }
 
 
-template <>
-bool Jvm::invokeStaticV<bool>(const JClass& receiver,
-                              const jmethodID id,
-                              va_list args)
+jobject Jvm::invoke(const Constructor& ctor, ...)
 {
-  return env->CallStaticBooleanMethodV(findClass(receiver), id, args);
+  Env env;
+  va_list args;
+  va_start(args, ctor);
+  jobject o = env->NewObjectV(findClass(ctor.clazz), ctor.id, args);
+  va_end(args);
+  check(env);
+  return o;
 }
 
 
 template <>
-char Jvm::invokeStaticV<char>(const JClass& receiver,
-                              const jmethodID id,
-                              va_list args)
+jobject Jvm::getStaticField<jobject>(const Field& field)
 {
-  return env->CallStaticCharMethodV(findClass(receiver), id, args);
+  Env env;
+  jobject o = env->GetStaticObjectField(findClass(field.clazz), field.id);
+  check(env);
+  return o;
 }
 
 
 template <>
-short Jvm::invokeStaticV<short>(const JClass& receiver,
-                                const jmethodID id,
-                                va_list args)
+bool Jvm::getStaticField<bool>(const Field& field)
 {
-  return env->CallStaticShortMethodV(findClass(receiver), id, args);
+  Env env;
+  bool b = env->GetStaticBooleanField(findClass(field.clazz), field.id);
+  check(env);
+  return b;
 }
 
 
 template <>
-int Jvm::invokeStaticV<int>(const JClass& receiver,
-                            const jmethodID id,
-                            va_list args)
+char Jvm::getStaticField<char>(const Field& field)
 {
-  return env->CallStaticIntMethodV(findClass(receiver), id, args);
+  Env env;
+  char c = env->GetStaticCharField(findClass(field.clazz), field.id);
+  check(env);
+  return c;
 }
 
 
 template <>
-long Jvm::invokeStaticV<long>(const JClass& receiver,
-                              const jmethodID id,
-                              va_list args)
+short Jvm::getStaticField<short>(const Field& field)
 {
-  return env->CallStaticLongMethodV(findClass(receiver), id, args);
+  Env env;
+  short s = env->GetStaticShortField(findClass(field.clazz), field.id);
+  check(env);
+  return s;
 }
 
 
 template <>
-float Jvm::invokeStaticV<float>(const JClass& receiver,
-                                const jmethodID id,
-                                va_list args)
+int Jvm::getStaticField<int>(const Field& field)
 {
-  return env->CallStaticFloatMethodV(findClass(receiver), id, args);
+  Env env;
+  int i = env->GetStaticIntField(findClass(field.clazz), field.id);
+  check(env);
+  return i;
 }
 
 
 template <>
-double Jvm::invokeStaticV<double>(const JClass& receiver,
-                                  const jmethodID id,
-                                  va_list args)
+long Jvm::getStaticField<long>(const Field& field)
 {
-  return env->CallStaticDoubleMethodV(findClass(receiver), id, args);
+  Env env;
+  long l = env->GetStaticLongField(findClass(field.clazz), field.id);
+  check(env);
+  return l;
 }
 
 
 template <>
-void Jvm::invokeStatic<void>(const JMethod& method, ...)
+float Jvm::getStaticField<float>(const Field& field)
 {
-  va_list args;
-  va_start(args, method);
-  invokeStaticV<void>(method.clazz, method.id, args);
-  va_end(args);
+  Env env;
+  float f = env->GetStaticFloatField(findClass(field.clazz), field.id);
+  check(env);
+  return f;
 }
 
 
-const Jvm::JClass Jvm::JClass::forName(const std::string& nativeName)
+template <>
+double Jvm::getStaticField<double>(const Field& field)
 {
-  return Jvm::JClass(nativeName, false /* not a native type */);
+  Env env;
+  double d = env->GetStaticDoubleField(findClass(field.clazz), field.id);
+  check(env);
+  return d;
 }
 
 
-Jvm::JClass::JClass(const JClass& other) : nativeName(other.nativeName),
-                                           isNative(other.isNative) {}
-
-
-Jvm::JClass::JClass(const std::string& _nativeName,
-                    bool _isNative) : nativeName(_nativeName),
-                                      isNative(_isNative) {}
+Jvm::Jvm(JavaVM* _jvm, JNI::Version _version, bool _exceptions)
+  : voidClass("V"),
+    booleanClass("Z"),
+    byteClass("B"),
+    charClass("C"),
+    shortClass("S"),
+    intClass("I"),
+    longClass("J"),
+    floatClass("F"),
+    doubleClass("D"),
+    stringClass(Class::named("java/lang/String")),
+    jvm(_jvm),
+    version(_version),
+    exceptions(_exceptions) {}
 
 
-const Jvm::JClass Jvm::JClass::arrayOf() const
+Jvm::~Jvm()
 {
-  return Jvm::JClass("[" + nativeName, isNative);
+  LOG(FATAL) << "Destroying the JVM is not supported";
 }
 
 
-Jvm::ConstructorFinder Jvm::JClass::constructor() const
+jobject Jvm::newGlobalRef(const jobject object)
 {
-  return Jvm::ConstructorFinder(*this);
+  Env env;
+  return env->NewGlobalRef(object);
 }
 
 
-Jvm::MethodFinder Jvm::JClass::method(const std::string& name) const
+void Jvm::deleteGlobalRef(const jobject object)
 {
-  return Jvm::MethodFinder(*this, name);
+  Env env;
+  if (object != NULL) {
+    env->DeleteGlobalRef(object);
+  }
 }
 
 
-std::string Jvm::JClass::signature() const
+jclass Jvm::findClass(const Class& clazz)
 {
-  return isNative ? nativeName : "L" + nativeName + ";";
+  Env env;
+
+  // TODO(John Sirois): Consider CHECK_NOTNULL -> return Option if
+  // re-purposing this code outside of tests.
+  return CHECK_NOTNULL(env->FindClass(clazz.name.c_str()));
 }
 
 
-Jvm::JField::JField(const JField& other) : clazz(other.clazz), id(other.id) {}
+jmethodID Jvm::findMethod(
+    const Jvm::Class& clazz,
+    const std::string& name,
+    const Jvm::Class& returnType,
+    const std::vector<Jvm::Class>& argTypes,
+    bool isStatic)
+{
+  Env env;
 
+  std::ostringstream signature;
+  signature << "(";
+  std::vector<Jvm::Class>::iterator args;
+  foreach (const Jvm::Class& type, argTypes) {
+    signature << type.signature();
+  }
+  signature << ")" << returnType.signature();
 
-Jvm::JField::JField(const JClass& _clazz, const jfieldID _id)
-    : clazz(_clazz), id(_id) {}
+  LOG(INFO) << "Looking up" << (isStatic ? " static " : " ")
+            << "method " << name << signature.str();
 
+  jmethodID id = isStatic
+    ? env->GetStaticMethodID(
+        findClass(clazz),
+        name.c_str(),
+        signature.str().c_str())
+    : env->GetMethodID(
+        findClass(clazz),
+        name.c_str(),
+        signature.str().c_str());
 
-Jvm::JField Jvm::findStaticField(const JClass& clazz, const std::string& name)
-{
-  jfieldID id =
-      env->GetStaticFieldID(findClass(clazz),
-                            name.c_str(),
-                            clazz.signature().c_str());
-  return Jvm::JField(clazz, id);
+  // TODO(John Sirois): Consider CHECK_NOTNULL -> return Option if
+  // re-purposing this code outside of tests.
+  return CHECK_NOTNULL(id);
 }
 
 
-template <>
-jobject Jvm::getStaticField<jobject>(const JField& field)
+template<>
+void Jvm::invokeV<void>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  jobject result = env->GetStaticObjectField(findClass(field.clazz), field.id);
-  CHECK(result != NULL);
-  return result;
+  Env env;
+  env->CallVoidMethodV(receiver, id, args);
+  check(env);
 }
 
 
 template <>
-bool Jvm::getStaticField<bool>(const JField& field)
+jobject Jvm::invokeV<jobject>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticBooleanField(findClass(field.clazz), field.id);
+  Env env;
+  jobject o = env->CallObjectMethodV(receiver, id, args);
+  check(env);
+  return o;
 }
 
 
 template <>
-char Jvm::getStaticField<char>(const JField& field)
+bool Jvm::invokeV<bool>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticCharField(findClass(field.clazz), field.id);
+  Env env;
+  bool b = env->CallBooleanMethodV(receiver, id, args);
+  check(env);
+  return b;
 }
 
 
 template <>
-short Jvm::getStaticField<short>(const JField& field)
+char Jvm::invokeV<char>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticShortField(findClass(field.clazz), field.id);
+  Env env;
+  char c = env->CallCharMethodV(receiver, id, args);
+  check(env);
+  return c;
 }
 
 
 template <>
-int Jvm::getStaticField<int>(const JField& field)
+short Jvm::invokeV<short>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticIntField(findClass(field.clazz), field.id);
+  Env env;
+  short s = env->CallShortMethodV(receiver, id, args);
+  check(env);
+  return s;
 }
 
 
 template <>
-long Jvm::getStaticField<long>(const JField& field)
+int Jvm::invokeV<int>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticLongField(findClass(field.clazz), field.id);
+  Env env;
+  int i = env->CallIntMethodV(receiver, id, args);
+  check(env);
+  return i;
 }
 
 
 template <>
-float Jvm::getStaticField<float>(const JField& field)
+long Jvm::invokeV<long>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticFloatField(findClass(field.clazz), field.id);
+  Env env;
+  long l = env->CallLongMethodV(receiver, id, args);
+  check(env);
+  return l;
 }
 
 
 template <>
-double Jvm::getStaticField<double>(const JField& field)
+float Jvm::invokeV<float>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->GetStaticDoubleField(findClass(field.clazz), field.id);
+  Env env;
+  float f = env->CallFloatMethodV(receiver, id, args);
+  check(env);
+  return f;
 }
 
 
-Jvm::Jvm(const std::vector<std::string>& options, JNIVersion jniVersion)
-  : voidClass("V"),
-    booleanClass("Z"),
-    byteClass("B"),
-    charClass("C"),
-    shortClass("S"),
-    intClass("I"),
-    longClass("J"),
-    floatClass("F"),
-    doubleClass("D"),
-    stringClass(JClass::forName("java/lang/String")),
-    jvm(NULL),
-    env(NULL)
+template <>
+double Jvm::invokeV<double>(
+    const jobject receiver,
+    const jmethodID id,
+    va_list args)
 {
-  JavaVMInitArgs vmArgs;
-  vmArgs.version = jniVersion;
-  vmArgs.ignoreUnrecognized = false;
-
-  JavaVMOption* opts = new JavaVMOption[options.size()];
-  for (size_t i = 0; i < options.size(); i++) {
-    opts[i].optionString = const_cast<char*>(options[i].c_str());
-  }
-  vmArgs.nOptions = options.size();
-  vmArgs.options = opts;
-
-  int result = JNI_CreateJavaVM(&jvm, JNIENV_CAST(&env), &vmArgs);
-  CHECK(result != JNI_ERR) << "Failed to create JVM!";
-
-  delete[] opts;
+  Env env;
+  double d = env->CallDoubleMethodV(receiver, id, args);
+  check(env);
+  return d;
 }
 
 
-Jvm::~Jvm()
+template<>
+void Jvm::invokeStaticV<void>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  CHECK(0 == jvm->DestroyJavaVM()) << "Failed to destroy JVM";
+  Env env;
+  env->CallStaticVoidMethodV(findClass(receiver), id, args);
+  check(env);
 }
 
 
-void Jvm::attachDaemon()
+template <>
+jobject Jvm::invokeStaticV<jobject>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  jvm->AttachCurrentThreadAsDaemon(JNIENV_CAST(&env), NULL);
+  Env env;
+  jobject o = env->CallStaticObjectMethodV(findClass(receiver), id, args);
+  check(env);
+  return o;
 }
 
 
-void Jvm::attach()
+template <>
+bool Jvm::invokeStaticV<bool>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  jvm->AttachCurrentThread(JNIENV_CAST(&env), NULL);
+  Env env;
+  bool b = env->CallStaticBooleanMethodV(findClass(receiver), id, args);
+  check(env);
+  return b;
 }
 
 
-void Jvm::detach()
+template <>
+char Jvm::invokeStaticV<char>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  jvm->DetachCurrentThread();
+  Env env;
+  char c = env->CallStaticCharMethodV(findClass(receiver), id, args);
+  check(env);
+  return c;
 }
 
 
-jclass Jvm::findClass(const JClass& clazz)
+template <>
+short Jvm::invokeStaticV<short>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  jclass cls = env->FindClass(clazz.nativeName.c_str());
-  // TODO(John Sirois): consider CHECK -> return Option if re-purposing this
-  // code outside of tests.
-  CHECK(cls != NULL);
-  return cls;
+  Env env;
+  short s = env->CallStaticShortMethodV(findClass(receiver), id, args);
+  check(env);
+  return s;
 }
 
 
-jobject Jvm::string(const std::string& str)
+template <>
+int Jvm::invokeStaticV<int>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->NewStringUTF(str.c_str());
+  Env env;
+  int i = env->CallStaticIntMethodV(findClass(receiver), id, args);
+  check(env);
+  return i;
 }
 
 
-jobject Jvm::newGlobalRef(const jobject object)
+template <>
+long Jvm::invokeStaticV<long>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  return env->NewGlobalRef(object);
+  Env env;
+  long l = env->CallStaticLongMethodV(findClass(receiver), id, args);
+  check(env);
+  return l;
 }
 
 
-void Jvm::deleteGlobalRef(const jobject object)
+template <>
+float Jvm::invokeStaticV<float>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
 {
-  env->DeleteGlobalRef(object);
+  Env env;
+  float f = env->CallStaticFloatMethodV(findClass(receiver), id, args);
+  check(env);
+  return f;
 }
 
 
-void Jvm::deleteGlobalRefSafe(const jobject object)
-{
-  if (object != NULL) {
-    deleteGlobalRef(object);
+template <>
+double Jvm::invokeStaticV<double>(
+    const Class& receiver,
+    const jmethodID id,
+    va_list args)
+{
+  Env env;
+  double d = env->CallStaticDoubleMethodV(findClass(receiver), id, args);
+  check(env);
+  return d;
+}
+
+
+void Jvm::check(JNIEnv* env)
+{
+  if (env->ExceptionCheck() == JNI_TRUE) {
+    if (!exceptions) {
+      env->ExceptionDescribe();
+      EXIT(1) << "Caught a JVM exception, not propagating";
+    } else {
+      java::lang::Throwable throwable;
+      Object* object = &throwable;
+      object->object = env->ExceptionOccurred();
+      env->ExceptionClear();
+      throw throwable;
+    }
   }
 }
 
-Jvm::Attach::Attach(Jvm* jvm, bool daemon) : _jvm(jvm)
+
+// N.B. Both Jvm::invoke<void> and Jvm::invokeStatic<void> template
+// instantiations need to be defined AFTER template instantions that
+// they use (i.e., Jvm::invokeV<void>, Jvm::invokeStaticV<void>).
+
+template <>
+void Jvm::invoke<void>(const jobject receiver, const Method& method, ...)
 {
-  if (daemon) {
-    _jvm->attachDaemon();
-  } else {
-    _jvm->attach();
-  }
+  va_list args;
+  va_start(args, method);
+  invokeV<void>(receiver, method.id, args);
+  va_end(args);
 }
 
 
-Jvm::Attach::~Attach()
+template <>
+void Jvm::invokeStatic<void>(const Method& method, ...)
 {
-  // TODO(John Sirois): this detaches too early under nested use, attach by a
-  // given thread should incr, this should decr and only detach on 0
-  _jvm->detach();
+  va_list args;
+  va_start(args, method);
+  invokeStaticV<void>(method.clazz, method.id, args);
+  va_end(args);
 }
-
-} // namespace internal
-} // namespace mesos

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/jvm.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/jvm.hpp b/src/jvm/jvm.hpp
index 6a31bd8..a3ea86a 100644
--- a/src/jvm/jvm.hpp
+++ b/src/jvm/jvm.hpp
@@ -3,10 +3,13 @@
 
 #include <jni.h>
 
-#include <glog/logging.h>
-
+#include <string>
 #include <vector>
 
+#include <stout/error.hpp>
+#include <stout/try.hpp>
+
+
 // Some compilers give us warnings about 'dereferencing type-punned
 // pointer will break strict-aliasing rules' when we cast our JNIEnv**
 // to void**. We use this function to do the magic for us.
@@ -16,118 +19,149 @@ inline void** JNIENV_CAST(JNIEnv** env)
 }
 
 
-namespace mesos {
-namespace internal {
+struct JNI
+{
+  enum Version
+  {
+    v_1_1 = JNI_VERSION_1_1,
+    v_1_2 = JNI_VERSION_1_2,
+    v_1_4 = JNI_VERSION_1_4,
+    v_1_6 = JNI_VERSION_1_6
+  };
+};
 
-// Facilitates embedding a jvm and calling into it.
-//
-// TODO(John Sirois): Fix variadic methods.  Possibly a way to do this with
-// typelists, type concatenation and unwinding builder inheritance.
-//
-// TODO(John Sirois): Support finding static methods.
+// Facilitates embedding a JVM and calling into it.
 class Jvm
 {
 public:
   // Forward declarations.
   class ConstructorFinder;
   class MethodFinder;
-  class JConstructor;
+  class Constructor;
   class MethodSignature;
-  class JMethod;
-
-  // An opaque class descriptor that can be used to find constructors, methods
-  // and fields.
-  class JClass
+  class Method;
+
+  // Starts a new embedded JVM with the given -D options. Each option
+  // supplied should be of the standard form: '-Dproperty=value'.
+  // Returns the singleton Jvm instance or an error if the JVM had
+  // already been created. Note that you can only create one JVM
+  // instance per process since destructing a JVM has issues, see:
+  // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4712793.  In
+  // addition, most JVM's use signals and couldn't possibly play
+  // nicely with one another.
+  // TODO(benh): Add a 'create' which just takes an already
+  // constructed JavaVM. This will be useful for when a JVM is calling
+  // into native code versus native code embedding a JVM.
+  // TODO(John Sirois): Consider elevating classpath as a top-level
+  // JVM configuration parameter since it will likely always need to
+  // be specified. Ditto for and non '-X' options.
+  static Try<Jvm*> create(
+      const std::vector<std::string>& options = std::vector<std::string>(),
+      JNI::Version version = JNI::v_1_6,
+      bool exceptions = false);
+
+  // Returns true if the JVM has already been created.
+  static bool created();
+
+  // Returns the singleton JVM instance, creating it with no options
+  // and a default version if necessary.
+  static Jvm* get();
+
+  // An opaque class descriptor that can be used to find constructors,
+  // methods and fields.
+  class Class
   {
   public:
-    // A factory for new java reference type class descriptors given the native
-    // name.  To obtain class descriptors for native types, use the fields in
-    // Jvm.
-    static const JClass forName(const std::string& nativeName);
+    // A factory for new Java reference type class descriptors given
+    // the fully-qualified class name (e.g., 'java/io/File'). To
+    // obtain class descriptors for native types (int, short, etc),
+    // use the fields in Jvm.
+    static const Class named(const std::string& name);
 
-    JClass(const JClass& other);
+    Class(const Class& that);
 
     // Returns the class of an array of the current class.
-    const JClass arrayOf() const;
+    const Class arrayOf() const;
 
-    // Creates a builder that can be used to locate a constructor of this
-    // class with Jvm::findConstructor.
+    // Creates a builder that can be used to locate a constructor of
+    // this class with Jvm::findConstructor.
     ConstructorFinder constructor() const;
 
-    // Creates a builder that can be used to locate an instance method of this
-    // class with Jvm::findMethod.
+    // Creates a builder that can be used to locate an instance method
+    // of this class with Jvm::findMethod.
     MethodFinder method(const std::string& name) const;
 
   private:
     friend class Jvm;
 
-    JClass(const std::string& nativeName,
-           bool isNative = true);
+    Class(const std::string& name, bool native = true);
 
     std::string signature() const;
 
-    std::string nativeName;
-    bool isNative;
+    std::string name;
+    bool native;
   };
 
 
-  // A builder that is used to specify a constructor by specifying its parameter
-  // list with zero or more calls to ConstructorFinder::parameter.
+  // A builder that is used to specify a constructor by specifying its
+  // parameter list with zero or more calls to
+  // ConstructorFinder::parameter.
   class ConstructorFinder
   {
   public:
     // Adds a parameter to the constructor parameter list.
-    ConstructorFinder& parameter(const JClass& type);
+    ConstructorFinder& parameter(const Class& clazz);
 
   private:
-    friend class JClass;
+    friend class Class;
     friend class Jvm;
 
-    ConstructorFinder(const JClass& type);
+    ConstructorFinder(const Class& clazz);
 
-    const JClass type;
-    std::vector<JClass> parameters;
+    const Class clazz;
+    std::vector<Class> parameters;
   };
 
 
-  // An opaque constructor descriptor that can be used to create new instances
-  // of a class using Jvm::invokeConstructor.
-  class JConstructor
+  // An opaque constructor descriptor that can be used to create new
+  // instances of a class using Jvm::invokeConstructor.
+  class Constructor
   {
   public:
-    JConstructor(const JConstructor& other);
+    Constructor(const Constructor& that);
 
   private:
     friend class Jvm;
 
-    JConstructor(const JClass& clazz, const jmethodID id);
+    Constructor(const Class& clazz, const jmethodID id);
 
-    const JClass clazz;
+    const Class clazz;
     const jmethodID id;
   };
 
 
-  // A builder that is used to specify an instance method by specifying its
-  // parameter list with zero or more calls to MethodFinder::parameter and a
-  // final call to MethodFinder::returns to get an opaque specification of the
-  // method for use with Jvm::findMethod.
+  // A builder that is used to specify an instance method by
+  // specifying its parameter list with zero or more calls to
+  // MethodFinder::parameter and a final call to MethodFinder::returns
+  // to get an opaque specification of the method for use with
+  // Jvm::findMethod.
   class MethodFinder
   {
   public:
     // Adds a parameter to the method parameter list.
-    MethodFinder& parameter(const JClass& type);
+    MethodFinder& parameter(const Class& type);
 
     // Terminates description of a method by specifying its return type.
-    MethodSignature returns(const JClass& type) const;
+    MethodSignature returns(const Class& type) const;
 
   private:
-    friend class JClass;
+    friend class Class;
 
-    MethodFinder(const JClass& clazz, const std::string& name);
+    MethodFinder(const Class& clazz, const std::string& name);
 
-    const JClass clazz;
+    const Class clazz;
     const std::string name;
-    std::vector<JClass> parameters;
+    std::vector<Class> parameters;
   };
 
 
@@ -135,153 +169,237 @@ public:
   class MethodSignature
   {
   public:
-    MethodSignature(const MethodSignature& other);
+    MethodSignature(const MethodSignature& that);
 
   private:
     friend class Jvm;
     friend class MethodFinder;
 
-    MethodSignature(const JClass& clazz,
+    MethodSignature(const Class& clazz,
                     const std::string& name,
-                    const JClass& returnType,
-                    const std::vector<JClass>& parameters);
+                    const Class& returnType,
+                    const std::vector<Class>& parameters);
 
-    const JClass clazz;
+    const Class clazz;
     const std::string name;
-    const JClass returnType;
-    std::vector<JClass> parameters;
+    const Class returnType;
+    std::vector<Class> parameters;
   };
 
 
   // An opaque method descriptor that can be used to invoke instance methods
   // using Jvm::invokeMethod.
-  class JMethod
+  class Method
   {
   public:
-    JMethod(const JMethod& other);
+    Method(const Method& that);
 
   private:
     friend class Jvm;
     friend class MethodSignature;
 
-    JMethod(const JClass& clazz, const jmethodID id);
+    Method(const Class& clazz, const jmethodID id);
 
-    const JClass clazz;
+    const Class clazz;
     const jmethodID id;
   };
 
 
   // An opaque field descriptor that can be used to access fields using
   // methods like Jvm::getStaticField.
-  class JField
+  class Field
   {
   public:
-    JField(const JField& other);
+    Field(const Field& that);
 
   private:
     friend class Jvm;
 
-    JField(const JClass& clazz, const jfieldID id);
+    Field(const Class& clazz, const jfieldID id);
 
-    const JClass clazz;
+    const Class clazz;
     const jfieldID id;
   };
 
 
-  // RAII container for c++/jvm thread binding management.
-  class Attach
+  // Base class for all JVM objects. This object "stores" the
+  // underlying global reference and performs the appropriate
+  // operations across copies and assignments.
+  class Object
   {
   public:
-    Attach(Jvm* jvm, bool daemon = true);
-    ~Attach();
+    Object() : object(NULL) {}
+
+    Object(jobject _object)
+      : object(Jvm::get()->newGlobalRef(_object)) {}
+
+    Object(const Object& that)
+    {
+      object = Jvm::get()->newGlobalRef(that.object);
+    }
+
+    ~Object()
+    {
+      if (object != NULL) {
+        Jvm::get()->deleteGlobalRef(object);
+      }
+    }
+
+    Object& operator = (const Object& that)
+    {
+      if (object != NULL) {
+        Jvm::get()->deleteGlobalRef(object);
+      }
+      object = Jvm::get()->newGlobalRef(that.object);
+      return *this;
+    }
+
+    operator jobject () const
+    {
+      return object;
+    }
+
+  protected:
+    friend class Jvm; // For manipulating object.
+
+    jobject object;
+  };
+
+  // Helper for providing access to static variables in a class. You
+  // can use this to delay the variable lookup until it's actually
+  // accessed in order to keep the JVM from getting constructed too
+  // early. See Level in jvm/org/apache/log4j.hpp for an example.
+  // TODO(benh): Make this work for instance variables too (i.e.,
+  // StaticVariable -> Variable).
+  // TODO(benh): Provide template specialization for primitive
+  // types (e.g., StaticVariable<int>, StaticVariable<short>,
+  // StaticVariable<std::string>).
+  template <typename T, const char* name>
+  class StaticVariable
+  {
+  public:
+    StaticVariable(const Class& _clazz)
+      : clazz(_clazz)
+    {
+      // Check that T extends Object.
+      { T* t = NULL; Object* o = t; (void) o; }
+    }
+
+    operator T () const
+    {
+      // Note that we actually look up the field lazily (upon first
+      // invocation operator) so that we don't possibly create the JVM
+      // too early.
+      static Field field = Jvm::get()->findStaticField(clazz, name);
+      T t;
+      t.object = Jvm::get()->getStaticField<jobject>(field);
+      return t;
+    }
 
   private:
-    Jvm* _jvm;
+    const Class clazz;
   };
 
-  friend class Attach;
-
-  enum JNIVersion
+  // Each thread that wants to interact with the JVM needs a JNI
+  // environment which must be obtained by "attaching" to the JVM. We
+  // use the following RAII class to provide the environment and also
+  // make sure a thread is attached and properly detached. Note that
+  // nested constructions are no-ops and use the same environment (and
+  // without detaching too early).
+  // TODO(benh): Support putting a 'Jvm::Env' into a thread-local
+  // variable so we can "attach" to the JVM once.
+  class Env
   {
-    v_1_1 = JNI_VERSION_1_1,
-    v_1_2 = JNI_VERSION_1_2,
-    v_1_4 = JNI_VERSION_1_4,
-    v_1_6 = JNI_VERSION_1_6
+  public:
+    Env(bool daemon = true);
+    ~Env();
+
+    JNIEnv* operator -> () const { return env; }
+
+    operator JNIEnv* () const { return env; }
+
+  private:
+    JNIEnv* env;
+    bool detach; // A nested use of Env should not detach the thread.
   };
 
-  // Starts a new embedded jvm with the given -D options.  Each option supplied
-  // should be of the standard form: '-Dproperty=value'.
-  //
-  // TODO(John Sirois): Consider elevating classpath as a top level jvm
-  // configuration parameter since it will likely always need to be specified.
-  // Ditto for and non -X java option.
-  Jvm(const std::vector<std::string>& options,
-      JNIVersion jniVersion = Jvm::v_1_6);
-  ~Jvm();
+  friend class Env;
 
-  const JClass voidClass;
-  const JClass booleanClass;
-  const JClass byteClass;
-  const JClass charClass;
-  const JClass shortClass;
-  const JClass intClass;
-  const JClass longClass;
-  const JClass floatClass;
-  const JClass doubleClass;
-  const JClass stringClass;
+  const Class voidClass;
+  const Class booleanClass;
+  const Class byteClass;
+  const Class charClass;
+  const Class shortClass;
+  const Class intClass;
+  const Class longClass;
+  const Class floatClass;
+  const Class doubleClass;
+  const Class stringClass;
 
-  jobject string(const std::string& str);
+  jstring string(const std::string& s);
 
-  JConstructor findConstructor(const ConstructorFinder& constructor);
-  JMethod findMethod(const MethodSignature& signature);
-  JMethod findStaticMethod(const MethodSignature& signature);
-  JField findStaticField(const JClass& clazz, const std::string& name);
+  Constructor findConstructor(const ConstructorFinder& finder);
+  Method findMethod(const MethodSignature& signature);
+  Method findStaticMethod(const MethodSignature& signature);
+  Field findStaticField(const Class& clazz, const std::string& name);
 
-  jobject invoke(const JConstructor& ctor, ...);
+  // TODO(John Sirois): Add "type checking" to variadic method
+  // calls. Possibly a way to do this with typelists, type
+  // concatenation and unwinding builder inheritance.
+
+  jobject invoke(const Constructor& ctor, ...);
 
   template <typename T>
-  T invoke(const jobject receiver, const JMethod& method, ...);
+  T invoke(const jobject receiver, const Method& method, ...);
 
   template <typename T>
-  T invokeStatic(const JMethod& method, ...);
+  T invokeStatic(const Method& method, ...);
 
   template <typename T>
-  T getStaticField(const JField& field);
+  T getStaticField(const Field& field);
+
+  // Checks the exception state of an environment.
+  void check(JNIEnv* env);
 
+private:
+  friend class Object; // For creating global references.
+
+  Jvm(JavaVM* jvm, JNI::Version version, bool exceptions);
+  ~Jvm();
+
+private:
   jobject newGlobalRef(const jobject object);
   void deleteGlobalRef(const jobject object);
-  void deleteGlobalRefSafe(const jobject object);
 
-private:
-  jclass findClass(const JClass& clazz);
+  jclass findClass(const Class& clazz);
 
-  jmethodID findMethod(const Jvm::JClass& clazz,
+  jmethodID findMethod(const Jvm::Class& clazz,
                        const std::string& name,
-                       const Jvm::JClass& returnType,
-                       const std::vector<Jvm::JClass> argTypes,
+                       const Jvm::Class& returnType,
+                       const std::vector<Jvm::Class>& argTypes,
                        bool isStatic);
 
   template <typename T>
   T invokeV(const jobject receiver, const jmethodID id, va_list args);
 
   template <typename T>
-  T invokeStaticV(const JClass& receiver, const jmethodID id, va_list args);
+  T invokeStaticV(const Class& receiver, const jmethodID id, va_list args);
 
-  void attachDaemon();
-  void attach();
-  void detach();
+  // Singleton instance.
+  static Jvm* instance;
 
   JavaVM* jvm;
-  JNIEnv* env;
+  const JNI::Version version;
+  const bool exceptions;
 };
 
 
 template <>
-void Jvm::invoke<void>(const jobject receiver, const JMethod& method, ...);
+void Jvm::invoke<void>(const jobject receiver, const Method& method, ...);
 
 
 template <typename T>
-T Jvm::invoke(const jobject receiver, const JMethod& method, ...)
+T Jvm::invoke(const jobject receiver, const Method& method, ...)
 {
   va_list args;
   va_start(args, method);
@@ -292,11 +410,11 @@ T Jvm::invoke(const jobject receiver, const JMethod& method, ...)
 
 
 template <>
-void Jvm::invokeStatic<void>(const JMethod& method, ...);
+void Jvm::invokeStatic<void>(const Method& method, ...);
 
 
 template <typename T>
-T Jvm::invokeStatic(const JMethod& method, ...)
+T Jvm::invokeStatic(const Method& method, ...)
 {
   va_list args;
   va_start(args, method);
@@ -305,7 +423,4 @@ T Jvm::invokeStatic(const JMethod& method, ...)
   return result;
 }
 
-} // namespace internal
-} // namespace mesos
-
 #endif // __JVM_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/org/apache/log4j.cpp
----------------------------------------------------------------------
diff --git a/src/jvm/org/apache/log4j.cpp b/src/jvm/org/apache/log4j.cpp
new file mode 100644
index 0000000..b73df8c
--- /dev/null
+++ b/src/jvm/org/apache/log4j.cpp
@@ -0,0 +1,16 @@
+#include <jvm/org/apache/log4j.hpp>
+
+namespace org {
+namespace apache {
+namespace log4j {
+
+// Static storage and initialization.
+const char LEVEL_OFF[] = "OFF";
+
+Jvm::StaticVariable<Level, LEVEL_OFF> Level::OFF =
+  Jvm::StaticVariable<Level, LEVEL_OFF>(
+      Jvm::Class::named("org/apache/log4j/Level"));
+
+} // namespace log4j {
+} // namespace apache {
+} // namespace org {

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/org/apache/log4j.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/org/apache/log4j.hpp b/src/jvm/org/apache/log4j.hpp
new file mode 100644
index 0000000..6b5ba4b
--- /dev/null
+++ b/src/jvm/org/apache/log4j.hpp
@@ -0,0 +1,69 @@
+#ifndef __ORG_APACHE_LOG4J_HPP__
+#define __ORG_APACHE_LOG4J_HPP__
+
+#include <jvm/jvm.hpp>
+
+namespace org {
+namespace apache {
+namespace log4j {
+
+// Forward declaration.
+extern const char LEVEL_OFF[];
+
+
+class Level : public Jvm::Object // TODO(benh): Extends Priority.
+{
+public:
+  friend class Jvm::StaticVariable<Level, LEVEL_OFF>;
+
+  static Jvm::StaticVariable<Level, LEVEL_OFF> OFF;
+
+  Level() {} // No default constuctors.
+};
+
+
+class Category : public Jvm::Object
+{
+public:
+  void setLevel(const Level& level)
+  {
+    static Jvm::Method method = Jvm::get()->findMethod(
+        Jvm::Class::named("org/apache/log4j/Category")
+        .method("setLevel")
+        .parameter(Jvm::Class::named("org/apache/log4j/Level"))
+        .returns(Jvm::get()->voidClass));
+
+    Jvm::get()->invoke<void>(object, method, (jobject) level);
+  }
+
+protected:
+  Category() {} // No default constructors.
+};
+
+
+class Logger : public Category
+{
+public:
+  static Logger getRootLogger()
+  {
+    static Jvm::Method method = Jvm::get()->findStaticMethod(
+        Jvm::Class::named("org/apache/log4j/Logger")
+        .method("getRootLogger")
+        .returns(Jvm::Class::named("org/apache/log4j/Logger")));
+
+    Logger logger;
+    logger.object = Jvm::get()->invokeStatic<jobject>(method);
+
+    return logger;
+  }
+
+protected:
+  Logger() {} // No default constructors.
+};
+
+
+} // namespace log4j {
+} // namespace apache {
+} // namespace org {
+
+#endif // __ORG_APACHE_LOG4J_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/jvm/org/apache/zookeeper.hpp
----------------------------------------------------------------------
diff --git a/src/jvm/org/apache/zookeeper.hpp b/src/jvm/org/apache/zookeeper.hpp
new file mode 100644
index 0000000..dac1456
--- /dev/null
+++ b/src/jvm/org/apache/zookeeper.hpp
@@ -0,0 +1,168 @@
+#ifndef __ORG_APACHE_ZOOKEEPER_HPP__
+#define __ORG_APACHE_ZOOKEEPER_HPP__
+
+#include <jvm/jvm.hpp>
+
+#include <jvm/java/io.hpp>
+#include <jvm/java/net.hpp>
+
+// Package 'org.apache.zookeeper.persistence'.
+
+namespace org {
+namespace apache {
+namespace zookeeper {
+namespace persistence {
+
+class FileTxnSnapLog : public Jvm::Object
+{
+public:
+  FileTxnSnapLog(const java::io::File& dataDir,
+                 const java::io::File& snapDir)
+  {
+    static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+        Jvm::Class::named(
+            "org/apache/zookeeper/server/persistence/FileTxnSnapLog")
+        .constructor()
+        .parameter(Jvm::Class::named("java/io/File"))
+        .parameter(Jvm::Class::named("java/io/File")));
+
+    object = Jvm::get()->invoke(
+        constructor, (jobject) dataDir, (jobject) snapDir);
+  }
+};
+
+} // namespace persistence {
+} // namespace zookeeper {
+} // namespace apache {
+} // namespace org {
+
+
+// Package 'org.apache.zookeeper.server'.
+
+namespace org {
+namespace apache {
+namespace zookeeper {
+namespace server {
+
+class ZooKeeperServer : public Jvm::Object
+{
+public:
+  class DataTreeBuilder : public Jvm::Object {};
+
+  class BasicDataTreeBuilder : public DataTreeBuilder
+  {
+  public:
+    BasicDataTreeBuilder()
+    {
+      static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+          Jvm::Class::named(
+              "org/apache/zookeeper/server/ZooKeeperServer$BasicDataTreeBuilder")
+          .constructor());
+
+      object = Jvm::get()->invoke(constructor);
+    }
+  };
+
+  ZooKeeperServer(const persistence::FileTxnSnapLog& txnLogFactory,
+                  const DataTreeBuilder& treeBuilder)
+  {
+    static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+        Jvm::Class::named("org/apache/zookeeper/server/ZooKeeperServer")
+        .constructor()
+        .parameter(
+            Jvm::Class::named(
+                "org/apache/zookeeper/server/persistence/FileTxnSnapLog"))
+        .parameter(
+            Jvm::Class::named(
+                "org/apache/zookeeper/server/ZooKeeperServer$DataTreeBuilder")));
+
+    object = Jvm::get()->invoke(
+        constructor, (jobject) txnLogFactory, (jobject) treeBuilder);
+  }
+
+  int getClientPort()
+  {
+    static Jvm::Method method = Jvm::get()->findMethod(
+        Jvm::Class::named("org/apache/zookeeper/server/ZooKeeperServer")
+        .method("getClientPort")
+        .returns(Jvm::get()->intClass));
+
+    return Jvm::get()->invoke<int>(object, method);
+  }
+
+  void closeSession(int64_t sessionId)
+  {
+    static Jvm::Method method = Jvm::get()->findMethod(
+        Jvm::Class::named("org/apache/zookeeper/server/ZooKeeperServer")
+        .method("closeSession")
+        .parameter(Jvm::get()->longClass)
+        .returns(Jvm::get()->voidClass));
+
+    Jvm::get()->invoke<void>(object, method, sessionId);
+  }
+};
+
+
+class NIOServerCnxn : public Jvm::Object
+{
+public:
+  class Factory : public Jvm::Object // TODO(benh): Extends Thread.
+  {
+  public:
+    Factory(const java::net::InetSocketAddress& addr)
+    {
+      static Jvm::Constructor constructor = Jvm::get()->findConstructor(
+          Jvm::Class::named(
+              "org/apache/zookeeper/server/NIOServerCnxn$Factory")
+          .constructor()
+          .parameter(Jvm::Class::named("java/net/InetSocketAddress")));
+
+      object = Jvm::get()->invoke(constructor, (jobject) addr);
+    }
+
+    void startup(const ZooKeeperServer& zks)
+    {
+      static Jvm::Method method = Jvm::get()->findMethod(
+          Jvm::Class::named(
+              "org/apache/zookeeper/server/NIOServerCnxn$Factory")
+          .method("startup")
+          .parameter(Jvm::Class::named(
+                         "org/apache/zookeeper/server/ZooKeeperServer"))
+          .returns(Jvm::get()->voidClass));
+
+      Jvm::get()->invoke<void>(object, method, (jobject) zks);
+    }
+
+    bool isAlive()
+    {
+      static Jvm::Method method = Jvm::get()->findMethod(
+          Jvm::Class::named(
+              "org/apache/zookeeper/server/NIOServerCnxn$Factory")
+          .method("isAlive")
+          .returns(Jvm::get()->booleanClass));
+
+      return Jvm::get()->invoke<bool>(object, method);
+    }
+
+    void shutdown()
+    {
+      static Jvm::Method method = Jvm::get()->findMethod(
+          Jvm::Class::named(
+              "org/apache/zookeeper/server/NIOServerCnxn$Factory")
+          .method("shutdown")
+          .returns(Jvm::get()->voidClass));
+
+      Jvm::get()->invoke<void>(object, method);
+    }
+  };
+
+private:
+  NIOServerCnxn() {} // No default constructors.
+};
+
+} // namespace server {
+} // namespace zookeeper {
+} // namespace apache {
+} // namespace org {
+
+#endif // __ORG_APACHE_ZOOKEEPER_HPP__

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/tests/zookeeper_test.cpp
----------------------------------------------------------------------
diff --git a/src/tests/zookeeper_test.cpp b/src/tests/zookeeper_test.cpp
index fb61f2d..90c6aba 100644
--- a/src/tests/zookeeper_test.cpp
+++ b/src/tests/zookeeper_test.cpp
@@ -24,14 +24,17 @@
 
 #include <tr1/functional>
 
+#include <jvm/jvm.hpp>
+
+#include <jvm/org/apache/log4j.hpp>
+#include <jvm/org/apache/log4j.hpp>
+
 #include <stout/lambda.hpp>
 
 #include "common/lock.hpp"
 
 #include "logging/logging.hpp"
 
-#include "jvm/jvm.hpp"
-
 #include "tests/utils.hpp"
 #include "tests/zookeeper_test.hpp"
 #include "tests/zookeeper_test_server.hpp"
@@ -40,45 +43,12 @@ namespace mesos {
 namespace internal {
 namespace tests {
 
-const Milliseconds ZooKeeperTest::NO_TIMEOUT(5000);
-
-// Note that we NEVER delete the Jvm instance because you can only
-// create one JVM since destructing a JVM has issues (see:
-// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4712793).
-Jvm* ZooKeeperTest::jvm = NULL;
-
-
-static void silenceServerLogs(Jvm* jvm)
-{
-  Jvm::Attach attach(jvm);
-
-  Jvm::JClass loggerClass = Jvm::JClass::forName("org/apache/log4j/Logger");
-  jobject rootLogger =jvm->invokeStatic<jobject>(
-      jvm->findStaticMethod(loggerClass
-                            .method("getRootLogger")
-                            .returns(loggerClass)));
-
-  Jvm::JClass levelClass = Jvm::JClass::forName("org/apache/log4j/Level");
-  jvm->invoke<void>(
-      rootLogger,
-      jvm->findMethod(loggerClass
-                      .method("setLevel")
-                      .parameter(levelClass)
-                      .returns(jvm->voidClass)),
-      jvm->getStaticField<jobject>(jvm->findStaticField(levelClass, "OFF")));
-}
-
-
-static void silenceClientLogs()
-{
-  // TODO(jsirois): Put this in the C++ API.
-  zoo_set_debug_level(ZOO_LOG_LEVEL_ERROR);
-}
+const Duration ZooKeeperTest::NO_TIMEOUT = Milliseconds(5000);
 
 
 void ZooKeeperTest::SetUpTestCase()
 {
-  if (jvm == NULL) {
+  if (!Jvm::created()) {
     std::string zkHome = flags.build_dir +
       "/third_party/zookeeper-" ZOOKEEPER_VERSION;
 
@@ -88,13 +58,19 @@ void ZooKeeperTest::SetUpTestCase()
 
     LOG(INFO) << "Using classpath setup: " << classpath << std::endl;
 
-    std::vector<std::string> opts;
-    opts.push_back(classpath);
-    jvm = new Jvm(opts);
+    std::vector<std::string> options;
+    options.push_back(classpath);
+    Try<Jvm*> jvm = Jvm::create(options);
+    CHECK_SOME(jvm);
 
     if (!flags.verbose) {
-      silenceServerLogs(jvm);
-      silenceClientLogs();
+      // Silence server logs.
+      org::apache::log4j::Logger::getRootLogger()
+        .setLevel(org::apache::log4j::Level::OFF);
+
+      // Silence client logs.
+      // TODO(jsirois): Create C++ ZooKeeper::setLevel.
+      zoo_set_debug_level(ZOO_LOG_LEVEL_ERROR);
     }
   }
 }
@@ -102,18 +78,8 @@ void ZooKeeperTest::SetUpTestCase()
 
 void ZooKeeperTest::SetUp()
 {
-  MesosTest::SetUp();
-  server = new ZooKeeperTestServer(jvm);
   server->startNetwork();
-};
-
-
-void ZooKeeperTest::TearDown()
-{
-  delete server;
-  server = NULL;
-  MesosTest::TearDown();
-};
+}
 
 
 ZooKeeperTest::TestWatcher::TestWatcher()

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/tests/zookeeper_test.hpp
----------------------------------------------------------------------
diff --git a/src/tests/zookeeper_test.hpp b/src/tests/zookeeper_test.hpp
index 61a3d25..7bd396b 100644
--- a/src/tests/zookeeper_test.hpp
+++ b/src/tests/zookeeper_test.hpp
@@ -29,8 +29,6 @@
 
 #include <stout/duration.hpp>
 
-#include "jvm/jvm.hpp"
-
 #include "tests/utils.hpp"
 #include "tests/zookeeper_test_server.hpp"
 
@@ -82,7 +80,6 @@ public:
   class TestWatcher : public Watcher
   {
   public:
-
     // Encapsulates all the state of a ZooKeeper watcher event.
     struct Event {
       Event(int _type, int _state, const std::string& _path)
@@ -119,21 +116,18 @@ public:
     pthread_cond_t cond;
   };
 
-  ZooKeeperTest() : server(NULL) {}
+  ZooKeeperTest() : server(new ZooKeeperTestServer()) {}
+  virtual ~ZooKeeperTest() { delete server; }
 
   static void SetUpTestCase();
 
 protected:
   virtual void SetUp();
-  virtual void TearDown();
 
   // A very long session timeout that simulates no timeout for test cases.
-  static const Milliseconds NO_TIMEOUT;
+  static const Duration NO_TIMEOUT;
 
   ZooKeeperTestServer* server;
-
-private:
-  static Jvm* jvm;
 };
 
 } // namespace tests {

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/tests/zookeeper_test_server.cpp
----------------------------------------------------------------------
diff --git a/src/tests/zookeeper_test_server.cpp b/src/tests/zookeeper_test_server.cpp
index 5c82a1e..8051b4d 100644
--- a/src/tests/zookeeper_test_server.cpp
+++ b/src/tests/zookeeper_test_server.cpp
@@ -16,130 +16,48 @@
  * limitations under the License.
  */
 
-#include <jni.h>
-#include <stdarg.h>
+#include <jvm/jvm.hpp>
 
-#include <glog/logging.h>
+#include <jvm/java/io.hpp>
+#include <jvm/java/net.hpp>
 
-#include <sstream>
-#include <vector>
+#include <jvm/org/apache/zookeeper.hpp>
 
-#include <stout/uuid.hpp>
+#include <stout/os.hpp>
 
-#include "jvm/jvm.hpp"
+#include "logging/logging.hpp"
 
 #include "tests/zookeeper_test_server.hpp"
 
+using org::apache::zookeeper::persistence::FileTxnSnapLog;
+
+using org::apache::zookeeper::server::NIOServerCnxn;
+using org::apache::zookeeper::server::ZooKeeperServer;
+
 namespace mesos {
 namespace internal {
 namespace tests {
 
-ZooKeeperTestServer::ZooKeeperTestServer(Jvm* _jvm)
-  : jvm(_jvm),
+ZooKeeperTestServer::ZooKeeperTestServer()
+  : zooKeeperServer(NULL),
+    connectionFactory(NULL),
     port(0),
     started(false)
 {
-  Jvm::Attach attach(jvm);
-
-  Jvm::JClass fileClass = Jvm::JClass::forName("java/io/File");
-  fileConstructor = new Jvm::JConstructor(
-      jvm->findConstructor(
-          fileClass
-          .constructor()
-          .parameter(jvm->stringClass)));
-
-  Jvm::JClass inetSocketAddressClass =
-      Jvm::JClass::forName("java/net/InetSocketAddress");
-  inetSocketAddressConstructor = new Jvm::JConstructor(
-      jvm->findConstructor(
-          inetSocketAddressClass
-          .constructor()
-          .parameter(jvm->intClass)));
-
-  Jvm::JClass cnxnFactoryClass =
-      Jvm::JClass::forName("org/apache/zookeeper/server/NIOServerCnxn$Factory");
-  cnxnFactoryConstructor = new Jvm::JConstructor(
-      jvm->findConstructor(
-          cnxnFactoryClass
-          .constructor()
-          .parameter(inetSocketAddressClass)));
-
-  Jvm::JClass zkServerClass =
-      Jvm::JClass::forName("org/apache/zookeeper/server/ZooKeeperServer");
-  startup = new Jvm::JMethod(
-      jvm->findMethod(
-          cnxnFactoryClass
-          .method("startup")
-          .parameter(zkServerClass)
-          .returns(jvm->voidClass)));
-
-  isAlive = new Jvm::JMethod(
-      jvm->findMethod(
-          cnxnFactoryClass
-          .method("isAlive")
-          .returns(jvm->booleanClass)));
-
-  shutdown = new Jvm::JMethod(
-      jvm->findMethod(
-          cnxnFactoryClass
-          .method("shutdown")
-          .returns(jvm->voidClass)));
-
-  dataDir = createTempDir();
-  snapDir = createTempDir();
-  Jvm::JClass snapLogClass =
-    Jvm::JClass::forName(
-        "org/apache/zookeeper/server/"
-        "persistence/FileTxnSnapLog");
-
-  snapLog = jvm->newGlobalRef(
-      jvm->invoke(
-          jvm->findConstructor(snapLogClass
-                               .constructor()
-                               .parameter(fileClass)
-                               .parameter(fileClass)),
-          dataDir->file,
-          snapDir->file));
-
-  dataTreeBuilder = jvm->newGlobalRef(
-      jvm->invoke(
-          jvm->findConstructor(
-              Jvm::JClass::forName(
-                  "org/apache/zookeeper/server/"
-                  "ZooKeeperServer$BasicDataTreeBuilder").constructor())));
-
-  Jvm::JClass dataTreeBuilderClass(
-      Jvm::JClass::forName("org/apache/zookeeper/server/"
-                           "ZooKeeperServer$DataTreeBuilder"));
-
-  zooKeeperServer = jvm->newGlobalRef(
-      jvm->invoke(
-          jvm->findConstructor(zkServerClass
-                               .constructor()
-                               .parameter(snapLogClass)
-                               .parameter(dataTreeBuilderClass)),
-          snapLog,
-          dataTreeBuilder));
-
-  getClientPort = new Jvm::JMethod(
-      jvm->findMethod(zkServerClass
-                      .method("getClientPort")
-                      .returns(jvm->intClass)));
-
-  closeSession = new Jvm::JMethod(
-      jvm->findMethod(zkServerClass
-                      .method("closeSession")
-                      .parameter(jvm->longClass)
-                      .returns(jvm->voidClass)));
-}
-
-
-const ZooKeeperTestServer::TemporaryDirectory* ZooKeeperTestServer::createTempDir()
-{
-  std::string tmpdir = "/tmp/zks-" + UUID::random().toString();
-  jobject file =
-    jvm->newGlobalRef(jvm->invoke(*fileConstructor, jvm->string(tmpdir)));
-  return new TemporaryDirectory(jvm, tmpdir, file);
+  // Create temporary directories for the FileTxnSnapLog.
+  Try<std::string> directory = os::mkdtemp();
+  CHECK_SOME(directory);
+  java::io::File dataDir(directory.get());
+  dataDir.deleteOnExit();
+
+  directory = os::mkdtemp();
+  CHECK_SOME(directory);
+  java::io::File snapDir(directory.get());
+  snapDir.deleteOnExit();
+
+  zooKeeperServer = new ZooKeeperServer(
+      FileTxnSnapLog(dataDir, snapDir),
+      ZooKeeperServer::BasicDataTreeBuilder());
 }
 
 
@@ -147,51 +65,30 @@ ZooKeeperTestServer::~ZooKeeperTestServer()
 {
   shutdownNetwork();
 
-  Jvm::Attach attach(jvm);
-
-  jvm->deleteGlobalRefSafe(inetSocketAddress);
-  jvm->deleteGlobalRefSafe(connectionFactory);
-  jvm->deleteGlobalRefSafe(snapLog);
-  jvm->deleteGlobalRefSafe(dataTreeBuilder);
-  jvm->deleteGlobalRefSafe(zooKeeperServer);
-
-  delete fileConstructor;
-  delete getClientPort;
-  delete closeSession;
-
-  delete inetSocketAddressConstructor;
-  delete cnxnFactoryConstructor;
-
-  delete startup;
-  delete isAlive;
-  delete shutdown;
-
-  delete dataDir;
-  delete snapDir;
+  delete zooKeeperServer;
+  delete connectionFactory;
 }
 
 
 void ZooKeeperTestServer::expireSession(int64_t sessionId)
 {
-  Jvm::Attach attach(jvm);
-
-  jvm->invoke<void>(zooKeeperServer, *closeSession, sessionId);
+  zooKeeperServer->closeSession(sessionId);
 }
 
 
 std::string ZooKeeperTestServer::connectString() const
 {
-  checkStarted();
+  CHECK(port > 0) << "Illegal state, must call startNetwork first!";
   return "127.0.0.1:" + stringify(port);
 }
 
 
 void ZooKeeperTestServer::shutdownNetwork()
 {
-  Jvm::Attach attach(jvm);
-
-  if (started && jvm->invoke<bool>(connectionFactory, *isAlive)) {
-    jvm->invoke<void>(connectionFactory, *shutdown);
+  if (started && connectionFactory->isAlive()) {
+    connectionFactory->shutdown();
+    delete connectionFactory;
+    connectionFactory = NULL;
     LOG(INFO) << "Shutdown ZooKeeperTestServer on port " << port << std::endl;
   }
 }
@@ -199,28 +96,24 @@ void ZooKeeperTestServer::shutdownNetwork()
 
 int ZooKeeperTestServer::startNetwork()
 {
-  Jvm::Attach attach(jvm);
+  connectionFactory = new NIOServerCnxn::Factory(
+      java::net::InetSocketAddress(port));
 
-  inetSocketAddress =
-      jvm->newGlobalRef(jvm->invoke(*inetSocketAddressConstructor, port));
-  connectionFactory =
-      jvm->newGlobalRef(
-          jvm->invoke(*cnxnFactoryConstructor, inetSocketAddress));
+  connectionFactory->startup(*zooKeeperServer);
+
+  if (port == 0) {
+    // We save the ephemeral port so if/when we restart the network
+    // the clients will reconnect to the same server. Note that this
+    // might not actually be kosher because it's possible that another
+    // process could bind to our ephemeral port after we unbind.
+    port = zooKeeperServer->getClientPort();
+  }
 
-  jvm->invoke<void>(connectionFactory, *startup, zooKeeperServer);
-  port = jvm->invoke<int>(zooKeeperServer, *getClientPort);
   LOG(INFO) << "Started ZooKeeperTestServer on port " << port;
   started = true;
   return port;
 }
 
-
-void ZooKeeperTestServer::checkStarted() const
-{
-  CHECK(port > 0) << "Illegal state, must call startNetwork first!";
-}
-
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {
-

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/233edea2/src/tests/zookeeper_test_server.hpp
----------------------------------------------------------------------
diff --git a/src/tests/zookeeper_test_server.hpp b/src/tests/zookeeper_test_server.hpp
index bfa841c..97a8524 100644
--- a/src/tests/zookeeper_test_server.hpp
+++ b/src/tests/zookeeper_test_server.hpp
@@ -19,13 +19,13 @@
 #ifndef __ZOOKEEPER_TEST_SERVER_HPP__
 #define __ZOOKEEPER_TEST_SERVER_HPP__
 
-#include <jni.h>
+#include <string>
 
 #include <glog/logging.h>
 
-#include <stout/os.hpp>
+#include <jvm/org/apache/zookeeper.hpp>
 
-#include "jvm/jvm.hpp"
+#include <stout/os.hpp>
 
 #include "zookeeper/zookeeper.hpp"
 
@@ -40,7 +40,7 @@ namespace tests {
 class ZooKeeperTestServer
 {
 public:
-  ZooKeeperTestServer(Jvm* jvm);
+  ZooKeeperTestServer();
   ~ZooKeeperTestServer();
 
   // Gets a connection string that can be used to attach a ZooKeeper client to
@@ -67,54 +67,11 @@ public:
   void expireSession(int64_t sessionId);
 
 private:
-  // TODO(John Sirois): factor out TemporaryDirectory + createTempDir() to utils
-  struct TemporaryDirectory
-  {
-    Jvm* jvm;
-    const std::string path;
-    const jobject file;
-
-    TemporaryDirectory(Jvm* _jvm,
-                       const std::string& _path,
-                       const jobject _file) : jvm(_jvm),
-                                              path(_path),
-                                              file(_file) {}
-
-    ~TemporaryDirectory()
-    {
-      jvm->deleteGlobalRef(file);
-      Try<Nothing> rmdir = os::rmdir(path);
-      if (rmdir.isError()) {
-        LOG(WARNING) << "Failed to delete temp dir '"
-                     << path << "': " << rmdir.error();
-      }
-    }
-  };
-
-  Jvm* jvm;
-
-  Jvm::JConstructor* fileConstructor;
-  jobject snapLog;
-  jobject dataTreeBuilder;
-  jobject zooKeeperServer;
-  Jvm::JMethod* getClientPort;
-  Jvm::JMethod* closeSession;
-
-  Jvm::JConstructor* inetSocketAddressConstructor;
-  jobject inetSocketAddress;
-  Jvm::JConstructor* cnxnFactoryConstructor;
-  jobject connectionFactory;
-  Jvm::JMethod* startup;
-  Jvm::JMethod* isAlive;
-  Jvm::JMethod* shutdown;
+  org::apache::zookeeper::server::ZooKeeperServer* zooKeeperServer;
+  org::apache::zookeeper::server::NIOServerCnxn::Factory* connectionFactory;
 
   int port;
   bool started;
-  const TemporaryDirectory* dataDir;
-  const TemporaryDirectory* snapDir;
-
-  const TemporaryDirectory* createTempDir();
-  void checkStarted() const;
 };
 
 } // namespace tests {