From 40138cee6b6f19a7725f3ce9316f285b86366a06 Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Wed, 10 Sep 2014 14:56:25 +0200 Subject: fdo#83753: consider JAVA_HOME and PATH when selecting JRE adapted algorithm that selects the Java runtime to be used so that Java installations associated with the JAVA_HOME and PATH environment variables are preferred over others Java installations are now analysed in the following order: * installation that the JAVA_HOME environment variable refers to (if it is set) * Java installations in PATH * other Java installation (algorithm that was used before) Signed-off-by: Stephan Bergmann Conflicts: jvmfwk/source/framework.cxx Change-Id: I3a3ade25322def0c0432b369848f13a6b82034a1 --- jvmfwk/inc/vendorplugin.hxx | 78 ++++++ .../plugins/sunmajor/pluginlib/sunjavaplugin.cxx | 99 ++++++++ jvmfwk/plugins/sunmajor/pluginlib/util.cxx | 24 +- jvmfwk/plugins/sunmajor/pluginlib/util.hxx | 6 + jvmfwk/source/framework.cxx | 281 +++++++++++++-------- 5 files changed, 384 insertions(+), 104 deletions(-) (limited to 'jvmfwk') diff --git a/jvmfwk/inc/vendorplugin.hxx b/jvmfwk/inc/vendorplugin.hxx index 3fd4d3591257..35131df27cef 100644 --- a/jvmfwk/inc/vendorplugin.hxx +++ b/jvmfwk/inc/vendorplugin.hxx @@ -24,6 +24,9 @@ #include #include #include "jni.h" +#include +#include +#include "../source/elements.hxx" /** @file @@ -168,6 +171,81 @@ javaPluginError jfw_plugin_getJavaInfoByPath( sal_Int32 nSizeExcludeList, JavaInfo ** ppInfo); + + +/** obtains information for a JRE referenced by the JAVA_HOME environment variable. + +

If the JAVA_HOME environment variable is set and points to a JRE whoose vendor + matches the requirements given by vecVendorInfos (i.e. it has a vendor that is + given in vecVendorInfos and the version requirements for the vendor are met), + then this function shall return a JavaInfo object for this JRE.

