Author: adrianc
Date: Wed Apr 29 13:52:27 2015
New Revision: 1676746
URL: http://svn.apache.org/r1676746
Log:
Fixed some bugs in startup code
(https://issues.apache.org/jira/browse/OFBIZ-6268):
1. Class path loading was ignoring component settings, so class paths for
disabled components were being loaded.
2. Configuration files were parsed twice.
3. Potential problem with unloading a loader that failed loading.
I was unable to test Cobertura because the necessary class
(org.ofbiz.base.config.CoberturaInstrumenter) isn't being compiled for some
reason.
Added:
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/NativeLibClassLoader.java
Modified:
ofbiz/trunk/framework/base/src/org/ofbiz/base/container/ComponentContainer.java
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/both.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/load-data.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/pos.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/rmi.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/start.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/test.properties
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/testlist.properties
Modified:
ofbiz/trunk/framework/base/src/org/ofbiz/base/container/ComponentContainer.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/container/ComponentContainer.java?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
---
ofbiz/trunk/framework/base/src/org/ofbiz/base/container/ComponentContainer.java
(original)
+++
ofbiz/trunk/framework/base/src/org/ofbiz/base/container/ComponentContainer.java
Wed Apr 29 13:52:27 2015
@@ -29,6 +29,8 @@ import org.ofbiz.base.component.AlreadyL
import org.ofbiz.base.component.ComponentConfig;
import org.ofbiz.base.component.ComponentException;
import org.ofbiz.base.component.ComponentLoaderConfig;
+import org.ofbiz.base.start.Classpath;
+import org.ofbiz.base.start.NativeLibClassLoader;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.FileUtil;
import org.ofbiz.base.util.UtilValidate;
@@ -94,21 +96,21 @@ public class ComponentContainer implemen
String parentPath;
try {
parentPath =
FileUtil.getFile(System.getProperty("ofbiz.home")).getCanonicalFile().toString().replaceAll("\\\\",
"/");
+ // load each component
+ if (components != null) {
+ for (ComponentLoaderConfig.ComponentDef def: components) {
+ loadComponentFromConfig(parentPath, def);
+ }
+ }
} catch (MalformedURLException e) {
throw new ComponentException(e.getMessage(), e);
} catch (IOException e) {
throw new ComponentException(e.getMessage(), e);
}
- // load each component
- if (components != null) {
- for (ComponentLoaderConfig.ComponentDef def: components) {
- this.loadComponentFromConfig(parentPath, def);
- }
- }
Debug.logInfo("All components loaded", module);
}
- private void loadComponentFromConfig(String parentPath,
ComponentLoaderConfig.ComponentDef def) {
+ private void loadComponentFromConfig(String parentPath,
ComponentLoaderConfig.ComponentDef def) throws IOException {
String location;
if (def.location.startsWith("/")) {
location = def.location;
@@ -135,7 +137,7 @@ public class ComponentContainer implemen
}
}
- private void loadComponentDirectory(String directoryName) {
+ private void loadComponentDirectory(String directoryName) throws
IOException {
Debug.logInfo("Auto-Loading component directory : [" + directoryName +
"]", module);
File parentPath = FileUtil.getFile(directoryName);
if (!parentPath.exists() || !parentPath.isDirectory()) {
@@ -190,13 +192,61 @@ public class ComponentContainer implemen
}
}
- private void loadComponent(ComponentConfig config) {
+ private void loadComponent(ComponentConfig config) throws IOException {
// make sure the component is enabled
if (!config.enabled()) {
- Debug.logInfo("Not Loaded component : [" +
config.getComponentName() + "] (disabled)", module);
+ Debug.logInfo("Not loading component [" +
config.getComponentName() + "] because it is disabled", module);
return;
}
- Debug.logInfo("Loaded component : [" + config.getComponentName() +
"]", module);
+ List<ComponentConfig.ClasspathInfo> classpathInfos =
config.getClasspathInfos();
+ String configRoot = config.getRootLocation();
+ configRoot = configRoot.replace('\\', '/');
+ // set the root to have a trailing slash
+ if (!configRoot.endsWith("/")) {
+ configRoot = configRoot + "/";
+ }
+ if (classpathInfos != null) {
+ Classpath classPath = new Classpath();
+ // TODO: If any components change the class loader, then this will
need to be changed.
+ NativeLibClassLoader classloader = (NativeLibClassLoader)
Thread.currentThread().getContextClassLoader();
+ for (ComponentConfig.ClasspathInfo cp: classpathInfos) {
+ String location = cp.location.replace('\\', '/');
+ // set the location to not have a leading slash
+ if (location.startsWith("/")) {
+ location = location.substring(1);
+ }
+ if (!"jar".equals(cp.type) && !"dir".equals(cp.type)) {
+ Debug.logError("Classpath type '" + cp.type + "' is not
supported; '" + location + "' not loaded", module);
+ continue;
+ }
+ String dirLoc = location;
+ if (dirLoc.endsWith("/*")) {
+ // strip off the slash splat
+ dirLoc = location.substring(0, location.length() - 2);
+ }
+ File path = FileUtil.getFile(configRoot + dirLoc);
+ if (path.exists()) {
+ if (path.isDirectory()) {
+ if ("dir".equals(cp.type)) {
+ classPath.addComponent(configRoot + location);
+ }
+ classPath.addFilesFromPath(path);
+ } else {
+ // add a single file
+ classPath.addComponent(configRoot + location);
+ }
+ } else {
+ Debug.logWarning("Location '" + configRoot + dirLoc + "'
does not exist", module);
+ }
+ }
+ for (URL url : classPath.getUrls()) {
+ classloader.addURL(url);
+ }
+ for (File folder : classPath.getNativeFolders()) {
+ classloader.addNativeClassPath(folder);
+ }
+ }
+ Debug.logInfo("Loaded component : [" + config.getComponentName() +
"]", module);
}
/**
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java Wed Apr
29 13:52:27 2015
@@ -25,147 +25,211 @@ import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
- * Class to handle CLASSPATH construction
+ * A class path accumulator.
+ * <p>You can build a class path by repeatedly calling the addXxx methods,
+ * then use the getXxx methods to get the accumulated class path.</p>
*/
public class Classpath {
- private List<File> _elements = new ArrayList<File>();
+ private static final String nativeLibExt =
System.mapLibraryName("someLib").replace("someLib", "").toLowerCase();
+ private List<File> elements = new ArrayList<File>();
+ private final List<File> nativeFolders = new ArrayList<File>();
- public Classpath() {}
+ /**
+ * Default constructor.
+ */
+ public Classpath() {
+ }
- public Classpath(String initial) {
- addClasspath(initial);
+ /**
+ * Adds a class path string. The string may include multiple paths
separated by
+ * a path separator.
+ *
+ * @param path
+ * @return <code>true</code> if any path elements were added
+ * @throws IOException if there was a problem parsing the class path
+ * @throws IllegalArgumentException if <code>path</code> is null or empty
+ */
+ public boolean addClassPath(String path) throws IOException {
+ if (path == null || path.isEmpty()) {
+ throw new IllegalArgumentException("path cannot be null or empty");
+ }
+ boolean added = false;
+ StringTokenizer t = new StringTokenizer(path, File.pathSeparator);
+ while (t.hasMoreTokens()) {
+ added |= addComponent(t.nextToken());
+ }
+ return added;
}
- public boolean addComponent(String component) {
- if ((component != null) && (component.length() > 0)) {
- return addComponent(new File(component));
+ /**
+ * Adds a class path component. The component may be a directory or a file.
+ * If <code>component</code> does not exist, the method does nothing.
+ *
+ * @param component The class path component to add
+ * @return <code>true</code> if the component was added
+ * @throws IOException if there was a problem parsing the component
+ * @throws IllegalArgumentException if <code>component</code> is null
+ */
+ public boolean addComponent(File component) throws IOException {
+ if (component == null) {
+ throw new IllegalArgumentException("component cannot be null");
+ }
+ if (component.exists()) {
+ File key = component.getCanonicalFile();
+ synchronized (elements) {
+ if (!elements.contains(key)) {
+ elements.add(key);
+ return true;
+ }
+ }
+ } else {
+ System.out.println("Warning : Module classpath component '" +
component + "' is not valid and will be ignored...");
}
return false;
}
- public boolean addComponent(File component) {
- if (component != null) {
- try {
- if (component.exists()) {
- File key = component.getCanonicalFile();
- if (!_elements.contains(key)) {
- _elements.add(key);
- return true;
+ /**
+ * Adds a class path component. The component may be a directory or a file.
+ * If <code>component</code> does not exist, the method does nothing.
+ *
+ * @param component The class path component to add
+ * @return <code>true</code> if the component was added
+ * @throws IOException if there was a problem parsing the component
+ * @throws IllegalArgumentException if <code>component</code> is null or
empty
+ */
+ public boolean addComponent(String component) throws IOException {
+ if (component == null || component.isEmpty()) {
+ throw new IllegalArgumentException("component cannot be null or
empty");
+ }
+ return addComponent(new File(component));
+ }
+
+ /**
+ * Scans a directory and adds all files ending with ".jar" or ".zip" to
+ * the class path.
+ * If <code>path</code> is not a directory, the method does nothing.
+ *
+ * @param path the directory to scan
+ * @throws IOException if there was a problem processing the directory
+ * @throws IllegalArgumentException if <code>path</code> is null
+ */
+ public void addFilesFromPath(File path) throws IOException {
+ if (path == null) {
+ throw new IllegalArgumentException("path cannot be null");
+ }
+ if (path.isDirectory() && path.exists()) {
+ // load all .jar, .zip files and native libs in this directory
+ boolean containsNativeLibs = false;
+ for (File file : path.listFiles()) {
+ String fileName = file.getName().toLowerCase();
+ if (fileName.endsWith(".jar") || fileName.endsWith(".zip")) {
+ File key = file.getCanonicalFile();
+ synchronized (elements) {
+ if (!elements.contains(key)) {
+ elements.add(key);
+ }
+ }
+ } else if (fileName.endsWith(nativeLibExt)) {
+ containsNativeLibs = true;
+ }
+ }
+ if (containsNativeLibs) {
+ File key = path.getCanonicalFile();
+ synchronized (nativeFolders) {
+ if (!nativeFolders.contains(key)) {
+ nativeFolders.add(key);
}
- } else {
- // In most cases, this warning can be ignored. The
JRE-supplied class path may include non-existent paths.
- System.out.println("Warning : Module classpath component
'" + component + "' is not valid and will be ignored...");
}
- } catch (IOException e) {}
+ }
+ } else {
+ System.out.println("Warning : Module classpath component '" + path
+ "' is not valid and will be ignored...");
}
- return false;
}
- public boolean addClasspath(String s) {
- boolean added = false;
- if (s != null) {
- StringTokenizer t = new StringTokenizer(s, File.pathSeparator);
- while (t.hasMoreTokens()) {
- added |= addComponent(t.nextToken());
+ /**
+ * Adds a directory that contains native libraries.
+ * If <code>path</code> does not exist, the method does nothing.
+ *
+ * @param path
+ * @return
+ * @throws IOException
+ * @throws IllegalArgumentException if <code>path</code> is null
+ */
+ public boolean addNativeClassPath(File path) throws IOException {
+ if (path == null) {
+ throw new IllegalArgumentException("path cannot be null");
+ }
+ if (path.exists()) {
+ File key = path.getCanonicalFile();
+ synchronized (nativeFolders) {
+ if (!nativeFolders.contains(key)) {
+ nativeFolders.add(key);
+ return true;
+ }
}
+ } else {
+ System.out.println("Warning : Module classpath component '" + path
+ "' is not valid and will be ignored...");
}
- return added;
+ return false;
}
-
private void appendPath(StringBuilder cp, String path) {
if (path.indexOf(' ') >= 0) {
cp.append('\"');
cp.append(path);
cp.append('"');
- }
- else {
+ } else {
cp.append(path);
}
- }
-
- public void instrument(String instrumenterFile, String
instrumenterClassName) {
- _elements = InstrumenterWorker.instrument(_elements, instrumenterFile,
instrumenterClassName);
}
- @Override
- public String toString() {
- StringBuilder cp = new StringBuilder(1024);
- int cnt = _elements.size();
- if (cnt >= 1) {
- cp.append(_elements.get(0).getPath());
- }
- for (int i = 1; i < cnt; i++) {
- cp.append(File.pathSeparatorChar);
- appendPath(cp, _elements.get(i).getPath());
+ /**
+ * Returns a list of folders containing native libraries.
+ *
+ * @return A list of folders containing native libraries
+ */
+ public List<File> getNativeFolders() {
+ synchronized (nativeFolders) {
+ return new ArrayList<File>(nativeFolders);
}
- return cp.toString();
}
- public URL[] getUrls() {
- int cnt = _elements.size();
- URL[] urls = new URL[cnt];
- for (int i = 0; i < cnt; i++) {
- try {
- urls[i] = _elements.get(i).toURI().toURL();
- } catch (MalformedURLException e) {
- // note: this is printing right to the console because at this
point we don't have the rest of the system up, not even the logging stuff
- System.out.println("Error adding classpath entry: " +
e.toString());
- e.printStackTrace();
+ /**
+ * Returns a list of class path component URLs.
+ *
+ * @return A list of class path component URLs
+ * @throws MalformedURLException
+ */
+ public URL[] getUrls() throws MalformedURLException {
+ synchronized (elements) {
+ int cnt = elements.size();
+ URL[] urls = new URL[cnt];
+ for (int i = 0; i < cnt; i++) {
+ urls[i] = elements.get(i).toURI().toURL();
}
+ return urls;
}
- return urls;
- }
-
- public ClassLoader getClassLoader() {
- ClassLoader parent = Thread.currentThread().getContextClassLoader();
- if (parent == null) {
- parent = Classpath.class.getClassLoader();
- }
- if (parent == null) {
- parent = ClassLoader.getSystemClassLoader();
- }
- return getClassLoader(parent);
}
- public ClassLoader getClassLoader(ClassLoader parent) {
- return new NativeLibClassLoader(getUrls(), parent);
- }
-
- public List<File> getElements() {
- return _elements;
- }
-
- /*
- * Native library class loader. This class is necessary because the
- * bootstrap ClassLoader caches the native library path - so any
- * changes to the library path are ignored (changes that might have
- * been made by loading OFBiz components).
- */
- private class NativeLibClassLoader extends URLClassLoader {
-
- private NativeLibClassLoader(URL[] urls, ClassLoader parent) {
- super(urls, parent);
- }
-
- @Override
- protected String findLibrary(String libname) {
- String[] libPaths =
System.getProperty("java.library.path").split(File.pathSeparator);
- String libFileName = System.mapLibraryName(libname);
- for (String path : libPaths) {
- File libFile = new File(path, libFileName);
- if (libFile.exists()) {
- return libFile.getAbsolutePath();
- }
+ @Override
+ public String toString() {
+ StringBuilder cp = new StringBuilder(1024);
+ synchronized (elements) {
+ int cnt = elements.size();
+ if (cnt >= 1) {
+ cp.append(elements.get(0).getPath());
+ }
+ for (int i = 1; i < cnt; i++) {
+ cp.append(File.pathSeparatorChar);
+ appendPath(cp, elements.get(i).getPath());
}
- return null;
}
+ return cp.toString();
}
}
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java Wed Apr 29
13:52:27 2015
@@ -18,19 +18,7 @@
*******************************************************************************/
package org.ofbiz.base.start;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
import java.io.File;
-import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -47,17 +35,6 @@ import java.util.TimeZone;
public class Config {
- private static final FileFilter componentLoadFilter = new FileFilter() {
- public boolean accept(File pathname) {
- return "component-load.xml".equals(pathname.getName());
- }
- };
- private static final FileFilter folderFilter = new FileFilter() {
- public boolean accept(File pathname) {
- return pathname.isDirectory();
- }
- };
-
public final InetAddress adminAddress;
public final String adminKey;
public final int adminPort;
@@ -72,6 +49,8 @@ public class Config {
public final String splashLogo;
public final boolean useShutdownHook;
public final Integer portOffset;
+ public final String classpathAddComponent;
+ public final String classpathAddFilesFromPath;
Config(String[] args) throws IOException {
String firstArg = args.length > 0 ? args[0] : "";
@@ -102,7 +81,9 @@ public class Config {
ofbizHome = ofbizHomeTmp;
System.setProperty("ofbiz.home", ofbizHome);
System.out.println("Set OFBIZ_HOME to - " + ofbizHome);
-
+ // Class paths
+ classpathAddComponent =
props.getProperty("ofbiz.start.classpath.addComponent");
+ classpathAddFilesFromPath =
props.getProperty("ofbiz.start.classpath.addFilesFromPath");
// log directory
logDir = getOfbizHomeProp(props, "ofbiz.log.dir", "runtime/logs");
@@ -298,109 +279,4 @@ public class Config {
}
return props;
}
-
- void initClasspath(Classpath classPath, Classpath libraryPath) throws
Exception {
- // add OFBIZ_HOME to class path
- classPath.addClasspath(this.ofbizHome);
- File home = new File(this.ofbizHome);
- collectClasspathEntries(new File(home, "framework"), classPath,
libraryPath);
- collectClasspathEntries(new File(home, "applications"), classPath,
libraryPath);
- collectClasspathEntries(new File(home, "specialpurpose"), classPath,
libraryPath);
- collectClasspathEntries(new File(home, "hot-deploy"), classPath,
libraryPath);
- System.setProperty("java.library.path", libraryPath.toString());
- classPath.instrument(this.instrumenterFile,
this.instrumenterClassName);
- }
-
- private void collectClasspathEntries(File folder, Classpath classpath,
Classpath libraryPath) throws ParserConfigurationException, IOException,
SAXException {
- if (!folder.exists() && !folder.isDirectory()) {
- return;
- }
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- File[] componentLoadFiles;
- List<File> ofbizComponents = new ArrayList<File>();
- componentLoadFiles = folder.listFiles(componentLoadFilter);
- if (componentLoadFiles != null && componentLoadFiles.length == 1) {
- File componentLoadFile = componentLoadFiles[0];
- // parse and get folder names to be processed
- Document document = builder.parse(componentLoadFile);
- Element element = document.getDocumentElement();
- NodeList loadComponents =
element.getElementsByTagName("load-component");
- for (int i = 0; i < loadComponents.getLength(); i++) {
- Node loadComponent = loadComponents.item(i);
- NamedNodeMap attributes = loadComponent.getAttributes();
- Node componentLocation =
attributes.getNamedItem("component-location");
- if (componentLocation == null) {
- continue;
- }
- ofbizComponents.add(new File(new File(folder,
componentLocation.getNodeValue()), "ofbiz-component.xml"));
- }
- } else {
- File[] componentFolders = folder.listFiles(folderFilter);
- for (File componentFolder: componentFolders) {
- File ofbizComponent = new File(componentFolder,
"ofbiz-component.xml");
- if (ofbizComponent.exists()) {
- ofbizComponents.add(ofbizComponent);
- }
- }
- }
- String nativeLibExt =
System.mapLibraryName("someLib").replace("someLib", "").toLowerCase();
- for (File ofbizComponent: ofbizComponents) {
- Document document = builder.parse(ofbizComponent);
- Element element = document.getDocumentElement();
- if (element.hasAttribute("enabled")) {
- if ("false".equals(element.getAttribute("enabled"))) {
- continue;
- }
- }
- NodeList classpathEntries =
element.getElementsByTagName("classpath");
- for (int i = 0; i < classpathEntries.getLength(); i++) {
- Node classpathEntry = classpathEntries.item(i);
- NamedNodeMap attributes = classpathEntry.getAttributes();
- Node type = attributes.getNamedItem("type");
- if (type == null || !("jar".equals(type.getNodeValue()) ||
"dir".equals(type.getNodeValue()))) {
- continue;
- }
- Node location = attributes.getNamedItem("location");
- String locationValue = location.getNodeValue();
- locationValue = locationValue.replace('\\', '/');
- // set the location to not have a leading slash
- if (locationValue.startsWith("/")) {
- locationValue = locationValue.substring(1);
- }
- String dirLoc = locationValue;
- if (dirLoc.endsWith("/*")) {
- // strip off the slash splat
- dirLoc = locationValue.substring(0, locationValue.length()
- 2);
- }
-
- String fileNameSeparator = ("\\".equals(File.separator) ? "\\"
+ File.separator : File.separator);
- dirLoc = dirLoc.replaceAll("/+|\\\\+", fileNameSeparator);
- File path = new File(ofbizComponent.getParent(), dirLoc);
- if (path.exists()) {
- if (path.isDirectory()) {
- if ("dir".equals(type.getNodeValue())) {
- classpath.addComponent(path.toString());
- }
- // load all .jar, .zip files and native libs in this
directory
- boolean containsNativeLibs = false;
- for (File file: path.listFiles()) {
- String fileName = file.getName().toLowerCase();
- if (fileName.endsWith(".jar") ||
fileName.endsWith(".zip")) {
- classpath.addComponent(file);
- } else if (fileName.endsWith(nativeLibExt)) {
- containsNativeLibs = true;
- }
- }
- if (containsNativeLibs) {
- libraryPath.addComponent(path);
- }
- } else {
- classpath.addComponent(path.toString());
- }
- }
- }
- }
- }
-
}
Added:
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java?rev=1676746&view=auto
==============================================================================
---
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
(added)
+++
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
Wed Apr 29 13:52:27 2015
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+
*******************************************************************************/
+
+// NOTE: Portions Originally Copyright 2002 Mort Bay Consulting (Australia)
Pty. Ltd. (this was taken from a code base released under the Apache License,
though no header was on this file)
+
+package org.ofbiz.base.start;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+/*
+ * Instrumenting class loader.
+ */
+public final class InstrumentingClassLoader extends NativeLibClassLoader {
+
+ private static final void copy(InputStream in, OutputStream out) throws
IOException {
+ byte[] buf = new byte[4096];
+ int r;
+ while ((r = in.read(buf)) != -1) {
+ out.write(buf, 0, r);
+ }
+ }
+
+ private final Instrumenter instrumenter;
+
+ InstrumentingClassLoader(URL[] urls, ClassLoader parent, String
instrumenterFileName, String instrumenterClassName)
+ throws Exception {
+ super(new URL[0], parent);
+ URLClassLoader tmpLoader = new URLClassLoader(urls,
InstrumenterWorker.class.getClassLoader());
+ try {
+ instrumenter = (Instrumenter)
tmpLoader.loadClass(instrumenterClassName).newInstance();
+ } finally {
+ tmpLoader.close();
+ }
+ File instrumenterFile = new File(instrumenterFileName);
+ instrumenterFile.delete();
+ instrumenter.open(instrumenterFile, true);
+ System.out.println("Instrumenter file opened");
+ for (URL url : urls) {
+ addURL(url);
+ }
+ }
+
+ @Override
+ public void addURL(URL url) {
+ File file;
+ try {
+ file = new File(url.toURI());
+ } catch (URISyntaxException e) {
+ file = new File(url.getPath());
+ }
+ String path = file.getPath();
+ if (path.matches(".*/ofbiz[^/]*\\.(jar|zip)")) {
+ String prefix = path.substring(0, path.length() - 4);
+ int slash = prefix.lastIndexOf("/");
+ if (slash != -1)
+ prefix = prefix.substring(slash + 1);
+ prefix += "-";
+ File zipTmp = null;
+ try {
+ zipTmp = File.createTempFile("instrumented-" + prefix,
path.substring(path.length() - 4));
+ zipTmp.deleteOnExit();
+ ZipInputStream zin = new ZipInputStream(new
FileInputStream(file));
+ ZipOutputStream zout = new ZipOutputStream(new
FileOutputStream(zipTmp));
+ ZipEntry entry;
+ while ((entry = zin.getNextEntry()) != null) {
+ InputStream in;
+ long size;
+ if (entry.getName().endsWith(".class")) {
+ ByteArrayOutputStream baos = new
ByteArrayOutputStream();
+ copy(zin, baos);
+ byte[] bytes =
instrumenter.instrumentClass(baos.toByteArray());
+ size = bytes.length;
+ in = new ByteArrayInputStream(bytes);
+ } else {
+ in = zin;
+ size = entry.getSize();
+ }
+ ZipEntry newEntry = new ZipEntry(entry);
+ newEntry.setSize(size);
+ newEntry.setCompressedSize(-1);
+ zout.putNextEntry(newEntry);
+ copy(in, zout);
+ if (entry.getName().endsWith(".class")) {
+ in.close();
+ }
+ }
+ zout.close();
+ System.out.println("Instrumented file: " +
zipTmp.getCanonicalPath());
+ super.addURL(zipTmp.toURI().toURL());
+ } catch (IOException e) {
+ System.err.println("Exception thrown while instrumenting " +
file + ": ");
+ e.printStackTrace(System.err);
+ if (zipTmp != null) {
+ zipTmp.delete();
+ }
+ }
+ } else {
+ super.addURL(url);
+ }
+ }
+
+ void closeInstrumenter() throws IOException {
+ instrumenter.close();
+ }
+}
Added:
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/NativeLibClassLoader.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/NativeLibClassLoader.java?rev=1676746&view=auto
==============================================================================
---
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/NativeLibClassLoader.java
(added)
+++
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/NativeLibClassLoader.java
Wed Apr 29 13:52:27 2015
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+
*******************************************************************************/
+
+// NOTE: Portions Originally Copyright 2002 Mort Bay Consulting (Australia)
Pty. Ltd. (this was taken from a code base released under the Apache License,
though no header was on this file)
+
+package org.ofbiz.base.start;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/*
+ * Native library class loader. This class is necessary because the
+ * bootstrap ClassLoader caches the native library path - so any
+ * changes to the library path are ignored (changes that might have
+ * been made by loading OFBiz components).
+ */
+public class NativeLibClassLoader extends URLClassLoader {
+
+ private final CopyOnWriteArrayList<String> libPaths = new
CopyOnWriteArrayList<String>();
+
+ NativeLibClassLoader(URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+ }
+
+ public void addNativeClassPath(File path) throws IOException {
+ if (path != null) {
+ libPaths.addIfAbsent(path.getCanonicalPath());
+ }
+ }
+
+ public void addNativeClassPath(String path) {
+ if (path != null) {
+ StringTokenizer t = new StringTokenizer(path, File.pathSeparator);
+ while (t.hasMoreTokens()) {
+ libPaths.addIfAbsent(t.nextToken());
+ }
+ }
+ }
+
+ @Override
+ public void addURL(URL url) {
+ super.addURL(url);
+ }
+
+ @Override
+ protected String findLibrary(String libname) {
+ String libFileName = System.mapLibraryName(libname);
+ for (String path : libPaths) {
+ File libFile = new File(path, libFileName);
+ if (libFile.exists()) {
+ return libFile.getAbsolutePath();
+ }
+ }
+ return null;
+ }
+
+ public List<String> getNativeLibPaths() {
+ return new ArrayList<String>(libPaths);
+ }
+}
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java Wed Apr 29
13:52:27 2015
@@ -185,13 +185,13 @@ public final class Start {
stream = new FileInputStream(globalSystemPropsFileName);
System.getProperties().load(stream);
} catch (IOException e) {
- throw new StartupException("Couldn't load global system
props", e);
+ throw (StartupException) new StartupException("Couldn't load
global system props").initCause(e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
- throw new StartupException("Couldn't close stream", e);
+ throw (StartupException) new
StartupException("Couldn't close stream").initCause(e);
}
}
}
@@ -199,7 +199,7 @@ public final class Start {
try {
this.config = new Config(args);
} catch (IOException e) {
- throw new StartupException("Couldn't fetch config instance", e);
+ throw (StartupException) new StartupException("Couldn't not fetch
config instance").initCause(e);
}
// parse the startup arguments
if (args.length > 1) {
@@ -239,18 +239,75 @@ public final class Start {
initStartLoaders();
}
- private void initStartLoaders() throws StartupException {
+ /**
+ * Creates a new <code>NativeLibClassLoader</code> instance, and
optionally loads it
+ * with base component class paths.
+ *
+ * @param addBaseClassPaths When set to <code>true</code>, the class
loader will be
+ * initialized with the class paths needed to get StartupLoaders to work
+ * @return A new <code>NativeLibClassLoader</code> instance
+ * @throws IOException
+ */
+ private NativeLibClassLoader createClassLoader() throws IOException {
+ ClassLoader parent = Thread.currentThread().getContextClassLoader();
+ if (parent != null) {
+ System.out.println("ClassLoader: " + parent.getClass().getName());
+ }
+ if (parent instanceof NativeLibClassLoader) {
+ parent = parent.getParent();
+ }
+ if (parent == null) {
+ parent = Start.class.getClassLoader();
+ if (parent == null) {
+ parent = ClassLoader.getSystemClassLoader();
+ }
+ }
Classpath classPath = new Classpath();
- Classpath libraryPath = new
Classpath(System.getProperty("java.library.path"));
+ /*
+ * Class paths needed to get StartupLoaders to work.
+ */
+ classPath.addComponent(config.ofbizHome);
+ String ofbizHomeTmp = config.ofbizHome;
+ if (!ofbizHomeTmp.isEmpty() && !ofbizHomeTmp.endsWith("/")) {
+ ofbizHomeTmp = ofbizHomeTmp.concat("/");
+ }
+ if (config.classpathAddComponent != null) {
+ String[] components = config.classpathAddComponent.split(",");
+ for (String component : components) {
+ classPath.addComponent(ofbizHomeTmp.concat(component.trim()));
+ }
+ }
+ if (config.classpathAddFilesFromPath != null) {
+ String[] paths = config.classpathAddFilesFromPath.split(",");
+ for (String path : paths) {
+ classPath.addFilesFromPath(new
File(ofbizHomeTmp.concat(path.trim())));
+ }
+ }
+ NativeLibClassLoader classloader = new
NativeLibClassLoader(classPath.getUrls(), parent);
+ if (config.instrumenterFile != null && config.instrumenterClassName !=
null) {
+ try {
+ classloader = new
InstrumentingClassLoader(classPath.getUrls(), parent, config.instrumenterFile,
+ config.instrumenterClassName);
+ } catch (Exception e) {
+ System.out.println("Instrumenter not enabled - " + e);
+ }
+ }
+
classloader.addNativeClassPath(System.getProperty("java.library.path"));
+ for (File folder : classPath.getNativeFolders()) {
+ classloader.addNativeClassPath(folder);
+ }
+ return classloader;
+ }
+
+ private void initStartLoaders() throws StartupException {
+ NativeLibClassLoader classloader = null;
try {
- this.config.initClasspath(classPath, libraryPath);
- } catch (Exception e) {
- throw new StartupException("Couldn't initialize classpath", e);
+ classloader = createClassLoader();
+ } catch (IOException e) {
+ throw new StartupException("Couldn't create NativeLibClassLoader",
e);
}
- ClassLoader classloader = classPath.getClassLoader();
Thread.currentThread().setContextClassLoader(classloader);
synchronized (this.loaders) {
- // initialize the loaders
for (Map<String, String> loaderMap : config.loaders) {
if (this.serverState.get() == ServerState.STOPPING) {
return;
@@ -259,8 +316,8 @@ public final class Start {
String loaderClassName = loaderMap.get("class");
Class<?> loaderClass =
classloader.loadClass(loaderClassName);
StartupLoader loader = (StartupLoader)
loaderClass.newInstance();
+ loaders.add(loader); // add before loading, so unload can
occur if error during loading
loader.load(config, loaderArgs.toArray(new
String[loaderArgs.size()]));
- loaders.add(loader);
} catch (ClassNotFoundException e) {
throw new StartupException(e.getMessage(), e);
} catch (InstantiationException e) {
@@ -271,7 +328,21 @@ public final class Start {
}
this.loaders.trimToSize();
}
- return;
+ if (classloader instanceof InstrumentingClassLoader) {
+ try {
+ ((InstrumentingClassLoader)classloader).closeInstrumenter();
+ } catch (IOException e) {
+ throw new StartupException(e.getMessage(), e);
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ for (String path : classloader.getNativeLibPaths()) {
+ if (sb.length() > 0) {
+ sb.append(File.pathSeparator);
+ }
+ sb.append(path);
+ }
+ System.setProperty("java.library.path", sb.toString());
}
private String sendSocketCommand(Control control) throws IOException,
ConnectException {
@@ -391,7 +462,8 @@ public final class Start {
try {
this.serverSocket = new ServerSocket(config.adminPort, 1,
config.adminAddress);
} catch (IOException e) {
- throw new StartupException("Couldn't create server socket(" +
config.adminAddress + ":" + config.adminPort + ")", e);
+ throw new StartupException("Couldn't create server socket(" +
config.adminAddress + ":" + config.adminPort + ")",
+ e);
}
setDaemon(false);
}
@@ -435,7 +507,8 @@ public final class Start {
while (!Thread.interrupted()) {
try {
Socket clientSocket = serverSocket.accept();
- System.out.println("Received connection from - " +
clientSocket.getInetAddress() + " : " + clientSocket.getPort());
+ System.out.println("Received connection from - " +
clientSocket.getInetAddress() + " : "
+ + clientSocket.getPort());
processClientRequest(clientSocket);
clientSocket.close();
} catch (IOException e) {
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/both.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/both.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/both.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/both.properties Wed
Apr 29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs
Modified:
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/load-data.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/load-data.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/load-data.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/load-data.properties
Wed Apr 29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/pos.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/pos.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/pos.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/pos.properties Wed Apr
29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/rmi.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/rmi.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/rmi.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/rmi.properties Wed Apr
29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/start.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/start.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/start.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/start.properties Wed
Apr 29 13:52:27 2015
@@ -23,6 +23,10 @@
# --- By default we will use the current directory
#ofbiz.home=
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Set these for shutting down when running as background process
ofbiz.admin.host=127.0.0.1
ofbiz.admin.port=10523
Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/test.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/test.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/test.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/test.properties Wed
Apr 29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs
Modified:
ofbiz/trunk/framework/start/src/org/ofbiz/base/start/testlist.properties
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/testlist.properties?rev=1676746&r1=1676745&r2=1676746&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/testlist.properties
(original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/testlist.properties
Wed Apr 29 13:52:27 2015
@@ -20,6 +20,10 @@
# OFBiz Startup Application Settings
####
+# --- Class paths needed to get StartupLoaders to work (see
Start.createClassLoader()).
+ofbiz.start.classpath.addComponent=framework/base/config,framework/base/dtd
+ofbiz.start.classpath.addFilesFromPath=framework/base/lib,framework/base/lib/commons,framework/base/build/lib
+
# --- Default logs directory (relative to ofbiz.home)
#ofbiz.log.dir=runtime/logs