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
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 
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 
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 
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"
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"
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"
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 #ifdef UNX
531     // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
532     // in the class path in order to have applet support.
533         if (sOptionString.match(sClassPathProp, 0) == sal_True)
534         {
535             bool emptyClassPath = (sOptionString == sClassPathProp);
536             char sep[] =  {SAL_PATHSEPARATOR, 0};
537             OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
538             if (sAddPath.getLength()) {
539                 sClassPathOption = sOptionString;
540                 if (!emptyClassPath) {
541                     sClassPathOption += rtl::OString(sep);
542                 }
543                 sClassPathOption += sAddPath;
544                 emptyClassPath = false;
545             } else
546                 sClassPathOption = sOptionString;
547             if (!emptyClassPath) {
548                 vecOptions.push_back(JavaVMOption());
549                 vecOptions.back().optionString = (char *) sClassPathOption.getStr();
550                 vecOptions.back().extraInfo = arOptions[i].extraInfo;
551             } // else avoid empty class path
552         }
553         else
554         {
555 #endif
556             vecOptions.push_back(JavaVMOption());
557             vecOptions.back().optionString = arOptions[i].optionString;
558             vecOptions.back().extraInfo = arOptions[i].extraInfo;
559 #ifdef UNX
560         }
561 #endif
562         sOptionString = vecOptions.back().optionString;
563         if (sOptionString.match(sClassPathProp, 0) == sal_True) {
564             // Check for empty entries in the class path
565             sal_Int32 nIndex = sClassPathProp.getLength();
566             rtl::OString sToken;
567             char empty1[] = {'.', 0};
568             char empty2[] = {'.', SAL_PATHDELIMITER, 0};
569             const rtl::OString sEmpty1 = rtl::OString(empty1);
570             const rtl::OString sEmpty2 = rtl::OString(empty2);
571             do {
572                 sToken = sOptionString.getToken(0, SAL_PATHSEPARATOR, nIndex);
573                 if ((sToken.getLength() == 0) ||
574                     (sToken == sEmpty1) ||
575                     (sToken == sEmpty2)) {
576                     fprintf(stderr,"[Java framework]sunjavaplugin"
577                             SAL_DLLEXTENSION
578                             " Rejecting empty class path entry !\n");
579                     return JFW_PLUGIN_E_INVALID_ARG;
580                 }
581             } while (nIndex >= 0);
582         }
583 #if OSL_DEBUG_LEVEL >= 2
584         JFW_TRACE2(OString("VM option: ") + OString(vecOptions.back().optionString) +
585                    OString("\n"));
586 #endif
587     }
588 
589 #ifdef MACOSX
590     vm_args.version= JNI_VERSION_1_4; // issue 88987
591 #else
592     vm_args.version= JNI_VERSION_1_2;
593 #endif
594     vm_args.options= &vecOptions[0];
595     vm_args.nOptions= vecOptions.size();
596     vm_args.ignoreUnrecognized= JNI_TRUE;
597 
598     /* We set a global flag which is used by the abort handler in order to
599        determine whether it is  should use longjmp to get back into this function.
600        That is, the abort handler determines if it is on the same stack as this function
601        and then jumps back into this function.
602     */
603     g_bInGetJavaVM = 1;
604     jint err;
605     JavaVM * pJavaVM = 0;
606     memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
607     int jmpval= setjmp( jmp_jvm_abort );
608     /* If jmpval is not "0" then this point was reached by a longjmp in the
609        abort_handler, which was called indirectly by JNI_CreateVM.
610     */
611     if( jmpval == 0)
612     {
613         //returns negative number on failure
614         err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
615         g_bInGetJavaVM = 0;
616     }
617     else
618         // set err to a positive number, so as or recognize that an abort (longjmp)
619         //occurred
620         err= 1;
621 
622     if(err != 0)
623     {
624         rtl::OUString message;
625         if( err < 0)
626         {
627             fprintf( stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
628                     "Can not create Java Virtual Machine\n");
629             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
630         }
631         else if( err > 0)
632         {
633             fprintf( stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
634                     "Can not create JavaVirtualMachine, abort handler was called.\n");
635             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
636         }
637     }
638     else
639     {
640         *ppVm = pJavaVM;
641         JFW_TRACE2( "[Java framework] sunjavaplugin" SAL_DLLEXTENSION " has created a VM.\n");
642     }
643 
644 
645    return errcode;
646 }
647 
648 extern "C"
649 javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
650 {
651     javaPluginError ret = JFW_PLUGIN_E_NONE;
652     if (!pInfo || !exist)
653         return JFW_PLUGIN_E_INVALID_ARG;
654     ::rtl::OUString sLocation(pInfo->sLocation);
655 
656     if (sLocation.getLength() == 0)
657         return JFW_PLUGIN_E_INVALID_ARG;
658     ::osl::DirectoryItem item;
659     ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
660     if (::osl::File::E_None == rc_item)
661     {
662         *exist = sal_True;
663     }
664     else if (::osl::File::E_NOENT == rc_item)
665     {
666         *exist = sal_False;
667     }
668     else
669     {
670         ret = JFW_PLUGIN_E_ERROR;
671     }
672 #ifdef MACOSX
673     //We can have the situation that the JavaVM runtime library is not
674     //contained within JAVA_HOME. Then the check for JAVA_HOME would return
675     //true although the runtime library may not be loadable.
676     if (ret == JFW_PLUGIN_E_NONE && *exist == sal_True)
677     {
678         rtl::OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
679         JFW_TRACE2(OUSTR("[Java framework] Checking existence of Java runtime library.\n"));
680 
681         ::osl::DirectoryItem itemRt;
682         ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
683         if (::osl::File::E_None == rc_itemRt)
684         {
685             *exist = sal_True;
686             JFW_TRACE2(OUSTR("[Java framework] Java runtime library exist: ")
687               + sRuntimeLib + OUSTR("\n"));
688 
689         }
690         else if (::osl::File::E_NOENT == rc_itemRt)
691         {
692             *exist = sal_False;
693             JFW_TRACE2(OUSTR("[Java framework] Java runtime library does not exist: ")
694                        + sRuntimeLib + OUSTR("\n"));
695         }
696         else
697         {
698             ret = JFW_PLUGIN_E_ERROR;
699             JFW_TRACE2(OUSTR("[Java framework] Error while looking for Java runtime library: ")
700                        + sRuntimeLib + OUSTR(" \n"));
701         }
702     }
703 #endif
704     return ret;
705 }
706 
707 
708