svn commit: r1676746 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/container/ start/src/org/ofbiz/base/start/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1676746 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/container/ start/src/org/ofbiz/base/start/

adrianc
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