1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_jvmfwk.hxx"
26 #if OSL_DEBUG_LEVEL > 0
27 #include <stdio.h>
28 #endif
29 #include <string.h>
30 
31 #include "boost/scoped_array.hpp"
32 #include "osl/diagnose.h"
33 #include "rtl/ustring.hxx"
34 #include "rtl/ustrbuf.hxx"
35 #include "osl/module.hxx"
36 #include "osl/mutex.hxx"
37 #include "osl/thread.hxx"
38 #include "osl/file.hxx"
39 #include "rtl/instance.hxx"
40 #include "osl/getglobalmutex.hxx"
41 #include <setjmp.h>
42 #include <signal.h>
43 #include <stack>
44 
45 #include "jni.h"
46 #include "rtl/byteseq.hxx"
47 #include "jvmfwk/vendorplugin.h"
48 #include "util.hxx"
49 #include "sunversion.hxx"
50 #include "vendorlist.hxx"
51 #include "diagnostics.h"
52 
53 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
54 #define SUN_MICRO "Sun Microsystems Inc."
55 
56 using namespace osl;
57 using namespace rtl;
58 using namespace std;
59 using namespace jfw_plugin;
60 
61 namespace {
62 
63 struct PluginMutex: public ::rtl::Static<osl::Mutex, PluginMutex> {};
64 
65 #if defined UNX
getPluginJarPath(const OUString & sVendor,const OUString & sLocation,const OUString & sVersion)66 OString getPluginJarPath(
67     const OUString & sVendor,
68     const OUString& sLocation,
69     const OUString& sVersion)
70 {
71     OString ret;
72     OUString sName1(RTL_CONSTASCII_USTRINGPARAM("javaplugin.jar"));
73     OUString sName2(RTL_CONSTASCII_USTRINGPARAM("plugin.jar"));
74     OUString sPath;
75     if (sVendor.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SUN_MICRO))))
76     {
77         SunVersion ver142("1.4.2-ea");
78         SunVersion ver150("1.5.0-ea");
79         SunVersion ver(sVersion);
80         OSL_ASSERT(ver142 && ver150 && ver);
81 
82         OUString sName;
83         if (ver < ver142)
84         {
85             sName = sName1;
86         }
87         else if (ver < ver150)
88         {//this will cause ea, beta etc. to have plugin.jar in path.
89             //but this does not harm. 1.5.0-beta < 1.5.0
90             sName = sName2;
91         }
92         if (sName.getLength())
93         {
94             sName = sLocation + OUSTR("/lib/") + sName;
95             OSL_VERIFY(
96                 osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
97                 == osl_File_E_None);
98         }
99     }
100     else
101     {
102         char sep[] =  {SAL_PATHSEPARATOR, 0};
103         OUString sName(sLocation + OUSTR("/lib/") + sName1);
104         OUString sPath1;
105         OUString sPath2;
106         if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
107             == osl_File_E_None)
108         {
109             sName = sLocation + OUSTR("/lib/") + sName2;
110             if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
111                 == osl_File_E_None)
112             {
113                 sPath = sPath1 + OUString::createFromAscii(sep) + sPath2;
114             }
115         }
116         OSL_ASSERT(sPath.getLength());
117     }
118     ret = rtl::OUStringToOString(sPath, osl_getThreadTextEncoding());
119 
120     return ret;
121 }
122 #endif // UNX
123 
124 
createJavaInfo(const rtl::Reference<VendorBase> & info)125 JavaInfo* createJavaInfo(const rtl::Reference<VendorBase> & info)
126 {
127     JavaInfo* pInfo = (JavaInfo*) rtl_allocateMemory(sizeof(JavaInfo));
128     if (pInfo == NULL)
129         return NULL;
130     rtl::OUString sVendor = info->getVendor();
131     pInfo->sVendor = sVendor.pData;
132     rtl_uString_acquire(sVendor.pData);
133     rtl::OUString sHome = info->getHome();
134     pInfo->sLocation = sHome.pData;
135     rtl_uString_acquire(pInfo->sLocation);
136     rtl::OUString sVersion = info->getVersion();
137     pInfo->sVersion = sVersion.pData;
138     rtl_uString_acquire(pInfo->sVersion);
139     pInfo->nFeatures = info->supportsAccessibility() ? 1 : 0;
140     pInfo->nRequirements = info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0;
141     rtl::OUStringBuffer buf(1024);
142     buf.append(info->getRuntimeLibrary());
143     if (info->getLibraryPaths().getLength() > 0)
144     {
145         buf.appendAscii("\n");
146         buf.append(info->getLibraryPaths());
147         buf.appendAscii("\n");
148     }
149 
150     rtl::OUString sVendorData = buf.makeStringAndClear();
151     rtl::ByteSequence byteSeq( (sal_Int8*) sVendorData.pData->buffer,
152                                sVendorData.getLength() * sizeof(sal_Unicode));
153     pInfo->arVendorData = byteSeq.get();
154     rtl_byte_sequence_acquire(pInfo->arVendorData);
155 
156     return pInfo;
157 }
158 
getRuntimeLib(const rtl::ByteSequence & data)159 rtl::OUString getRuntimeLib(const rtl::ByteSequence & data)
160 {
161     const sal_Unicode* chars = (sal_Unicode*) data.getConstArray();
162     sal_Int32 len = data.getLength();
163     rtl::OUString sData(chars, len / 2);
164     //the runtime lib is on the first line
165     sal_Int32 index = 0;
166     rtl::OUString aToken = sData.getToken( 0, '\n', index);
167 
168     return aToken;
169 }
170 
171 jmp_buf jmp_jvm_abort;
172 sig_atomic_t g_bInGetJavaVM = 0;
173 
abort_handler()174 extern "C" void JNICALL abort_handler()
175 {
176     // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
177     if( g_bInGetJavaVM != 0 )
178     {
179         fprintf( stderr, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
180         longjmp( jmp_jvm_abort, 0);
181     }
182 }
183 
184 }
185 
186 extern "C"
jfw_plugin_getAllJavaInfos(rtl_uString * sVendor,rtl_uString * sMinVersion,rtl_uString * sMaxVersion,rtl_uString ** arExcludeList,sal_Int32 nLenList,JavaInfo *** parJavaInfo,sal_Int32 * nLenInfoList)187 javaPluginError jfw_plugin_getAllJavaInfos(
188     rtl_uString *sVendor,
189     rtl_uString *sMinVersion,
190     rtl_uString *sMaxVersion,
191     rtl_uString  * *arExcludeList,
192     sal_Int32  nLenList,
193     JavaInfo*** parJavaInfo,
194     sal_Int32 *nLenInfoList)
195 {
196     OSL_ASSERT(sVendor);
197     OSL_ASSERT(sMinVersion);
198     OSL_ASSERT(sMaxVersion);
199     OSL_ASSERT(parJavaInfo);
200     OSL_ASSERT(parJavaInfo);
201     OSL_ASSERT(nLenInfoList);
202     if (!sVendor || !sMinVersion || !sMaxVersion || !parJavaInfo || !nLenInfoList)
203         return JFW_PLUGIN_E_INVALID_ARG;
204 
205     //nLenlist contains the number of element in arExcludeList.
206     //If no exclude list is provided then nLenList must be 0
207     OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
208     if (arExcludeList == NULL && nLenList > 0)
209         return JFW_PLUGIN_E_INVALID_ARG;
210 
211     OUString ouVendor(sVendor);
212     OUString ouMinVer(sMinVersion);
213     OUString ouMaxVer(sMaxVersion);
214 
215     OSL_ASSERT(ouVendor.getLength() > 0);
216     if (ouVendor.getLength() == 0)
217         return JFW_PLUGIN_E_INVALID_ARG;
218 
219     JavaInfo** arInfo = NULL;
220 
221     //Find all JREs
222     vector<rtl::Reference<VendorBase> > vecInfos =
223         getAllJREInfos();
224     vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
225 
226     typedef vector<rtl::Reference<VendorBase> >::iterator it;
227     for (it i= vecInfos.begin(); i != vecInfos.end(); i++)
228     {
229         const rtl::Reference<VendorBase>& cur = *i;
230 
231         if (ouVendor.equals(cur->getVendor()) == sal_False)
232             continue;
233 
234         if (ouMinVer.getLength() > 0)
235         {
236             try
237             {
238                 if (cur->compareVersions(sMinVersion) == -1)
239                     continue;
240             }
241             catch (MalformedVersionException&)
242             {
243                 //The minVersion was not recognized as valid for this vendor.
244                 JFW_ENSURE(
245                     0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
246                     + ouMinVer + OUSTR(" for vendor: ") + cur->getVendor()
247                     + OUSTR(" .Check minimum Version.") );
248                 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
249             }
250         }
251 
252         if (ouMaxVer.getLength() > 0)
253         {
254             try
255             {
256                 if (cur->compareVersions(sMaxVersion) == 1)
257                     continue;
258             }
259             catch (MalformedVersionException&)
260             {
261                 //The maxVersion was not recognized as valid for this vendor.
262                 JFW_ENSURE(
263                     0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
264                     + ouMaxVer + OUSTR(" for vendor: ") + cur->getVendor()
265                     + OUSTR(" .Check maximum Version.") );
266                 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
267             }
268         }
269 
270         if( arExcludeList != NULL)
271         {
272             bool bExclude = false;
273             for (int j = 0; j < nLenList; j++)
274             {
275                 rtl::OUString sExVer(arExcludeList[j]);
276                 try
277                 {
278                     if (cur->compareVersions(sExVer) == 0)
279                     {
280                         bExclude = true;
281                         break;
282                     }
283                 }
284                 catch (MalformedVersionException&)
285                 {
286                     //The excluded version was not recognized as valid for this vendor.
287                     JFW_ENSURE(
288                         0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
289                         + sExVer + OUSTR(" for vendor: ") + cur->getVendor()
290                         + OUSTR(" .Check excluded versions.") );
291                     return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
292                 }
293             }
294             if (bExclude == true)
295                 continue;
296         }
297         vecVerifiedInfos.push_back(*i);
298     }
299     //Now vecVerifiedInfos contains all those JREs which meet the version requirements
300     //Transfer them into the array that is passed out.
301     arInfo = (JavaInfo**) rtl_allocateMemory(vecVerifiedInfos.size() * sizeof (JavaInfo*));
302     int j = 0;
303     typedef vector<rtl::Reference<VendorBase> >::const_iterator cit;
304     for (cit ii = vecVerifiedInfos.begin(); ii != vecVerifiedInfos.end(); ii++, j++)
305     {
306         arInfo[j] = createJavaInfo(*ii);
307     }
308     *nLenInfoList = vecVerifiedInfos.size();
309 
310 
311     *parJavaInfo = arInfo;
312     return JFW_PLUGIN_E_NONE;
313 }
314 
315 extern "C"
jfw_plugin_getJavaInfoByPath(rtl_uString * path,rtl_uString * sVendor,rtl_uString * sMinVersion,rtl_uString * sMaxVersion,rtl_uString ** arExcludeList,sal_Int32 nLenList,JavaInfo ** ppInfo)316 javaPluginError jfw_plugin_getJavaInfoByPath(
317     rtl_uString *path,
318     rtl_uString *sVendor,
319     rtl_uString *sMinVersion,
320     rtl_uString *sMaxVersion,
321     rtl_uString  *  *arExcludeList,
322     sal_Int32  nLenList,
323     JavaInfo ** ppInfo)
324 {
325     javaPluginError errcode = JFW_PLUGIN_E_NONE;
326 
327     OSL_ASSERT(path);
328     OSL_ASSERT(sVendor);
329     OSL_ASSERT(sMinVersion);
330     OSL_ASSERT(sMaxVersion);
331     if (!path || !sVendor || !sMinVersion || !sMaxVersion || !ppInfo)
332         return JFW_PLUGIN_E_INVALID_ARG;
333     OUString ouPath(path);
334     OSL_ASSERT(ouPath.getLength() > 0);
335     if (ouPath.getLength() == 0)
336         return JFW_PLUGIN_E_INVALID_ARG;
337 
338     //nLenlist contains the number of element in arExcludeList.
339     //If no exclude list is provided then nLenList must be 0
340     OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
341     if (arExcludeList == NULL && nLenList > 0)
342         return JFW_PLUGIN_E_INVALID_ARG;
343 
344     OUString ouVendor(sVendor);
345     OUString ouMinVer(sMinVersion);
346     OUString ouMaxVer(sMaxVersion);
347 
348     OSL_ASSERT(ouVendor.getLength() > 0);
349     if (ouVendor.getLength() == 0)
350         return JFW_PLUGIN_E_INVALID_ARG;
351 
352     rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(ouPath);
353     if (aVendorInfo.is() == sal_False)
354         return JFW_PLUGIN_E_NO_JRE;
355 
356     //Check if the detected JRE matches the version requirements
357     if (ouVendor.equals(aVendorInfo->getVendor()) == sal_False)
358         return JFW_PLUGIN_E_NO_JRE;
359 
360     if (ouMinVer.getLength() > 0)
361     {
362         int nRes = 0;
363         try
364         {
365             nRes = aVendorInfo->compareVersions(ouMinVer);
366         }
367         catch (MalformedVersionException&)
368         {
369             //The minVersion was not recognized as valid for this vendor.
370             JFW_ENSURE(
371                 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
372                 + ouMinVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
373                 + OUSTR(" .Check minimum Version.") );
374             return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
375         }
376         if (nRes < 0)
377             return JFW_PLUGIN_E_FAILED_VERSION;
378     }
379 
380     if (ouMaxVer.getLength() > 0)
381     {
382         int nRes = 0;
383         try
384         {
385             nRes = aVendorInfo->compareVersions(ouMaxVer);
386         }
387         catch (MalformedVersionException&)
388         {
389             //The maxVersion was not recognized as valid for this vendor.
390             JFW_ENSURE(
391                 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
392                 + ouMaxVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
393                 + OUSTR(" .Check maximum Version.") );
394             return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
395         }
396         if (nRes > 0)
397             return JFW_PLUGIN_E_FAILED_VERSION;
398     }
399 
400     if( arExcludeList != NULL)
401     {
402         for (int i = 0; i < nLenList; i++)
403         {
404             rtl::OUString sExVer(arExcludeList[i]);
405             int nRes = 0;
406             try
407             {
408                 nRes = aVendorInfo->compareVersions(sExVer);
409             }
410             catch (MalformedVersionException&)
411             {
412                 //The excluded version was not recognized as valid for this vendor.
413                 JFW_ENSURE(
414                     0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
415                     + sExVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
416                     + OUSTR(" .Check excluded versions.") );
417                 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
418             }
419             if (nRes == 0)
420                 return JFW_PLUGIN_E_FAILED_VERSION;
421         }
422     }
423     *ppInfo = createJavaInfo(aVendorInfo);
424 
425     return errcode;
426 }
427 
428 /** starts a Java Virtual Machine.
429     <p>
430     The function shall ensure, that the VM does not abort the process
431     during instantiation.
432     </p>
433  */
434 extern "C"
jfw_plugin_startJavaVirtualMachine(const JavaInfo * pInfo,const JavaVMOption * arOptions,sal_Int32 cOptions,JavaVM ** ppVm,JNIEnv ** ppEnv)435 javaPluginError jfw_plugin_startJavaVirtualMachine(
436     const JavaInfo *pInfo,
437     const JavaVMOption* arOptions,
438     sal_Int32 cOptions,
439     JavaVM ** ppVm,
440     JNIEnv ** ppEnv)
441 {
442     // unless guard is volatile the following warning occurs on gcc:
443     // warning: variable 't' might be clobbered by `longjmp' or `vfork'
444     volatile osl::MutexGuard guard(PluginMutex::get());
445     // unless errcode is volatile the following warning occurs on gcc:
446     // warning: variable 'errcode' might be clobbered by `longjmp' or `vfork'
447     volatile javaPluginError errcode = JFW_PLUGIN_E_NONE;
448     if ( pInfo == NULL || ppVm == NULL || ppEnv == NULL)
449         return JFW_PLUGIN_E_INVALID_ARG;
450     //Check if the Vendor (pInfo->sVendor) is supported by this plugin
451     if ( ! isVendorSupported(pInfo->sVendor))
452         return JFW_PLUGIN_E_WRONG_VENDOR;
453     rtl::OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
454     JFW_TRACE2(OUSTR("[Java framework] Using Java runtime library: ")
455               + sRuntimeLib + OUSTR(".\n"));
456     // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
457     // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
458     // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
459     oslModule moduleRt = 0;
460 #if defined(LINUX)
461     if ((moduleRt = osl_loadModule(sRuntimeLib.pData,
462                                    SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW)) == 0 )
463 #else
464     if ((moduleRt = osl_loadModule(sRuntimeLib.pData, SAL_LOADMODULE_DEFAULT)) == 0)
465 #endif
466      {
467          JFW_ENSURE(0, OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
468                              " could not load Java runtime library: \n")
469                     + sRuntimeLib + OUSTR("\n"));
470          JFW_TRACE0(OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
471                              " could not load Java runtime library: \n")
472                     + sRuntimeLib +  OUSTR("\n"));
473          return JFW_PLUGIN_E_VM_CREATION_FAILED;
474      }
475 
476 #ifdef UNX
477     //Setting the JAVA_HOME is needed for awt
478     rtl::OUString javaHome(RTL_CONSTASCII_USTRINGPARAM("JAVA_HOME="));
479     rtl::OUString sPathLocation;
480     osl_getSystemPathFromFileURL(pInfo->sLocation, & sPathLocation.pData);
481     javaHome += sPathLocation;
482     rtl::OString osJavaHome = rtl::OUStringToOString(
483         javaHome, osl_getThreadTextEncoding());
484     putenv(strdup(osJavaHome.getStr()));
485 #endif
486 
487     typedef jint JNICALL JNI_InitArgs_Type(void *);
488     typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
489     rtl::OUString sSymbolCreateJava(
490             RTL_CONSTASCII_USTRINGPARAM("JNI_CreateJavaVM"));
491 
492     JNI_CreateVM_Type * pCreateJavaVM = (JNI_CreateVM_Type *) osl_getFunctionSymbol(
493         moduleRt, sSymbolCreateJava.pData);
494     if (!pCreateJavaVM)
495     {
496         OSL_ASSERT(0);
497         rtl::OString sLib = rtl::OUStringToOString(
498             sRuntimeLib, osl_getThreadTextEncoding());
499         rtl::OString sSymbol = rtl::OUStringToOString(
500             sSymbolCreateJava, osl_getThreadTextEncoding());
501         fprintf(stderr,"[Java framework]sunjavaplugin" SAL_DLLEXTENSION
502                 "Java runtime library: %s does not export symbol %s !\n",
503                 sLib.getStr(), sSymbol.getStr());
504         return JFW_PLUGIN_E_VM_CREATION_FAILED;
505     }
506 
507     // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
508     // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
509     JavaVMInitArgs vm_args;
510 
511     std::vector<JavaVMOption> vecOptions;
512     vecOptions.reserve(cOptions + 1);
513 
514     // We set an abort handler which is called when the VM calls _exit during
515     // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
516     // all some directories of the Java installation. This is necessary for
517     // all versions below 1.5.1
518     vecOptions.push_back(JavaVMOption());
519     vecOptions.back().optionString = (char *) "abort";
520     vecOptions.back().extraInfo = (void* )(sal_IntPtr)abort_handler;
521 #if OSL_DEBUG_LEVEL >= 2
522         JFW_TRACE2(OString("VM option: ") + OString(vecOptions.back().optionString) +
523                    OString("\n"));
524 #endif
525     rtl::OString sClassPathProp("-Djava.class.path=");
526     rtl::OString sClassPathOption;
527     for (int i = 0; i < cOptions; i++)
528     {
529         rtl::OString sOptionString = arOptions[i].optionString;
530         if (sOptionString.match(sClassPathProp, 0) == sal_True)
531         {
532             // This option sets the class path
533             bool emptyClassPath = (sOptionString == sClassPathProp);
534             char sep[] =  {SAL_PATHSEPARATOR, 0};
535             OString sAddPath;
536             sClassPathOption = sOptionString;
537             // Add the installation directory as default class path
538             OUString macro(RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program"));
539             rtl::Bootstrap::expandMacros(macro);
540             OUString instDirectory;
541             osl_getSystemPathFromFileURL(macro.pData, &instDirectory.pData);
542             sAddPath = rtl::OUStringToOString(instDirectory, RTL_TEXTENCODING_UTF8);
543             if (sAddPath.getLength()) {
544                 if (!emptyClassPath) {
545                     sClassPathOption += rtl::OString(sep);
546                 }
547                 sClassPathOption += sAddPath;
548                 emptyClassPath = false;
549             }
550 #ifdef UNX
551             // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
552             // in the class path in order to have applet support.
553             sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
554             if (sAddPath.getLength()) {
555                 if (!emptyClassPath) {
556                     sClassPathOption += rtl::OString(sep);
557                 }
558                 sClassPathOption += sAddPath;
559                 emptyClassPath = false;
560             }
561 #endif
562             if (!emptyClassPath) {
563                 vecOptions.push_back(JavaVMOption());
564                 vecOptions.back().optionString = (char *) sClassPathOption.getStr();
565                 vecOptions.back().extraInfo = arOptions[i].extraInfo;
566             } // else avoid empty class path
567         }
568         else
569         {
570             vecOptions.push_back(JavaVMOption());
571             vecOptions.back().optionString = arOptions[i].optionString;
572             vecOptions.back().extraInfo = arOptions[i].extraInfo;
573         }
574         sOptionString = vecOptions.back().optionString;
575         if (sOptionString.match(sClassPathProp, 0) == sal_True) {
576             // Check for empty entries in the class path
577             sal_Int32 nIndex = sClassPathProp.getLength();
578             rtl::OString sToken;
579             char empty1[] = {'.', 0};
580             char empty2[] = {'.', SAL_PATHDELIMITER, 0};
581             const rtl::OString sEmpty1 = rtl::OString(empty1);
582             const rtl::OString sEmpty2 = rtl::OString(empty2);
583             do {
584                 sToken = sOptionString.getToken(0, SAL_PATHSEPARATOR, nIndex);
585                 if ((sToken.getLength() == 0) ||
586                     (sToken == sEmpty1) ||
587                     (sToken == sEmpty2)) {
588                     fprintf(stderr,"[Java framework]sunjavaplugin"
589                             SAL_DLLEXTENSION
590                             " Rejecting empty class path entry !\n");
591                     return JFW_PLUGIN_E_INVALID_ARG;
592                 }
593             } while (nIndex >= 0);
594         }
595 #if OSL_DEBUG_LEVEL >= 2
596         JFW_TRACE2(OString("VM option: ") + OString(vecOptions.back().optionString) +
597                    OString("\n"));
598 #endif
599     }
600 
601 #ifdef MACOSX
602     vm_args.version= JNI_VERSION_1_4; // issue 88987
603 #else
604     vm_args.version= JNI_VERSION_1_2;
605 #endif
606     vm_args.options= &vecOptions[0];
607     vm_args.nOptions= vecOptions.size();
608     vm_args.ignoreUnrecognized= JNI_TRUE;
609 
610     /* We set a global flag which is used by the abort handler in order to
611        determine whether it is  should use longjmp to get back into this function.
612        That is, the abort handler determines if it is on the same stack as this function
613        and then jumps back into this function.
614     */
615     g_bInGetJavaVM = 1;
616     jint err;
617     JavaVM * pJavaVM = 0;
618     memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
619     int jmpval= setjmp( jmp_jvm_abort );
620     /* If jmpval is not "0" then this point was reached by a longjmp in the
621        abort_handler, which was called indirectly by JNI_CreateVM.
622     */
623     if( jmpval == 0)
624     {
625         //returns negative number on failure
626         err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
627         g_bInGetJavaVM = 0;
628     }
629     else
630         // set err to a positive number, so as or recognize that an abort (longjmp)
631         //occurred
632         err= 1;
633 
634     if(err != 0)
635     {
636         rtl::OUString message;
637         if( err < 0)
638         {
639             fprintf( stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
640                     "Can not create Java Virtual Machine\n");
641             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
642         }
643         else if( err > 0)
644         {
645             fprintf( stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
646                     "Can not create JavaVirtualMachine, abort handler was called.\n");
647             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
648         }
649     }
650     else
651     {
652         *ppVm = pJavaVM;
653         JFW_TRACE2( "[Java framework] sunjavaplugin" SAL_DLLEXTENSION " has created a VM.\n");
654     }
655 
656 
657    return errcode;
658 }
659 
660 extern "C"
jfw_plugin_existJRE(const JavaInfo * pInfo,sal_Bool * exist)661 javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
662 {
663     javaPluginError ret = JFW_PLUGIN_E_NONE;
664     if (!pInfo || !exist)
665         return JFW_PLUGIN_E_INVALID_ARG;
666     ::rtl::OUString sLocation(pInfo->sLocation);
667 
668     if (sLocation.getLength() == 0)
669         return JFW_PLUGIN_E_INVALID_ARG;
670     ::osl::DirectoryItem item;
671     ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
672     if (::osl::File::E_None == rc_item)
673     {
674         *exist = sal_True;
675     }
676     else if (::osl::File::E_NOENT == rc_item)
677     {
678         *exist = sal_False;
679     }
680     else
681     {
682         ret = JFW_PLUGIN_E_ERROR;
683     }
684 #ifdef MACOSX
685     //We can have the situation that the JavaVM runtime library is not
686     //contained within JAVA_HOME. Then the check for JAVA_HOME would return
687     //true although the runtime library may not be loadable.
688     if (ret == JFW_PLUGIN_E_NONE && *exist == sal_True)
689     {
690         rtl::OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
691         JFW_TRACE2(OUSTR("[Java framework] Checking existence of Java runtime library.\n"));
692 
693         ::osl::DirectoryItem itemRt;
694         ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
695         if (::osl::File::E_None == rc_itemRt)
696         {
697             *exist = sal_True;
698             JFW_TRACE2(OUSTR("[Java framework] Java runtime library exist: ")
699               + sRuntimeLib + OUSTR("\n"));
700 
701         }
702         else if (::osl::File::E_NOENT == rc_itemRt)
703         {
704             *exist = sal_False;
705             JFW_TRACE2(OUSTR("[Java framework] Java runtime library does not exist: ")
706                        + sRuntimeLib + OUSTR("\n"));
707         }
708         else
709         {
710             ret = JFW_PLUGIN_E_ERROR;
711             JFW_TRACE2(OUSTR("[Java framework] Error while looking for Java runtime library: ")
712                        + sRuntimeLib + OUSTR(" \n"));
713         }
714     }
715 #endif
716     return ret;
717 }
718 
719 
720