LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / jvmfwk / source / framework.cxx
blobf71e82ef3c60433564ba9a854ac73c2516ca9138
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
23 #include <cassert>
24 #include <memory>
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>
35 #include <vector>
36 #include <algorithm>
37 #include "framework.hxx"
38 #include <fwkutil.hxx>
39 #include <elements.hxx>
40 #include <fwkbase.hxx>
42 namespace {
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);
59 try
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(
70 true,
71 aVendorSettings,
72 & arInfos,
73 infos);
75 if (plerr != javaPluginError::NONE)
76 return JFW_E_ERROR;
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
86 //added manually
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(
97 ii,
98 aVendorSettings,
99 &aInfo);
100 if (plerr == javaPluginError::NoJre)
101 continue;
102 if (plerr == javaPluginError::FailedVersion)
103 continue;
104 if (plerr == javaPluginError::WrongArch)
105 continue;
106 else if (plerr != javaPluginError::NONE)
107 return JFW_E_ERROR;
109 // Was this JRE already added?
110 if (std::none_of(
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);
124 return JFW_E_NONE;
126 catch (const jfw::FrameworkException& e)
128 SAL_WARN( "jfw", e.message);
129 return e.errorCode;
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
145 //been created.
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
162 if (!aInfo)
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)
192 return errcode;
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();
197 if (!cp.isEmpty())
199 sUserClassPath =
200 "-Djava.class.path=" + cp;
203 else
204 OSL_ASSERT(false);
205 pInfo = aInfo.get();
207 assert(pInfo != nullptr);
209 #ifdef _WIN32
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.
214 OUString sPATH;
215 osl_getEnvironment(OUString("PATH").pData, &sPATH.pData);
216 OUString sJRELocation;
217 osl::FileBase::getSystemPathFromFileURL(pInfo->sLocation + "/bin", sJRELocation);
218 if (sPATH.isEmpty())
219 sPATH = sJRELocation;
220 else
221 sPATH = sJRELocation + OUStringChar(SAL_PATHSEPARATOR) + sPATH;
222 osl_setEnvironment(OUString("PATH").pData, sPATH.pData);
223 #endif // _WIN32
225 // create JavaVMOptions array that is passed to the plugin
226 // it contains the classpath and all options set in the
227 //options dialog
228 std::unique_ptr<JavaVMOption[]> sarJOptions(
229 new JavaVMOption[
230 arOptions.size() + (sUserClassPath.isEmpty() ? 1 : 2) + vmParams.size()]);
231 JavaVMOption * arOpt = sarJOptions.get();
232 if (! arOpt)
233 return JFW_E_ERROR;
235 //The first argument is the classpath
236 int index = 0;
237 if (!sUserClassPath.isEmpty()) {
238 arOpt[index].optionString= const_cast<char*>(sUserClassPath.getStr());
239 arOpt[index].extraInfo = nullptr;
240 ++index;
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;
247 ++index;
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;
254 index ++;
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;
266 index++;
269 //start Java
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;
281 else
283 g_pJavaVM = pVm;
284 *ppVM = pVm;
287 catch (const jfw::FrameworkException& e)
289 errcode = e.errorCode;
290 SAL_WARN( "jfw", e.message);
293 return errcode;
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)
327 bInfoFound = true;
330 // if no Java installation was detected by using JAVA_HOME,
331 // query PATH for Java installations
332 if (!bInfoFound)
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]);
341 bInfoFound = true;
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
349 if (!bInfoFound)
351 //get all installations
352 std::vector<std::unique_ptr<JavaInfo>> arInfos;
353 javaPluginError plerr = jfw_plugin_getAllJavaInfos(
354 false,
355 aVendorSettings,
356 & arInfos,
357 infos);
359 if (plerr == javaPluginError::NONE && !arInfos.empty())
361 aCurrentInfo = std::move(arInfos[0]);
364 if (!aCurrentInfo)
365 {//The plug-ins did not find a suitable Java. Now try the paths which have been
366 //added manually.
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(
377 JRELocation,
378 aVendorSettings,
379 &aInfo);
380 if (err == javaPluginError::NoJre)
381 continue;
382 if (err == javaPluginError::FailedVersion)
383 continue;
384 else if (err !=javaPluginError::NONE)
385 return JFW_E_ERROR;
387 if (aInfo)
389 aCurrentInfo = std::move(aInfo);
390 break;
392 }//end iterate over paths
395 if (aCurrentInfo)
397 jfw::NodeJava javaNode(jfw::NodeJava::USER);
398 javaNode.setJavaInfo(aCurrentInfo.get(),true);
399 javaNode.write();
400 //remember that this JRE was selected in this process
401 jfw::setJavaSelected();
403 if (pInfo !=nullptr)
405 *pInfo = std::move(aCurrentInfo);
408 else
410 errcode = JFW_E_NO_JAVA_FOUND;
413 catch (const jfw::FrameworkException& e)
415 errcode = e.errorCode;
416 SAL_WARN( "jfw", e.message );
419 return errcode;
422 bool jfw_areEqualJavaInfo(JavaInfo const * pInfoA,JavaInfo const * pInfoB)
424 if (pInfoA == pInfoB)
425 return true;
426 if (pInfoA == nullptr || pInfoB == nullptr)
427 return false;
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)
434 return true;
436 return false;
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))
451 != JFW_E_NONE)
452 throw jfw::FrameworkException(
453 JFW_E_CONFIGURATION,
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.");
459 return JFW_E_NONE;
462 const jfw::MergedSettings settings;
463 *ppInfo = settings.createJavaInfo();
464 if (!*ppInfo)
466 return JFW_E_NONE;
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())
475 ppInfo->reset();
476 return JFW_E_INVALID_SETTINGS;
479 catch (const jfw::FrameworkException& e)
481 errcode = e.errorCode;
482 SAL_WARN( "jfw", e.message );
484 return errcode;
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(
507 pPath,
508 aVendorSettings,
509 ppInfo);
511 if(plerr == javaPluginError::FailedVersion)
512 {//found JRE but it has the wrong version
513 ppInfo->reset();
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 );
526 return errcode;
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)
542 return errcode;
544 if (!jfw_areEqualJavaInfo(currentInfo.get(), pInfo))
546 jfw::NodeJava node(jfw::NodeJava::USER);
547 node.setJavaInfo(pInfo, false);
548 node.write();
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 );
558 return errcode;
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);
583 node.write();
585 catch (const jfw::FrameworkException& e)
587 errcode = e.errorCode;
588 SAL_WARN( "jfw", e.message );
590 return errcode;
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 );
610 return errcode;
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);
624 node.write();
626 catch (const jfw::FrameworkException& e)
628 errcode = e.errorCode;
629 SAL_WARN( "jfw", e.message );
632 return errcode;
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 );
652 return errcode;
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);
665 node.write();
667 catch (const jfw::FrameworkException& e)
669 errcode = e.errorCode;
670 SAL_WARN( "jfw", e.message );
672 return errcode;
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 );
692 return errcode;
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);
704 node.load();
705 node.addJRELocation(sLocation);
706 node.write();
708 catch (const jfw::FrameworkException& e)
710 errcode = e.errorCode;
711 SAL_WARN( "jfw", e.message );
714 return errcode;
718 javaFrameworkError jfw_existJRE(const JavaInfo *pInfo, bool *exist)
720 javaPluginError plerr = jfw_plugin_existJRE(pInfo, exist);
722 javaFrameworkError ret = JFW_E_NONE;
723 switch (plerr)
725 case javaPluginError::NONE:
726 ret = JFW_E_NONE;
727 break;
728 case javaPluginError::Error:
729 ret = JFW_E_ERROR;
730 break;
731 default:
732 ret = JFW_E_ERROR;
734 return ret;
737 void jfw_lock()
739 jfw::FwkMutex().acquire();
742 void jfw_unlock()
744 jfw::FwkMutex().release();
747 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */