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     boost::scoped_array<JavaVMOption> sarOptions(
512         new JavaVMOption[cOptions + 1]);
513     JavaVMOption * options = sarOptions.get();
514 
515     // We set an abort handler which is called when the VM calls _exit during
516     // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
517     // all some directories of the Java installation. This is necessary for
518     // all versions below 1.5.1
519     options[0].optionString= (char *) "abort";
520     options[0].extraInfo= (void* )(sal_IntPtr)abort_handler;
521     rtl::OString sClassPathProp("-Djava.class.path=");
522     rtl::OString sClassPathOption;
523     for (int i = 0; i < cOptions; i++)
524     {
525 #ifdef UNX
526     // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
527     // in the class path in order to have applet support.
528         rtl::OString sClassPath = arOptions[i].optionString;
529         if (sClassPath.match(sClassPathProp, 0) == sal_True)
530         {
531             char sep[] =  {SAL_PATHSEPARATOR, 0};
532             OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
533             if (sAddPath.getLength())
534                 sClassPathOption = sClassPath + rtl::OString(sep) + sAddPath;
535             else
536                 sClassPathOption = sClassPath;
537             options[i+1].optionString = (char *) sClassPathOption.getStr();
538             options[i+1].extraInfo = arOptions[i].extraInfo;
539         }
540         else
541         {
542 #endif
543             options[i+1].optionString = arOptions[i].optionString;
544             options[i+1].extraInfo = arOptions[i].extraInfo;
545 #ifdef UNX
546         }
547 #endif
548 #if OSL_DEBUG_LEVEL >= 2
549         JFW_TRACE2(OString("VM option: ") + OString(options[i+1].optionString) +
550                    OString("\n"));
551 #endif
552     }
553 
554 #ifdef MACOSX
555     vm_args.version= JNI_VERSION_1_4; // issue 88987
556 #else
557     vm_args.version= JNI_VERSION_1_2;
558 #endif
559     vm_args.options= options;
560     vm_args.nOptions= cOptions + 1;
561     vm_args.ignoreUnrecognized= JNI_TRUE;
562 
563     /* We set a global flag which is used by the abort handler in order to
564        determine whether it is  should use longjmp to get back into this function.
565        That is, the abort handler determines if it is on the same stack as this function
566        and then jumps back into this function.
567     */
568     g_bInGetJavaVM = 1;
569     jint err;
570     JavaVM * pJavaVM = 0;
571     memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
572     int jmpval= setjmp( jmp_jvm_abort );
573     /* If jmpval is not "0" then this point was reached by a longjmp in the
574        abort_handler, which was called indirectly by JNI_CreateVM.
575     */
576     if( jmpval == 0)
577     {
578         //returns negative number on failure
579         err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
580         g_bInGetJavaVM = 0;
581     }
582     else
583         // set err to a positive number, so as or recognize that an abort (longjmp)
584         //occurred
585         err= 1;
586 
587     if(err != 0)
588     {
589         rtl::OUString message;
590         if( err < 0)
591         {
592             fprintf(stderr,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
593                     "Can not create Java Virtual Machine\n");
594             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
595         }
596         else if( err > 0)
597         {
598             fprintf(stderr,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
599                     "Can not create JavaVirtualMachine, abort handler was called.\n");
600             errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
601         }
602     }
603     else
604     {
605         *ppVm = pJavaVM;
606         JFW_TRACE2("[Java framework] sunjavaplugin"SAL_DLLEXTENSION " has created a VM.\n");
607     }
608 
609 
610    return errcode;
611 }
612 
613 extern "C"
614 javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
615 {
616     javaPluginError ret = JFW_PLUGIN_E_NONE;
617     if (!pInfo || !exist)
618         return JFW_PLUGIN_E_INVALID_ARG;
619     ::rtl::OUString sLocation(pInfo->sLocation);
620 
621     if (sLocation.getLength() == 0)
622         return JFW_PLUGIN_E_INVALID_ARG;
623     ::osl::DirectoryItem item;
624     ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
625     if (::osl::File::E_None == rc_item)
626     {
627         *exist = sal_True;
628     }
629     else if (::osl::File::E_NOENT == rc_item)
630     {
631         *exist = sal_False;
632     }
633     else
634     {
635         ret = JFW_PLUGIN_E_ERROR;
636     }
637 #ifdef MACOSX
638     //We can have the situation that the JavaVM runtime library is not
639     //contained within JAVA_HOME. Then the check for JAVA_HOME would return
640     //true although the runtime library may not be loadable.
641     if (ret == JFW_PLUGIN_E_NONE && *exist == sal_True)
642     {
643         rtl::OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
644         JFW_TRACE2(OUSTR("[Java framework] Checking existence of Java runtime library.\n"));
645 
646         ::osl::DirectoryItem itemRt;
647         ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
648         if (::osl::File::E_None == rc_itemRt)
649         {
650             *exist = sal_True;
651             JFW_TRACE2(OUSTR("[Java framework] Java runtime library exist: ")
652               + sRuntimeLib + OUSTR("\n"));
653 
654         }
655         else if (::osl::File::E_NOENT == rc_itemRt)
656         {
657             *exist = sal_False;
658             JFW_TRACE2(OUSTR("[Java framework] Java runtime library does not exist: ")
659                        + sRuntimeLib + OUSTR("\n"));
660         }
661         else
662         {
663             ret = JFW_PLUGIN_E_ERROR;
664             JFW_TRACE2(OUSTR("[Java framework] Error while looking for Java runtime library: ")
665                        + sRuntimeLib + OUSTR(" \n"));
666         }
667     }
668 #endif
669     return ret;
670 }
671 
672 
673