summaryrefslogtreecommitdiffstats
path: root/stoc/source/javavm/javavm.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /stoc/source/javavm/javavm.cxx
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'stoc/source/javavm/javavm.cxx')
-rw-r--r--stoc/source/javavm/javavm.cxx1595
1 files changed, 1595 insertions, 0 deletions
diff --git a/stoc/source/javavm/javavm.cxx b/stoc/source/javavm/javavm.cxx
new file mode 100644
index 000000000..7df1fed46
--- /dev/null
+++ b/stoc/source/javavm/javavm.cxx
@@ -0,0 +1,1595 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "javavm.hxx"
+
+#include "interact.hxx"
+#include "jvmargs.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/java/JavaNotFoundException.hpp>
+#include <com/sun/star/java/InvalidJavaSettingsException.hpp>
+#include <com/sun/star/java/RestartRequiredException.hpp>
+#include <com/sun/star/java/JavaDisabledException.hpp>
+#include <com/sun/star/java/JavaVMCreationFailureException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <jvmaccess/classpath.hxx>
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+#include <rtl/process.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <uno/current_context.hxx>
+#include <jvmfwk/framework.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <jni.h>
+
+#include <stack>
+#include <string.h>
+#include <time.h>
+#include <memory>
+#include <vector>
+
+// Properties of the javavm can be put
+// as a comma separated list in this
+// environment variable
+#ifdef UNIX
+#define TIMEZONE "MEZ"
+#else
+#define TIMEZONE "MET"
+#endif
+
+/* Within this implementation of the com.sun.star.java.JavaVirtualMachine
+ * service and com.sun.star.java.theJavaVirtualMachine singleton, the method
+ * com.sun.star.java.XJavaVM.getJavaVM relies on the following:
+ * 1 The string "$URE_INTERNAL_JAVA_DIR/" is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into an internal (see the
+ * com.sun.star.uri.ExternalUriReferenceTranslator service), hierarchical URI
+ * reference relative to which the URE JAR files can be addressed.
+ * 2 The string "$URE_INTERNAL_JAVA_CLASSPATH" is either not expandable via the
+ * com.sun.star.util.theMacroExpander singleton
+ * (com.sun.star.lang.IllegalArgumentException), or is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into a list of zero or more
+ * internal (see the com.sun.star.uri.ExternalUriReferenceTranslator service)
+ * URIs, where any space characters (U+0020) are ignored (and, in particular,
+ * separate adjacent URIs).
+ * If either of these requirements is not met, getJavaVM raises a
+ * com.sun.star.uno.RuntimeException.
+ */
+
+using stoc_javavm::JavaVirtualMachine;
+
+namespace {
+
+
+class NoJavaIniException: public css::uno::Exception
+{
+};
+
+class SingletonFactory:
+ private cppu::WeakImplHelper< css::lang::XEventListener >
+{
+public:
+ static css::uno::Reference< css::uno::XInterface > getSingleton(
+ css::uno::Reference< css::uno::XComponentContext > const & rContext);
+
+private:
+ SingletonFactory() {}
+
+ virtual ~SingletonFactory() override {}
+
+ SingletonFactory(const SingletonFactory&) = delete;
+ SingletonFactory& operator=(const SingletonFactory&) = delete;
+
+ virtual void SAL_CALL disposing(css::lang::EventObject const &) override;
+
+ static void dispose();
+
+ // TODO ok to keep these static?
+ static osl::Mutex m_aMutex;
+ static css::uno::Reference< css::uno::XInterface > m_xSingleton;
+ static bool m_bDisposed;
+};
+
+css::uno::Reference< css::uno::XInterface > SingletonFactory::getSingleton(
+ css::uno::Reference< css::uno::XComponentContext > const & rContext)
+{
+ css::uno::Reference< css::uno::XInterface > xSingleton;
+ css::uno::Reference< css::lang::XComponent > xComponent;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (!m_xSingleton.is())
+ {
+ if (m_bDisposed)
+ throw css::lang::DisposedException();
+ xComponent.set( rContext, css::uno::UNO_QUERY_THROW);
+ m_xSingleton = static_cast< cppu::OWeakObject * >(
+ new JavaVirtualMachine(rContext));
+ }
+ xSingleton = m_xSingleton;
+ }
+ if (xComponent.is())
+ try
+ {
+ xComponent->addEventListener(new SingletonFactory);
+ }
+ catch (...)
+ {
+ dispose();
+ throw;
+ }
+ return xSingleton;
+}
+
+void SAL_CALL SingletonFactory::disposing(css::lang::EventObject const &)
+{
+ dispose();
+}
+
+void SingletonFactory::dispose()
+{
+ css::uno::Reference< css::lang::XComponent > xComponent;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ xComponent.set( m_xSingleton, css::uno::UNO_QUERY);
+ m_xSingleton.clear();
+ m_bDisposed = true;
+ }
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+osl::Mutex SingletonFactory::m_aMutex;
+css::uno::Reference< css::uno::XInterface > SingletonFactory::m_xSingleton;
+bool SingletonFactory::m_bDisposed = false;
+
+OUString serviceGetImplementationName()
+{
+ return "com.sun.star.comp.stoc.JavaVirtualMachine";
+}
+
+css::uno::Sequence< OUString > serviceGetSupportedServiceNames()
+{
+ return css::uno::Sequence< OUString > { "com.sun.star.java.JavaVirtualMachine" };
+}
+
+css::uno::Reference< css::uno::XInterface > serviceCreateInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & rContext)
+{
+ // Only one single instance of this service is ever constructed, and is
+ // available until the component context used to create this instance is
+ // disposed. Afterwards, this function throws a DisposedException (as do
+ // all relevant methods on the single service instance).
+ return SingletonFactory::getSingleton(rContext);
+}
+
+cppu::ImplementationEntry const aServiceImplementation[]
+ = { { serviceCreateInstance,
+ serviceGetImplementationName,
+ serviceGetSupportedServiceNames,
+ cppu::createSingleComponentFactory,
+ nullptr, 0 },
+ { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } };
+
+typedef std::stack< jvmaccess::VirtualMachine::AttachGuard * > GuardStack;
+
+extern "C" {
+
+static void destroyAttachGuards(void * pData)
+{
+ GuardStack * pStack = static_cast< GuardStack * >(pData);
+ if (pStack != nullptr)
+ {
+ while (!pStack->empty())
+ {
+ delete pStack->top();
+ pStack->pop();
+ }
+ delete pStack;
+ }
+}
+
+}
+
+bool askForRetry(css::uno::Any const & rException)
+{
+ css::uno::Reference< css::uno::XCurrentContext > xContext(
+ css::uno::getCurrentContext());
+ if (xContext.is())
+ {
+ css::uno::Reference< css::task::XInteractionHandler > xHandler;
+ xContext->getValueByName("java-vm.interaction-handler")
+ >>= xHandler;
+ if (xHandler.is())
+ {
+ rtl::Reference< stoc_javavm::InteractionRequest > xRequest(
+ new stoc_javavm::InteractionRequest(rException));
+ xHandler->handle(xRequest.get());
+ return xRequest->retry();
+ }
+ }
+ return false;
+}
+
+// Only gets the properties if the "Proxy Server" entry in the option dialog is
+// set to manual (i.e. not to none)
+/// @throws css::uno::Exception
+void getINetPropsFromConfig(stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry = xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx );
+ if(!xConfRegistry.is()) throw css::uno::RuntimeException("javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Inet", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+// if ooInetProxyType is not 0 then read the settings
+ css::uno::Reference<css::registry::XRegistryKey> proxyEnable= xRegistryRootKey->openKey("Settings/ooInetProxyType");
+ if( proxyEnable.is() && 0 != proxyEnable->getLongValue())
+ {
+ // read ftp proxy name
+ css::uno::Reference<css::registry::XRegistryKey> ftpProxy_name = xRegistryRootKey->openKey("Settings/ooInetFTPProxyName");
+ if(ftpProxy_name.is() && !ftpProxy_name->getStringValue().isEmpty()) {
+ OUString ftpHost = "ftp.proxyHost=" + ftpProxy_name->getStringValue();
+
+ // read ftp proxy port
+ css::uno::Reference<css::registry::XRegistryKey> ftpProxy_port = xRegistryRootKey->openKey("Settings/ooInetFTPProxyPort");
+ if(ftpProxy_port.is() && ftpProxy_port->getLongValue()) {
+ OUString ftpPort = "ftp.proxyPort=" + OUString::number(ftpProxy_port->getLongValue());
+
+ pjvm->pushProp(ftpHost);
+ pjvm->pushProp(ftpPort);
+ }
+ }
+
+ // read http proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyName");
+ if(httpProxy_name.is() && !httpProxy_name->getStringValue().isEmpty()) {
+ OUString httpHost = "http.proxyHost=" + httpProxy_name->getStringValue();
+
+ // read http proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyPort");
+ if(httpProxy_port.is() && httpProxy_port->getLongValue()) {
+ OUString httpPort = "http.proxyPort=" + OUString::number(httpProxy_port->getLongValue());
+
+ pjvm->pushProp(httpHost);
+ pjvm->pushProp(httpPort);
+ }
+ }
+
+ // read https proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyName");
+ if(httpsProxy_name.is() && !httpsProxy_name->getStringValue().isEmpty()) {
+ OUString httpsHost = "https.proxyHost=" + httpsProxy_name->getStringValue();
+
+ // read https proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyPort");
+ if(httpsProxy_port.is() && httpsProxy_port->getLongValue()) {
+ OUString httpsPort = "https.proxyPort=" + OUString::number(httpsProxy_port->getLongValue());
+
+ pjvm->pushProp(httpsHost);
+ pjvm->pushProp(httpsPort);
+ }
+ }
+
+ // read nonProxyHosts
+ css::uno::Reference<css::registry::XRegistryKey> nonProxies_name = xRegistryRootKey->openKey("Settings/ooInetNoProxy");
+ if(nonProxies_name.is() && !nonProxies_name->getStringValue().isEmpty()) {
+ OUString value = nonProxies_name->getStringValue();
+ // replace the separator ";" by "|"
+ value = value.replace(';', '|');
+
+ OUString httpNonProxyHosts = "http.nonProxyHosts=" + value;
+ OUString ftpNonProxyHosts = "ftp.nonProxyHosts=" + value;
+
+ pjvm->pushProp(httpNonProxyHosts);
+ pjvm->pushProp(ftpNonProxyHosts);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getDefaultLocaleFromConfig(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext( "com.sun.star.configuration.ConfigurationRegistry", xCtx );
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Setup", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+ // Since 1.7 Java knows DISPLAY and FORMAT locales, which match our UI and
+ // system locale. See
+ // http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/569b1b644416/src/share/classes/java/util/Locale.java
+ // https://docs.oracle.com/javase/tutorial/i18n/locale/scope.html
+ // https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html
+
+ // Read UI language/locale.
+ css::uno::Reference<css::registry::XRegistryKey> xUILocale = xRegistryRootKey->openKey("L10N/ooLocale");
+ if(xUILocale.is() && !xUILocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xUILocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ if(!language.isEmpty()) {
+ OUString prop = "user.language=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ // As of Java 7 also script is supported.
+ if(!script.isEmpty()) {
+ OUString prop = "user.script=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country=" + country;
+ pjvm->pushProp(prop);
+ }
+
+ // Java 7 DISPLAY category is our UI language/locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.display=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.display=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.display=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ // Read system locale.
+ css::uno::Reference<css::registry::XRegistryKey> xLocale = xRegistryRootKey->openKey("L10N/ooSetupSystemLocale");
+ if(xLocale.is() && !xLocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xLocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ // Java 7 FORMAT category is our system locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.format=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.format=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.format=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getJavaPropsFromSafetySettings(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx)
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx);
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open(
+ "org.openoffice.Office.Java",
+ true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey =
+ xConfRegistry_simple->getRootKey();
+
+ if (xRegistryRootKey.is())
+ {
+ css::uno::Reference<css::registry::XRegistryKey> key_NetAccess= xRegistryRootKey->openKey("VirtualMachine/NetAccess");
+ if (key_NetAccess.is())
+ {
+ sal_Int32 val= key_NetAccess->getLongValue();
+ OUString sVal;
+ switch( val)
+ {
+ case 0: sVal = "host";
+ break;
+ case 1: sVal = "unrestricted";
+ break;
+ case 3: sVal = "none";
+ break;
+ }
+ OUString sProperty = "appletviewer.security.mode=" + sVal;
+ pjvm->pushProp(sProperty);
+ }
+ css::uno::Reference<css::registry::XRegistryKey> key_CheckSecurity= xRegistryRootKey->openKey(
+ "VirtualMachine/Security");
+ if( key_CheckSecurity.is())
+ {
+ bool val = static_cast<bool>(key_CheckSecurity->getLongValue());
+ OUString sProperty("stardiv.security.disableSecurity=");
+ if( val)
+ sProperty += "false";
+ else
+ sProperty += "true";
+ pjvm->pushProp( sProperty);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+void setTimeZone(stoc_javavm::JVM * pjvm) throw() {
+ /* A Bug in the Java function
+ ** struct Hjava_util_Properties * java_lang_System_initProperties(
+ ** struct Hjava_lang_System *this,
+ ** struct Hjava_util_Properties *props);
+ ** This function doesn't detect MEZ, MET or "W. Europe Standard Time"
+ */
+ struct tm *tmData;
+ time_t clock = time(nullptr);
+ tzset();
+ tmData = localtime(&clock);
+#ifdef MACOSX
+ char * p = tmData->tm_zone;
+#elif defined(_MSC_VER)
+ char * p = _tzname[0];
+ (void)tmData;
+#else
+ char * p = tzname[0];
+ (void)tmData;
+#endif
+
+ if (!strcmp(TIMEZONE, p))
+ pjvm->pushProp("user.timezone=ECT");
+}
+
+/// @throws css::uno::Exception
+void initVMConfiguration(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext > &xCtx)
+{
+ stoc_javavm::JVM jvm;
+ try {
+ getINetPropsFromConfig(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception &) {
+ TOOLS_INFO_EXCEPTION("stoc", "can not get INETProps");
+ }
+
+ try {
+ getDefaultLocaleFromConfig(&jvm, xSMgr,xCtx);
+ }
+ catch(const css::uno::Exception &) {
+ TOOLS_INFO_EXCEPTION("stoc", "can not get locale");
+ }
+
+ try
+ {
+ getJavaPropsFromSafetySettings(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception &) {
+ TOOLS_INFO_EXCEPTION("stoc", "couldn't get safety settings");
+ }
+
+ *pjvm= jvm;
+
+ // rhbz#1285356, native look will be gtk2, which crashes
+ // when gtk3 is already loaded. Until there is a solution
+ // java-side force look and feel to something that doesn't
+ // crash when we are using gtk3
+ if (getenv("STOC_FORCE_SYSTEM_LAF"))
+ pjvm->pushProp("swing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel");
+
+ setTimeZone(pjvm);
+}
+
+class DetachCurrentThread {
+public:
+ explicit DetachCurrentThread(JavaVM * jvm): m_jvm(jvm) {}
+
+ ~DetachCurrentThread() {
+ if (m_jvm->DetachCurrentThread() != 0) {
+ OSL_ASSERT(false);
+ }
+ }
+
+ DetachCurrentThread(const DetachCurrentThread&) = delete;
+ DetachCurrentThread& operator=(const DetachCurrentThread&) = delete;
+
+private:
+ JavaVM * m_jvm;
+};
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void * javavm_component_getFactory(char const * pImplName,
+ void * pServiceManager,
+ void * pRegistryKey)
+{
+ return cppu::component_getFactoryHelper(pImplName, pServiceManager,
+ pRegistryKey,
+ aServiceImplementation);
+}
+
+JavaVirtualMachine::JavaVirtualMachine(
+ css::uno::Reference< css::uno::XComponentContext > const & rContext):
+ JavaVirtualMachine_Impl(m_aMutex),
+ m_xContext(rContext),
+ m_bDisposed(false),
+ m_pJavaVm(nullptr),
+ m_aAttachGuards(destroyAttachGuards) // TODO check for validity
+{}
+
+void SAL_CALL
+JavaVirtualMachine::initialize(css::uno::Sequence< css::uno::Any > const &
+ rArguments)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "bad call to initialize",
+ static_cast< cppu::OWeakObject * >(this));
+ css::beans::NamedValue val;
+ if (rArguments.getLength() == 1 && (rArguments[0] >>= val) && val.Name == "UnoVirtualMachine" )
+ {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::UnoVirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::UnoVirtualMachine * >(nullptr));
+ val.Value >>= nPointer;
+ m_xUnoVirtualMachine =
+ reinterpret_cast< jvmaccess::UnoVirtualMachine * >(nPointer);
+ } else {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::VirtualMachine * >(nullptr));
+ if (rArguments.getLength() == 1)
+ rArguments[0] >>= nPointer;
+ rtl::Reference< jvmaccess::VirtualMachine > vm(
+ reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer));
+ if (vm.is()) {
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(vm, nullptr);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ throw css::lang::IllegalArgumentException(
+ "sequence of exactly one any containing either (a) a"
+ " com.sun.star.beans.NamedValue with Name"
+ " \"UnoVirtualMachine\" and Value a hyper representing a"
+ " non-null pointer to a jvmaccess:UnoVirtualMachine, or (b)"
+ " a hyper representing a non-null pointer to a"
+ " jvmaccess::VirtualMachine required",
+ static_cast< cppu::OWeakObject * >(this), 0);
+ }
+ m_xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+}
+
+OUString SAL_CALL JavaVirtualMachine::getImplementationName()
+{
+ return serviceGetImplementationName();
+}
+
+sal_Bool SAL_CALL
+JavaVirtualMachine::supportsService(OUString const & rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL
+JavaVirtualMachine::getSupportedServiceNames()
+{
+ return serviceGetSupportedServiceNames();
+}
+
+css::uno::Any SAL_CALL
+JavaVirtualMachine::getJavaVM(css::uno::Sequence< sal_Int8 > const & rProcessId)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ css::uno::Sequence< sal_Int8 > aId(16);
+ rtl_getGlobalProcessId(reinterpret_cast< sal_uInt8 * >(aId.getArray()));
+ enum ReturnType {
+ RETURN_JAVAVM, RETURN_VIRTUALMACHINE, RETURN_UNOVIRTUALMACHINE };
+ ReturnType returnType =
+ rProcessId.getLength() == 17 && rProcessId[16] == 0
+ ? RETURN_VIRTUALMACHINE
+ : rProcessId.getLength() == 17 && rProcessId[16] == 1
+ ? RETURN_UNOVIRTUALMACHINE
+ : RETURN_JAVAVM;
+ css::uno::Sequence< sal_Int8 > aProcessId(rProcessId);
+ if (returnType != RETURN_JAVAVM)
+ aProcessId.realloc(16);
+ if (aId != aProcessId)
+ return css::uno::Any();
+
+ std::unique_ptr<JavaInfo> info;
+ while (!m_xVirtualMachine.is()) // retry until successful
+ {
+ stoc_javavm::JVM aJvm;
+ initVMConfiguration(&aJvm, m_xContext->getServiceManager(),
+ m_xContext);
+ const std::vector<OUString> & props = aJvm.getProperties();
+ std::vector<OUString> options;
+ options.reserve(props.size());
+ for (auto const& i : props)
+ {
+ options.push_back(i.startsWith("-") ? i : "-D" + i);
+ }
+
+ JNIEnv * pMainThreadEnv = nullptr;
+ javaFrameworkError errcode = JFW_E_NONE;
+
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errcode = JFW_E_NO_SELECT;
+ else
+ errcode = jfw_startVM(info.get(), options, & m_pJavaVm,
+ & pMainThreadEnv);
+
+ bool bStarted = false;
+ switch (errcode)
+ {
+ case JFW_E_NONE: bStarted = true; break;
+ case JFW_E_NO_SELECT:
+ {
+ // No Java configured. We silently run the Java configuration
+ info.reset();
+ javaFrameworkError errFind = jfw_findAndSelectJRE(&info);
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errFind = JFW_E_NO_JAVA_FOUND;
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ else if (errFind == JFW_E_NO_JAVA_FOUND)
+ {
+
+ //Warning MessageBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform this task.
+ //Please install a JRE and restart %PRODUCTNAME.
+ css::java::JavaNotFoundException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " No suitable JRE found!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::makeAny(exc));
+ return css::uno::Any();
+ }
+ else
+ {
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while searching for a Java, " + OUString::number(errFind), nullptr);
+ }
+ }
+ case JFW_E_INVALID_SETTINGS:
+ {
+ //Warning MessageBox:
+ // The %PRODUCTNAME configuration has been changed. Under Tools
+ // - Options - %PRODUCTNAME - Java, select the Java runtime environment
+ // you want to have used by %PRODUCTNAME.
+ css::java::InvalidJavaSettingsException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " Java settings have changed!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::makeAny(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_JAVA_DISABLED:
+ {
+ bool bDontEnableJava = false;
+ auto xContext(css::uno::getCurrentContext());
+ if (xContext.is())
+ xContext->getValueByName("DontEnableJava") >>= bDontEnableJava;
+ if (bDontEnableJava)
+ return css::uno::Any();
+
+ //QueryBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform
+ //this task. However, use of a JRE has been disabled. Do you want to
+ //enable the use of a JRE now?
+ css::java::JavaDisabledException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is disabled!",
+ static_cast< cppu::OWeakObject * >(this));
+ if( ! askForRetry(css::uno::makeAny(exc)))
+ return css::uno::Any();
+ continue;
+ }
+ case JFW_E_VM_CREATION_FAILED:
+ {
+ //If the creation failed because the JRE has been uninstalled then
+ //we search another one. As long as there is a javaldx, we should
+ //never come into this situation. javaldx checks always if the JRE
+ //still exist.
+ std::unique_ptr<JavaInfo> aJavaInfo;
+ if (JFW_E_NONE == jfw_getSelectedJRE(&aJavaInfo))
+ {
+ bool bExist = false;
+ if (JFW_E_NONE == jfw_existJRE(aJavaInfo.get(), &bExist))
+ {
+ if (!bExist
+ && ! (aJavaInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
+ {
+ info.reset();
+ javaFrameworkError errFind = jfw_findAndSelectJRE(
+ &info);
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ }
+ }
+ }
+
+ //Error: %PRODUCTNAME requires a Java
+ //runtime environment (JRE) to perform this task. The selected JRE
+ //is defective. Please select another version or install a new JRE
+ //and select it under Tools - Options - %PRODUCTNAME - Java.
+ css::java::JavaVMCreationFailureException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is defective!",
+ static_cast< cppu::OWeakObject * >(this), 0);
+ askForRetry(css::uno::makeAny(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_RUNNING_JVM:
+ {
+ //This service should make sure that we do not start java twice.
+ OSL_ASSERT(false);
+ break;
+ }
+ case JFW_E_NEED_RESTART:
+ {
+ //Error:
+ //For the selected Java runtime environment to work properly,
+ //%PRODUCTNAME must be restarted. Please restart %PRODUCTNAME now.
+ css::java::RestartRequiredException exc(
+ "JavaVirtualMachine::getJavaVM failed because "
+ "Office must be restarted before Java can be used!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::makeAny(exc));
+ return css::uno::Any();
+ }
+ default:
+ //RuntimeException: error is somewhere in the java framework.
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while starting Java!", nullptr);
+ }
+
+ if (bStarted)
+ {
+ {
+ DetachCurrentThread detach(m_pJavaVm);
+ // necessary to make debugging work; this thread will be
+ // suspended when the destructor of detach returns
+ m_xVirtualMachine = new jvmaccess::VirtualMachine(
+ m_pJavaVm, JNI_VERSION_1_2, true, pMainThreadEnv);
+ setUpUnoVirtualMachine(pMainThreadEnv);
+ }
+ // Listen for changes in the configuration (e.g. proxy settings):
+ // TODO this is done too late; changes to the configuration done
+ // after the above call to initVMConfiguration are lost
+ registerConfigChangesListener();
+
+ break;
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ try {
+ jvmaccess::VirtualMachine::AttachGuard guard(m_xVirtualMachine);
+ setUpUnoVirtualMachine(guard.getEnvironment());
+ } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException occurred",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ }
+ switch (returnType) {
+ default: // RETURN_JAVAVM
+ if (m_pJavaVm == nullptr) {
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine service was initialized in a way"
+ " that the requested JavaVM pointer is not available",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+ return css::uno::makeAny(reinterpret_cast< sal_IntPtr >(m_pJavaVm));
+ case RETURN_VIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::makeAny(
+ reinterpret_cast< sal_Int64 >(
+ m_xUnoVirtualMachine->getVirtualMachine().get()));
+ case RETURN_UNOVIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::makeAny(
+ reinterpret_cast< sal_Int64 >(m_xUnoVirtualMachine.get()));
+ }
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMStarted()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ return m_xUnoVirtualMachine.is();
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMEnabled()
+{
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ }
+// stoc_javavm::JVM aJvm;
+// initVMConfiguration(&aJvm, m_xContext->getServiceManager(), m_xContext);
+// return aJvm.isEnabled();
+ //ToDo
+ bool bEnabled = false;
+ if (jfw_getEnabled( & bEnabled) != JFW_E_NONE)
+ throw css::uno::RuntimeException();
+ return bEnabled;
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isThreadAttached()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ // TODO isThreadAttached only returns true if the thread was attached via
+ // registerThread:
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ return pStack != nullptr && !pStack->empty();
+}
+
+void SAL_CALL JavaVirtualMachine::registerThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::registerThread: null VirtualMachine",
+ static_cast< cppu::OWeakObject * >(this));
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr)
+ {
+ pStack = new GuardStack;
+ m_aAttachGuards.setData(pStack);
+ }
+ try
+ {
+ pStack->push(
+ new jvmaccess::VirtualMachine::AttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine()));
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "JavaVirtualMachine::registerThread: jvmaccess::"
+ "VirtualMachine::AttachGuard::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::revokeThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: null VirtualMachine",
+ static_cast< cppu::OWeakObject * >(this));
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr || pStack->empty())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: no matching registerThread",
+ static_cast< cppu::OWeakObject * >(this));
+ delete pStack->top();
+ pStack->pop();
+}
+
+void SAL_CALL
+JavaVirtualMachine::disposing(css::lang::EventObject const & rSource)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (rSource.Source == m_xInetConfiguration)
+ m_xInetConfiguration.clear();
+ if (rSource.Source == m_xJavaConfiguration)
+ m_xJavaConfiguration.clear();
+}
+
+void SAL_CALL JavaVirtualMachine::elementInserted(
+ css::container::ContainerEvent const &)
+{}
+
+void SAL_CALL JavaVirtualMachine::elementRemoved(
+ css::container::ContainerEvent const &)
+{}
+
+// If a user changes the setting, for example for proxy settings, then this
+// function will be called from the configuration manager. Even if the .xml
+// file does not contain an entry yet and that entry has to be inserted, this
+// function will be called. We call java.lang.System.setProperty for the new
+// values.
+void SAL_CALL JavaVirtualMachine::elementReplaced(
+ css::container::ContainerEvent const & rEvent)
+{
+ // TODO Using the new value stored in rEvent is wrong here. If two threads
+ // receive different elementReplaced calls in quick succession, it is
+ // unspecified which changes the JVM's system properties last. A correct
+ // solution must atomically (i.e., protected by a mutex) read the latest
+ // value from the configuration and set it as a system property at the JVM.
+
+ OUString aAccessor;
+ rEvent.Accessor >>= aAccessor;
+ OUString aPropertyName;
+ OUString aPropertyName2;
+ OUString aPropertyValue;
+ bool bSecurityChanged = false;
+ if ( aAccessor == "ooInetProxyType" )
+ {
+ // Proxy none, manually
+ sal_Int32 value = 0;
+ rEvent.Element >>= value;
+ setINetSettingsInVM(value != 0);
+ return;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyName" )
+ {
+ aPropertyName = "http.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyPort" )
+ {
+ aPropertyName = "http.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyName" )
+ {
+ aPropertyName = "https.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyPort" )
+ {
+ aPropertyName = "https.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetFTPProxyName" )
+ {
+ aPropertyName = "ftp.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetFTPProxyPort" )
+ {
+ aPropertyName = "ftp.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetNoProxy" )
+ {
+ aPropertyName = "http.nonProxyHosts";
+ aPropertyName2 = "ftp.nonProxyHosts";
+ rEvent.Element >>= aPropertyValue;
+ aPropertyValue = aPropertyValue.replace(';', '|');
+ }
+ else if ( aAccessor == "NetAccess" )
+ {
+ aPropertyName = "appletviewer.security.mode";
+ sal_Int32 n = 0;
+ if (rEvent.Element >>= n)
+ switch (n)
+ {
+ case 0:
+ aPropertyValue = "host";
+ break;
+ case 1:
+ aPropertyValue = "unrestricted";
+ break;
+ case 3:
+ aPropertyValue = "none";
+ break;
+ }
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else if ( aAccessor == "Security" )
+ {
+ aPropertyName = "stardiv.security.disableSecurity";
+ bool b;
+ if (rEvent.Element >>= b)
+ if (b)
+ aPropertyValue = "false";
+ else
+ aPropertyValue = "true";
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else
+ return;
+
+ rtl::Reference< jvmaccess::VirtualMachine > xVirtualMachine;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_xUnoVirtualMachine.is()) {
+ xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+ }
+ }
+ if (!xVirtualMachine.is())
+ return;
+
+ try
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ xVirtualMachine);
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // call java.lang.System.setProperty
+ // String setProperty( String key, String value)
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ jstring jsPropName= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName.getStr()), aPropertyName.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // remove the property if it does not have a value ( user left the dialog field empty)
+ // or if the port is set to 0
+ aPropertyValue= aPropertyValue.trim();
+ if( aPropertyValue.isEmpty() ||
+ ( ( aPropertyName == "ftp.proxyPort" || aPropertyName == "http.proxyPort" /*|| aPropertyName == "socksProxyPort"*/ ) && aPropertyValue == "0" )
+ )
+ {
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // call java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Properties.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsPropName);
+
+ // special case for ftp.nonProxyHosts and http.nonProxyHosts. The office only
+ // has a value for two java properties
+ if (!aPropertyName2.isEmpty())
+ {
+ jstring jsPropName2= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName2.getStr()), aPropertyName2.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsPropName2);
+ }
+ }
+ else
+ {
+ // Change the Value of the property
+ jstring jsPropValue= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyValue.getStr()), aPropertyValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsPropName, jsPropValue);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+
+ // special case for ftp.nonProxyHosts and http.nonProxyHosts. The office only
+ // has a value for two java properties
+ if (!aPropertyName2.isEmpty())
+ {
+ jstring jsPropName2= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName2.getStr()), aPropertyName2.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jsPropValue= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyValue.getStr()), aPropertyValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsPropName2, jsPropValue);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ }
+
+ // If the settings for Security and NetAccess changed then we have to notify the SandboxSecurity
+ // SecurityManager
+ // call System.getSecurityManager()
+ if (bSecurityChanged)
+ {
+ jmethodID jmGetSecur= pJNIEnv->GetStaticMethodID( jcSystem,"getSecurityManager","()Ljava/lang/SecurityManager;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getSecurityManager", nullptr);
+ jobject joSecur= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetSecur);
+ if (joSecur != nullptr)
+ {
+ // Make sure the SecurityManager is our SandboxSecurity
+ // FindClass("com.sun.star.lib.sandbox.SandboxSecurityManager" only worked at the first time
+ // this code was executed. Maybe it is a security feature. However, all attempts to debug the
+ // SandboxSecurity class (maybe the VM invokes checkPackageAccess) failed.
+// jclass jcSandboxSec= pJNIEnv->FindClass("com.sun.star.lib.sandbox.SandboxSecurity");
+// if(pJNIEnv->ExceptionOccurred()) throw RuntimeException("JNI:FindClass com.sun.star.lib.sandbox.SandboxSecurity");
+// jboolean bIsSand= pJNIEnv->IsInstanceOf( joSecur, jcSandboxSec);
+ // The SecurityManagers class Name must be com.sun.star.lib.sandbox.SandboxSecurity
+ jclass jcSec= pJNIEnv->GetObjectClass( joSecur);
+ jclass jcClass= pJNIEnv->FindClass("java/lang/Class");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java.lang.Class", nullptr);
+ jmethodID jmName= pJNIEnv->GetMethodID( jcClass,"getName","()Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.lang.Class.getName", nullptr);
+ jstring jsClass= static_cast<jstring>(pJNIEnv->CallObjectMethod( jcSec, jmName));
+ const jchar* jcharName= pJNIEnv->GetStringChars( jsClass, nullptr);
+ OUString sName(reinterpret_cast<sal_Unicode const *>(jcharName));
+ bool bIsSandbox;
+ bIsSandbox = sName == "com.sun.star.lib.sandbox.SandboxSecurity";
+ pJNIEnv->ReleaseStringChars( jsClass, jcharName);
+
+ if (bIsSandbox)
+ {
+ // call SandboxSecurity.reset
+ jmethodID jmReset= pJNIEnv->GetMethodID( jcSec,"reset","()V");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ pJNIEnv->CallVoidMethod( joSecur, jmReset);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallVoidMethod com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ }
+ }
+ }
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+JavaVirtualMachine::~JavaVirtualMachine()
+{
+ if (m_xInetConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xInetConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+ if (m_xJavaConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xJavaConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::disposing()
+{
+ css::uno::Reference< css::container::XContainer > xContainer1;
+ css::uno::Reference< css::container::XContainer > xContainer2;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ m_bDisposed = true;
+ xContainer1 = m_xInetConfiguration;
+ m_xInetConfiguration.clear();
+ xContainer2 = m_xJavaConfiguration;
+ m_xJavaConfiguration.clear();
+ }
+ if (xContainer1.is())
+ xContainer1->removeContainerListener(this);
+ if (xContainer2.is())
+ xContainer2->removeContainerListener(this);
+}
+
+/*We listen to changes in the configuration. For example, the user changes the proxy
+ settings in the options dialog (menu tools). Then we are notified of this change and
+ if the java vm is already running we change the properties (System.lang.System.setProperties)
+ through JNI.
+ To receive notifications this class implements XContainerListener.
+*/
+void JavaVirtualMachine::registerConfigChangesListener()
+{
+ try
+ {
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
+ m_xContext->getValueByName(
+ "/singletons/com.sun.star.configuration.theDefaultProvider"),
+ css::uno::UNO_QUERY);
+
+ if (xConfigProvider.is())
+ {
+ // We register this instance as listener to changes in org.openoffice.Inet/Settings
+ // arguments for ConfigurationAccess
+ css::uno::Sequence<css::uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Inet/Settings"))},
+ {"depth", css::uno::Any(sal_Int32(-1))}
+ }));
+ m_xInetConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments),
+ css::uno::UNO_QUERY);
+
+ if (m_xInetConfiguration.is())
+ m_xInetConfiguration->addContainerListener(this);
+
+ // now register as listener to changes in org.openoffice.Java/VirtualMachine
+ css::uno::Sequence<css::uno::Any> aArguments2(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Office.Java/VirtualMachine"))},
+ {"depth", css::uno::Any(sal_Int32(-1))} // depth: -1 means unlimited
+ }));
+ m_xJavaConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments2),
+ css::uno::UNO_QUERY);
+
+ if (m_xJavaConfiguration.is())
+ m_xJavaConfiguration->addContainerListener(this);
+ }
+ }catch(const css::uno::Exception &)
+ {
+ TOOLS_INFO_EXCEPTION("stoc", "could not set up listener for Configuration");
+ }
+}
+
+// param true: all Inet setting are set as Java Properties on a live VM.
+// false: the Java net properties are set to empty value.
+void JavaVirtualMachine::setINetSettingsInVM(bool set_reset)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ try
+ {
+ if (m_xUnoVirtualMachine.is())
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine());
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // The Java Properties
+ OUString sFtpProxyHost("ftp.proxyHost");
+ OUString sFtpProxyPort("ftp.proxyPort");
+ OUString sFtpNonProxyHosts ("ftp.nonProxyHosts");
+ OUString sHttpProxyHost("http.proxyHost");
+ OUString sHttpProxyPort("http.proxyPort");
+ OUString sHttpNonProxyHosts("http.nonProxyHosts");
+
+ // create Java Properties as JNI strings
+ jstring jsFtpProxyHost= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpProxyHost.getStr()), sFtpProxyHost.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsFtpProxyPort= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpProxyPort.getStr()), sFtpProxyPort.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsFtpNonProxyHosts= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpNonProxyHosts.getStr()), sFtpNonProxyHosts.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpProxyHost= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyHost.getStr()), sHttpProxyHost.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpProxyPort= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyPort.getStr()), sHttpProxyPort.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpNonProxyHosts= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpNonProxyHosts.getStr()), sHttpNonProxyHosts.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // prepare java.lang.System.setProperty
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // prepare java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+
+ if (set_reset)
+ {
+ // Set all network properties with the VM
+ JVM jvm;
+ getINetPropsFromConfig( &jvm, m_xContext->getServiceManager(), m_xContext);
+ const ::std::vector< OUString> & Props = jvm.getProperties();
+
+ for( auto& prop : Props)
+ {
+ sal_Int32 index= prop.indexOf( '=');
+ OUString propName= prop.copy( 0, index);
+ OUString propValue= prop.copy( index + 1);
+
+ if( propName == sFtpProxyHost)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpProxyHost, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sFtpProxyPort)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpProxyPort, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sFtpNonProxyHosts)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpNonProxyHosts, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpProxyHost)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyHost, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpProxyPort)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyPort, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpNonProxyHosts)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpNonProxyHosts, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ }
+ }
+ else
+ {
+ // call java.util.Properties.remove
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Property.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpProxyHost);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpProxyPort);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpNonProxyHosts);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyHost);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyPort);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpNonProxyHosts);
+ }
+ }
+ }
+ catch (css::uno::RuntimeException &)
+ {
+ OSL_FAIL("RuntimeException");
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ OSL_FAIL("jvmaccess::VirtualMachine::AttachGuard::CreationException");
+ }
+}
+
+void JavaVirtualMachine::setUpUnoVirtualMachine(JNIEnv * environment) {
+ css::uno::Reference< css::util::XMacroExpander > exp = css::util::theMacroExpander::get(m_xContext);
+ OUString baseUrl;
+ try {
+ baseUrl = exp->expandMacros("$URE_INTERNAL_JAVA_DIR/");
+ } catch (css::lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "css::lang::IllegalArgumentException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ OUString classPath;
+ try {
+ classPath = exp->expandMacros("$URE_INTERNAL_JAVA_CLASSPATH");
+ } catch (css::lang::IllegalArgumentException &) {}
+ jclass class_URLClassLoader = environment->FindClass(
+ "java/net/URLClassLoader");
+ if (class_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URLClassLoader = environment->GetMethodID(
+ class_URLClassLoader, "<init>", "([Ljava/net/URL;)V");
+ if (ctor_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_URL = environment->FindClass("java/net/URL");
+ if (class_URL == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_1 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/lang/String;)V");
+ if (ctor_URL_1 == nullptr) {
+ handleJniException(environment);
+ }
+ jvalue args[3];
+ args[0].l = environment->NewString(
+ reinterpret_cast< jchar const * >(baseUrl.getStr()),
+ static_cast< jsize >(baseUrl.getLength()));
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject base = environment->NewObjectA(class_URL, ctor_URL_1, args);
+ if (base == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_2 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/net/URL;Ljava/lang/String;)V");
+ if (ctor_URL_2 == nullptr) {
+ handleJniException(environment);
+ }
+ jobjectArray classpath = jvmaccess::ClassPath::translateToUrls(
+ m_xContext, environment, classPath);
+ if (classpath == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = environment->NewStringUTF("unoloader.jar");
+ if (args[1].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectA(class_URL, ctor_URL_2, args);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectArray(1, class_URL, args[0].l);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject cl1 = environment->NewObjectA(
+ class_URLClassLoader, ctor_URLClassLoader, args);
+ if (cl1 == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID method_loadClass = environment->GetMethodID(
+ class_URLClassLoader, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ if (method_loadClass == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewStringUTF(
+ "com.sun.star.lib.unoloader.UnoClassLoader");
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_UnoClassLoader = static_cast< jclass >(
+ environment->CallObjectMethodA(cl1, method_loadClass, args));
+ if (class_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_UnoClassLoader = environment->GetMethodID(
+ class_UnoClassLoader, "<init>",
+ "(Ljava/net/URL;[Ljava/net/URL;Ljava/lang/ClassLoader;)V");
+ if (ctor_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = classpath;
+ args[2].l = cl1;
+ jobject cl2 = environment->NewObjectA(
+ class_UnoClassLoader, ctor_UnoClassLoader, args);
+ if (cl2 == nullptr) {
+ handleJniException(environment);
+ }
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(
+ m_xVirtualMachine, cl2);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+void JavaVirtualMachine::handleJniException(JNIEnv * environment) {
+#if defined DBG_UTIL
+ environment->ExceptionDescribe();
+#else
+ environment->ExceptionClear();
+#endif
+ throw css::uno::RuntimeException(
+ "JNI exception occurred",
+ static_cast< cppu::OWeakObject * >(this));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */