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