Apache Mesos
jvm.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __JVM_HPP__
18 #define __JVM_HPP__
19 
20 #include <jni.h>
21 
22 #include <string>
23 #include <vector>
24 
25 #include <stout/error.hpp>
26 #include <stout/try.hpp>
27 
28 
29 // Some compilers give us warnings about 'dereferencing type-punned
30 // pointer will break strict-aliasing rules' when we cast our JNIEnv**
31 // to void**. We use this function to do the magic for us.
32 inline void** JNIENV_CAST(JNIEnv** env)
33 {
34  return reinterpret_cast<void**>(env);
35 }
36 
37 
38 struct JNI
39 {
40  enum Version
41  {
42  v_1_1 = JNI_VERSION_1_1,
43  v_1_2 = JNI_VERSION_1_2,
44  v_1_4 = JNI_VERSION_1_4,
45  v_1_6 = JNI_VERSION_1_6
46  };
47 };
48 
49 // Facilitates embedding a JVM and calling into it.
50 class Jvm
51 {
52 public:
53  // Forward declarations.
54  class ConstructorFinder;
55  class MethodFinder;
56  class Constructor;
57  class MethodSignature;
58  class Method;
59 
60  // Starts a new embedded JVM with the given -D options. Each option
61  // supplied should be of the standard form: '-Dproperty=value'.
62  // Returns the singleton Jvm instance or an error if the JVM had
63  // already been created. Note that you can only create one JVM
64  // instance per process since destructing a JVM has issues, see:
65  // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4712793. In
66  // addition, most JVM's use signals and couldn't possibly play
67  // nicely with one another.
68  // TODO(benh): Add a 'create' which just takes an already
69  // constructed JavaVM. This will be useful for when a JVM is calling
70  // into native code versus native code embedding a JVM.
71  // TODO(John Sirois): Consider elevating classpath as a top-level
72  // JVM configuration parameter since it will likely always need to
73  // be specified. Ditto for and non '-X' options.
74  static Try<Jvm*> create(
75  const std::vector<std::string>& options = std::vector<std::string>(),
77  bool exceptions = false);
78 
79  // Returns true if the JVM has already been created.
80  static bool created();
81 
82  // Returns the singleton JVM instance, creating it with no options
83  // and a default version if necessary.
84  static Jvm* get();
85 
86  // An opaque class descriptor that can be used to find constructors,
87  // methods and fields.
88  class Class
89  {
90  public:
91  // A factory for new Java reference type class descriptors given
92  // the fully qualified class name (e.g., 'java/io/File'). To
93  // obtain class descriptors for native types (int, short, etc),
94  // use the fields in Jvm.
95  static const Class named(const std::string& name);
96 
97  Class(const Class& that);
98 
99  // Returns the class of an array of the current class.
100  const Class arrayOf() const;
101 
102  // Creates a builder that can be used to locate a constructor of
103  // this class with Jvm::findConstructor.
104  ConstructorFinder constructor() const;
105 
106  // Creates a builder that can be used to locate an instance method
107  // of this class with Jvm::findMethod.
108  MethodFinder method(const std::string& name) const;
109 
110  private:
111  friend class Jvm;
112 
113  Class(const std::string& name, bool native = true);
114 
115  std::string signature() const;
116 
117  std::string name;
118  bool native;
119  };
120 
121 
122  // A builder that is used to specify a constructor by specifying its
123  // parameter list with zero or more calls to
124  // ConstructorFinder::parameter.
126  {
127  public:
128  // Adds a parameter to the constructor parameter list.
129  ConstructorFinder& parameter(const Class& clazz);
130 
131  private:
132  friend class Class;
133  friend class Jvm;
134 
135  explicit ConstructorFinder(const Class& clazz);
136 
137  const Class clazz;
138  std::vector<Class> parameters;
139  };
140 
141 
142  // An opaque constructor descriptor that can be used to create new
143  // instances of a class using Jvm::invokeConstructor.
145  {
146  public:
147  Constructor(const Constructor& that);
148 
149  private:
150  friend class Jvm;
151 
152  Constructor(const Class& clazz, const jmethodID id);
153 
154  const Class clazz;
155  const jmethodID id;
156  };
157 
158 
159  // A builder that is used to specify an instance method by
160  // specifying its parameter list with zero or more calls to
161  // MethodFinder::parameter and a final call to MethodFinder::returns
162  // to get an opaque specification of the method for use with
163  // Jvm::findMethod.
165  {
166  public:
167  // Adds a parameter to the method parameter list.
168  MethodFinder& parameter(const Class& type);
169 
170  // Terminates description of a method by specifying its return type.
171  MethodSignature returns(const Class& type) const;
172 
173  private:
174  friend class Class;
175 
176  MethodFinder(const Class& clazz, const std::string& name);
177 
178  const Class clazz;
179  const std::string name;
180  std::vector<Class> parameters;
181  };
182 
183 
184  // An opaque method specification for use with Jvm::findMethod.
186  {
187  public:
188  MethodSignature(const MethodSignature& that);
189 
190  private:
191  friend class Jvm;
192  friend class MethodFinder;
193 
194  MethodSignature(const Class& clazz,
195  const std::string& name,
196  const Class& returnType,
197  const std::vector<Class>& parameters);
198 
199  const Class clazz;
200  const std::string name;
201  const Class returnType;
202  std::vector<Class> parameters;
203  };
204 
205 
206  // An opaque method descriptor that can be used to invoke instance methods
207  // using Jvm::invokeMethod.
208  class Method
209  {
210  public:
211  Method(const Method& that);
212 
213  private:
214  friend class Jvm;
215  friend class MethodSignature;
216 
217  Method(const Class& clazz, const jmethodID id);
218 
219  const Class clazz;
220  const jmethodID id;
221  };
222 
223 
224  // An opaque field descriptor that can be used to access fields using
225  // methods like Jvm::getStaticField.
226  class Field
227  {
228  public:
229  Field(const Field& that);
230 
231  private:
232  friend class Jvm;
233 
234  Field(const Class& clazz, const jfieldID id);
235 
236  const Class clazz;
237  const jfieldID id;
238  };
239 
240 
241  // Base class for all JVM objects. This object "stores" the
242  // underlying global reference and performs the appropriate
243  // operations across copies and assignments.
244  class Object
245  {
246  public:
247  Object() : object(nullptr) {}
248 
249  explicit Object(jobject _object)
250  : object(Jvm::get()->newGlobalRef(_object)) {}
251 
252  Object(const Object& that)
253  : object(nullptr)
254  {
255  if (that.object != nullptr) {
256  object = Jvm::get()->newGlobalRef(that.object);
257  }
258  }
259 
261  {
262  if (object != nullptr) {
263  Jvm::get()->deleteGlobalRef(object);
264  }
265  }
266 
267  Object& operator=(const Object& that)
268  {
269  if (object != nullptr) {
270  Jvm::get()->deleteGlobalRef(object);
271  object = nullptr;
272  }
273  if (that.object != nullptr) {
274  object = Jvm::get()->newGlobalRef(that.object);
275  }
276  return *this;
277  }
278 
279  operator jobject() const
280  {
281  return object;
282  }
283 
284  protected:
285  friend class Jvm; // For manipulating object.
286 
287  jobject object;
288  };
289 
290 
291  class Null : public Object {};
292 
293 
294  template <typename T, const char* name, const char* signature>
295  class Variable
296  {
297  public:
298  explicit Variable(const Class& _clazz)
299  : clazz(_clazz)
300  {
301  // Check that T extends Object.
302  { T* t = nullptr; Object* o = t; (void) o; }
303  }
304 
305  Variable(const Class& _clazz, const Object& _object)
306  : clazz(_clazz), object(_object)
307  {
308  // Check that T extends Object.
309  { T* t = nullptr; Object* o = t; (void) o; }
310  }
311 
312  // TODO(benh): Implement cast operator (like in StaticVariable).
313  // This requires implementing Jvm::getField too.
314 
315  template <typename U>
316  Variable& operator=(const U& u)
317  {
318  // Check that U extends Object (but not necessarily T since U
319  // might be 'Null').
320  { U* u = nullptr; Object* o = u; (void) o; }
321 
322  // Note that we actually look up the field lazily (upon first
323  // assignment operator) so that we don't possibly create the JVM
324  // too early.
325  static Field field = Jvm::get()->findField(clazz, name, signature);
326 
327  Jvm::get()->setField<jobject>(object, field, u);
328 
329  return *this;
330  }
331 
332  void bind(const Object& _object) { object = _object; }
333 
334  private:
335  const Class clazz;
336  Object object; // Not const so we can do late binding.
337  };
338 
339  // Helper for providing access to static variables in a class. You
340  // can use this to delay the variable lookup until it's actually
341  // accessed in order to keep the JVM from getting constructed too
342  // early. See Level in jvm/org/apache/log4j.hpp for an example.
343  // TODO(benh): Provide template specialization for primitive
344  // types (e.g., StaticVariable<int>, StaticVariable<short>,
345  // StaticVariable<std::string>).
346  template <typename T, const char* name, const char* signature>
348  {
349  public:
350  explicit StaticVariable(const Class& _clazz)
351  : clazz(_clazz)
352  {
353  // Check that T extends Object.
354  { T* t = nullptr; Object* o = t; (void) o; }
355  }
356 
357  operator T() const
358  {
359  // Note that we actually look up the field lazily (upon first
360  // invocation operator) so that we don't possibly create the JVM
361  // too early.
362  static Field field =
363  Jvm::get()->findStaticField(clazz, name, signature);
364  T t;
365  t.object = Jvm::get()->getStaticField<jobject>(field);
366  return t;
367  }
368 
369  private:
370  const Class clazz;
371  };
372 
373  // Each thread that wants to interact with the JVM needs a JNI
374  // environment which must be obtained by "attaching" to the JVM. We
375  // use the following RAII class to provide the environment and also
376  // make sure a thread is attached and properly detached. Note that
377  // nested constructions are no-ops and use the same environment (and
378  // without detaching too early).
379  // TODO(benh): Support putting a 'Jvm::Env' into a thread-local
380  // variable so we can "attach" to the JVM once.
381  class Env
382  {
383  public:
384  explicit Env(bool daemon = true);
385  ~Env();
386 
387  JNIEnv* operator->() const { return env; }
388 
389  operator JNIEnv*() const { return env; }
390 
391  private:
392  JNIEnv* env;
393  bool detach; // A nested use of Env should not detach the thread.
394  };
395 
396  friend class Env;
397 
408 
409  jstring string(const std::string& s);
410 
411  Constructor findConstructor(const ConstructorFinder& finder);
412 
413  Method findMethod(const MethodSignature& signature);
414 
415  Method findStaticMethod(const MethodSignature& signature);
416 
417  Field findField(
418  const Class& clazz,
419  const std::string& name,
420  const std::string& signature);
421 
422  Field findStaticField(
423  const Class& clazz,
424  const std::string& name,
425  const std::string& signature);
426 
427  // TODO(John Sirois): Add "type checking" to variadic method
428  // calls. Possibly a way to do this with typelists, type
429  // concatenation and unwinding builder inheritance.
430 
431  jobject invoke(const Constructor ctor, ...);
432 
433  template <typename T>
434  T invoke(const jobject receiver, const Method method, ...);
435 
436  template <typename T>
437  T invokeStatic(const Method method, ...);
438 
439  template <typename T>
440  void setField(jobject receiver, const Field& field, T t);
441 
442  template <typename T>
443  T getStaticField(const Field& field);
444 
445  // Checks the exception state of an environment.
446  void check(JNIEnv* env);
447 
448 private:
449  friend class Object; // For creating global references.
450 
451  Jvm(JavaVM* jvm, JNI::Version version, bool exceptions);
452  ~Jvm();
453 
454 private:
455  jobject newGlobalRef(const jobject object);
456  void deleteGlobalRef(const jobject object);
457 
458  jclass findClass(const Class& clazz);
459 
460  jmethodID findMethod(const Jvm::Class& clazz,
461  const std::string& name,
462  const Jvm::Class& returnType,
463  const std::vector<Jvm::Class>& argTypes,
464  bool isStatic);
465 
466  template <typename T>
467  T invokeV(const jobject receiver, const jmethodID id, va_list args);
468 
469  template <typename T>
470  T invokeStaticV(const Class& receiver, const jmethodID id, va_list args);
471 
472  // Singleton instance.
473  static Jvm* instance;
474 
475  JavaVM* jvm;
476  const JNI::Version version;
477  const bool exceptions;
478 };
479 
480 
481 template <>
482 void Jvm::invoke<void>(const jobject receiver, const Method method, ...);
483 
484 
485 template <typename T>
486 T Jvm::invoke(const jobject receiver, const Method method, ...)
487 {
488  va_list args;
489  va_start(args, method);
490  const T result = invokeV<T>(receiver, method.id, args);
491  va_end(args);
492  return result;
493 }
494 
495 
496 template <>
497 void Jvm::invokeStatic<void>(const Method method, ...);
498 
499 
500 template <typename T>
501 T Jvm::invokeStatic(const Method method, ...)
502 {
503  va_list args;
504  va_start(args, method);
505  const T result = invokeStaticV<T>(method.clazz, method.id, args);
506  va_end(args);
507  return result;
508 }
509 
510 #endif // __JVM_HPP__
Version
Definition: jvm.hpp:40
Try< std::vector< std::string > > get(const std::string &hierarchy, const std::string &cgroup="/")
const Class booleanClass
Definition: jvm.hpp:399
Definition: jvm.hpp:38
Definition: check.hpp:33
Object & operator=(const Object &that)
Definition: jvm.hpp:267
const Class floatClass
Definition: jvm.hpp:405
const Class voidClass
Definition: jvm.hpp:398
Try< Nothing > check()
Definition: uuid.hpp:33
Definition: jvm.hpp:88
const Class intClass
Definition: jvm.hpp:403
Definition: jvm.hpp:164
Definition: jvm.hpp:125
Object(jobject _object)
Definition: jvm.hpp:249
Definition: jvm.hpp:144
void bind(const Object &_object)
Definition: jvm.hpp:332
const Class doubleClass
Definition: jvm.hpp:406
Definition: jvm.hpp:381
Definition: jvm.hpp:295
Definition: jvm.hpp:45
process::Future< Version > version()
Definition: version.hpp:32
Definition: jvm.hpp:208
Definition: jvm.hpp:291
Definition: jvm.hpp:44
Object(const Object &that)
Definition: jvm.hpp:252
Definition: jvm.hpp:244
Variable(const Class &_clazz, const Object &_object)
Definition: jvm.hpp:305
Field findField(const Class &clazz, const std::string &name, const std::string &signature)
Definition: jvm.hpp:43
Variable(const Class &_clazz)
Definition: jvm.hpp:298
static Jvm * get()
jobject object
Definition: jvm.hpp:287
T invokeStatic(const Method method,...)
Definition: jvm.hpp:501
void setField(jobject receiver, const Field &field, T t)
const Class shortClass
Definition: jvm.hpp:402
Definition: jvm.hpp:185
Field findStaticField(const Class &clazz, const std::string &name, const std::string &signature)
void ** JNIENV_CAST(JNIEnv **env)
Definition: jvm.hpp:32
JNIEnv * operator->() const
Definition: jvm.hpp:387
Definition: version.hpp:41
StaticVariable(const Class &_clazz)
Definition: jvm.hpp:350
Try< uint32_t > type(const std::string &path)
const Class byteClass
Definition: jvm.hpp:400
Definition: jvm.hpp:347
jobject invoke(const Constructor ctor,...)
Variable & operator=(const U &u)
Definition: jvm.hpp:316
Try< Nothing > create(const std::string &hierarchy, const std::string &cgroup, bool recursive=false)
const Class stringClass
Definition: jvm.hpp:407
~Object()
Definition: jvm.hpp:260
Definition: jvm.hpp:50
const Class charClass
Definition: jvm.hpp:401
const Class longClass
Definition: jvm.hpp:404
Object()
Definition: jvm.hpp:247
T getStaticField(const Field &field)
constexpr const char * name
Definition: shell.hpp:43
Definition: jvm.hpp:42
Definition: jvm.hpp:226
Class
Definition: elf.hpp:38