SheafSystem  0.0.0.0
jvm_launcher.cc
1 
2 //
3 // Copyright (c) 2014 Limit Point Systems, Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // 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 
18 // Implementation for class jvm_launcher
19 
20 #include "SheafSystem/jvm_launcher.h"
21 #include "SheafSystem/std_cstdlib.h"
22 #include "SheafSystem/std_iostream.h"
23 #include "SheafSystem/std_string.h"
24 #include "SheafSystem/std_unistd.h"
25 #include <jni.h>
26 
27 
29 int
31 launch(const char* main_class_name, int argc, char* argv[], bool verbose)
32 {
33  // Handle VM options.
34 
35  char* class_path = getenv("CLASSPATH");
36  char* ld_library_path = getenv("LD_LIBRARY_PATH");
37 
38  return launch(main_class_name, argc, argv, class_path, ld_library_path, verbose);
39 }
40 
41 
43 int
45 launch(const char* main_class_name, int argc, char* argv[],
46  const char* xclass_path, const char* xld_library_path, bool verbose)
47 {
48  //std::cout << "jvm_launcher::launch xclass_path = " << xclass_path << std::endl;
49  //std::cout << "jvm_launcher::launch xld_library_path = " << xld_library_path << std::endl;
50 
51  // to be set from within the process.
52 
53  // Currently using -rpath to get libraries, so we comment this call out.
54  // re_exec(argc, argv, xclass_path, xld_library_path);
55 
56  JavaVM* vm;
57  JNIEnv* env;
58 
59  // Handle VM options.
60 
61  // Set default paths to ".".
62 
63  std::string class_path(xclass_path);
64  std::string ld_library_path(xld_library_path);
65 
66  // Append the user's path if a passed-in value differs from the user's.
67  // This is so we can move the executable and still have it work (provided
68  // the user's CLASSPATH and LD_LIBRARY_PATH are set correctly).
69  // Note: We might replicate some paths here but that shouldn't be a
70  // problem,
71 
72  char* ucp = getenv("CLASSPATH");
73  if(ucp != NULL)
74  {
75  std::string user_class_path(ucp);
76  if(class_path != user_class_path)
77  {
78  class_path += ":" + user_class_path;
79  }
80  }
81 
82  char* uld = getenv("LD_LIBRARY_PATH");
83  if(uld != NULL)
84  {
85  std::string user_ld_library_path(uld);
86  if(ld_library_path != ld_library_path)
87  {
88  ld_library_path += ":" + user_ld_library_path;
89  }
90  }
91 
92  //std::cout << "jvm_launcher::launch class_path = " << class_path << std::endl;
93  //std::cout << "jvm_launcher::launch ld_library_path = " << ld_library_path << std::endl;
94 
95  // Allocate the VM options array.
96 
97  JavaVMOption options[3];
98 
99  std::string s0("-Djava.class.path=");
100  s0 += class_path;
101  options[0].optionString = const_cast<char*>(s0.c_str());
102 
103  std::string s1("-Djava.library.path=");
104  s1 += ld_library_path;
105  options[1].optionString = const_cast<char*>(s1.c_str());
106 
107  options[2].optionString = const_cast<char*>("-verbose");
108 
109  int num_options = verbose ? 3 : 2;
110 
111  JavaVMInitArgs vm_args;
112  vm_args.version = JNI_VERSION_1_4;
113  vm_args.options = options;
114  vm_args.nOptions = num_options;
115  vm_args.ignoreUnrecognized = JNI_TRUE;
116 
117  jint rval = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args);
118  if(rval < 0)
119  {
120  std::cout << "Couldn't create the Java VM" << std::endl;
121  return(1);
122  }
123 
124  jclass main_class = env->FindClass(main_class_name);
125  if(main_class == 0)
126  {
127  std::cout << main_class_name << " class not found" << std::endl;
128  return(2);
129  }
130 
131  jmethodID main_method_id =
132  env->GetStaticMethodID(main_class, "main", "([Ljava/lang/String;)V");
133 
134  if(main_method_id == 0)
135  {
136  std::cout << "main() method not found" << std::endl;
137  return(3);
138  }
139 
140  // Add any command line arguments (ie: 1,2,3,...) to the args array.
141 
142  jclass string_class = env->FindClass("java/lang/String");
143  jobjectArray args = env->NewObjectArray(argc-1, string_class, NULL);
144  if(args == 0)
145  {
146  std::cout << "Out of memory" << std::endl;
147  return(4);
148  }
149 
150  // Take care of no args case ("" implies no args).
151 
152  if(argc == 1)
153  {
154  jstring argString = env->NewStringUTF("");
155  env->SetObjectArrayElement(args, 0, argString);
156  }
157  else
158  {
159  for(int i=1; i<argc; ++i)
160  {
161  jstring argString = env->NewStringUTF(argv[i]);
162  env->SetObjectArrayElement(args, i-1, argString);
163  }
164  }
165 
166  // Invoke the main method (public static void main(String[] args)).
167 
168  env->CallStaticVoidMethod(main_class, main_method_id, args);
169 
170  // Unload the VM when this is the last thread.
171 
172  vm->DestroyJavaVM();
173 
174  return 0;
175 }
176 
178 void
180 re_exec(int argc, char* argv[],
181  const char* xclass_path, const char* xld_library_path)
182 {
183  //NOTE: We re-exec this same process exactly once so that we
184  // get the LD_LIBRARY_PATH environment variable to be
185  // used correctly by unix. In unix, LD_LIBRARY_PATH
186  // is only looked at at load time. Even though unix
187  // allows a given process to change LD_LIBRARY_PATH
188  // as much as it wants, it will never use it again
189  // after loading. So the trick here is to set
190  // LD_LIBRARY_PATH in the parent and then use
191  // execvp to replace that process with a copy
192  // which gets the modified environment. We use
193  // another temporary environment variable to
194  // allow us to prevent infinite recursion.
195 
196  // Environment variable to set temporatily in order to
197  // prevent infinite recursion here.
198 
199  static const char* env_name = "__HAVE_SET_ENV_SO_LD_LIBRARY_PATH_WORKS__";
200 
201  if(getenv(env_name) != NULL)
202  {
203  unsetenv(env_name);
204  }
205  else
206  {
207  setenv(env_name, "yes", 1);
208  setenv("LD_LIBRARY_PATH", xld_library_path, 1);
209  setenv("CLASSPATH", xclass_path, 1);
210 
211  if(execvp(argv[0], argv))
212  {
213  perror(argv[0]);
214  exit(1);
215  }
216  }
217 }
218 
219 //
220 // An "extern" function which can more easily be execed from a "dlsym"
221 // (dynamic linker method ) provided function pointer.
222 //
223 // extern "C" int launch_jvm(const char* main_class_name, int argc, char** argv,
224 // const char* xclass_path, const char* xld_library_path)
225 // {
226 // return jvm_launcher::launch(main_class_name, argc, argv, xclass_path, xld_library_path);
227 // }
228 
229 
int launch(const char *main_class_name, int argc, char *argv[], bool verbose=false)
Launch the Java virtual machine, using the current CLASSPATH and LD_LIBRARY_PATH environment variable...
Definition: jvm_launcher.cc:31
void re_exec(int argc, char *argv[], const char *class_path, const char *ld_library_path)
Re-exec the current process with the using specified CLASSPATH and LD_LIBRARY_PATH environment variab...