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 |
Free forum by Nabble | Edit this page |