]
Chris Pheby commented on JBTM-2189:
-----------------------------------
If you would prefer a patch or pull request, please advise and I will prepare it in the
appropriate form.
Bootstrapping from Complex Classloader (OneJar)
-----------------------------------------------
Key: JBTM-2189
URL:
https://issues.jboss.org/browse/JBTM-2189
Project: JBoss Transaction Manager
Issue Type: Feature Request
Security Level: Public(Everyone can see)
Components: Common
Affects Versions: 5.0.1
Environment: JDK 8, OneJar 0.97
Reporter: Chris Pheby
Assignee: Tom Jenkinson
I am using Narayana within a JavaSE application. The application is compiled into a
single Jar. When executing, Narayana fails to bootstrap properly.
The first problem is within com.arjuna.common.util.ConfigurationInfo.
Lines 111-115 aim to load the MANIFEST file from the classpath:
String pathToManifest = basePath+"/META-INF/MANIFEST.MF";
InputStream is = null;
try {
is = new URL(pathToManifest).openStream();
I replaced this with:
InputStream is = null;
// BEGIN - WORKAROUND FOR ONE-JAR
try {
String targetPrefix = pathToThisClass.substring(0, pathToThisClass.length() -
"/com/arjuna/common/util/ConfigurationInfo.class".length());
Enumeration<URL> resources =
ConfigurationInfo.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
URL next = resources.nextElement();
if (next.toString().startsWith(targetPrefix)) {
is = next.openStream();
break;
}
}
// END - WORKAROUND FOR ONE-JAR
This should work for all environments.
Changes are also required in
com.arjuna.common.util.propertyservice.AbstractPropertiesFactory to attempt loading from
classpath as well as file system:
The last line of initDefaultProperties (195) needed changing to:
defaultProperties = getPropertiesFromClasspath(propertyFileName,
PropertiesFactoryStax.class.getClassLoader());
if (defaultProperties == null) {
defaultProperties = getPropertiesFromFile(propertyFileName,
PropertiesFactoryStax.class.getClassLoader());
}
}
and the following methods added / replaced:
/**
* Returns the config properties read from a specified relative location on the
classpath.
*
* @param propertyFileName the file name relative to the classpath root.
* @return the Properties loaded from the specified source.
*/
public Properties getPropertiesFromClasspath(String propertyFileName, ClassLoader
classLoader) {
Properties properties = null;
try {
Enumeration<URL> resources =
ConfigurationInfo.class.getClassLoader().getResources(propertyFileName);
while (resources.hasMoreElements()) {
URL next = resources.nextElement();
properties = loadFromStream(next.openStream());
return properties;
}
} catch(Exception e) {
return null;
}
return properties;
}
/**
* Returns the config properties read from a specified location.
*
* @param propertyFileName the file name. If relative, this is located using the
FileLocator algorithm.
* @return the Properties loaded from the specified source.
*/
public Properties getPropertiesFromFile(String propertyFileName, ClassLoader
classLoader) {
String propertiesSourceUri = null;
try
{
// This is the point where the search path is applied - user.dir (pwd),
user.home, java.home, classpath
propertiesSourceUri =
com.arjuna.common.util.propertyservice.FileLocator.locateFile(propertyFileName,
classLoader);
}
catch(FileNotFoundException fileNotFoundException)
{
// try falling back to a default file built into the .jar
// Note the default- prefix on the name, to avoid finding it from the .jar at
the previous stage
// in cases where the .jar comes before the etc dir on the classpath.
URL url =
AbstractPropertiesFactory.class.getResource("/default-"+propertyFileName);
if(url == null) {
throw new RuntimeException("missing property file
"+propertyFileName);
} else {
propertiesSourceUri = url.toString();
}
}
catch (IOException e)
{
throw new RuntimeException("invalid property file
"+propertiesSourceUri, e);
}
Properties properties = null;
try {
properties = loadFromFile(propertiesSourceUri);
properties = applySystemProperties(properties);
} catch(Exception e) {
throw new RuntimeException("unable to load properties from
"+propertiesSourceUri, e);
}
return properties;
}
private Properties loadFromStream(InputStream inputStream) throws IOException {
Properties inputProperties = new Properties();
Properties outputProperties = new Properties();
try {
loadFromXML(inputProperties,inputStream);
} finally {
inputStream.close();
}
Enumeration namesEnumeration = inputProperties.propertyNames();
while(namesEnumeration.hasMoreElements()) {
String propertyName = (String)namesEnumeration.nextElement();
String propertyValue = inputProperties.getProperty(propertyName);
propertyValue = propertyValue.trim();
// perform JBossAS style property substitutions. JBTM-369
propertyValue = StringPropertyReplacer.replaceProperties(propertyValue);
outputProperties.setProperty(propertyName, propertyValue);
}
return outputProperties;
}