merge the formfield patch from ooo-build
[ooovba.git] / jvmfwk / plugins / sunmajor / pluginlib / sunjavaplugin.cxx
bloba4c7f4f904ce286404f0b64ef2572eb5c01ae22d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sunjavaplugin.cxx,v $
10 * $Revision: 1.26 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_jvmfwk.hxx"
33 #if OSL_DEBUG_LEVEL > 0
34 #include <stdio.h>
35 #endif
36 #include <string.h>
38 #include "boost/scoped_array.hpp"
39 #include "osl/diagnose.h"
40 #include "rtl/ustring.hxx"
41 #include "rtl/ustrbuf.hxx"
42 #include "osl/module.hxx"
43 #include "osl/mutex.hxx"
44 #include "osl/thread.hxx"
45 #include "osl/file.hxx"
46 #include "rtl/instance.hxx"
47 #include "osl/getglobalmutex.hxx"
48 #include <setjmp.h>
49 #include <signal.h>
50 #include <stack>
52 #include "jni.h"
53 #include "rtl/byteseq.hxx"
54 #include "jvmfwk/vendorplugin.h"
55 #include "util.hxx"
56 #include "sunversion.hxx"
57 #include "vendorlist.hxx"
58 #include "diagnostics.h"
60 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
61 #define SUN_MICRO "Sun Microsystems Inc."
63 using namespace osl;
64 using namespace rtl;
65 using namespace std;
66 using namespace jfw_plugin;
68 namespace {
70 struct PluginMutex: public ::rtl::Static<osl::Mutex, PluginMutex> {};
72 #if defined UNX
73 OString getPluginJarPath(
74 const OUString & sVendor,
75 const OUString& sLocation,
76 const OUString& sVersion)
78 OString ret;
79 OUString sName1(RTL_CONSTASCII_USTRINGPARAM("javaplugin.jar"));
80 OUString sName2(RTL_CONSTASCII_USTRINGPARAM("plugin.jar"));
81 OUString sPath;
82 if (sVendor.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SUN_MICRO))))
84 SunVersion ver142("1.4.2-ea");
85 SunVersion ver150("1.5.0-ea");
86 SunVersion ver(sVersion);
87 OSL_ASSERT(ver142 && ver150 && ver);
89 OUString sName;
90 if (ver < ver142)
92 sName = sName1;
94 else if (ver < ver150)
95 {//this will cause ea, beta etc. to have plugin.jar in path.
96 //but this does not harm. 1.5.0-beta < 1.5.0
97 sName = sName2;
99 if (sName.getLength())
101 sName = sLocation + OUSTR("/lib/") + sName;
102 OSL_VERIFY(
103 osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
104 == osl_File_E_None);
107 else
109 char sep[] = {SAL_PATHSEPARATOR, 0};
110 OUString sName(sLocation + OUSTR("/lib/") + sName1);
111 OUString sPath1;
112 OUString sPath2;
113 if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
114 == osl_File_E_None)
116 sName = sLocation + OUSTR("/lib/") + sName2;
117 if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
118 == osl_File_E_None)
120 sPath = sPath1 + OUString::createFromAscii(sep) + sPath2;
123 OSL_ASSERT(sPath.getLength());
125 ret = rtl::OUStringToOString(sPath, osl_getThreadTextEncoding());
127 return ret;
129 #endif // UNX
132 JavaInfo* createJavaInfo(const rtl::Reference<VendorBase> & info)
134 JavaInfo* pInfo = (JavaInfo*) rtl_allocateMemory(sizeof(JavaInfo));
135 if (pInfo == NULL)
136 return NULL;
137 rtl::OUString sVendor = info->getVendor();
138 pInfo->sVendor = sVendor.pData;
139 rtl_uString_acquire(sVendor.pData);
140 rtl::OUString sHome = info->getHome();
141 pInfo->sLocation = sHome.pData;
142 rtl_uString_acquire(pInfo->sLocation);
143 rtl::OUString sVersion = info->getVersion();
144 pInfo->sVersion = sVersion.pData;
145 rtl_uString_acquire(pInfo->sVersion);
146 pInfo->nFeatures = info->supportsAccessibility() ? 1 : 0;
147 pInfo->nRequirements = info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0;
148 rtl::OUStringBuffer buf(1024);
149 buf.append(info->getRuntimeLibrary());
150 if (info->getLibraryPaths().getLength() > 0)
152 buf.appendAscii("\n");
153 buf.append(info->getLibraryPaths());
154 buf.appendAscii("\n");
157 rtl::OUString sVendorData = buf.makeStringAndClear();
158 rtl::ByteSequence byteSeq( (sal_Int8*) sVendorData.pData->buffer,
159 sVendorData.getLength() * sizeof(sal_Unicode));
160 pInfo->arVendorData = byteSeq.get();
161 rtl_byte_sequence_acquire(pInfo->arVendorData);
163 return pInfo;
166 rtl::OUString getRuntimeLib(const rtl::ByteSequence & data)
168 const sal_Unicode* chars = (sal_Unicode*) data.getConstArray();
169 sal_Int32 len = data.getLength();
170 rtl::OUString sData(chars, len / 2);
171 //the runtime lib is on the first line
172 sal_Int32 index = 0;
173 rtl::OUString aToken = sData.getToken( 0, '\n', index);
175 return aToken;
178 jmp_buf jmp_jvm_abort;
179 sig_atomic_t g_bInGetJavaVM = 0;
181 void abort_handler()
183 // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
184 if( g_bInGetJavaVM != 0 )
186 fprintf( stderr, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
187 longjmp( jmp_jvm_abort, 0);
193 extern "C"
194 javaPluginError jfw_plugin_getAllJavaInfos(
195 rtl_uString *sVendor,
196 rtl_uString *sMinVersion,
197 rtl_uString *sMaxVersion,
198 rtl_uString * *arExcludeList,
199 sal_Int32 nLenList,
200 JavaInfo*** parJavaInfo,
201 sal_Int32 *nLenInfoList)
203 OSL_ASSERT(sVendor);
204 OSL_ASSERT(sMinVersion);
205 OSL_ASSERT(sMaxVersion);
206 OSL_ASSERT(parJavaInfo);
207 OSL_ASSERT(parJavaInfo);
208 OSL_ASSERT(nLenInfoList);
209 if (!sVendor || !sMinVersion || !sMaxVersion || !parJavaInfo || !nLenInfoList)
210 return JFW_PLUGIN_E_INVALID_ARG;
212 //nLenlist contains the number of element in arExcludeList.
213 //If no exclude list is provided then nLenList must be 0
214 OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
215 if (arExcludeList == NULL && nLenList > 0)
216 return JFW_PLUGIN_E_INVALID_ARG;
218 OUString ouVendor(sVendor);
219 OUString ouMinVer(sMinVersion);
220 OUString ouMaxVer(sMaxVersion);
222 OSL_ASSERT(ouVendor.getLength() > 0);
223 if (ouVendor.getLength() == 0)
224 return JFW_PLUGIN_E_INVALID_ARG;
226 JavaInfo** arInfo = NULL;
228 //Find all JREs
229 vector<rtl::Reference<VendorBase> > vecInfos =
230 getAllJREInfos();
231 vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
233 typedef vector<rtl::Reference<VendorBase> >::iterator it;
234 for (it i= vecInfos.begin(); i != vecInfos.end(); i++)
236 const rtl::Reference<VendorBase>& cur = *i;
238 if (ouVendor.equals(cur->getVendor()) == sal_False)
239 continue;
241 if (ouMinVer.getLength() > 0)
245 if (cur->compareVersions(sMinVersion) == -1)
246 continue;
248 catch (MalformedVersionException&)
250 //The minVersion was not recognized as valid for this vendor.
251 JFW_ENSURE(
252 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
253 + ouMinVer + OUSTR(" for vendor: ") + cur->getVendor()
254 + OUSTR(" .Check minimum Version.") );
255 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
259 if (ouMaxVer.getLength() > 0)
263 if (cur->compareVersions(sMaxVersion) == 1)
264 continue;
266 catch (MalformedVersionException&)
268 //The maxVersion was not recognized as valid for this vendor.
269 JFW_ENSURE(
270 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
271 + ouMaxVer + OUSTR(" for vendor: ") + cur->getVendor()
272 + OUSTR(" .Check maximum Version.") );
273 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
277 if (arExcludeList > 0)
279 bool bExclude = false;
280 for (int j = 0; j < nLenList; j++)
282 rtl::OUString sExVer(arExcludeList[j]);
285 if (cur->compareVersions(sExVer) == 0)
287 bExclude = true;
288 break;
291 catch (MalformedVersionException&)
293 //The excluded version was not recognized as valid for this vendor.
294 JFW_ENSURE(
295 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
296 + sExVer + OUSTR(" for vendor: ") + cur->getVendor()
297 + OUSTR(" .Check excluded versions.") );
298 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
301 if (bExclude == true)
302 continue;
304 vecVerifiedInfos.push_back(*i);
306 //Now vecVerifiedInfos contains all those JREs which meet the version requirements
307 //Transfer them into the array that is passed out.
308 arInfo = (JavaInfo**) rtl_allocateMemory(vecVerifiedInfos.size() * sizeof (JavaInfo*));
309 int j = 0;
310 typedef vector<rtl::Reference<VendorBase> >::const_iterator cit;
311 for (cit ii = vecVerifiedInfos.begin(); ii != vecVerifiedInfos.end(); ii++, j++)
313 arInfo[j] = createJavaInfo(*ii);
315 *nLenInfoList = vecVerifiedInfos.size();
318 *parJavaInfo = arInfo;
319 return JFW_PLUGIN_E_NONE;
322 extern "C"
323 javaPluginError jfw_plugin_getJavaInfoByPath(
324 rtl_uString *path,
325 rtl_uString *sVendor,
326 rtl_uString *sMinVersion,
327 rtl_uString *sMaxVersion,
328 rtl_uString * *arExcludeList,
329 sal_Int32 nLenList,
330 JavaInfo ** ppInfo)
332 javaPluginError errcode = JFW_PLUGIN_E_NONE;
334 OSL_ASSERT(path);
335 OSL_ASSERT(sVendor);
336 OSL_ASSERT(sMinVersion);
337 OSL_ASSERT(sMaxVersion);
338 if (!path || !sVendor || !sMinVersion || !sMaxVersion || !ppInfo)
339 return JFW_PLUGIN_E_INVALID_ARG;
340 OUString ouPath(path);
341 OSL_ASSERT(ouPath.getLength() > 0);
342 if (ouPath.getLength() == 0)
343 return JFW_PLUGIN_E_INVALID_ARG;
345 //nLenlist contains the number of element in arExcludeList.
346 //If no exclude list is provided then nLenList must be 0
347 OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
348 if (arExcludeList == NULL && nLenList > 0)
349 return JFW_PLUGIN_E_INVALID_ARG;
351 OUString ouVendor(sVendor);
352 OUString ouMinVer(sMinVersion);
353 OUString ouMaxVer(sMaxVersion);
355 OSL_ASSERT(ouVendor.getLength() > 0);
356 if (ouVendor.getLength() == 0)
357 return JFW_PLUGIN_E_INVALID_ARG;
359 rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(ouPath);
360 if (aVendorInfo.is() == sal_False)
361 return JFW_PLUGIN_E_NO_JRE;
363 //Check if the detected JRE matches the version requirements
364 if (ouVendor.equals(aVendorInfo->getVendor()) == sal_False)
365 return JFW_PLUGIN_E_NO_JRE;
367 if (ouMinVer.getLength() > 0)
369 int nRes = 0;
372 nRes = aVendorInfo->compareVersions(ouMinVer);
374 catch (MalformedVersionException&)
376 //The minVersion was not recognized as valid for this vendor.
377 JFW_ENSURE(
378 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
379 + ouMinVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
380 + OUSTR(" .Check minimum Version.") );
381 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
383 if (nRes < 0)
384 return JFW_PLUGIN_E_FAILED_VERSION;
387 if (ouMaxVer.getLength() > 0)
389 int nRes = 0;
392 nRes = aVendorInfo->compareVersions(ouMaxVer);
394 catch (MalformedVersionException&)
396 //The maxVersion was not recognized as valid for this vendor.
397 JFW_ENSURE(
398 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
399 + ouMaxVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
400 + OUSTR(" .Check maximum Version.") );
401 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
403 if (nRes > 0)
404 return JFW_PLUGIN_E_FAILED_VERSION;
407 if (arExcludeList > 0)
409 for (int i = 0; i < nLenList; i++)
411 rtl::OUString sExVer(arExcludeList[i]);
412 int nRes = 0;
415 nRes = aVendorInfo->compareVersions(sExVer);
417 catch (MalformedVersionException&)
419 //The excluded version was not recognized as valid for this vendor.
420 JFW_ENSURE(
421 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
422 + sExVer + OUSTR(" for vendor: ") + aVendorInfo->getVendor()
423 + OUSTR(" .Check excluded versions.") );
424 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
426 if (nRes == 0)
427 return JFW_PLUGIN_E_FAILED_VERSION;
430 *ppInfo = createJavaInfo(aVendorInfo);
432 return errcode;
435 /** starts a Java Virtual Machine.
437 The function shall ensure, that the VM does not abort the process
438 during instantiation.
439 </p>
441 extern "C"
442 javaPluginError jfw_plugin_startJavaVirtualMachine(
443 const JavaInfo *pInfo,
444 const JavaVMOption* arOptions,
445 sal_Int32 cOptions,
446 JavaVM ** ppVm,
447 JNIEnv ** ppEnv)
449 // unless guard is volatile the following warning occurs on gcc:
450 // warning: variable 't' might be clobbered by `longjmp' or `vfork'
451 volatile osl::MutexGuard guard(PluginMutex::get());
452 // unless errcode is volatile the following warning occurs on gcc:
453 // warning: variable 'errcode' might be clobbered by `longjmp' or `vfork'
454 volatile javaPluginError errcode = JFW_PLUGIN_E_NONE;
455 if ( pInfo == NULL || ppVm == NULL || ppEnv == NULL)
456 return JFW_PLUGIN_E_INVALID_ARG;
457 //Check if the Vendor (pInfo->sVendor) is supported by this plugin
458 if ( ! isVendorSupported(pInfo->sVendor))
459 return JFW_PLUGIN_E_WRONG_VENDOR;
460 rtl::OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
461 JFW_TRACE2(OUSTR("[Java framework] Using Java runtime library: ")
462 + sRuntimeLib + OUSTR(".\n"));
463 // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
464 // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
465 // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
466 oslModule moduleRt = 0;
467 #if defined(LINUX)
468 if ((moduleRt = osl_loadModule(sRuntimeLib.pData,
469 SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW)) == 0 )
470 #else
471 if ((moduleRt = osl_loadModule(sRuntimeLib.pData, SAL_LOADMODULE_DEFAULT)) == 0)
472 #endif
474 JFW_ENSURE(0, OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
475 " could not load Java runtime library: \n")
476 + sRuntimeLib + OUSTR("."));
477 JFW_TRACE0(OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
478 " could not load Java runtime library: \n")
479 + sRuntimeLib + OUSTR("."));
480 return JFW_PLUGIN_E_VM_CREATION_FAILED;
483 #ifdef UNX
484 //Setting the JAVA_HOME is needed for awt
485 rtl::OUString javaHome(RTL_CONSTASCII_USTRINGPARAM("JAVA_HOME="));
486 rtl::OUString sPathLocation;
487 osl_getSystemPathFromFileURL(pInfo->sLocation, & sPathLocation.pData);
488 javaHome += sPathLocation;
489 rtl::OString osJavaHome = rtl::OUStringToOString(
490 javaHome, osl_getThreadTextEncoding());
491 putenv(strdup(osJavaHome.getStr()));
492 #endif
494 typedef jint JNICALL JNI_InitArgs_Type(void *);
495 typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
496 rtl::OUString sSymbolCreateJava(
497 RTL_CONSTASCII_USTRINGPARAM("JNI_CreateJavaVM"));
499 JNI_CreateVM_Type * pCreateJavaVM = (JNI_CreateVM_Type *) osl_getFunctionSymbol(
500 moduleRt, sSymbolCreateJava.pData);
501 if (!pCreateJavaVM)
503 OSL_ASSERT(0);
504 rtl::OString sLib = rtl::OUStringToOString(
505 sRuntimeLib, osl_getThreadTextEncoding());
506 rtl::OString sSymbol = rtl::OUStringToOString(
507 sSymbolCreateJava, osl_getThreadTextEncoding());
508 fprintf(stderr,"[Java framework]sunjavaplugin"SAL_DLLEXTENSION
509 "Java runtime library: %s does not export symbol %s !\n",
510 sLib.getStr(), sSymbol.getStr());
511 return JFW_PLUGIN_E_VM_CREATION_FAILED;
514 // The office sets a signal handler at startup. That causes a crash
515 // with java 1.3 under Solaris. To make it work, we set back the
516 // handler
517 #ifdef UNX
518 struct sigaction act;
519 act.sa_handler=SIG_DFL;
520 act.sa_flags= 0;
521 sigaction( SIGSEGV, &act, NULL);
522 sigaction( SIGPIPE, &act, NULL);
523 sigaction( SIGBUS, &act, NULL);
524 sigaction( SIGILL, &act, NULL);
525 sigaction( SIGFPE, &act, NULL);
526 #endif
528 // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
529 // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
530 JavaVMInitArgs vm_args;
532 boost::scoped_array<JavaVMOption> sarOptions(
533 new JavaVMOption[cOptions + 1]);
534 JavaVMOption * options = sarOptions.get();
536 // We set an abort handler which is called when the VM calls _exit during
537 // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
538 // all some directories of the Java installation. This is necessary for
539 // all versions below 1.5.1
540 options[0].optionString= (char *) "abort";
541 options[0].extraInfo= (void* )(sal_IntPtr)abort_handler;
542 rtl::OString sClassPathProp("-Djava.class.path=");
543 rtl::OString sClassPathOption;
544 for (int i = 0; i < cOptions; i++)
546 #ifdef UNX
547 // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
548 // in the class path in order to have applet support.
549 rtl::OString sClassPath = arOptions[i].optionString;
550 if (sClassPath.match(sClassPathProp, 0) == sal_True)
552 char sep[] = {SAL_PATHSEPARATOR, 0};
553 OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
554 if (sAddPath.getLength())
555 sClassPathOption = sClassPath + rtl::OString(sep) + sAddPath;
556 else
557 sClassPathOption = sClassPath;
558 options[i+1].optionString = (char *) sClassPathOption.getStr();
559 options[i+1].extraInfo = arOptions[i].extraInfo;
561 else
563 #endif
564 options[i+1].optionString = arOptions[i].optionString;
565 options[i+1].extraInfo = arOptions[i].extraInfo;
566 #ifdef UNX
568 #endif
569 #if OSL_DEBUG_LEVEL >= 2
570 JFW_TRACE2(OString("VM option: ") + OString(options[i+1].optionString) +
571 OString("\n"));
572 #endif
575 #ifdef MACOSX
576 vm_args.version= JNI_VERSION_1_4; // issue 88987
577 #else
578 vm_args.version= JNI_VERSION_1_2;
579 #endif
580 vm_args.options= options;
581 vm_args.nOptions= cOptions + 1;
582 vm_args.ignoreUnrecognized= JNI_TRUE;
584 /* We set a global flag which is used by the abort handler in order to
585 determine whether it is should use longjmp to get back into this function.
586 That is, the abort handler determines if it is on the same stack as this function
587 and then jumps back into this function.
589 g_bInGetJavaVM = 1;
590 jint err;
591 JavaVM * pJavaVM = 0;
592 memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
593 int jmpval= setjmp( jmp_jvm_abort );
594 /* If jmpval is not "0" then this point was reached by a longjmp in the
595 abort_handler, which was called indirectly by JNI_CreateVM.
597 if( jmpval == 0)
599 //returns negative number on failure
600 err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
601 g_bInGetJavaVM = 0;
603 else
604 // set err to a positive number, so as or recognize that an abort (longjmp)
605 //occurred
606 err= 1;
608 if(err != 0)
610 rtl::OUString message;
611 if( err < 0)
613 fprintf(stderr,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
614 "Can not create Java Virtual Machine\n");
615 errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
617 else if( err > 0)
619 fprintf(stderr,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
620 "Can not create JavaVirtualMachine, abort handler was called.\n");
621 errcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
624 else
626 *ppVm = pJavaVM;
627 JFW_TRACE2("[Java framework] sunjavaplugin"SAL_DLLEXTENSION " has created a VM.\n");
631 return errcode;