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>
29 #include <osl/file.hxx>
30 #include <osl/process.h>
31 #include <osl/thread.hxx>
32 #include <jvmfwk/framework.hxx>
33 #include <vendorbase.hxx>
34 #include <vendorplugin.hxx>
37 #include "framework.hxx"
38 #include <fwkutil.hxx>
39 #include <elements.hxx>
40 #include <fwkbase.hxx>
44 bool g_bEnabledSwitchedOn
= false;
46 JavaVM
* g_pJavaVM
= nullptr;
48 bool areEqualJavaInfo(
49 JavaInfo
const * pInfoA
,JavaInfo
const * pInfoB
)
51 return jfw_areEqualJavaInfo(pInfoA
, pInfoB
);
56 javaFrameworkError
jfw_findAllJREs(std::vector
<std::unique_ptr
<JavaInfo
>> *pparInfo
)
58 assert(pparInfo
!= nullptr);
61 osl::MutexGuard
guard(jfw::FwkMutex());
63 jfw::VendorSettings aVendorSettings
;
64 std::vector
<std::unique_ptr
<JavaInfo
>> vecInfo
;
66 //Use all plug-in libraries to get Java installations.
67 std::vector
<std::unique_ptr
<JavaInfo
>> arInfos
;
68 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> infos
;
69 javaPluginError plerr
= jfw_plugin_getAllJavaInfos(
75 if (plerr
!= javaPluginError::NONE
)
78 for (auto & j
: arInfos
)
79 vecInfo
.push_back(std::move(j
));
81 // direct mode disregards Java settings, so only retrieve
82 // JREs from settings when application mode is used
83 if (jfw::getMode() == jfw::JFW_MODE_APPLICATION
)
85 //get the list of paths to jre locations which have been
87 const jfw::MergedSettings settings
;
88 const std::vector
<OUString
> vecJRELocations
=
89 settings
.getJRELocations();
90 //Check if any plugin can detect JREs at the location
91 // of the paths added by jfw_addJRELocation
92 //Check every manually added location
93 for (auto const & ii
: vecJRELocations
)
95 std::unique_ptr
<JavaInfo
> aInfo
;
96 plerr
= jfw_plugin_getJavaInfoByPath(
100 if (plerr
== javaPluginError::NoJre
)
102 if (plerr
== javaPluginError::FailedVersion
)
104 if (plerr
== javaPluginError::WrongArch
)
106 else if (plerr
!= javaPluginError::NONE
)
109 // Was this JRE already added?
111 vecInfo
.begin(), vecInfo
.end(),
112 [&aInfo
](std::unique_ptr
<JavaInfo
> const & info
) {
113 return areEqualJavaInfo(
114 info
.get(), aInfo
.get());
117 vecInfo
.push_back(std::move(aInfo
));
122 *pparInfo
= std::move(vecInfo
);
126 catch (const jfw::FrameworkException
& e
)
128 SAL_WARN( "jfw", e
.message
);
133 javaFrameworkError
jfw_startVM(
134 JavaInfo
const * pInfo
, std::vector
<OUString
> const & arOptions
,
135 JavaVM
** ppVM
, JNIEnv
** ppEnv
)
137 assert(ppVM
!= nullptr);
138 javaFrameworkError errcode
= JFW_E_NONE
;
142 osl::MutexGuard
guard(jfw::FwkMutex());
144 //We keep this pointer so we can determine if a VM has already
146 if (g_pJavaVM
!= nullptr)
147 return JFW_E_RUNNING_JVM
;
149 std::vector
<OString
> vmParams
;
150 OString sUserClassPath
;
151 std::unique_ptr
<JavaInfo
> aInfo
;
152 if (pInfo
== nullptr)
154 jfw::JFW_MODE mode
= jfw::getMode();
155 if (mode
== jfw::JFW_MODE_APPLICATION
)
157 const jfw::MergedSettings settings
;
158 if (!settings
.getEnabled())
159 return JFW_E_JAVA_DISABLED
;
160 aInfo
= settings
.createJavaInfo();
161 //check if a Java has ever been selected
163 return JFW_E_NO_SELECT
;
165 //check if the javavendors.xml has changed after a Java was selected
166 OString sVendorUpdate
= jfw::getElementUpdated();
168 if (sVendorUpdate
!= settings
.getJavaInfoAttrVendorUpdate())
169 return JFW_E_INVALID_SETTINGS
;
171 //check if JAVA is disabled
172 //If Java is enabled, but it was disabled when this process was started
173 // then no preparational work, such as setting the LD_LIBRARY_PATH, was
174 //done. Therefore if a JRE needs it, it must not be started.
175 if (g_bEnabledSwitchedOn
&&
176 (aInfo
->nRequirements
& JFW_REQUIRE_NEEDRESTART
))
177 return JFW_E_NEED_RESTART
;
179 //Check if the selected Java was set in this process. If so it
180 //must not have the requirements flag JFW_REQUIRE_NEEDRESTART
181 if ((aInfo
->nRequirements
& JFW_REQUIRE_NEEDRESTART
)
182 && jfw::wasJavaSelectedInSameProcess())
183 return JFW_E_NEED_RESTART
;
185 vmParams
= settings
.getVmParametersUtf8();
186 sUserClassPath
= jfw::makeClassPathOption(settings
.getUserClassPath());
187 } // end mode FWK_MODE_OFFICE
188 else if (mode
== jfw::JFW_MODE_DIRECT
)
190 errcode
= jfw_getSelectedJRE(&aInfo
);
191 if (errcode
!= JFW_E_NONE
)
193 //In direct mode the options are specified by bootstrap variables
194 //of the form UNO_JAVA_JFW_PARAMETER_1 .. UNO_JAVA_JFW_PARAMETER_n
195 vmParams
= jfw::BootParams::getVMParameters();
196 auto const cp
= jfw::BootParams::getClasspath();
200 "-Djava.class.path=" + cp
;
207 assert(pInfo
!= nullptr);
210 // Alternative JREs (AdoptOpenJDK, Azul Zulu) are missing the bin/ folder in
211 // java.library.path. Somehow setting java.library.path accordingly doesn't work,
212 // but the PATH gets picked up, so add it there.
213 // Without this hack, some features don't work in alternative JREs.
215 osl_getEnvironment(OUString("PATH").pData
, &sPATH
.pData
);
216 OUString sJRELocation
;
217 osl::FileBase::getSystemPathFromFileURL(pInfo
->sLocation
+ "/bin", sJRELocation
);
219 sPATH
= sJRELocation
;
221 sPATH
= sJRELocation
+ OUStringChar(SAL_PATHSEPARATOR
) + sPATH
;
222 osl_setEnvironment(OUString("PATH").pData
, sPATH
.pData
);
225 // create JavaVMOptions array that is passed to the plugin
226 // it contains the classpath and all options set in the
228 std::unique_ptr
<JavaVMOption
[]> sarJOptions(
230 arOptions
.size() + (sUserClassPath
.isEmpty() ? 1 : 2) + vmParams
.size()]);
231 JavaVMOption
* arOpt
= sarJOptions
.get();
235 //The first argument is the classpath
237 if (!sUserClassPath
.isEmpty()) {
238 arOpt
[index
].optionString
= const_cast<char*>(sUserClassPath
.getStr());
239 arOpt
[index
].extraInfo
= nullptr;
242 // Set a flag that this JVM has been created via the JNI Invocation API
243 // (used, for example, by UNO remote bridges to share a common thread pool
244 // factory among Java and native bridge implementations):
245 arOpt
[index
].optionString
= const_cast<char *>("-Dorg.openoffice.native=");
246 arOpt
[index
].extraInfo
= nullptr;
249 //add the options set by options dialog
250 for (auto const & vmParam
: vmParams
)
252 arOpt
[index
].optionString
= const_cast<char*>(vmParam
.getStr());
253 arOpt
[index
].extraInfo
= nullptr;
256 //add all options of the arOptions argument
257 std::vector
<OString
> convertedOptions
;
258 for (auto const & ii
: arOptions
)
260 OString conv
= OUStringToOString(ii
, osl_getThreadTextEncoding());
261 convertedOptions
.push_back(conv
);
262 // keep conv.getStr() alive until after the call to
263 // jfw_plugin_startJavaVirtualMachine below
264 arOpt
[index
].optionString
= const_cast<char *>(conv
.getStr());
265 arOpt
[index
].extraInfo
= nullptr;
270 JavaVM
*pVm
= nullptr;
271 SAL_INFO("jfw", "Starting Java");
272 javaPluginError plerr
= jfw_plugin_startJavaVirtualMachine(pInfo
, arOpt
, index
, & pVm
, ppEnv
);
273 if (plerr
== javaPluginError::VmCreationFailed
)
275 errcode
= JFW_E_VM_CREATION_FAILED
;
277 else if (plerr
!= javaPluginError::NONE
)
279 errcode
= JFW_E_ERROR
;
287 catch (const jfw::FrameworkException
& e
)
289 errcode
= e
.errorCode
;
290 SAL_WARN( "jfw", e
.message
);
296 /** We do not use here jfw_findAllJREs and then check if a JavaInfo
297 meets the requirements, because that means using all plug-ins, which
298 may take quite a while. The implementation first inspects JAVA_HOME and
299 PATH environment variables. If no suitable JavaInfo is found there, it
300 inspects all JavaInfos found by the jfw_plugin_get* functions.
302 javaFrameworkError
jfw_findAndSelectJRE(std::unique_ptr
<JavaInfo
> *pInfo
)
304 javaFrameworkError errcode
= JFW_E_NONE
;
307 osl::MutexGuard
guard(jfw::FwkMutex());
308 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
309 return JFW_E_DIRECT_MODE
;
310 std::unique_ptr
<JavaInfo
> aCurrentInfo
;
313 // 'bInfoFound' indicates whether a Java installation has been found
314 bool bInfoFound
= false;
316 // get list of vendors for Java installations
317 jfw::VendorSettings aVendorSettings
;
319 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> infos
;
321 // first inspect Java installation that the JAVA_HOME
322 // environment variable points to (if it is set)
323 if (jfw_plugin_getJavaInfoFromJavaHome(
324 aVendorSettings
, &aCurrentInfo
, infos
)
325 == javaPluginError::NONE
)
330 // if no Java installation was detected by using JAVA_HOME,
331 // query PATH for Java installations
334 std::vector
<std::unique_ptr
<JavaInfo
>> vecJavaInfosFromPath
;
335 if (jfw_plugin_getJavaInfosFromPath(
336 aVendorSettings
, vecJavaInfosFromPath
, infos
)
337 == javaPluginError::NONE
)
339 assert(!vecJavaInfosFromPath
.empty());
340 aCurrentInfo
= std::move(vecJavaInfosFromPath
[0]);
346 // if no suitable Java installation has been found yet:
347 // first use jfw_plugin_getAllJavaInfos to find a suitable Java installation,
348 // then try paths that have been added manually
351 //get all installations
352 std::vector
<std::unique_ptr
<JavaInfo
>> arInfos
;
353 javaPluginError plerr
= jfw_plugin_getAllJavaInfos(
359 if (plerr
== javaPluginError::NONE
&& !arInfos
.empty())
361 aCurrentInfo
= std::move(arInfos
[0]);
365 {//The plug-ins did not find a suitable Java. Now try the paths which have been
367 //get the list of paths to jre locations which have been added manually
368 const jfw::MergedSettings settings
;
369 //node.loadFromSettings();
370 const std::vector
<OUString
> & vecJRELocations
=
371 settings
.getJRELocations();
372 //use all plug-ins to determine the JavaInfo objects
373 for (auto const & JRELocation
: vecJRELocations
)
375 std::unique_ptr
<JavaInfo
> aInfo
;
376 javaPluginError err
= jfw_plugin_getJavaInfoByPath(
380 if (err
== javaPluginError::NoJre
)
382 if (err
== javaPluginError::FailedVersion
)
384 else if (err
!=javaPluginError::NONE
)
389 aCurrentInfo
= std::move(aInfo
);
392 }//end iterate over paths
397 jfw::NodeJava
javaNode(jfw::NodeJava::USER
);
398 javaNode
.setJavaInfo(aCurrentInfo
.get(),true);
400 //remember that this JRE was selected in this process
401 jfw::setJavaSelected();
405 *pInfo
= std::move(aCurrentInfo
);
410 errcode
= JFW_E_NO_JAVA_FOUND
;
413 catch (const jfw::FrameworkException
& e
)
415 errcode
= e
.errorCode
;
416 SAL_WARN( "jfw", e
.message
);
422 bool jfw_areEqualJavaInfo(JavaInfo
const * pInfoA
,JavaInfo
const * pInfoB
)
424 if (pInfoA
== pInfoB
)
426 if (pInfoA
== nullptr || pInfoB
== nullptr)
428 if (pInfoA
->sVendor
== pInfoB
->sVendor
429 && pInfoA
->sLocation
== pInfoB
->sLocation
430 && pInfoA
->sVersion
== pInfoB
->sVersion
431 && pInfoA
->nRequirements
== pInfoB
->nRequirements
432 && pInfoA
->arVendorData
== pInfoB
->arVendorData
)
439 javaFrameworkError
jfw_getSelectedJRE(std::unique_ptr
<JavaInfo
> *ppInfo
)
441 assert(ppInfo
!= nullptr);
442 javaFrameworkError errcode
= JFW_E_NONE
;
445 osl::MutexGuard
guard(jfw::FwkMutex());
447 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
449 if ((errcode
= jfw_getJavaInfoByPath(
450 jfw::BootParams::getJREHome(), ppInfo
))
452 throw jfw::FrameworkException(
454 "[Java framework] The JRE specified by the bootstrap "
455 "variable UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME "
456 " could not be recognized. Check the values and make sure that you "
457 "use a plug-in library that can recognize that JRE.");
462 const jfw::MergedSettings settings
;
463 *ppInfo
= settings
.createJavaInfo();
468 //If the javavendors.xml has changed, then the current selected
469 //Java is not valid anymore
470 // /java/javaInfo/@vendorUpdate != javaSelection/updated (javavendors.xml)
471 OString sUpdated
= jfw::getElementUpdated();
473 if (sUpdated
!= settings
.getJavaInfoAttrVendorUpdate())
476 return JFW_E_INVALID_SETTINGS
;
479 catch (const jfw::FrameworkException
& e
)
481 errcode
= e
.errorCode
;
482 SAL_WARN( "jfw", e
.message
);
487 bool jfw_isVMRunning()
489 osl::MutexGuard
guard(jfw::FwkMutex());
490 return g_pJavaVM
!= nullptr;
493 javaFrameworkError
jfw_getJavaInfoByPath(OUString
const & pPath
, std::unique_ptr
<JavaInfo
> *ppInfo
)
495 assert(ppInfo
!= nullptr);
496 javaFrameworkError errcode
= JFW_E_NONE
;
499 osl::MutexGuard
guard(jfw::FwkMutex());
501 jfw::VendorSettings aVendorSettings
;
503 //ask all plugins if this is a JRE.
504 //If so check if it meets the version requirements.
505 //Only if it does return a JavaInfo
506 javaPluginError plerr
= jfw_plugin_getJavaInfoByPath(
511 if(plerr
== javaPluginError::FailedVersion
)
512 {//found JRE but it has the wrong version
514 errcode
= JFW_E_FAILED_VERSION
;
516 OSL_ASSERT(plerr
== javaPluginError::NONE
|| plerr
== javaPluginError::NoJre
);
517 if (!*ppInfo
&& errcode
!= JFW_E_FAILED_VERSION
)
518 errcode
= JFW_E_NOT_RECOGNIZED
;
520 catch (const jfw::FrameworkException
& e
)
522 errcode
= e
.errorCode
;
523 SAL_WARN( "jfw", e
.message
);
530 javaFrameworkError
jfw_setSelectedJRE(JavaInfo
const *pInfo
)
532 javaFrameworkError errcode
= JFW_E_NONE
;
535 osl::MutexGuard
guard(jfw::FwkMutex());
536 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
537 return JFW_E_DIRECT_MODE
;
538 //check if pInfo is the selected JRE
539 std::unique_ptr
<JavaInfo
> currentInfo
;
540 errcode
= jfw_getSelectedJRE( & currentInfo
);
541 if (errcode
!= JFW_E_NONE
&& errcode
!= JFW_E_INVALID_SETTINGS
)
544 if (!jfw_areEqualJavaInfo(currentInfo
.get(), pInfo
))
546 jfw::NodeJava
node(jfw::NodeJava::USER
);
547 node
.setJavaInfo(pInfo
, false);
549 //remember that the JRE was selected in this process
550 jfw::setJavaSelected();
553 catch (const jfw::FrameworkException
& e
)
555 errcode
= e
.errorCode
;
556 SAL_WARN( "jfw", e
.message
);
560 javaFrameworkError
jfw_setEnabled(bool bEnabled
)
562 javaFrameworkError errcode
= JFW_E_NONE
;
565 osl::MutexGuard
guard(jfw::FwkMutex());
566 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
567 return JFW_E_DIRECT_MODE
;
569 if (!g_bEnabledSwitchedOn
&& bEnabled
)
571 //When the process started then Enabled was false.
572 //This is first time enabled is set to true.
573 //That means, no preparational work has been done, such as setting the
574 //LD_LIBRARY_PATH, etc.
576 //check if Enabled is false;
577 const jfw::MergedSettings settings
;
578 if (!settings
.getEnabled())
579 g_bEnabledSwitchedOn
= true;
581 jfw::NodeJava
node(jfw::NodeJava::USER
);
582 node
.setEnabled(bEnabled
);
585 catch (const jfw::FrameworkException
& e
)
587 errcode
= e
.errorCode
;
588 SAL_WARN( "jfw", e
.message
);
593 javaFrameworkError
jfw_getEnabled(bool *pbEnabled
)
595 assert(pbEnabled
!= nullptr);
596 javaFrameworkError errcode
= JFW_E_NONE
;
599 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
600 return JFW_E_DIRECT_MODE
;
601 osl::MutexGuard
guard(jfw::FwkMutex());
602 jfw::MergedSettings settings
;
603 *pbEnabled
= settings
.getEnabled();
605 catch (const jfw::FrameworkException
& e
)
607 errcode
= e
.errorCode
;
608 SAL_WARN( "jfw", e
.message
);
614 javaFrameworkError
jfw_setVMParameters(std::vector
<OUString
> const & arOptions
)
616 javaFrameworkError errcode
= JFW_E_NONE
;
619 osl::MutexGuard
guard(jfw::FwkMutex());
620 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
621 return JFW_E_DIRECT_MODE
;
622 jfw::NodeJava
node(jfw::NodeJava::USER
);
623 node
.setVmParameters(arOptions
);
626 catch (const jfw::FrameworkException
& e
)
628 errcode
= e
.errorCode
;
629 SAL_WARN( "jfw", e
.message
);
635 javaFrameworkError
jfw_getVMParameters(std::vector
<OUString
> * parOptions
)
637 javaFrameworkError errcode
= JFW_E_NONE
;
640 osl::MutexGuard
guard(jfw::FwkMutex());
641 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
642 return JFW_E_DIRECT_MODE
;
644 const jfw::MergedSettings settings
;
645 settings
.getVmParametersArray(parOptions
);
647 catch (const jfw::FrameworkException
& e
)
649 errcode
= e
.errorCode
;
650 SAL_WARN( "jfw", e
.message
);
655 javaFrameworkError
jfw_setUserClassPath(OUString
const & pCp
)
657 javaFrameworkError errcode
= JFW_E_NONE
;
660 osl::MutexGuard
guard(jfw::FwkMutex());
661 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
662 return JFW_E_DIRECT_MODE
;
663 jfw::NodeJava
node(jfw::NodeJava::USER
);
664 node
.setUserClassPath(pCp
);
667 catch (const jfw::FrameworkException
& e
)
669 errcode
= e
.errorCode
;
670 SAL_WARN( "jfw", e
.message
);
675 javaFrameworkError
jfw_getUserClassPath(OUString
* ppCP
)
677 assert(ppCP
!= nullptr);
678 javaFrameworkError errcode
= JFW_E_NONE
;
681 osl::MutexGuard
guard(jfw::FwkMutex());
682 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
683 return JFW_E_DIRECT_MODE
;
684 const jfw::MergedSettings settings
;
685 *ppCP
= settings
.getUserClassPath();
687 catch (const jfw::FrameworkException
& e
)
689 errcode
= e
.errorCode
;
690 SAL_WARN( "jfw", e
.message
);
695 javaFrameworkError
jfw_addJRELocation(OUString
const & sLocation
)
697 javaFrameworkError errcode
= JFW_E_NONE
;
700 osl::MutexGuard
guard(jfw::FwkMutex());
701 if (jfw::getMode() == jfw::JFW_MODE_DIRECT
)
702 return JFW_E_DIRECT_MODE
;
703 jfw::NodeJava
node(jfw::NodeJava::USER
);
705 node
.addJRELocation(sLocation
);
708 catch (const jfw::FrameworkException
& e
)
710 errcode
= e
.errorCode
;
711 SAL_WARN( "jfw", e
.message
);
718 javaFrameworkError
jfw_existJRE(const JavaInfo
*pInfo
, bool *exist
)
720 javaPluginError plerr
= jfw_plugin_existJRE(pInfo
, exist
);
722 javaFrameworkError ret
= JFW_E_NONE
;
725 case javaPluginError::NONE
:
728 case javaPluginError::Error
:
739 jfw::FwkMutex().acquire();
744 jfw::FwkMutex().release();
747 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */