1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
26 #include <rtl/ref.hxx>
27 #include <rtl/ustring.hxx>
28 #include <osl/diagnose.h>
30 #include <osl/file.hxx>
31 #include <osl/process.h>
33 #include <osl/thread.hxx>
34 #include <jvmfwk/framework.hxx>
35 #include <vendorbase.hxx>
36 #include <vendorplugin.hxx>
39 #include "framework.hxx"
40 #include <fwkutil.hxx>
41 #include <elements.hxx>
42 #include <fwkbase.hxx>
46 bool g_bEnabledSwitchedOn
= false;
48 JavaVM
* g_pJavaVM
= nullptr;
50 bool areEqualJavaInfo(
51 JavaInfo
const * pInfoA
,JavaInfo
const * pInfoB
)
53 return jfw_areEqualJavaInfo(pInfoA
, pInfoB
);
58 javaFrameworkError
jfw_findAllJREs(std::vector
<std::unique_ptr
<JavaInfo
>> *pparInfo
)
60 assert(pparInfo
!= nullptr);
63 osl::MutexGuard
guard(jfw::FwkMutex());
65 jfw::VendorSettings aVendorSettings
;
66 std::vector
<std::unique_ptr
<JavaInfo
>> vecInfo
;
68 //Use all plug-in libraries to get Java installations.
69 std::vector
<std::unique_ptr
<JavaInfo
>> arInfos
;
70 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> infos
;
71 javaPluginError plerr
= jfw_plugin_getAllJavaInfos(
77 if (plerr
!= javaPluginError::NONE
)
80 for (auto & j
: arInfos
)
81 vecInfo
.push_back(std::move(j
));
83 // direct mode disregards Java settings, so only retrieve
84 // JREs from settings when application mode is used
85 if (jfw::getMode() == jfw::JFW_MODE_APPLICATION
)
87 //get the list of paths to jre locations which have been
89 const jfw::MergedSettings settings
;
90 const std::vector
<OUString
> vecJRELocations
=
91 settings
.getJRELocations();
92 //Check if any plugin can detect JREs at the location
93 // of the paths added by jfw_addJRELocation
94 //Check every manually added location
95 for (auto const & ii
: vecJRELocations
)
97 std::unique_ptr
<JavaInfo
> aInfo
;
98 plerr
= jfw_plugin_getJavaInfoByPath(
102 if (plerr
== javaPluginError::NoJre
)
104 if (plerr
== javaPluginError::FailedVersion
)
106 if (plerr
== javaPluginError::WrongArch
)
108 else if (plerr
!= javaPluginError::NONE
)
111 // Was this JRE already added?
113 vecInfo
.begin(), vecInfo
.end(),
114 [&aInfo
](std::unique_ptr
<JavaInfo
> const & info
) {
115 return areEqualJavaInfo(
116 info
.get(), aInfo
.get());
119 vecInfo
.push_back(std::move(aInfo
));
124 *pparInfo
= std::move(vecInfo
);
128 catch (const jfw::FrameworkException
& e
)
130 SAL_WARN( "jfw", e
.message
);
135 javaFrameworkError
jfw_startVM(
136 JavaInfo
const * pInfo
, std::vector
<OUString
> const & arOptions
,
137 JavaVM
** ppVM
, JNIEnv
** ppEnv
)
139 assert(ppVM
!= nullptr);
140 javaFrameworkError errcode
= JFW_E_NONE
;
144 osl::MutexGuard
guard(jfw::FwkMutex());
146 //We keep this pointer so we can determine if a VM has already
148 if (g_pJavaVM
!= nullptr)
149 return JFW_E_RUNNING_JVM
;
151 std::vector
<OString
> vmParams
;
152 OString sUserClassPath
;
153 std::unique_ptr
<JavaInfo
> aInfo
;
154 if (pInfo
== nullptr)
156 jfw::JFW_MODE mode
= jfw::getMode();
157 if (mode
== jfw::JFW_MODE_APPLICATION
)
159 const jfw::MergedSettings settings
;
160 if (!settings
.getEnabled())
161 return JFW_E_JAVA_DISABLED
;
162 aInfo
= settings
.createJavaInfo();
163 //check if a Java has ever been selected
165 return JFW_E_NO_SELECT
;
167 //check if the javavendors.xml has changed after a Java was selected
168 OString sVendorUpdate
= jfw::getElementUpdated();
170 if (sVendorUpdate
!= settings
.getJavaInfoAttrVendorUpdate())
171 return JFW_E_INVALID_SETTINGS
;
173 //check if JAVA is disabled
174 //If Java is enabled, but it was disabled when this process was started
175 // then no preparational work, such as setting the LD_LIBRARY_PATH, was
176 //done. Therefore if a JRE needs it, it must not be started.
177 if (g_bEnabledSwitchedOn
&&
178 (aInfo
->nRequirements
& JFW_REQUIRE_NEEDRESTART
))
179 return JFW_E_NEED_RESTART
;
181 //Check if the selected Java was set in this process. If so it
182 //must not have the requirements flag JFW_REQUIRE_NEEDRESTART
183 if ((aInfo
->nRequirements
& JFW_REQUIRE_NEEDRESTART
)
184 && jfw::wasJavaSelectedInSameProcess())
185 return JFW_E_NEED_RESTART
;
187 vmParams
= settings
.getVmParametersUtf8();
188 sUserClassPath
= jfw::makeClassPathOption(settings
.getUserClassPath());
189 } // end mode FWK_MODE_OFFICE
190 else if (mode
== jfw::JFW_MODE_DIRECT
)
192 errcode
= jfw_getSelectedJRE(&aInfo
);
193 if (errcode
!= JFW_E_NONE
)
195 //In direct mode the options are specified by bootstrap variables
196 //of the form UNO_JAVA_JFW_PARAMETER_1 .. UNO_JAVA_JFW_PARAMETER_n
197 vmParams
= jfw::BootParams::getVMParameters();
198 auto const cp
= jfw::BootParams::getClasspath();
202 "-Djava.class.path=" + cp
;
209 assert(pInfo
!= nullptr);
212 // Alternative JREs (AdoptOpenJDK, Azul Zulu) are missing the bin/ folder in
213 // java.library.path. Somehow setting java.library.path accordingly doesn't work,
214 // but the PATH gets picked up, so add it there.
215 // Without this hack, some features don't work in alternative JREs.
217 osl_getEnvironment(OUString("PATH").pData
, &sPATH
.pData
);
218 OUString sJRELocation
;
219 osl::FileBase::getSystemPathFromFileURL(pInfo
->sLocation
+ "/bin", sJRELocation
);
221 sPATH
= sJRELocation
;
223 sPATH
= sJRELocation
+ OUStringChar(SAL_PATHSEPARATOR
) + sPATH
;
224 osl_setEnvironment(OUString("PATH").pData
, sPATH
.pData
);
227 // create JavaVMOptions array that is passed to the plugin
228 // it contains the classpath and all options set in the
230 std::unique_ptr
<JavaVMOption
[]> sarJOptions(
232 arOptions
.size() + (sUserClassPath
.isEmpty() ? 2 : 3) + vmParams
.size()]);
233 JavaVMOption
* arOpt
= sarJOptions
.get();
237 //The first argument is the classpath
239 if (!sUserClassPath
.isEmpty()) {
240 arOpt
[index
].optionString
= const_cast<char*>(sUserClassPath
.getStr());
241 arOpt
[index
].extraInfo
= nullptr;
244 // Set a flag that this JVM has been created via the JNI Invocation API
245 // (used, for example, by UNO remote bridges to share a common thread pool
246 // factory among Java and native bridge implementations):
247 arOpt
[index
].optionString
= const_cast<char *>("-Dorg.openoffice.native=");
248 arOpt
[index
].extraInfo
= nullptr;
251 // Don't intercept SIGTERM
252 arOpt
[index
].optionString
= const_cast<char *>("-Xrs");
253 arOpt
[index
].extraInfo
= nullptr;
256 //add the options set by options dialog
257 for (auto const & vmParam
: vmParams
)
259 arOpt
[index
].optionString
= const_cast<char*>(vmParam
.getStr());
260 arOpt
[index
].extraInfo
= nullptr;
263 //add all options of the arOptions argument
264 std::vector
<OString
> convertedOptions
;
265 for (auto const & ii
: arOptions
)
267 OString conv
= OUStringToOString(ii
, osl_getThreadTextEncoding());
268 convertedOptions
.push_back(conv
);
269 // keep conv.getStr() alive until after the call to
270 // jfw_plugin_startJavaVirtualMachine below
271 arOpt
[index
].optionString
= const_cast<char *>(conv
.getStr());
272 arOpt
[index
].extraInfo
= nullptr;
277 JavaVM
*pVm
= nullptr;
278 SAL_INFO("jfw", "Starting Java");
279 javaPluginError plerr
= jfw_plugin_startJavaVirtualMachine(pInfo
, arOpt
, index
, & pVm
, ppEnv
);
280 if (plerr
== javaPluginError::VmCreationFailed
)
282 errcode
= JFW_E_VM_CREATION_FAILED
;
284 else if (plerr
!= javaPluginError::NONE
)
286 errcode
= JFW_E_ERROR
;
294 catch (const jfw::FrameworkException
& e
)
296 errcode
= e
.errorCode
;
297 SAL_WARN( "jfw", e
.message
);
303 /** We do not use here jfw_findAllJREs and then check if a JavaInfo
304 meets the requirements, because that means using all plug-ins, which
305 may take quite a while. The implementation first inspects JAVA_HOME and
306 PATH environment variables. If no suitable JavaInfo is found there, it
307 inspects all JavaInfos found by the jfw_plugin_get* functions.
309 javaFrameworkError
jfw_findAndSelectJRE(std::unique_ptr
<JavaInfo
> *pInfo
)
311 javaFrameworkError errcode
= JFW_E_NONE
;
314 osl::MutexGuard
guard(jfw::FwkMutex());
315 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
316 return JFW_E_DIRECT_MODE
;
317 std::unique_ptr
<JavaInfo
> aCurrentInfo
;
320 // 'bInfoFound' indicates whether a Java installation has been found
321 bool bInfoFound
= false;
323 // get list of vendors for Java installations
324 jfw::VendorSettings aVendorSettings
;
326 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> infos
;
328 // first inspect Java installation that the JAVA_HOME
329 // environment variable points to (if it is set)
330 if (jfw_plugin_getJavaInfoFromJavaHome(
331 aVendorSettings
, &aCurrentInfo
, infos
)
332 == javaPluginError::NONE
)
337 // if no Java installation was detected by using JAVA_HOME,
338 // query PATH for Java installations
341 std::vector
<std::unique_ptr
<JavaInfo
>> vecJavaInfosFromPath
;
342 if (jfw_plugin_getJavaInfosFromPath(
343 aVendorSettings
, vecJavaInfosFromPath
, infos
)
344 == javaPluginError::NONE
)
346 assert(!vecJavaInfosFromPath
.empty());
347 aCurrentInfo
= std::move(vecJavaInfosFromPath
[0]);
353 // if no suitable Java installation has been found yet:
354 // first use jfw_plugin_getAllJavaInfos to find a suitable Java installation,
355 // then try paths that have been added manually
358 //get all installations
359 std::vector
<std::unique_ptr
<JavaInfo
>> arInfos
;
360 javaPluginError plerr
= jfw_plugin_getAllJavaInfos(
366 if (plerr
== javaPluginError::NONE
&& !arInfos
.empty())
368 aCurrentInfo
= std::move(arInfos
[0]);
372 {//The plug-ins did not find a suitable Java. Now try the paths which have been
374 //get the list of paths to jre locations which have been added manually
375 const jfw::MergedSettings settings
;
376 //node.loadFromSettings();
377 const std::vector
<OUString
> & vecJRELocations
=
378 settings
.getJRELocations();
379 //use all plug-ins to determine the JavaInfo objects
380 for (auto const & JRELocation
: vecJRELocations
)
382 std::unique_ptr
<JavaInfo
> aInfo
;
383 javaPluginError err
= jfw_plugin_getJavaInfoByPath(
387 if (err
== javaPluginError::NoJre
)
389 if (err
== javaPluginError::FailedVersion
)
391 else if (err
!=javaPluginError::NONE
)
396 aCurrentInfo
= std::move(aInfo
);
399 }//end iterate over paths
404 jfw::NodeJava
javaNode(jfw::NodeJava::USER
);
405 javaNode
.setJavaInfo(aCurrentInfo
.get(),true);
407 //remember that this JRE was selected in this process
408 jfw::setJavaSelected();
412 *pInfo
= std::move(aCurrentInfo
);
417 errcode
= JFW_E_NO_JAVA_FOUND
;
420 catch (const jfw::FrameworkException
& e
)
422 errcode
= e
.errorCode
;
423 SAL_WARN( "jfw", e
.message
);
429 bool jfw_areEqualJavaInfo(JavaInfo
const * pInfoA
,JavaInfo
const * pInfoB
)
431 if (pInfoA
== pInfoB
)
433 if (pInfoA
== nullptr || pInfoB
== nullptr)
435 if (pInfoA
->sVendor
== pInfoB
->sVendor
436 && pInfoA
->sLocation
== pInfoB
->sLocation
437 && pInfoA
->sVersion
== pInfoB
->sVersion
438 && pInfoA
->nRequirements
== pInfoB
->nRequirements
439 && pInfoA
->arVendorData
== pInfoB
->arVendorData
)
446 javaFrameworkError
jfw_getSelectedJRE(std::unique_ptr
<JavaInfo
> *ppInfo
)
448 assert(ppInfo
!= nullptr);
449 javaFrameworkError errcode
= JFW_E_NONE
;
452 osl::MutexGuard
guard(jfw::FwkMutex());
454 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
456 if ((errcode
= jfw_getJavaInfoByPath(
457 jfw::BootParams::getJREHome(), ppInfo
))
459 throw jfw::FrameworkException(
461 "[Java framework] The JRE specified by the bootstrap "
462 "variable UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME "
463 " could not be recognized. Check the values and make sure that you "
464 "use a plug-in library that can recognize that JRE.");
469 const jfw::MergedSettings settings
;
470 *ppInfo
= settings
.createJavaInfo();
475 //If the javavendors.xml has changed, then the current selected
476 //Java is not valid anymore
477 // /java/javaInfo/@vendorUpdate != javaSelection/updated (javavendors.xml)
478 OString sUpdated
= jfw::getElementUpdated();
480 if (sUpdated
!= settings
.getJavaInfoAttrVendorUpdate())
483 return JFW_E_INVALID_SETTINGS
;
486 catch (const jfw::FrameworkException
& e
)
488 errcode
= e
.errorCode
;
489 SAL_WARN( "jfw", e
.message
);
494 bool jfw_isVMRunning()
496 osl::MutexGuard
guard(jfw::FwkMutex());
497 return g_pJavaVM
!= nullptr;
500 javaFrameworkError
jfw_getJavaInfoByPath(OUString
const & pPath
, std::unique_ptr
<JavaInfo
> *ppInfo
)
502 assert(ppInfo
!= nullptr);
503 javaFrameworkError errcode
= JFW_E_NONE
;
506 osl::MutexGuard
guard(jfw::FwkMutex());
508 jfw::VendorSettings aVendorSettings
;
510 //ask all plugins if this is a JRE.
511 //If so check if it meets the version requirements.
512 //Only if it does return a JavaInfo
513 javaPluginError plerr
= jfw_plugin_getJavaInfoByPath(
518 if(plerr
== javaPluginError::FailedVersion
)
519 {//found JRE but it has the wrong version
521 errcode
= JFW_E_FAILED_VERSION
;
523 OSL_ASSERT(plerr
== javaPluginError::NONE
|| plerr
== javaPluginError::NoJre
);
524 if (!*ppInfo
&& errcode
!= JFW_E_FAILED_VERSION
)
525 errcode
= JFW_E_NOT_RECOGNIZED
;
527 catch (const jfw::FrameworkException
& e
)
529 errcode
= e
.errorCode
;
530 SAL_WARN( "jfw", e
.message
);
537 javaFrameworkError
jfw_setSelectedJRE(JavaInfo
const *pInfo
)
539 javaFrameworkError errcode
= JFW_E_NONE
;
542 osl::MutexGuard
guard(jfw::FwkMutex());
543 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
544 return JFW_E_DIRECT_MODE
;
545 //check if pInfo is the selected JRE
546 std::unique_ptr
<JavaInfo
> currentInfo
;
547 errcode
= jfw_getSelectedJRE( & currentInfo
);
548 if (errcode
!= JFW_E_NONE
&& errcode
!= JFW_E_INVALID_SETTINGS
)
551 if (!jfw_areEqualJavaInfo(currentInfo
.get(), pInfo
))
553 jfw::NodeJava
node(jfw::NodeJava::USER
);
554 node
.setJavaInfo(pInfo
, false);
556 //remember that the JRE was selected in this process
557 jfw::setJavaSelected();
560 catch (const jfw::FrameworkException
& e
)
562 errcode
= e
.errorCode
;
563 SAL_WARN( "jfw", e
.message
);
567 javaFrameworkError
jfw_setEnabled(bool bEnabled
)
569 javaFrameworkError errcode
= JFW_E_NONE
;
572 osl::MutexGuard
guard(jfw::FwkMutex());
573 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
574 return JFW_E_DIRECT_MODE
;
576 if (!g_bEnabledSwitchedOn
&& bEnabled
)
578 //When the process started then Enabled was false.
579 //This is first time enabled is set to true.
580 //That means, no preparational work has been done, such as setting the
581 //LD_LIBRARY_PATH, etc.
583 //check if Enabled is false;
584 const jfw::MergedSettings settings
;
585 if (!settings
.getEnabled())
586 g_bEnabledSwitchedOn
= true;
588 jfw::NodeJava
node(jfw::NodeJava::USER
);
589 node
.setEnabled(bEnabled
);
592 catch (const jfw::FrameworkException
& e
)
594 errcode
= e
.errorCode
;
595 SAL_WARN( "jfw", e
.message
);
600 javaFrameworkError
jfw_getEnabled(bool *pbEnabled
)
602 assert(pbEnabled
!= nullptr);
603 javaFrameworkError errcode
= JFW_E_NONE
;
606 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
607 return JFW_E_DIRECT_MODE
;
608 osl::MutexGuard
guard(jfw::FwkMutex());
609 jfw::MergedSettings settings
;
610 *pbEnabled
= settings
.getEnabled();
612 catch (const jfw::FrameworkException
& e
)
614 errcode
= e
.errorCode
;
615 SAL_WARN( "jfw", e
.message
);
621 javaFrameworkError
jfw_setVMParameters(std::vector
<OUString
> const & arOptions
)
623 javaFrameworkError errcode
= JFW_E_NONE
;
626 osl::MutexGuard
guard(jfw::FwkMutex());
627 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
628 return JFW_E_DIRECT_MODE
;
629 jfw::NodeJava
node(jfw::NodeJava::USER
);
630 node
.setVmParameters(arOptions
);
633 catch (const jfw::FrameworkException
& e
)
635 errcode
= e
.errorCode
;
636 SAL_WARN( "jfw", e
.message
);
642 javaFrameworkError
jfw_getVMParameters(std::vector
<OUString
> * parOptions
)
644 javaFrameworkError errcode
= JFW_E_NONE
;
647 osl::MutexGuard
guard(jfw::FwkMutex());
648 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
649 return JFW_E_DIRECT_MODE
;
651 const jfw::MergedSettings settings
;
652 settings
.getVmParametersArray(parOptions
);
654 catch (const jfw::FrameworkException
& e
)
656 errcode
= e
.errorCode
;
657 SAL_WARN( "jfw", e
.message
);
662 javaFrameworkError
jfw_setUserClassPath(OUString
const & pCp
)
664 javaFrameworkError errcode
= JFW_E_NONE
;
667 osl::MutexGuard
guard(jfw::FwkMutex());
668 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
669 return JFW_E_DIRECT_MODE
;
670 jfw::NodeJava
node(jfw::NodeJava::USER
);
671 node
.setUserClassPath(pCp
);
674 catch (const jfw::FrameworkException
& e
)
676 errcode
= e
.errorCode
;
677 SAL_WARN( "jfw", e
.message
);
682 javaFrameworkError
jfw_getUserClassPath(OUString
* ppCP
)
684 assert(ppCP
!= nullptr);
685 javaFrameworkError errcode
= JFW_E_NONE
;
688 osl::MutexGuard
guard(jfw::FwkMutex());
689 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
690 return JFW_E_DIRECT_MODE
;
691 const jfw::MergedSettings settings
;
692 *ppCP
= settings
.getUserClassPath();
694 catch (const jfw::FrameworkException
& e
)
696 errcode
= e
.errorCode
;
697 SAL_WARN( "jfw", e
.message
);
702 javaFrameworkError
jfw_addJRELocation(OUString
const & sLocation
)
704 javaFrameworkError errcode
= JFW_E_NONE
;
707 osl::MutexGuard
guard(jfw::FwkMutex());
708 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
709 return JFW_E_DIRECT_MODE
;
710 jfw::NodeJava
node(jfw::NodeJava::USER
);
712 node
.addJRELocation(sLocation
);
715 catch (const jfw::FrameworkException
& e
)
717 errcode
= e
.errorCode
;
718 SAL_WARN( "jfw", e
.message
);
725 javaFrameworkError
jfw_existJRE(const JavaInfo
*pInfo
, bool *exist
)
727 javaPluginError plerr
= jfw_plugin_existJRE(pInfo
, exist
);
729 javaFrameworkError ret
= JFW_E_NONE
;
732 case javaPluginError::NONE
:
735 case javaPluginError::Error
:
746 jfw::FwkMutex().acquire();
751 jfw::FwkMutex().release();
754 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */