diff options
Diffstat (limited to 'jvmfwk/source')
-rw-r--r-- | jvmfwk/source/elements.cxx | 971 | ||||
-rw-r--r-- | jvmfwk/source/framework.cxx | 749 | ||||
-rw-r--r-- | jvmfwk/source/framework.hxx | 41 | ||||
-rw-r--r-- | jvmfwk/source/fwkbase.cxx | 524 | ||||
-rw-r--r-- | jvmfwk/source/fwkutil.cxx | 194 | ||||
-rw-r--r-- | jvmfwk/source/javasettings.xsd | 70 | ||||
-rw-r--r-- | jvmfwk/source/javasettings_template.xml | 52 | ||||
-rw-r--r-- | jvmfwk/source/libxmlutil.cxx | 136 |
8 files changed, 2737 insertions, 0 deletions
diff --git a/jvmfwk/source/elements.cxx b/jvmfwk/source/elements.cxx new file mode 100644 index 000000000..c48f942ef --- /dev/null +++ b/jvmfwk/source/elements.cxx @@ -0,0 +1,971 @@ +/* -*- 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 <elements.hxx> +#include <osl/mutex.hxx> +#include <osl/file.hxx> +#include <fwkutil.hxx> +#include <fwkbase.hxx> +#include "framework.hxx" +#include <libxmlutil.hxx> +#include <algorithm> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <optional> +#include <string.h> + +// For backwards compatibility, the nRequirements flag word is +// read/written as potentially signed hexadecimal number (though that has no +// practical relevance given that it has only one flag with value 0x01 +// defined). + +using namespace osl; +namespace jfw +{ + +static OString getElement(OString const & docPath, + xmlChar const * pathExpression) +{ + //Prepare the xml document and context + OSL_ASSERT(!docPath.isEmpty()); + jfw::CXmlDocPtr doc(xmlParseFile(docPath.getStr())); + if (doc == nullptr) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function getElement (elements.cxx)"); + + jfw::CXPathContextPtr context(xmlXPathNewContext(doc)); + if (xmlXPathRegisterNs(context, reinterpret_cast<xmlChar const *>("jf"), + reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function getElement (elements.cxx)"); + + CXPathObjectPtr pathObj = xmlXPathEvalExpression(pathExpression, context); + OString sValue; + if (xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + { + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function getElement (elements.cxx)"); + } + sValue = reinterpret_cast<char*>(pathObj->nodesetval->nodeTab[0]->content); + return sValue; +} + +OString getElementUpdated() +{ + return getElement(jfw::getVendorSettingsPath(), + reinterpret_cast<xmlChar const *>("/jf:javaSelection/jf:updated/text()")); +} + +void createSettingsStructure(xmlDoc * document, bool * bNeedsSave) +{ + OString sExcMsg("[Java framework] Error in function createSettingsStructure " + "(elements.cxx)."); + xmlNode * root = xmlDocGetRootElement(document); + if (root == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + bool bFound = false; + xmlNode * cur = root->children; + while (cur != nullptr) + { + if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0) + { + bFound = true; + break; + } + cur = cur->next; + } + if (bFound) + { + *bNeedsSave = false; + return; + } + //We will modify this document + *bNeedsSave = true; + // Now we create the child elements ------------------ + //Get xsi:nil namespace + xmlNs* nsXsi = xmlSearchNsByHref( + document, root, reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + + //<enabled xsi:nil="true" + xmlNode * nodeEn = xmlNewTextChild( + root, nullptr, reinterpret_cast<xmlChar const *>("enabled"), reinterpret_cast<xmlChar const *>("")); + if (nodeEn == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlSetNsProp(nodeEn, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true")); + //add a new line + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(root, nodeCrLf); + + //<userClassPath xsi:nil="true"> + xmlNode * nodeUs = xmlNewTextChild( + root, nullptr, reinterpret_cast<xmlChar const *>("userClassPath"), reinterpret_cast<xmlChar const *>("")); + if (nodeUs == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlSetNsProp(nodeUs, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true")); + //add a new line + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(root, nodeCrLf); + + //<vmParameters xsi:nil="true"> + xmlNode * nodeVm = xmlNewTextChild( + root, nullptr, reinterpret_cast<xmlChar const *>("vmParameters"), reinterpret_cast<xmlChar const *>("")); + if (nodeVm == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlSetNsProp(nodeVm, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true")); + //add a new line + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(root, nodeCrLf); + + //<jreLocations xsi:nil="true"> + xmlNode * nodeJre = xmlNewTextChild( + root, nullptr, reinterpret_cast<xmlChar const *>("jreLocations"), reinterpret_cast<xmlChar const *>("")); + if (nodeJre == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlSetNsProp(nodeJre, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true")); + //add a new line + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(root, nodeCrLf); + + //<javaInfo xsi:nil="true"> + xmlNode * nodeJava = xmlNewTextChild( + root, nullptr, reinterpret_cast<xmlChar const *>("javaInfo"), reinterpret_cast<xmlChar const *>("")); + if (nodeJava == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlSetNsProp(nodeJava, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true")); + //add a new line + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(root, nodeCrLf); +} + +NodeJava::NodeJava(Layer layer): + m_layer(layer) +{ + //This class reads and write to files which should only be done in + //application mode + if (getMode() == JFW_MODE_DIRECT) + throw FrameworkException( + JFW_E_DIRECT_MODE, + "[Java framework] Trying to access settings files in direct mode."); +} + + +void NodeJava::load() +{ + const OString sExcMsg("[Java framework] Error in function NodeJava::load" + "(elements.cxx)."); + if (SHARED == m_layer) + { + //we do not support yet to write into the shared installation + + //check if shared settings exist at all. + OUString sURL(BootParams::getSharedData()); + jfw::FileStatus s = sURL.isEmpty() + ? FILE_DOES_NOT_EXIST : checkFileURL(sURL); + if (s == FILE_INVALID) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Invalid file for shared Java settings."); + else if (s == FILE_DOES_NOT_EXIST) + //Writing shared data is not supported yet. + return; + } + else if (USER == m_layer) + { + if (!prepareSettingsDocument()) + { + SAL_INFO("jfw.level1", "no path to load user settings document from"); + return; + } + } + else + { + OSL_FAIL("[Java framework] Unknown enum used."); + } + + + //Read the user elements + OString sSettingsPath = getSettingsPath(); + //There must not be a share settings file + CXmlDocPtr docUser(xmlParseFile(sSettingsPath.getStr())); + if (docUser == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + xmlNode * cur = xmlDocGetRootElement(docUser); + if (cur == nullptr || cur->children == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + CXmlCharPtr sNil; + cur = cur->children; + while (cur != nullptr) + { + if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0) + { + //only overwrite share settings if xsi:nil="false" + sNil = xmlGetNsProp( + cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if (sNil == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + { + CXmlCharPtr sEnabled( xmlNodeListGetString( + docUser, cur->children, 1)); + if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("true")) == 0) + m_enabled = std::optional<sal_Bool>(true); + else if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("false")) == 0) + m_enabled = std::optional<sal_Bool>(false); + } + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("userClassPath")) == 0) + { + sNil = xmlGetNsProp( + cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if (sNil == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + { + CXmlCharPtr sUser(xmlNodeListGetString( + docUser, cur->children, 1)); + m_userClassPath = std::optional<OUString>(OUString(sUser)); + } + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("javaInfo")) == 0) + { + sNil = xmlGetNsProp( + cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if (sNil == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + { + if (! m_javaInfo) + m_javaInfo = std::optional<CNodeJavaInfo>(CNodeJavaInfo()); + m_javaInfo->loadFromNode(docUser, cur); + } + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vmParameters")) == 0) + { + sNil = xmlGetNsProp( + cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if (sNil == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + { + if ( ! m_vmParameters) + m_vmParameters = std::optional<std::vector<OUString> >( + std::vector<OUString> ()); + + xmlNode * pOpt = cur->children; + while (pOpt != nullptr) + { + if (xmlStrcmp(pOpt->name, reinterpret_cast<xmlChar const *>("param")) == 0) + { + CXmlCharPtr sOpt = xmlNodeListGetString( + docUser, pOpt->children, 1); + m_vmParameters->push_back(sOpt); + } + pOpt = pOpt->next; + } + } + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("jreLocations")) == 0) + { + sNil = xmlGetNsProp( + cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if (sNil == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + { + if (! m_JRELocations) + m_JRELocations = std::optional<std::vector<OUString> >( + std::vector<OUString>()); + + xmlNode * pLoc = cur->children; + while (pLoc != nullptr) + { + if (xmlStrcmp(pLoc->name, reinterpret_cast<xmlChar const *>("location")) == 0) + { + CXmlCharPtr sLoc = xmlNodeListGetString( + docUser, pLoc->children, 1); + m_JRELocations->push_back(sLoc); + } + pLoc = pLoc->next; + } + } + } + cur = cur->next; + } +} + +OString NodeJava::getSettingsPath() const +{ + OString ret; + switch (m_layer) + { + case USER: ret = getUserSettingsPath(); break; + case SHARED: ret = getSharedSettingsPath(); break; + default: + OSL_FAIL("[Java framework] NodeJava::getSettingsPath()"); + } + return ret; +} + +OUString NodeJava::getSettingsURL() const +{ + OUString ret; + switch (m_layer) + { + case USER: ret = BootParams::getUserData(); break; + case SHARED: ret = BootParams::getSharedData(); break; + default: + OSL_FAIL("[Java framework] NodeJava::getSettingsURL()"); + } + return ret; +} + +bool NodeJava::prepareSettingsDocument() const +{ + OString sExcMsg( + "[Java framework] Error in function prepareSettingsDocument" + " (elements.cxx)."); + if (!createSettingsDocument()) + { + return false; + } + OString sSettings = getSettingsPath(); + CXmlDocPtr doc(xmlParseFile(sSettings.getStr())); + if (!doc) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + bool bNeedsSave = false; + createSettingsStructure(doc, & bNeedsSave); + if (bNeedsSave) + { + if (xmlSaveFormatFileEnc( + sSettings.getStr(), doc,"UTF-8", 1) == -1) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + } + return true; +} + +void NodeJava::write() const +{ + OString sExcMsg("[Java framework] Error in function NodeJava::writeSettings " + "(elements.cxx)."); + CXmlDocPtr docUser; + CXPathContextPtr contextUser; + CXPathObjectPtr pathObj; + + if (!prepareSettingsDocument()) + { + SAL_INFO("jfw.level1", "no path to write settings document to"); + return; + } + + //Read the user elements + OString sSettingsPath = getSettingsPath(); + docUser = xmlParseFile(sSettingsPath.getStr()); + if (docUser == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + contextUser = xmlXPathNewContext(docUser); + if (xmlXPathRegisterNs(contextUser, reinterpret_cast<xmlChar const *>("jf"), + reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + xmlNode * root = xmlDocGetRootElement(docUser); + //Get xsi:nil namespace + xmlNs* nsXsi = xmlSearchNsByHref(docUser, + root, + reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + + //set the <enabled> element + //The element must exist + if (m_enabled) + { + pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:enabled"), + contextUser); + if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0]; + xmlSetNsProp(nodeEnabled, + nsXsi, + reinterpret_cast<xmlChar const *>("nil"), + reinterpret_cast<xmlChar const *>("false")); + + if (m_enabled == std::optional<sal_Bool>(true)) + xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("true")); + else + xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("false")); + } + + //set the <userClassPath> element + //The element must exist + if (m_userClassPath) + { + pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:userClassPath"), + contextUser); + if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0]; + xmlSetNsProp(nodeEnabled, nsXsi, reinterpret_cast<xmlChar const *>("nil"),reinterpret_cast<xmlChar const *>("false")); + xmlNodeSetContent(nodeEnabled,static_cast<xmlChar*>(CXmlCharPtr(*m_userClassPath))); + } + + //set <javaInfo> element + if (m_javaInfo) + { + pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:javaInfo"), + contextUser); + if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + m_javaInfo->writeToNode( + docUser, pathObj->nodesetval->nodeTab[0]); + } + + //set <vmParameters> element + if (m_vmParameters) + { + pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:vmParameters"), + contextUser); + if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlNode* vmParameters = pathObj->nodesetval->nodeTab[0]; + //set xsi:nil = false; + xmlSetNsProp(vmParameters, nsXsi,reinterpret_cast<xmlChar const *>("nil"), + reinterpret_cast<xmlChar const *>("false")); + + //remove option elements + xmlNode* cur = vmParameters->children; + while (cur != nullptr) + { + xmlNode* lastNode = cur; + cur = cur->next; + xmlUnlinkNode(lastNode); + xmlFreeNode(lastNode); + } + //add a new line after <vmParameters> + if (!m_vmParameters->empty()) + { + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(vmParameters, nodeCrLf); + } + + for (auto const & vmParameter : *m_vmParameters) + { + xmlNewTextChild(vmParameters, nullptr, reinterpret_cast<xmlChar const *>("param"), + CXmlCharPtr(vmParameter)); + //add a new line + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(vmParameters, nodeCrLf); + } + } + + //set <jreLocations> element + if (m_JRELocations) + { + pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:jreLocations"), + contextUser); + if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlNode* jreLocationsNode = pathObj->nodesetval->nodeTab[0]; + //set xsi:nil = false; + xmlSetNsProp(jreLocationsNode, nsXsi,reinterpret_cast<xmlChar const *>("nil"), + reinterpret_cast<xmlChar const *>("false")); + + //remove option elements + xmlNode* cur = jreLocationsNode->children; + while (cur != nullptr) + { + xmlNode* lastNode = cur; + cur = cur->next; + xmlUnlinkNode(lastNode); + xmlFreeNode(lastNode); + } + //add a new line after <vmParameters> + if (!m_JRELocations->empty()) + { + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(jreLocationsNode, nodeCrLf); + } + + for (auto const & JRELocation : *m_JRELocations) + { + xmlNewTextChild(jreLocationsNode, nullptr, reinterpret_cast<xmlChar const *>("location"), + CXmlCharPtr(JRELocation)); + //add a new line + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(jreLocationsNode, nodeCrLf); + } + } + + if (xmlSaveFormatFile(sSettingsPath.getStr(), docUser, 1) == -1) + throw FrameworkException(JFW_E_ERROR, sExcMsg); +} + +void NodeJava::setEnabled(bool bEnabled) +{ + m_enabled = std::optional<sal_Bool>(bEnabled); +} + + +void NodeJava::setUserClassPath(const OUString & sClassPath) +{ + m_userClassPath = std::optional<OUString>(sClassPath); +} + +void NodeJava::setJavaInfo(const JavaInfo * pInfo, bool bAutoSelect) +{ + if (!m_javaInfo) + m_javaInfo = std::optional<CNodeJavaInfo>(CNodeJavaInfo()); + m_javaInfo->bAutoSelect = bAutoSelect; + m_javaInfo->bNil = false; + + if (pInfo != nullptr) + { + m_javaInfo->m_bEmptyNode = false; + m_javaInfo->sVendor = pInfo->sVendor; + m_javaInfo->sLocation = pInfo->sLocation; + m_javaInfo->sVersion = pInfo->sVersion; + m_javaInfo->nRequirements = pInfo->nRequirements; + m_javaInfo->arVendorData = pInfo->arVendorData; + } + else + { + m_javaInfo->m_bEmptyNode = true; + m_javaInfo->sVendor.clear(); + m_javaInfo->sLocation.clear(); + m_javaInfo->sVersion.clear(); + m_javaInfo->nRequirements = 0; + m_javaInfo->arVendorData = rtl::ByteSequence(); + } +} + +void NodeJava::setVmParameters(std::vector<OUString> const & arOptions) +{ + m_vmParameters = std::optional<std::vector<OUString> >(arOptions); +} + +void NodeJava::addJRELocation(OUString const & sLocation) +{ + if (!m_JRELocations) + m_JRELocations = std::optional<std::vector<OUString> >( + std::vector<OUString> ()); + //only add the path if not already present + std::vector<OUString>::const_iterator it = + std::find(m_JRELocations->begin(), m_JRELocations->end(), sLocation); + if (it == m_JRELocations->end()) + m_JRELocations->push_back(sLocation); +} + +jfw::FileStatus NodeJava::checkSettingsFileStatus(OUString const & sURL) +{ + jfw::FileStatus ret = FILE_DOES_NOT_EXIST; + + //check the file time + ::osl::DirectoryItem item; + File::RC rc = ::osl::DirectoryItem::get(sURL, item); + if (File::E_None == rc) + { + ::osl::FileStatus stat(osl_FileStatus_Mask_Validate); + File::RC rc_stat = item.getFileStatus(stat); + if (File::E_None == rc_stat) + { + ret = FILE_OK; + } + else if (File::E_NOENT == rc_stat) + { + ret = FILE_DOES_NOT_EXIST; + } + else + { + ret = FILE_INVALID; + } + } + else if(File::E_NOENT == rc) + { + ret = FILE_DOES_NOT_EXIST; + } + else + { + ret = FILE_INVALID; + } + return ret; +} + +bool NodeJava::createSettingsDocument() const +{ + const OUString sURL = getSettingsURL(); + if (sURL.isEmpty()) + { + return false; + } + //make sure there is a user directory + OString sExcMsg("[Java framework] Error in function createSettingsDocument " + "(elements.cxx)."); + // check if javasettings.xml already exist + if (FILE_OK == checkSettingsFileStatus(sURL)) + return true; + + //make sure that the directories are created in case they do not exist + FileBase::RC rcFile = Directory::createPath(getDirFromFile(sURL)); + if (rcFile != FileBase::E_EXIST && rcFile != FileBase::E_None) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + //javasettings.xml does not exist yet + CXmlDocPtr doc(xmlNewDoc(reinterpret_cast<xmlChar const *>("1.0"))); + if (! doc) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + //Create the root element and name spaces + xmlNodePtr root = xmlNewDocNode( + doc, nullptr, reinterpret_cast<xmlChar const *>("java"), reinterpret_cast<xmlChar const *>("\n")); + + if (root == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + if (xmlNewNs(root, reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK),nullptr) == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (xmlNewNs(root,reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE),reinterpret_cast<xmlChar const *>("xsi")) == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + xmlDocSetRootElement(doc, root); + + //Create a comment + xmlNodePtr com = xmlNewComment( + reinterpret_cast<xmlChar const *>("This is a generated file. Do not alter this file!")); + if (com == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + if (xmlAddPrevSibling(root, com) == nullptr) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + const OString path = getSettingsPath(); + if (xmlSaveFormatFileEnc(path.getStr(), doc,"UTF-8", 1) == -1) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + return true; +} + + +CNodeJavaInfo::CNodeJavaInfo() : + m_bEmptyNode(false), bNil(true), bAutoSelect(true), + nRequirements(0) +{ +} + +void CNodeJavaInfo::loadFromNode(xmlDoc * pDoc, xmlNode * pJavaInfo) +{ + OString sExcMsg("[Java framework] Error in function NodeJavaInfo::loadFromNode " + "(elements.cxx)."); + + OSL_ASSERT(pJavaInfo && pDoc); + if (pJavaInfo->children == nullptr) + return; + //Get the xsi:nil attribute; + CXmlCharPtr sNil = xmlGetNsProp( + pJavaInfo, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + if ( ! sNil) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("true")) == 0) + bNil = true; + else if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0) + bNil = false; + else + throw FrameworkException(JFW_E_ERROR, sExcMsg); + if (bNil) + return; + + //Get javaInfo@manuallySelected attribute + CXmlCharPtr sAutoSelect = xmlGetProp( + pJavaInfo, reinterpret_cast<xmlChar const *>("autoSelect")); + if ( ! sAutoSelect) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("true")) == 0) + bAutoSelect = true; + else if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("false")) == 0) + bAutoSelect = false; + else + throw FrameworkException(JFW_E_ERROR, sExcMsg); + + xmlNode * cur = pJavaInfo->children; + + while (cur != nullptr) + { + if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendor")) == 0) + { + CXmlCharPtr xmlVendor = xmlNodeListGetString( + pDoc, cur->children, 1); + if (! xmlVendor) + return; + sVendor = xmlVendor; + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("location")) == 0) + { + CXmlCharPtr xmlLocation = xmlNodeListGetString( + pDoc, cur->children, 1); + sLocation = xmlLocation; + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("version")) == 0) + { + CXmlCharPtr xmlVersion = xmlNodeListGetString( + pDoc, cur->children, 1); + sVersion = xmlVersion; + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("requirements")) == 0) + { + CXmlCharPtr xmlRequire = xmlNodeListGetString( + pDoc, cur->children, 1); + OUString sRequire = xmlRequire; + nRequirements = sRequire.toInt64(16); +#ifdef MACOSX + //javaldx is not used anymore in the mac build. In case the Java + //corresponding to the saved settings does not exist anymore the + //javavm services will look for an existing Java after creation of + //the JVM failed. See stoc/source/javavm/javavm.cxx. Only if + //nRequirements does not have the flag JFW_REQUIRE_NEEDRESTART the + //jvm of the new selected JRE will be started. Old settings (before + //OOo 3.3) still contain the flag which can be safely ignored. + nRequirements &= ~JFW_REQUIRE_NEEDRESTART; +#endif + } + else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendorData")) == 0) + { + CXmlCharPtr xmlData = xmlNodeListGetString( + pDoc, cur->children, 1); + xmlChar* _data = static_cast<xmlChar*>(xmlData); + if (_data) + { + rtl::ByteSequence seq(reinterpret_cast<sal_Int8*>(_data), strlen(reinterpret_cast<char*>(_data))); + arVendorData = decodeBase16(seq); + } + } + cur = cur->next; + } + + if (sVendor.isEmpty()) + m_bEmptyNode = true; + //Get the javainfo attributes + CXmlCharPtr sVendorUpdate = xmlGetProp(pJavaInfo, + reinterpret_cast<xmlChar const *>("vendorUpdate")); + if ( ! sVendorUpdate) + throw FrameworkException(JFW_E_ERROR, sExcMsg); + sAttrVendorUpdate = sVendorUpdate; +} + + +void CNodeJavaInfo::writeToNode(xmlDoc* pDoc, + xmlNode* pJavaInfoNode) const + +{ + OSL_ASSERT(pJavaInfoNode && pDoc); + //write the attribute vendorSettings + + //javaInfo@vendorUpdate + //creates the attribute if necessary + OString sUpdated = getElementUpdated(); + + xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("vendorUpdate"), + reinterpret_cast<xmlChar const *>(sUpdated.getStr())); + + //javaInfo@autoSelect + xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("autoSelect"), + reinterpret_cast<xmlChar const *>(bAutoSelect ? "true" : "false")); + + //Set xsi:nil in javaInfo element to false + //the xmlNs pointer must not be destroyed + xmlNs* nsXsi = xmlSearchNsByHref(pDoc, + pJavaInfoNode, + reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE)); + + xmlSetNsProp(pJavaInfoNode, + nsXsi, + reinterpret_cast<xmlChar const *>("nil"), + reinterpret_cast<xmlChar const *>("false")); + + //Delete the children of JavaInfo + xmlNode* cur = pJavaInfoNode->children; + while (cur != nullptr) + { + xmlNode* lastNode = cur; + cur = cur->next; + xmlUnlinkNode(lastNode); + xmlFreeNode(lastNode); + } + + //If the JavaInfo was set with an empty value, + //then we are done. + if (m_bEmptyNode) + return; + + //add a new line after <javaInfo> + xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + //Create the vendor element + xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("vendor"), + CXmlCharPtr(sVendor)); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + //Create the location element + xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("location"), + CXmlCharPtr(sLocation)); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + //Create the version element + xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("version"), + CXmlCharPtr(sVersion)); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + //Create the features element, for backwards compatibility (it used to support one flag + // JFW_FEATURE_ACCESSBRIDGE = 0x01, but is ignored and always written as zero now) + xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("features"), + reinterpret_cast<xmlChar const *>("0")); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + + //Create the requirements element + OUString sRequirements = OUString::number( + nRequirements, 16); + xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("requirements"), + CXmlCharPtr(sRequirements)); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); + + + //Create the vendorData element + rtl::ByteSequence data = encodeBase16(arVendorData); + xmlNode* dataNode = xmlNewChild(pJavaInfoNode, nullptr, + reinterpret_cast<xmlChar const *>("vendorData"), + reinterpret_cast<xmlChar const *>("")); + xmlNodeSetContentLen(dataNode, + reinterpret_cast<xmlChar*>(data.getArray()), data.getLength()); + //add a new line for better readability + nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n")); + xmlAddChild(pJavaInfoNode, nodeCrLf); +} + +std::unique_ptr<JavaInfo> CNodeJavaInfo::makeJavaInfo() const +{ + if (bNil || m_bEmptyNode) + return std::unique_ptr<JavaInfo>(); + return std::unique_ptr<JavaInfo>( + new JavaInfo{ + sVendor, sLocation, sVersion, nRequirements, + arVendorData}); +} + + +MergedSettings::MergedSettings(): + m_bEnabled(false) +{ + NodeJava settings(NodeJava::USER); + settings.load(); + NodeJava sharedSettings(NodeJava::SHARED); + sharedSettings.load(); + merge(sharedSettings, settings); +} + +MergedSettings::~MergedSettings() +{ +} + +void MergedSettings::merge(const NodeJava & share, const NodeJava & user) +{ + if (user.getEnabled()) + m_bEnabled = * user.getEnabled(); + else if (share.getEnabled()) + m_bEnabled = * share.getEnabled(); + else + m_bEnabled = true; + + if (user.getUserClassPath()) + m_sClassPath = * user.getUserClassPath(); + else if (share.getUserClassPath()) + m_sClassPath = * share.getUserClassPath(); + + if (user.getJavaInfo()) + m_javaInfo = * user.getJavaInfo(); + else if (share.getJavaInfo()) + m_javaInfo = * share.getJavaInfo(); + + if (user.getVmParameters()) + m_vmParams = * user.getVmParameters(); + else if (share.getVmParameters()) + m_vmParams = * share.getVmParameters(); + + if (user.getJRELocations()) + m_JRELocations = * user.getJRELocations(); + else if (share.getJRELocations()) + m_JRELocations = * share.getJRELocations(); +} + + +::std::vector< OString> MergedSettings::getVmParametersUtf8() const +{ + ::std::vector< OString> ret; + for (auto const & vmParam : m_vmParams) + { + ret.push_back( OUStringToOString(vmParam, RTL_TEXTENCODING_UTF8)); + } + return ret; +} + + +std::unique_ptr<JavaInfo> MergedSettings::createJavaInfo() const +{ + return m_javaInfo.makeJavaInfo(); +} +#ifdef _WIN32 +bool MergedSettings::getJavaInfoAttrAutoSelect() const +{ + return m_javaInfo.bAutoSelect; +} +#endif +void MergedSettings::getVmParametersArray(std::vector<OUString> * parParams) + const +{ + assert(parParams != nullptr); + osl::MutexGuard guard(FwkMutex()); + + *parParams = m_vmParams; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/jvmfwk/source/framework.cxx b/jvmfwk/source/framework.cxx new file mode 100644 index 000000000..8aa85082b --- /dev/null +++ b/jvmfwk/source/framework.cxx @@ -0,0 +1,749 @@ +/* -*- 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/ref.hxx> +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> +#ifdef _WIN32 +#include <osl/file.hxx> +#include <osl/process.h> +#endif +#include <osl/thread.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; + } +} + +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(); + sUserClassPath = jfw::makeClassPathOption(settings.getUserClassPath()); + } // 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() ? 1 : 2) + 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; + + //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."); + + 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: */ diff --git a/jvmfwk/source/framework.hxx b/jvmfwk/source/framework.hxx new file mode 100644 index 000000000..39bda148b --- /dev/null +++ b/jvmfwk/source/framework.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_JVMFWK_SOURCE_FRAMEWORK_HXX +#define INCLUDED_JVMFWK_SOURCE_FRAMEWORK_HXX + +#include <jvmfwk/framework.hxx> + +namespace jfw +{ + +class FrameworkException : public std::exception +{ +public: + + FrameworkException(javaFrameworkError err, const OString& msg): + errorCode(err), message(msg) + { + } + javaFrameworkError errorCode; + OString message; +}; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/jvmfwk/source/fwkbase.cxx b/jvmfwk/source/fwkbase.cxx new file mode 100644 index 000000000..225437011 --- /dev/null +++ b/jvmfwk/source/fwkbase.cxx @@ -0,0 +1,524 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <libxml/xpathInternals.h> +#include <osl/file.hxx> +#include <osl/thread.hxx> +#include <o3tl/string_view.hxx> +#include "framework.hxx" +#include <fwkutil.hxx> +#include <elements.hxx> +#include <fwkbase.hxx> + +using namespace osl; + + +#define UNO_JAVA_JFW_PARAMETER "UNO_JAVA_JFW_PARAMETER_" +#define UNO_JAVA_JFW_JREHOME "UNO_JAVA_JFW_JREHOME" +#define UNO_JAVA_JFW_ENV_JREHOME "UNO_JAVA_JFW_ENV_JREHOME" +#define UNO_JAVA_JFW_CLASSPATH "UNO_JAVA_JFW_CLASSPATH" +#define UNO_JAVA_JFW_ENV_CLASSPATH "UNO_JAVA_JFW_ENV_CLASSPATH" +#define UNO_JAVA_JFW_CLASSPATH_URLS "UNO_JAVA_JFW_CLASSPATH_URLS" +#define UNO_JAVA_JFW_VENDOR_SETTINGS "UNO_JAVA_JFW_VENDOR_SETTINGS" + +namespace jfw +{ +static bool g_bJavaSet = false; + +namespace { + +#if defined _WIN32 + // The paths are used in libxml. On Windows, it takes UTF-8 paths. +constexpr rtl_TextEncoding PathEncoding() { return RTL_TEXTENCODING_UTF8; } +#else +rtl_TextEncoding PathEncoding() { return osl_getThreadTextEncoding(); } +#endif + +OString getVendorSettingsPath(OUString const & sURL) +{ + if (sURL.isEmpty()) + return OString(); + OUString sSystemPathSettings; + if (osl_getSystemPathFromFileURL(sURL.pData, + & sSystemPathSettings.pData) != osl_File_E_None) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function getVendorSettingsPath (fwkbase.cxx) "); + OString osSystemPathSettings = OUStringToOString(sSystemPathSettings, PathEncoding()); + return osSystemPathSettings; +} + +OUString getParam(OUString const & name) +{ + OUString retVal; + bool b = Bootstrap()->getFrom(name, retVal); + SAL_INFO( + "jfw", + "Using bootstrap parameter " << name << " = \"" << retVal << "\"" + << (b ? "" : " (undefined)")); + return retVal; +} + +OUString getParamFirstUrl(OUString const & name) +{ + // Some parameters can consist of multiple URLs (separated by space + // characters, although trim() harmlessly also removes other white-space), + // of which only the first is used: + return getParam(name).trim().getToken(0, ' '); +} + +}//blind namespace + + +VendorSettings::VendorSettings() +{ + OUString xmlDocVendorSettingsFileUrl(BootParams::getVendorSettings()); + //Prepare the xml document and context + OString sSettingsPath = getVendorSettingsPath(xmlDocVendorSettingsFileUrl); + if (sSettingsPath.isEmpty()) + { + OString sMsg("[Java framework] A vendor settings file was not specified." + "Check the bootstrap parameter " UNO_JAVA_JFW_VENDOR_SETTINGS "."); + SAL_WARN( "jfw", sMsg ); + throw FrameworkException(JFW_E_CONFIGURATION, sMsg); + } + if (sSettingsPath.isEmpty()) + return; + + m_xmlDocVendorSettings = xmlParseFile(sSettingsPath.getStr()); + if (m_xmlDocVendorSettings == nullptr) + throw FrameworkException( + JFW_E_ERROR, + OString::Concat("[Java framework] Error while parsing file: ") + + sSettingsPath + "."); + + m_xmlPathContextVendorSettings = xmlXPathNewContext(m_xmlDocVendorSettings); + int res = xmlXPathRegisterNs( + m_xmlPathContextVendorSettings, reinterpret_cast<xmlChar const *>("jf"), + reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)); + if (res == -1) + throw FrameworkException(JFW_E_ERROR, + "[Java framework] Error in constructor VendorSettings::VendorSettings() (fwkbase.cxx)"); +} + +VersionInfo VendorSettings::getVersionInformation(std::u16string_view sVendor) const +{ + OSL_ASSERT(!sVendor.empty()); + OString osVendor = OUStringToOString(sVendor, RTL_TEXTENCODING_UTF8); + CXPathObjectPtr pathObject = xmlXPathEvalExpression( + reinterpret_cast<xmlChar const *>( + OString( + "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" + osVendor + + "\"]/jf:minVersion").getStr()), + m_xmlPathContextVendorSettings); + if (xmlXPathNodeSetIsEmpty(pathObject->nodesetval)) + { + return { + {}, +#if defined MACOSX && defined __aarch64__ + "17", +#else + "1.8.0", +#endif + ""}; + } + + VersionInfo aVersionInfo; + //Get minVersion + OString sExpression = + "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" + + osVendor + "\"]/jf:minVersion"; + + CXPathObjectPtr xPathObjectMin = + xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>(sExpression.getStr()), + m_xmlPathContextVendorSettings); + if (xmlXPathNodeSetIsEmpty(xPathObjectMin->nodesetval)) + { + aVersionInfo.sMinVersion.clear(); + } + else + { + CXmlCharPtr sVersion = xmlNodeListGetString( + m_xmlDocVendorSettings, + xPathObjectMin->nodesetval->nodeTab[0]->xmlChildrenNode, 1); + OString osVersion(sVersion); + aVersionInfo.sMinVersion = OStringToOUString( + osVersion, RTL_TEXTENCODING_UTF8); + } + + //Get maxVersion + sExpression = "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" + + osVendor + "\"]/jf:maxVersion"; + CXPathObjectPtr xPathObjectMax = xmlXPathEvalExpression( + reinterpret_cast<xmlChar const *>(sExpression.getStr()), + m_xmlPathContextVendorSettings); + if (xmlXPathNodeSetIsEmpty(xPathObjectMax->nodesetval)) + { + aVersionInfo.sMaxVersion.clear(); + } + else + { + CXmlCharPtr sVersion = xmlNodeListGetString( + m_xmlDocVendorSettings, + xPathObjectMax->nodesetval->nodeTab[0]->xmlChildrenNode, 1); + OString osVersion(sVersion); + aVersionInfo.sMaxVersion = OStringToOUString( + osVersion, RTL_TEXTENCODING_UTF8); + } + + //Get excludeVersions + sExpression = "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" + + osVendor + "\"]/jf:excludeVersions/jf:version"; + CXPathObjectPtr xPathObjectVersions = + xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>(sExpression.getStr()), + m_xmlPathContextVendorSettings); + if (!xmlXPathNodeSetIsEmpty(xPathObjectVersions->nodesetval)) + { + xmlNode* cur = xPathObjectVersions->nodesetval->nodeTab[0]; + while (cur != nullptr) + { + if (cur->type == XML_ELEMENT_NODE ) + { + if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("version")) == 0) + { + CXmlCharPtr sVersion = xmlNodeListGetString( + m_xmlDocVendorSettings, cur->xmlChildrenNode, 1); + OString osVersion(sVersion); + OUString usVersion = OStringToOUString( + osVersion, RTL_TEXTENCODING_UTF8); + aVersionInfo.vecExcludeVersions.push_back(usVersion); + } + } + cur = cur->next; + } + } + return aVersionInfo; +} + +::std::vector<OString> BootParams::getVMParameters() +{ + ::std::vector<OString> vecParams; + + for (sal_Int32 i = 1; ; i++) + { + OUString sName = UNO_JAVA_JFW_PARAMETER + OUString::number(i); + OUString sValue; + if (Bootstrap()->getFrom(sName, sValue)) + { + OString sParam = + OUStringToOString(sValue, osl_getThreadTextEncoding()); + vecParams.push_back(sParam); + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " << sName << " = " << sParam); + } + else + break; + } + return vecParams; +} + +OUString BootParams::getUserData() +{ + return getParamFirstUrl("UNO_JAVA_JFW_USER_DATA"); +} + +OUString BootParams::getSharedData() +{ + return getParamFirstUrl("UNO_JAVA_JFW_SHARED_DATA"); +} + +OString BootParams::getClasspath() +{ + OString sClassPath; + OUString sCP; + if (Bootstrap()->getFrom( UNO_JAVA_JFW_CLASSPATH, sCP )) + { + sClassPath = OUStringToOString(sCP, PathEncoding()); + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_CLASSPATH " = " + << sClassPath); + } + + OUString sEnvCP; + if (Bootstrap()->getFrom( UNO_JAVA_JFW_ENV_CLASSPATH, sEnvCP )) + { + char * pCp = getenv("CLASSPATH"); + if (pCp) + { + sClassPath += OStringChar(SAL_PATHSEPARATOR) + pCp; + } + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_ENV_CLASSPATH + " and class path is: " << (pCp ? pCp : "")); + } + + return sClassPath; +} + +OUString BootParams::getVendorSettings() +{ + OUString sVendor; + if (Bootstrap()->getFrom(UNO_JAVA_JFW_VENDOR_SETTINGS, sVendor)) + { + //check the value of the bootstrap variable + jfw::FileStatus s = checkFileURL(sVendor); + if (s != FILE_OK) + { + //This bootstrap parameter can contain a relative URL + OUString sAbsoluteUrl; + OUString sBaseDir = getLibraryLocation(); + if (File::getAbsoluteFileURL(sBaseDir, sVendor, sAbsoluteUrl) + != File::E_None) + throw FrameworkException( + JFW_E_CONFIGURATION, + "[Java framework] Invalid value for bootstrap variable: " + UNO_JAVA_JFW_VENDOR_SETTINGS); + sVendor = sAbsoluteUrl; + s = checkFileURL(sVendor); + if (s == jfw::FILE_INVALID || s == jfw::FILE_DOES_NOT_EXIST) + { + throw FrameworkException( + JFW_E_CONFIGURATION, + "[Java framework] Invalid value for bootstrap variable: " + UNO_JAVA_JFW_VENDOR_SETTINGS); + } + } + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_VENDOR_SETTINGS " = " + << sVendor); + } + return sVendor; +} + +OUString BootParams::getJREHome() +{ + OUString sJRE; + OUString sEnvJRE; + bool bJRE = Bootstrap()->getFrom(UNO_JAVA_JFW_JREHOME, sJRE); + bool bEnvJRE = Bootstrap()->getFrom(UNO_JAVA_JFW_ENV_JREHOME, sEnvJRE); + + if (bJRE && bEnvJRE) + { + throw FrameworkException( + JFW_E_CONFIGURATION, + "[Java framework] Both bootstrap parameter " + UNO_JAVA_JFW_JREHOME" and " + UNO_JAVA_JFW_ENV_JREHOME" are set. However only one of them can be set." + "Check bootstrap parameters: environment variables, command line " + "arguments, rc/ini files for executable and java framework library."); + } + else if (bEnvJRE) + { + const char * pJRE = getenv("JAVA_HOME"); + if (pJRE == nullptr) + { + throw FrameworkException( + JFW_E_CONFIGURATION, + "[Java framework] Both bootstrap parameter " + UNO_JAVA_JFW_ENV_JREHOME" is set, but the environment variable " + "JAVA_HOME is not set."); + } + OString osJRE(pJRE); + OUString usJRE = OStringToOUString(osJRE, osl_getThreadTextEncoding()); + if (File::getFileURLFromSystemPath(usJRE, sJRE) != File::E_None) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function BootParams::getJREHome() " + "(fwkbase.cxx)."); + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_ENV_JREHOME + " with JAVA_HOME = " << pJRE); + } + else if (getMode() == JFW_MODE_DIRECT && !bJRE) + { + throw FrameworkException( + JFW_E_CONFIGURATION, + "[Java framework] The bootstrap parameter " + UNO_JAVA_JFW_ENV_JREHOME" or " UNO_JAVA_JFW_JREHOME + " must be set in direct mode."); + } + + SAL_INFO_IF( + bJRE, "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_JREHOME " = " << sJRE); + return sJRE; +} + +OUString BootParams::getClasspathUrls() +{ + OUString sParams; + Bootstrap()->getFrom( UNO_JAVA_JFW_CLASSPATH_URLS, sParams); + SAL_INFO( + "jfw.level2", + "Using bootstrap parameter " UNO_JAVA_JFW_CLASSPATH_URLS " = " + << sParams); + return sParams; +} + +JFW_MODE getMode() +{ + static bool g_bMode = false; + static JFW_MODE g_mode = JFW_MODE_APPLICATION; + + if (!g_bMode) + { + //check if either of the "direct mode" bootstrap variables is set + bool bDirectMode = true; + OUString sValue; + const rtl::Bootstrap * aBoot = Bootstrap(); + if (!aBoot->getFrom(UNO_JAVA_JFW_JREHOME, sValue)) + { + if (!aBoot->getFrom(UNO_JAVA_JFW_ENV_JREHOME, sValue)) + { + if (!aBoot->getFrom(UNO_JAVA_JFW_CLASSPATH, sValue)) + { + if (!aBoot->getFrom(UNO_JAVA_JFW_ENV_CLASSPATH, sValue)) + { + OUString sParams = UNO_JAVA_JFW_PARAMETER + + OUString::number(1); + if (!aBoot->getFrom(sParams, sValue)) + { + bDirectMode = false; + } + } + } + } + } + + if (bDirectMode) + g_mode = JFW_MODE_DIRECT; + else + g_mode = JFW_MODE_APPLICATION; + g_bMode = true; + } + + return g_mode; +} + +OUString getApplicationClassPath() +{ + OSL_ASSERT(getMode() == JFW_MODE_APPLICATION); + OUString sParams = BootParams::getClasspathUrls(); + if (sParams.isEmpty()) + return OUString(); + + OUStringBuffer buf; + sal_Int32 index = 0; + do + { + OUString token( o3tl::trim(o3tl::getToken(sParams, 0, ' ', index )) ); + if (!token.isEmpty()) + { + OUString systemPathElement; + oslFileError rc = osl_getSystemPathFromFileURL( + token.pData, &systemPathElement.pData ); + OSL_ASSERT( rc == osl_File_E_None ); + if (rc == osl_File_E_None && !systemPathElement.isEmpty()) + { + if (buf.getLength() > 0) + buf.append( SAL_PATHSEPARATOR ); + buf.append( systemPathElement ); + } + } + } + while (index >= 0); + return buf.makeStringAndClear(); +} + +OString makeClassPathOption(std::u16string_view sUserClassPath) +{ + //Compose the class path + OString sPaths; + OUStringBuffer sBufCP(4096); + + // append all user selected jars to the class path + if (!sUserClassPath.empty()) + sBufCP.append(sUserClassPath); + + //append all jar libraries and components to the class path + OUString sAppCP = getApplicationClassPath(); + if (!sAppCP.isEmpty()) + { + if (!sUserClassPath.empty()) + { + sBufCP.append(SAL_PATHSEPARATOR); + } + sBufCP.append(sAppCP); + } + + sPaths = OUStringToOString(sBufCP.makeStringAndClear(), PathEncoding()); + if (sPaths.isEmpty()) { + return ""; + } + + OString sOptionClassPath = "-Djava.class.path=" + sPaths; + return sOptionClassPath; +} + +OString getUserSettingsPath() +{ + return getSettingsPath(BootParams::getUserData()); +} + +OString getSharedSettingsPath() +{ + return getSettingsPath(BootParams::getSharedData()); +} + +OString getSettingsPath( const OUString & sURL) +{ + if (sURL.isEmpty()) + return OString(); + OUString sPath; + if (osl_getSystemPathFromFileURL(sURL.pData, + & sPath.pData) != osl_File_E_None) + throw FrameworkException( + JFW_E_ERROR, + "[Java framework] Error in function ::getSettingsPath (fwkbase.cxx)."); + return OUStringToOString(sPath, PathEncoding()); +} + +OString getVendorSettingsPath() +{ + return getVendorSettingsPath(BootParams::getVendorSettings()); +} + +void setJavaSelected() +{ + g_bJavaSet = true; +} + +bool wasJavaSelectedInSameProcess() +{ + //g_setJavaProcId not set means no Java selected + return g_bJavaSet; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/jvmfwk/source/fwkutil.cxx b/jvmfwk/source/fwkutil.cxx new file mode 100644 index 000000000..89cb2e541 --- /dev/null +++ b/jvmfwk/source/fwkutil.cxx @@ -0,0 +1,194 @@ +/* -*- 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 . + */ + + +#if defined(_WIN32) +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <algorithm> +#endif + +#include <osl/module.hxx> +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <sal/log.hxx> + +#include "framework.hxx" +#include <fwkutil.hxx> +#include <memory> + +using namespace osl; + + +namespace jfw +{ + +/** provides a bootstrap class which already knows the values from the + jvmfkwrc file. +*/ +const rtl::Bootstrap* Bootstrap() +{ + static const rtl::Bootstrap* SINGLETON = []() + { + OUString sIni = getLibraryLocation() + +#ifdef MACOSX + // For some reason the jvmfwk3rc file is traditionally in + // LIBO_URE_ETC_FOLDER + "/../" LIBO_URE_ETC_FOLDER +#endif + SAL_CONFIGFILE("/jvmfwk3"); + ::rtl::Bootstrap * bootstrap = new ::rtl::Bootstrap(sIni); + SAL_INFO("jfw.level2", "Using configuration file " << sIni); + return bootstrap; + }(); + return SINGLETON; +}; + +osl::Mutex& FwkMutex() +{ + static osl::Mutex SINGLETON; + return SINGLETON; +} + + +rtl::ByteSequence encodeBase16(const rtl::ByteSequence& rawData) +{ + static const char EncodingTable[] = + {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + sal_Int32 lenRaw = rawData.getLength(); + std::unique_ptr<char[]> pBuf(new char[lenRaw * 2]); + const sal_Int8* arRaw = rawData.getConstArray(); + + char* pCurBuf = pBuf.get(); + for (int i = 0; i < lenRaw; i++) + { + unsigned char curChar = arRaw[i]; + curChar >>= 4; + + *pCurBuf = EncodingTable[curChar]; + pCurBuf++; + + curChar = arRaw[i]; + curChar &= 0x0F; + + *pCurBuf = EncodingTable[curChar]; + pCurBuf++; + } + + rtl::ByteSequence ret(reinterpret_cast<sal_Int8*>(pBuf.get()), lenRaw * 2); + return ret; +} + +rtl::ByteSequence decodeBase16(const rtl::ByteSequence& data) +{ + static const char decodingTable[] = + {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + sal_Int32 lenData = data.getLength(); + sal_Int32 lenBuf = lenData / 2; //always divisible by two + std::unique_ptr<unsigned char[]> pBuf(new unsigned char[lenBuf]); + const sal_Int8* pData = data.getConstArray(); + for (sal_Int32 i = 0; i < lenBuf; i++) + { + sal_Int8 curChar = *pData++; + //find the index of the first 4bits + // TODO What happens if text is not valid Hex characters? + unsigned char nibble = 0; + for (unsigned char j = 0; j < 16; j++) + { + if (curChar == decodingTable[j]) + { + nibble = j; + break; + } + } + nibble <<= 4; + curChar = *pData++; + //find the index for the next 4bits + for (unsigned char j = 0; j < 16; j++) + { + if (curChar == decodingTable[j]) + { + nibble |= j; + break; + } + } + pBuf[i] = nibble; + } + rtl::ByteSequence ret(reinterpret_cast<sal_Int8*>(pBuf.get()), lenBuf ); + return ret; +} + +OUString getDirFromFile(std::u16string_view usFilePath) +{ + size_t index = usFilePath.rfind('/'); + return OUString(usFilePath.substr(0, index)); +} + +OUString getLibraryLocation() +{ + OUString libraryFileUrl; + + if (!osl::Module::getUrlFromAddress( + reinterpret_cast< oslGenericFunction >(getLibraryLocation), + libraryFileUrl)) + throw FrameworkException(JFW_E_ERROR, + "[Java framework] Error in function getLibraryLocation (fwkutil.cxx)."); + + return getDirFromFile(libraryFileUrl); +} + +jfw::FileStatus checkFileURL(const OUString & sURL) +{ + jfw::FileStatus ret = jfw::FILE_OK; + DirectoryItem item; + File::RC rc_item = DirectoryItem::get(sURL, item); + if (File::E_None == rc_item) + { + osl::FileStatus status(osl_FileStatus_Mask_Validate); + + File::RC rc_stat = item.getFileStatus(status); + if (File::E_None == rc_stat) + { + ret = FILE_OK; + } + else if (File::E_NOENT == rc_stat) + { + ret = FILE_DOES_NOT_EXIST; + } + else + { + ret = FILE_INVALID; + } + } + else if (File::E_NOENT == rc_item) + { + ret = FILE_DOES_NOT_EXIST; + } + else + { + ret = FILE_INVALID; + } + return ret; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/jvmfwk/source/javasettings.xsd b/jvmfwk/source/javasettings.xsd new file mode 100644 index 000000000..e0ccbd47e --- /dev/null +++ b/jvmfwk/source/javasettings.xsd @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . +--> + +<!-- + Document : javasettings.xsd + Created on : 25. März 2004, 16:16 + Author : jl97489 + Description: + Purpose of XML Schema document follows. +--> + +<schema targetNamespace="http://openoffice.org/2004/java/framework/1.0" + xmlns:jf="http://openoffice.org/2004/java/framework/1.0" + xmlns="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified"> + +<element name="java"> + <complexType> + <sequence> + <element name="enabled" nillable="true" default="true" type="boolean"/> + <element name="userClassPath" nillable="true" type="string"/> + <element name="vmParameters" nillable="true" type="jf:vmParametersType"/> + <element name="jreLocations" nillable="true" type="jf:jreLocationsType"/> + <element name="javaInfo" nillable="true" type="jf:javaInfoType"/> + </sequence> + </complexType> + +</element> + +<complexType name="javaInfoType"> + <sequence> + <element name="vendor" type="string"/> + <element name="location" type="string"/> + <element name="version" type="string"/> + <element name="features" default="0" type="unsignedLong"/> + <element name="requirements" default="0" type="unsignedLong"/> + <element name="vendorData" type="base64Binary"/> + </sequence> + <attribute name="vendorUpdate" type="date"/> +</complexType> + +<complexType name="vmParametersType"> + <sequence> + <element name="param" minOccurs="0" maxOccurs="unbounded" type="string"/> + </sequence> +</complexType> + +<complexType name="jreLocationsType"> + <sequence> + <element name="location" minOccurs="0" maxOccurs="unbounded" type="string"/> + </sequence> +</complexType> + +</schema> diff --git a/jvmfwk/source/javasettings_template.xml b/jvmfwk/source/javasettings_template.xml new file mode 100644 index 000000000..c73404c69 --- /dev/null +++ b/jvmfwk/source/javasettings_template.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . +--> + +<!-- +This file shows what elements the javasettings_platform.xml can contain. +The children of javaInfo are only created when a JRE is selected. The children of +vmParameters are only created when parameters are added and the children of +jreLocations are only created when the paths are added. +See CNodeJava::loadFromSettings and CNodeJava::writeSettings for details. +When extending the javavendors.xml then use the schema to verify it. +--> + +<java xmlns='http://openoffice.org/2004/java/framework/1.0' + xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' + xsi:schemaLocation='http://openoffice.org/2004/java/framework/1.0 file:/D:/cws-jl6/jvmfwk/source/javasettings.xsd'> + <classesDirectory>program/classes</classesDirectory> + <enabled xsi:nil="true"></enabled> + <userClassPath xsi:nil="true"></userClassPath> + <vmParameters xsi:nil="true"/> + <!--param>-Xdebug</param--> + <!--</vmParameters>--> + <jreLocations xsi:nil="true"/> + <!--location></location--> + <!--</jreLocations>--> + <javaInfo xsi:nil="true"/> + <!--javaInfo vendorUpdate="2004-03-27" xsi:nil="false"--> + <!--vendor></vendor> + <location></location> + <version></version> + <features></features> + <requirements></requirements> + <vendorData></vendorData> + </javaInfo--> + </java> + + diff --git a/jvmfwk/source/libxmlutil.cxx b/jvmfwk/source/libxmlutil.cxx new file mode 100644 index 000000000..f83e14143 --- /dev/null +++ b/jvmfwk/source/libxmlutil.cxx @@ -0,0 +1,136 @@ +/* -*- 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 <libxmlutil.hxx> + +namespace jfw +{ + +CXPathObjectPtr::CXPathObjectPtr():_object(nullptr) +{ +} +CXPathObjectPtr::CXPathObjectPtr(xmlXPathObject* pObj):_object(pObj) +{ +} +CXPathObjectPtr::~CXPathObjectPtr() +{ + xmlXPathFreeObject(_object); +} +CXPathObjectPtr & CXPathObjectPtr::operator = (xmlXPathObject* pObj) +{ + if (_object == pObj) + return *this; + + xmlXPathFreeObject(_object); + _object = pObj; + return *this; +} + +CXPathContextPtr::CXPathContextPtr(xmlXPathContextPtr aContext) + : _object(aContext) +{ +} + +CXPathContextPtr::CXPathContextPtr():_object(nullptr) +{ +} + +CXPathContextPtr::~CXPathContextPtr() +{ + xmlXPathFreeContext(_object); +} + +CXPathContextPtr & CXPathContextPtr::operator = (xmlXPathContextPtr pObj) +{ + if (_object == pObj) + return *this; + xmlXPathFreeContext(_object); + _object = pObj; + return *this; +} + + +CXmlDocPtr::CXmlDocPtr(xmlDoc* aDoc) + : _object(aDoc) +{ +} + +CXmlDocPtr::CXmlDocPtr():_object(nullptr) +{ +} + +CXmlDocPtr::~CXmlDocPtr() +{ + xmlFreeDoc(_object); +} +CXmlDocPtr & CXmlDocPtr::operator = (xmlDoc* pObj) +{ + if (_object == pObj) + return *this; + xmlFreeDoc(_object); + _object = pObj; + return *this; +} + + +CXmlCharPtr::CXmlCharPtr(xmlChar * aChar) + : _object(aChar) +{ +} + +CXmlCharPtr::CXmlCharPtr(std::u16string_view s): + _object(nullptr) +{ + OString o = OUStringToOString(s, RTL_TEXTENCODING_UTF8); + _object = xmlCharStrdup(o.getStr()); +} +CXmlCharPtr::CXmlCharPtr():_object(nullptr) +{ +} + +CXmlCharPtr::~CXmlCharPtr() +{ + xmlFree(_object); +} + +CXmlCharPtr & CXmlCharPtr::operator = (xmlChar* pObj) +{ + if (pObj == _object) + return *this; + xmlFree(_object); + _object = pObj; + return *this; +} + + +CXmlCharPtr::operator OUString() +{ + OUString ret; + if (_object != nullptr) + { + OString aOStr(reinterpret_cast<char*>(_object)); + ret = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8); + } + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |