/* -*- 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 <sal/config.h>
#include <sal/log.hxx>
#include <cassert>
#include <memory>
#include <rtl/bootstrap.hxx>
#include <rtl/ref.hxx>
#include <rtl/ustring.hxx>
#include <osl/diagnose.h>
#include <osl/file.hxx>
#ifdef _WIN32
#include <osl/process.h>
#endif
#include <osl/thread.hxx>
#include <o3tl/string_view.hxx>
#include <jvmfwk/framework.hxx>
#include <vendorbase.hxx>
#include <vendorplugin.hxx>
#include <vector>
#include <algorithm>
#include "framework.hxx"
#include <fwkutil.hxx>
#include <elements.hxx>
#include <fwkbase.hxx>
namespace {
bool g_bEnabledSwitchedOn = false;
JavaVM * g_pJavaVM = nullptr;
bool areEqualJavaInfo(
JavaInfo const * pInfoA,JavaInfo const * pInfoB)
{
return jfw_areEqualJavaInfo(pInfoA, pInfoB);
}
}
javaFrameworkError jfw_findAllJREs(std::vector<std::unique_ptr<JavaInfo>> *pparInfo)
{
assert(pparInfo != nullptr);
try
{
osl::MutexGuard guard(jfw::FwkMutex());
jfw::VendorSettings aVendorSettings;
std::vector<std::unique_ptr<JavaInfo>> vecInfo;
//Use all plug-in libraries to get Java installations.
std::vector<std::unique_ptr<JavaInfo>> arInfos;
std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
javaPluginError plerr = jfw_plugin_getAllJavaInfos(
true,
aVendorSettings,
& arInfos,
infos);
if (plerr != javaPluginError::NONE)
return JFW_E_ERROR;
for (auto & j: arInfos)
vecInfo.push_back(std::move(j));
// direct mode disregards Java settings, so only retrieve
// JREs from settings when application mode is used
if (jfw::getMode() == jfw::JFW_MODE_APPLICATION)
{
//get the list of paths to jre locations which have been
//added manually
const jfw::MergedSettings settings;
const std::vector<OUString>& vecJRELocations =
settings.getJRELocations();
//Check if any plugin can detect JREs at the location
// of the paths added by jfw_addJRELocation
//Check every manually added location
for (auto const & ii: vecJRELocations)
{
std::unique_ptr<JavaInfo> aInfo;
plerr = jfw_plugin_getJavaInfoByPath(
ii,
aVendorSettings,
&aInfo);
if (plerr == javaPluginError::NoJre)
continue;
if (plerr == javaPluginError::FailedVersion)
continue;
if (plerr == javaPluginError::WrongArch)
continue;
else if (plerr != javaPluginError::NONE)
return JFW_E_ERROR;
// Was this JRE already added?
if (std::none_of(
vecInfo.begin(), vecInfo.end(),
[&aInfo](std::unique_ptr<JavaInfo> const & info) {
return areEqualJavaInfo(
info.get(), aInfo.get());
}))
{
vecInfo.push_back(std::move(aInfo));
}
}
}
*pparInfo = std::move(vecInfo);
return JFW_E_NONE;
}
catch (const jfw::FrameworkException& e)
{
SAL_WARN( "jfw", e.message);
return e.errorCode;
}
}
std::vector<OUString> jfw_convertUserPathList(std::u16string_view sUserPath)
{
std::vector<OUString> result;
sal_Int32 nIdx = 0;
do
{
size_t nextColon = sUserPath.find(SAL_PATHSEPARATOR, nIdx);
std::u16string_view sToken;
if (nextColon != 0 && nextColon != std::u16string_view::npos)
sToken = sUserPath.substr(nIdx, nextColon - nIdx);
else
sToken = sUserPath.substr(nIdx, sUserPath.size() - nIdx);
// Check if we are in bootstrap variable mode (class path starts with '$').
// Then the class path must be in URL format.
if (o3tl::starts_with(sToken, u"$"))
{
// Detect open bootstrap variables - they might contain colons - we need to skip those.
size_t nBootstrapVarStart = sToken.find(u"${");
if (nBootstrapVarStart != std::u16string_view::npos)
{
size_t nBootstrapVarEnd = sToken.find(u"}", nBootstrapVarStart);
if (nBootstrapVarEnd == std::u16string_view::npos)
{
// Current colon is part of bootstrap variable - skip it!
const auto nAfterColon = (nextColon != std::string_view::npos) ? (nextColon + 1) : 0;
nextColon = sUserPath.find(SAL_PATHSEPARATOR, nAfterColon);
if (nextColon != 0 && nextColon != std::u16string_view::npos)
sToken = sUserPath.substr(nIdx, nextColon - nIdx);
else
sToken = sUserPath.substr(nIdx, sUserPath.size() - nIdx);
}
}
}
result.emplace_back(sToken);
if (nextColon == std::u16string_view::npos)
break;
nIdx = nextColon + 1;
} while (nIdx > 0);
return result;
}
javaFrameworkError jfw_startVM(
JavaInfo const * pInfo, std::vector<OUString> const & arOptions,
JavaVM ** ppVM, JNIEnv ** ppEnv)
{
assert(ppVM != nullptr);
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
//We keep this pointer so we can determine if a VM has already
//been created.
if (g_pJavaVM != nullptr)
return JFW_E_RUNNING_JVM;
std::vector<OString> vmParams;
OString sUserClassPath;
std::unique_ptr<JavaInfo> aInfo;
if (pInfo == nullptr)
{
jfw::JFW_MODE mode = jfw::getMode();
if (mode == jfw::JFW_MODE_APPLICATION)
{
const jfw::MergedSettings settings;
if (!settings.getEnabled())
return JFW_E_JAVA_DISABLED;
aInfo = settings.createJavaInfo();
//check if a Java has ever been selected
if (!aInfo)
return JFW_E_NO_SELECT;
//check if the javavendors.xml has changed after a Java was selected
OString sVendorUpdate = jfw::getElementUpdated();
if (sVendorUpdate != settings.getJavaInfoAttrVendorUpdate())
return JFW_E_INVALID_SETTINGS;
//check if JAVA is disabled
//If Java is enabled, but it was disabled when this process was started
// then no preparational work, such as setting the LD_LIBRARY_PATH, was
//done. Therefore if a JRE needs it, it must not be started.
if (g_bEnabledSwitchedOn &&
(aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
return JFW_E_NEED_RESTART;
//Check if the selected Java was set in this process. If so it
//must not have the requirements flag JFW_REQUIRE_NEEDRESTART
if ((aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART)
&& jfw::wasJavaSelectedInSameProcess())
return JFW_E_NEED_RESTART;
vmParams = settings.getVmParametersUtf8();
// Expand user classpath (might contain bootstrap vars)
const OUString& sUserPath(settings.getUserClassPath());
std::vector paths = jfw_convertUserPathList(sUserPath);
OUString sUserPathExpanded;
for (auto& path : paths)
{
if (!sUserPathExpanded.isEmpty())
sUserPathExpanded += OUStringChar(SAL_PATHSEPARATOR);
if (path.startsWith("$"))
{
OUString sURL = path;
rtl::Bootstrap::expandMacros(sURL);
osl::FileBase::getSystemPathFromFileURL(sURL, path);
}
sUserPathExpanded += path;
}
sUserClassPath = jfw::makeClassPathOption(sUserPathExpanded);
} // end mode FWK_MODE_OFFICE
else if (mode == jfw::JFW_MODE_DIRECT)
{
errcode = jfw_getSelectedJRE(&aInfo);
if (errcode != JFW_E_NONE)
return errcode;
//In direct mode the options are specified by bootstrap variables
//of the form UNO_JAVA_JFW_PARAMETER_1 .. UNO_JAVA_JFW_PARAMETER_n
vmParams = jfw::BootParams::getVMParameters();
auto const cp = jfw::BootParams::getClasspath();
if (!cp.isEmpty())
{
sUserClassPath =
"-Djava.class.path=" + cp;
}
}
else
OSL_ASSERT(false);
pInfo = aInfo.get();
}
assert(pInfo != nullptr);
#ifdef _WIN32
// Alternative JREs (AdoptOpenJDK, Azul Zulu) are missing the bin/ folder in
// java.library.path. Somehow setting java.library.path accordingly doesn't work,
// but the PATH gets picked up, so add it there.
// Without this hack, some features don't work in alternative JREs.
OUString sPATH;
osl_getEnvironment(OUString("PATH").pData, &sPATH.pData);
OUString sJRELocation;
osl::FileBase::getSystemPathFromFileURL(pInfo->sLocation + "/bin", sJRELocation);
if (sPATH.isEmpty())
sPATH = sJRELocation;
else
sPATH = sJRELocation + OUStringChar(SAL_PATHSEPARATOR) + sPATH;
osl_setEnvironment(OUString("PATH").pData, sPATH.pData);
#endif // _WIN32
// create JavaVMOptions array that is passed to the plugin
// it contains the classpath and all options set in the
//options dialog
std::unique_ptr<JavaVMOption[]> sarJOptions(
new JavaVMOption[
arOptions.size() + (sUserClassPath.isEmpty() ? 2 : 3) + vmParams.size()]);
JavaVMOption * arOpt = sarJOptions.get();
if (! arOpt)
return JFW_E_ERROR;
//The first argument is the classpath
int index = 0;
if (!sUserClassPath.isEmpty()) {
arOpt[index].optionString= const_cast<char*>(sUserClassPath.getStr());
arOpt[index].extraInfo = nullptr;
++index;
}
// Set a flag that this JVM has been created via the JNI Invocation API
// (used, for example, by UNO remote bridges to share a common thread pool
// factory among Java and native bridge implementations):
arOpt[index].optionString = const_cast<char *>("-Dorg.openoffice.native=");
arOpt[index].extraInfo = nullptr;
++index;
// Don't intercept SIGTERM
arOpt[index].optionString = const_cast<char *>("-Xrs");
arOpt[index].extraInfo = nullptr;
++index;
//add the options set by options dialog
for (auto const & vmParam : vmParams)
{
arOpt[index].optionString = const_cast<char*>(vmParam.getStr());
arOpt[index].extraInfo = nullptr;
index ++;
}
//add all options of the arOptions argument
std::vector<OString> convertedOptions;
for (auto const & ii: arOptions)
{
OString conv = OUStringToOString(ii, osl_getThreadTextEncoding());
convertedOptions.push_back(conv);
// keep conv.getStr() alive until after the call to
// jfw_plugin_startJavaVirtualMachine below
arOpt[index].optionString = const_cast<char *>(conv.getStr());
arOpt[index].extraInfo = nullptr;
index++;
}
//start Java
JavaVM *pVm = nullptr;
SAL_INFO("jfw", "Starting Java");
javaPluginError plerr = jfw_plugin_startJavaVirtualMachine(pInfo, arOpt, index, & pVm, ppEnv);
if (plerr == javaPluginError::VmCreationFailed)
{
errcode = JFW_E_VM_CREATION_FAILED;
}
else if (plerr != javaPluginError::NONE )
{
errcode = JFW_E_ERROR;
}
else
{
g_pJavaVM = pVm;
*ppVM = pVm;
}
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message);
}
return errcode;
}
/** We do not use here jfw_findAllJREs and then check if a JavaInfo
meets the requirements, because that means using all plug-ins, which
may take quite a while. The implementation first inspects JAVA_HOME and
PATH environment variables. If no suitable JavaInfo is found there, it
inspects all JavaInfos found by the jfw_plugin_get* functions.
*/
javaFrameworkError jfw_findAndSelectJRE(std::unique_ptr<JavaInfo> *pInfo)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
std::unique_ptr<JavaInfo> aCurrentInfo;
// 'bInfoFound' indicates whether a Java installation has been found
bool bInfoFound = false;
// get list of vendors for Java installations
jfw::VendorSettings aVendorSettings;
std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
// first inspect Java installation that the JAVA_HOME
// environment variable points to (if it is set)
if (jfw_plugin_getJavaInfoFromJavaHome(
aVendorSettings, &aCurrentInfo, infos)
== javaPluginError::NONE)
{
bInfoFound = true;
}
// if no Java installation was detected by using JAVA_HOME,
// query PATH for Java installations
if (!bInfoFound)
{
std::vector<std::unique_ptr<JavaInfo>> vecJavaInfosFromPath;
if (jfw_plugin_getJavaInfosFromPath(
aVendorSettings, vecJavaInfosFromPath, infos)
== javaPluginError::NONE)
{
assert(!vecJavaInfosFromPath.empty());
aCurrentInfo = std::move(vecJavaInfosFromPath[0]);
bInfoFound = true;
}
}
// if no suitable Java installation has been found yet:
// first use jfw_plugin_getAllJavaInfos to find a suitable Java installation,
// then try paths that have been added manually
if (!bInfoFound)
{
//get all installations
std::vector<std::unique_ptr<JavaInfo>> arInfos;
javaPluginError plerr = jfw_plugin_getAllJavaInfos(
false,
aVendorSettings,
& arInfos,
infos);
if (plerr == javaPluginError::NONE && !arInfos.empty())
{
aCurrentInfo = std::move(arInfos[0]);
}
if (!aCurrentInfo)
{//The plug-ins did not find a suitable Java. Now try the paths which have been
//added manually.
//get the list of paths to jre locations which have been added manually
const jfw::MergedSettings settings;
//node.loadFromSettings();
const std::vector<OUString> & vecJRELocations =
settings.getJRELocations();
//use all plug-ins to determine the JavaInfo objects
for (auto const & JRELocation : vecJRELocations)
{
std::unique_ptr<JavaInfo> aInfo;
javaPluginError err = jfw_plugin_getJavaInfoByPath(
JRELocation,
aVendorSettings,
&aInfo);
if (err == javaPluginError::NoJre)
continue;
if (err == javaPluginError::FailedVersion)
continue;
else if (err !=javaPluginError::NONE)
return JFW_E_ERROR;
if (aInfo)
{
aCurrentInfo = std::move(aInfo);
break;
}
}//end iterate over paths
}
}
if (aCurrentInfo)
{
jfw::NodeJava javaNode(jfw::NodeJava::USER);
javaNode.setJavaInfo(aCurrentInfo.get(),true);
javaNode.write();
//remember that this JRE was selected in this process
jfw::setJavaSelected();
if (pInfo !=nullptr)
{
*pInfo = std::move(aCurrentInfo);
}
}
else
{
errcode = JFW_E_NO_JAVA_FOUND;
}
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
bool jfw_areEqualJavaInfo(JavaInfo const * pInfoA,JavaInfo const * pInfoB)
{
if (pInfoA == pInfoB)
return true;
if (pInfoA == nullptr || pInfoB == nullptr)
return false;
if (pInfoA->sVendor == pInfoB->sVendor
&& pInfoA->sLocation == pInfoB->sLocation
&& pInfoA->sVersion == pInfoB->sVersion
&& pInfoA->nRequirements == pInfoB->nRequirements
&& pInfoA->arVendorData == pInfoB->arVendorData)
{
return true;
}
return false;
}
javaFrameworkError jfw_getSelectedJRE(std::unique_ptr<JavaInfo> *ppInfo)
{
assert(ppInfo != nullptr);
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
{
if ((errcode = jfw_getJavaInfoByPath(
jfw::BootParams::getJREHome(), ppInfo))
!= JFW_E_NONE)
throw jfw::FrameworkException(
JFW_E_CONFIGURATION,
"[Java framework] The JRE specified by the bootstrap "
"variable UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME "
" could not be recognized. Check the values and make sure that you "
"use a plug-in library that can recognize that JRE."_ostr);
return JFW_E_NONE;
}
const jfw::MergedSettings settings;
*ppInfo = settings.createJavaInfo();
if (!*ppInfo)
{
return JFW_E_NONE;
}
//If the javavendors.xml has changed, then the current selected
//Java is not valid anymore
// /java/javaInfo/@vendorUpdate != javaSelection/updated (javavendors.xml)
OString sUpdated = jfw::getElementUpdated();
if (sUpdated != settings.getJavaInfoAttrVendorUpdate())
{
ppInfo->reset();
return JFW_E_INVALID_SETTINGS;
}
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
bool jfw_isVMRunning()
{
osl::MutexGuard guard(jfw::FwkMutex());
return g_pJavaVM != nullptr;
}
javaFrameworkError jfw_getJavaInfoByPath(OUString const & pPath, std::unique_ptr<JavaInfo> *ppInfo)
{
assert(ppInfo != nullptr);
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
jfw::VendorSettings aVendorSettings;
//ask all plugins if this is a JRE.
//If so check if it meets the version requirements.
//Only if it does return a JavaInfo
javaPluginError plerr = jfw_plugin_getJavaInfoByPath(
pPath,
aVendorSettings,
ppInfo);
if(plerr == javaPluginError::FailedVersion)
{//found JRE but it has the wrong version
ppInfo->reset();
errcode = JFW_E_FAILED_VERSION;
}
OSL_ASSERT(plerr == javaPluginError::NONE || plerr == javaPluginError::NoJre);
if (!*ppInfo && errcode != JFW_E_FAILED_VERSION)
errcode = JFW_E_NOT_RECOGNIZED;
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_setSelectedJRE(JavaInfo const *pInfo)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
//check if pInfo is the selected JRE
std::unique_ptr<JavaInfo> currentInfo;
errcode = jfw_getSelectedJRE( & currentInfo);
if (errcode != JFW_E_NONE && errcode != JFW_E_INVALID_SETTINGS)
return errcode;
if (!jfw_areEqualJavaInfo(currentInfo.get(), pInfo))
{
jfw::NodeJava node(jfw::NodeJava::USER);
node.setJavaInfo(pInfo, false);
node.write();
//remember that the JRE was selected in this process
jfw::setJavaSelected();
}
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_setEnabled(bool bEnabled)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
if (!g_bEnabledSwitchedOn && bEnabled)
{
//When the process started then Enabled was false.
//This is first time enabled is set to true.
//That means, no preparational work has been done, such as setting the
//LD_LIBRARY_PATH, etc.
//check if Enabled is false;
const jfw::MergedSettings settings;
if (!settings.getEnabled())
g_bEnabledSwitchedOn = true;
}
jfw::NodeJava node(jfw::NodeJava::USER);
node.setEnabled(bEnabled);
node.write();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_getEnabled(bool *pbEnabled)
{
assert(pbEnabled != nullptr);
javaFrameworkError errcode = JFW_E_NONE;
try
{
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
osl::MutexGuard guard(jfw::FwkMutex());
jfw::MergedSettings settings;
*pbEnabled = settings.getEnabled();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_setVMParameters(std::vector<OUString> const & arOptions)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
jfw::NodeJava node(jfw::NodeJava::USER);
node.setVmParameters(arOptions);
node.write();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_getVMParameters(std::vector<OUString> * parOptions)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
const jfw::MergedSettings settings;
settings.getVmParametersArray(parOptions);
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_setUserClassPath(OUString const & pCp)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
jfw::NodeJava node(jfw::NodeJava::USER);
node.setUserClassPath(pCp);
node.write();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_getUserClassPath(OUString * ppCP)
{
assert(ppCP != nullptr);
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
const jfw::MergedSettings settings;
*ppCP = settings.getUserClassPath();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_addJRELocation(OUString const & sLocation)
{
javaFrameworkError errcode = JFW_E_NONE;
try
{
osl::MutexGuard guard(jfw::FwkMutex());
if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
return JFW_E_DIRECT_MODE;
jfw::NodeJava node(jfw::NodeJava::USER);
node.load();
node.addJRELocation(sLocation);
node.write();
}
catch (const jfw::FrameworkException& e)
{
errcode = e.errorCode;
SAL_WARN( "jfw", e.message );
}
return errcode;
}
javaFrameworkError jfw_existJRE(const JavaInfo *pInfo, bool *exist)
{
javaPluginError plerr = jfw_plugin_existJRE(pInfo, exist);
javaFrameworkError ret = JFW_E_NONE;
switch (plerr)
{
case javaPluginError::NONE:
ret = JFW_E_NONE;
break;
case javaPluginError::Error:
ret = JFW_E_ERROR;
break;
default:
ret = JFW_E_ERROR;
}
return ret;
}
void jfw_lock()
{
jfw::FwkMutex().acquire();
}
void jfw_unlock()
{
jfw::FwkMutex().release();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'mode == jfw::JFW_MODE_DIRECT' is always true.