+ + @param vecVendorInfos + [in] vector specifying the vendor and version requirements that the JRE must fulfill. + The vector contains pairs of vendors and the respective version requirements + for those vendors. The JRE must support the requirements of one given pair in the + vector (i.e. it must be of one of the vendors and meet the version requirements + - minVersion, maxVersion, excludeVersions - for that specific vendor). + @param ppInfo + [out] if the JAVA_HOME environment variable is set and points to a suitable + JRE, then then ppInfo contains + on return a pointer to its JavaInfo object. + + @return + JFW_PLUGIN_E_NONE the function ran successfully.
+ JFW_PLUGIN_E_INVALID_ARG an argument was not valid, for example + ppInfo is an invalid pointer. + JFW_PLUGIN_E_NO_JRE no suitable JRE could be detected at the given location. However, that + does not mean necessarily that there is no JRE. There could be a JRE but it has + a vendor which is not supported by this API implementation or it does not + meet the version requirements. + */ +javaPluginError jfw_plugin_getJavaInfoFromJavaHome( + std::vector> const& vecVendorInfos, + JavaInfo ** ppInfo); + + +/** obtains information about installations of Java Runtime Environments (JREs) + whose executable is in the PATH. + +

The function gathers information about available JREs which are on the PATH + (PATH environment variable) and meet the vendor and version requirements given by + vecVendorInfos (i.e. they have a vendor that is given in + vecVendorInfos and the version requirements for the vendor are met). +

+

+ The JavaInfo structures returned in vecJavaInfosFromPath should be ordered + according to their occurrence in the PATH. The one that is the first one on the PATH + is also the first element in the vector.

+

+ The function allocates memory for all the JavaInfo objects returned + in vecJavaInfosFromPath. The caller must free each JavaInfo object by calling + jfw_freeJavaInfo (#include "jvmfwk/framework.h"). +

+ @param vecVendorInfos + [in] vector specifying the vendor and version requirements that the JRE must fulfill. + The vector contains pairs of vendors and the respective version requirements + for those vendors. The JRE must support the requirements of one given pair in the + vector (i.e. it must be of one of the vendors and meet the version requirements + - minVersion, maxVersion, excludeVersions - for that specific vendor). + @param vecJavaInfosFromPath + [out] if the function runs successfully then vecJavaInfosFromPath + contains on return a vector of pointers to JavaInfo objects. + On return of this function, vecJavaInfosFromPath references + a newly created vector rather than the same vector as before with + the JavaInfo objects inserted into the existing vector. + + @return + JFW_PLUGIN_E_NONE the function ran successfully and at least one JRE + that meets the requirements was found.
+ JFW_PLUGIN_E_NO_JRE no JavaInfo that meets the version criteria was found + when inspecting the PATH + */ + +javaPluginError jfw_plugin_getJavaInfosFromPath( + std::vector> const& vecVendorInfos, + std::vector & vecJavaInfosFromPath); + /** starts a Java Virtual Machine.

The caller should provide all essential JavaVMOptions, such as the diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx index d0dac260a354..1771bcc018a5 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx @@ -404,6 +404,105 @@ javaPluginError jfw_plugin_getJavaInfoByPath( return errorcode; } +javaPluginError jfw_plugin_getJavaInfoFromJavaHome( + std::vector> const& vecVendorInfos, + JavaInfo ** ppInfo) +{ + if (!ppInfo) + return JFW_PLUGIN_E_INVALID_ARG; + + rtl::Reference infoJavaHome = getJavaInfoFromJavaHome(); + + if (!infoJavaHome.is()) + return JFW_PLUGIN_E_NO_JRE; + + //Check if the detected JRE matches the version requirements + typedef std::vector>::const_iterator ci_pl; + for (ci_pl vendorInfo = vecVendorInfos.begin(); vendorInfo != vecVendorInfos.end(); ++vendorInfo) + { + const OUString& vendor = vendorInfo->first; + jfw::VersionInfo versionInfo = vendorInfo->second; + + if (vendor.equals(infoJavaHome->getVendor())) + { + javaPluginError errorcode = checkJavaVersionRequirements( + infoJavaHome, + versionInfo.sMinVersion, + versionInfo.sMaxVersion, + versionInfo.getExcludeVersions(), + versionInfo.getExcludeVersionSize()); + + if (errorcode == JFW_PLUGIN_E_NONE) + { + *ppInfo = createJavaInfo(infoJavaHome); + return JFW_PLUGIN_E_NONE; + } + } + } + + return JFW_PLUGIN_E_NO_JRE; +} + +javaPluginError jfw_plugin_getJavaInfosFromPath( + std::vector> const& vecVendorInfos, + std::vector & javaInfosFromPath) +{ + // find JREs from PATH + vector> vecInfosFromPath; + createJavaInfoFromPath(vecInfosFromPath); + + vector > vecVerifiedInfos; + + // copy JREs that meet version requirements to vecVerifiedInfos + typedef vector >::iterator it; + for (it i= vecInfosFromPath.begin(); i != vecInfosFromPath.end(); ++i) + { + const rtl::Reference& cur = *i; + + typedef std::vector>::const_iterator ci_pl; + for (ci_pl vendorInfo = vecVendorInfos.begin(); vendorInfo != vecVendorInfos.end(); ++vendorInfo) + { + const OUString& vendor = vendorInfo->first; + jfw::VersionInfo versionInfo = vendorInfo->second; + + if (vendor.equals(cur->getVendor())) + { + javaPluginError errorcode = checkJavaVersionRequirements( + cur, + versionInfo.sMinVersion, + versionInfo.sMaxVersion, + versionInfo.getExcludeVersions(), + versionInfo.getExcludeVersionSize()); + + if (errorcode == JFW_PLUGIN_E_NONE) + { + vecVerifiedInfos.push_back(*i); + } + } + } + } + + if (vecVerifiedInfos.empty()) + return JFW_PLUGIN_E_NO_JRE; + + // Now vecVerifiedInfos contains all those JREs which meet the version requirements + // Transfer them into the vector that is passed out. + vector infosFromPath; + + typedef vector >::const_iterator cit; + for (cit ii = vecVerifiedInfos.begin(); ii != vecVerifiedInfos.end(); ++ii) + { + infosFromPath.push_back(createJavaInfo(*ii)); + } + + javaInfosFromPath = infosFromPath; + + return JFW_PLUGIN_E_NONE; +} + + + + #if defined(WNT) // Load msvcr71.dll using an explicit full path from where it is diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.cxx b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx index a30513962888..8924a5949301 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/util.cxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx @@ -1131,7 +1131,8 @@ void createJavaInfoFromPath(vector >& vecInfos) } } -void createJavaInfoFromJavaHome(vector >& vecInfos) + +rtl::Reference getJavaInfoFromJavaHome() { // Get Java from JAVA_HOME environment @@ -1142,11 +1143,28 @@ void createJavaInfoFromJavaHome(vector >& vecInfos) char *szJavaHome= getenv("JAVA_HOME"); if(szJavaHome) { - OUString sHome(szJavaHome,strlen(szJavaHome),osl_getThreadTextEncoding()); + OUString sHome(szJavaHome, strlen(szJavaHome), osl_getThreadTextEncoding()); OUString sHomeUrl; if(File::getFileURLFromSystemPath(sHome, sHomeUrl) == File::E_None) { - getJREInfoByPath(sHomeUrl, vecInfos); + return getJREInfoByPath(sHomeUrl); + } + } + + return NULL; +} + +void createJavaInfoFromJavaHome(vector >& vecInfos) +{ + rtl::Reference aInfo = getJavaInfoFromJavaHome(); + + if (aInfo.is()) + { + vector >::const_iterator it_impl= std::find_if( + vecInfos.begin(),vecInfos.end(), InfoFindSame(aInfo->getHome())); + if(it_impl == vecInfos.end()) + { + vecInfos.push_back(aInfo); } } } diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.hxx b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx index 0f0bf04f2619..38d3175dacc5 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/util.hxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx @@ -39,6 +39,12 @@ bool getJREInfoFromBinPath( const OUString& path, std::vector > & vecInfos); inline OUString getDirFromFile(const OUString& usFilePath); void createJavaInfoFromPath(std::vector >& vecInfos); + +/* Returns a VendorBase object if JAVA_HOME environment variable points + to a JRE. + */ +rtl::Reference getJavaInfoFromJavaHome(); + void createJavaInfoFromJavaHome(std::vector > &vecInfos); void createJavaInfoDirScan(std::vector >& vecInfos); #ifdef WNT diff --git a/jvmfwk/source/framework.cxx b/jvmfwk/source/framework.cxx index d43423df5cf4..75daa77b83eb 100644 --- a/jvmfwk/source/framework.cxx +++ b/jvmfwk/source/framework.cxx @@ -366,9 +366,9 @@ javaFrameworkError SAL_CALL jfw_startVM( /** 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 uses one plug-in and if - it already finds a suitable JRE then it is done and does not need to - load another plug-in + 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 SAL_CALL jfw_findAndSelectJRE(JavaInfo **pInfo) { @@ -380,134 +380,213 @@ javaFrameworkError SAL_CALL jfw_findAndSelectJRE(JavaInfo **pInfo) return JFW_E_DIRECT_MODE; sal_uInt64 nFeatureFlags = 0; jfw::CJavaInfo aCurrentInfo; -//Determine if accessibility support is needed + //Determine if accessibility support is needed bool bSupportAccessibility = jfw::isAccessibilitySupportDesired(); nFeatureFlags = bSupportAccessibility ? JFW_FEATURE_ACCESSBRIDGE : 0L; - //Get a list of services which provide Java information + + // 'bInfoFound' indicates whether a Java installation has been found + // that supports all desired features + bool bInfoFound = false; + + // get list of vendors for Java installations jfw::VendorSettings aVendorSettings; std::vector vecVendors = - aVendorSettings.getSupportedVendors(); - //Use every vendor to get Java installations. At the first usable - //Java the loop will break - typedef std::vector::const_iterator ci_pl; - for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i) + aVendorSettings.getSupportedVendors(); + + // save vendors and respective version requirements pair-wise in a vector + std::vector> versionInfos; + typedef std::vector::const_iterator ciVendor; + for (ciVendor i = vecVendors.begin(); i != vecVendors.end(); ++i) { const OUString & vendor = *i; jfw::VersionInfo versionInfo = aVendorSettings.getVersionInformation(vendor); - //get all installations of one vendor according to minVersion, - //maxVersion and excludeVersions - sal_Int32 cInfos = 0; - JavaInfo** arInfos = NULL; - javaPluginError plerr = jfw_plugin_getAllJavaInfos( - vendor, - versionInfo.sMinVersion, - versionInfo.sMaxVersion, - versionInfo.getExcludeVersions(), - versionInfo.getExcludeVersionSize(), - & arInfos, - & cInfos); + versionInfos.push_back( + std::pair(vendor, versionInfo)); + } - if (plerr != JFW_PLUGIN_E_NONE) - continue; - //iterate over all installations to find the best which has - //all features - if (cInfos == 0) + // first inspect Java installation that the JAVA_HOME + // environment variable points to (if it is set) + JavaInfo* pHomeInfo = NULL; + if (jfw_plugin_getJavaInfoFromJavaHome(versionInfos, &pHomeInfo) + == JFW_PLUGIN_E_NONE) + { + aCurrentInfo = pHomeInfo; + + // compare features + // if the user does not require any features (nFeatureFlags = 0) + // or the Java installation provides all features, then this installation is used + if ((pHomeInfo->nFeatures & nFeatureFlags) == nFeatureFlags) { - rtl_freeMemory(arInfos); - continue; + bInfoFound = true; } - bool bInfoFound = false; - for (int ii = 0; ii < cInfos; ii++) - { - JavaInfo* pJInfo = arInfos[ii]; + jfw_freeJavaInfo(pHomeInfo); + } - //We remember the very first installation in aCurrentInfo - if (aCurrentInfo.getLocation().isEmpty()) - aCurrentInfo = pJInfo; - // compare features - // If the user does not require any features (nFeatureFlags = 0) - // then the first installation is used - if ((pJInfo->nFeatures & nFeatureFlags) == nFeatureFlags) + // if no Java installation providing all features was detected by using JAVA_HOME, + // query PATH for Java installations + if (!bInfoFound) + { + std::vector vecJavaInfosFromPath; + if (jfw_plugin_getJavaInfosFromPath(versionInfos, vecJavaInfosFromPath) + == JFW_PLUGIN_E_NONE) + { + std::vector::const_iterator it = vecJavaInfosFromPath.begin(); + while(it != vecJavaInfosFromPath.end() && !bInfoFound) { - //the just found Java implements all required features - //currently there is only accessibility!!! - aCurrentInfo = pJInfo; - bInfoFound = true; - break; + JavaInfo* pJInfo = *it; + if (pJInfo != NULL) + { + // if the current Java installation implements all required features: use it + if ((pJInfo->nFeatures & nFeatureFlags) == nFeatureFlags) + { + aCurrentInfo = pJInfo; + bInfoFound = true; + } + else if ((JavaInfo*) aCurrentInfo == NULL) + { + // current Java installation does not provide all features + // but no Java installation has been detected before + // -> remember the current one until one is found + // that provides all features + aCurrentInfo = pJInfo; + } + + jfw_freeJavaInfo(pJInfo); + } + ++it; } } - //The array returned by jfw_plugin_getAllJavaInfos must be freed as well as - //its contents - for (int j = 0; j < cInfos; j++) - jfw_freeJavaInfo(arInfos[j]); - rtl_freeMemory(arInfos); - - if (bInfoFound == true) - break; - //All Java installations found by the current plug-in lib - //do not provide the required features. Try the next plug-in } - if ((JavaInfo*) aCurrentInfo == NULL) - {//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 & vecJRELocations = - settings.getJRELocations(); - //use every plug-in to determine the JavaInfo objects - bool bInfoFound = false; + + + // if no suitable Java installation has been found yet: + // first iterate over all vendors to find a suitable Java installation, + // then try paths that have been added manually + if (!bInfoFound) + { + //Use every vendor to get Java installations. At the first usable + //Java the loop will break + typedef std::vector::const_iterator ci_pl; for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i) { const OUString & vendor = *i; jfw::VersionInfo versionInfo = aVendorSettings.getVersionInformation(vendor); - typedef std::vector::const_iterator citLoc; - for (citLoc it = vecJRELocations.begin(); - it != vecJRELocations.end(); ++it) + //get all installations of one vendor according to minVersion, + //maxVersion and excludeVersions + sal_Int32 cInfos = 0; + JavaInfo** arInfos = NULL; + javaPluginError plerr = jfw_plugin_getAllJavaInfos( + vendor, + versionInfo.sMinVersion, + versionInfo.sMaxVersion, + versionInfo.getExcludeVersions(), + versionInfo.getExcludeVersionSize(), + & arInfos, + & cInfos); + + if (plerr != JFW_PLUGIN_E_NONE) + continue; + //iterate over all installations to find the best which has + //all features + if (cInfos == 0) { - jfw::CJavaInfo aInfo; - javaPluginError err = jfw_plugin_getJavaInfoByPath( - *it, - vendor, - versionInfo.sMinVersion, - versionInfo.sMaxVersion, - versionInfo.getExcludeVersions(), - versionInfo.getExcludeVersionSize(), - & aInfo.pInfo); - if (err == JFW_PLUGIN_E_NO_JRE) - continue; - if (err == JFW_PLUGIN_E_FAILED_VERSION) - continue; - else if (err !=JFW_PLUGIN_E_NONE) - return JFW_E_ERROR; - - if (aInfo) + rtl_freeMemory(arInfos); + continue; + } + for (int ii = 0; ii < cInfos; ii++) + { + JavaInfo* pJInfo = arInfos[ii]; + + //We remember the first installation in aCurrentInfo + // if no JavaInfo has been found before + if (aCurrentInfo.getLocation().isEmpty()) + aCurrentInfo = pJInfo; + // compare features + // If the user does not require any features (nFeatureFlags = 0) + // then the first installation is used + if ((pJInfo->nFeatures & nFeatureFlags) == nFeatureFlags) { - //We remember the very first installation in aCurrentInfo - if (aCurrentInfo.getLocation().isEmpty()) - aCurrentInfo = aInfo; - // compare features - // If the user does not require any features (nFeatureFlags = 0) - // then the first installation is used - if ((aInfo.getFeatures() & nFeatureFlags) == nFeatureFlags) - { - //the just found Java implements all required features - //currently there is only accessibility!!! - aCurrentInfo = aInfo; - bInfoFound = true; - break; - } + //the just found Java implements all required features + //currently there is only accessibility!!! + aCurrentInfo = pJInfo; + bInfoFound = true; + break; } - }//end iterate over paths + } + //The array returned by jfw_plugin_getAllJavaInfos must be freed as well as + //its contents + for (int j = 0; j < cInfos; j++) + jfw_freeJavaInfo(arInfos[j]); + rtl_freeMemory(arInfos); + if (bInfoFound == true) break; - }// end iterate plug-ins + //All Java installations found by the current plug-in lib + //do not provide the required features. Try the next plug-in + } + if ((JavaInfo*) aCurrentInfo == NULL) + {//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 & vecJRELocations = + settings.getJRELocations(); + //use every plug-in to determine the JavaInfo objects + for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i) + { + const OUString & vendor = *i; + jfw::VersionInfo versionInfo = + aVendorSettings.getVersionInformation(vendor); + + typedef std::vector::const_iterator citLoc; + for (citLoc it = vecJRELocations.begin(); + it != vecJRELocations.end(); ++it) + { + jfw::CJavaInfo aInfo; + javaPluginError err = jfw_plugin_getJavaInfoByPath( + *it, + vendor, + versionInfo.sMinVersion, + versionInfo.sMaxVersion, + versionInfo.getExcludeVersions(), + versionInfo.getExcludeVersionSize(), + & aInfo.pInfo); + if (err == JFW_PLUGIN_E_NO_JRE) + continue; + if (err == JFW_PLUGIN_E_FAILED_VERSION) + continue; + else if (err !=JFW_PLUGIN_E_NONE) + return JFW_E_ERROR; + + if (aInfo) + { + //We remember the very first installation in aCurrentInfo + if (aCurrentInfo.getLocation().isEmpty()) + aCurrentInfo = aInfo; + // compare features + // If the user does not require any features (nFeatureFlags = 0) + // then the first installation is used + if ((aInfo.getFeatures() & nFeatureFlags) == nFeatureFlags) + { + //the just found Java implements all required features + //currently there is only accessibility!!! + aCurrentInfo = aInfo; + bInfoFound = true; + break; + } + } + }//end iterate over paths + if (bInfoFound == true) + break; + }// end iterate plug-ins + } } if ((JavaInfo*) aCurrentInfo) { -- cgit