Author: taher
Date: Thu Dec 1 19:29:23 2016 New Revision: 1772256 URL: http://svn.apache.org/viewvc?rev=1772256&view=rev Log: Improved: Refactor and simplify the startup sequence in OFBiz (OFBIZ-8337) Continuing the refactoring work on the startup sequence, this commit specifically focuses on the ComponentContainer and how it loads components into the system. The following changes are made: - simplify and cleanup the ofbiz-containers.xml to have only one entry - substantially simplify the ComponentLoaderConfig class and remove unnecessary defined state - delete the JustLoadComponentsContainer (used to exist for the server command --testlist which no longer exists) - fully refactor the ComponentContainer class and breakup the messy logic into chunks of private methods. The methods are also properly documented. - remove an old reference to the testlist container which no longer exists Removed: ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/JustLoadComponentsContainer.java Modified: ofbiz/trunk/framework/base/config/ofbiz-containers.xml ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentLoaderConfig.java ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java ofbiz/trunk/framework/testtools/ofbiz-component.xml Modified: ofbiz/trunk/framework/base/config/ofbiz-containers.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/ofbiz-containers.xml?rev=1772256&r1=1772255&r2=1772256&view=diff ============================================================================== --- ofbiz/trunk/framework/base/config/ofbiz-containers.xml (original) +++ ofbiz/trunk/framework/base/config/ofbiz-containers.xml Thu Dec 1 19:29:23 2016 @@ -22,14 +22,6 @@ under the License. xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-containers.xsd"> <!-- load the ofbiz component container (always first) --> - <container name="component-container" loaders="main,rmi,load-data" class="org.apache.ofbiz.base.container.ComponentContainer"/> - - <container name="component-container-test" loaders="test" class="org.apache.ofbiz.base.container.ComponentContainer"/> - - <container name="component-container-limited" loaders="limited" class="org.apache.ofbiz.base.container.ComponentContainer"> - <property name="update-classpath" value="false"/> - </container> - - <container name="component-container" loaders="testlist" class="org.apache.ofbiz.base.container.JustLoadComponentsContainer"/> + <container name="component-container" loaders="main,rmi,load-data,test" class="org.apache.ofbiz.base.container.ComponentContainer"/> </ofbiz-containers> Modified: ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentLoaderConfig.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentLoaderConfig.java?rev=1772256&r1=1772255&r2=1772256&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentLoaderConfig.java (original) +++ ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentLoaderConfig.java Thu Dec 1 19:29:23 2016 @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import javax.xml.parsers.ParserConfigurationException; @@ -37,70 +36,29 @@ import org.w3c.dom.Element; import org.xml.sax.SAXException; /** - * ComponentLoaderConfig - Component Loader configuration + * ComponentLoaderConfig - Component Loader configuration utility class + * to handle component-load.xml files * */ -public class ComponentLoaderConfig { +public final class ComponentLoaderConfig { public static final String module = ComponentLoaderConfig.class.getName(); public static final String COMPONENT_LOAD_XML_FILENAME = "component-load.xml"; - public static final int SINGLE_COMPONENT = 0; - public static final int COMPONENT_DIRECTORY = 1; - private static final AtomicReference<List<ComponentDef>> componentDefsRef = new AtomicReference<List<ComponentDef>>(null); - - public static List<ComponentDef> getRootComponents(String configFile) throws ComponentException { - List<ComponentDef> existingInstance = componentDefsRef.get(); - if (existingInstance == null) { - if (configFile == null) { - configFile = COMPONENT_LOAD_XML_FILENAME; - } - URL xmlUrl = UtilURL.fromResource(configFile); - List<ComponentDef> newInstance = getComponentsFromConfig(xmlUrl); - if (componentDefsRef.compareAndSet(existingInstance, newInstance)) { - existingInstance = newInstance; - } else { - existingInstance = componentDefsRef.get(); - } - } - return existingInstance; + + public enum ComponentType { SINGLE_COMPONENT, COMPONENT_DIRECTORY } + + public static List<ComponentDef> getRootComponents() throws ComponentException { + URL xmlUrl = UtilURL.fromResource(COMPONENT_LOAD_XML_FILENAME); + return getComponentsFromConfig(xmlUrl); } public static List<ComponentDef> getComponentsFromConfig(URL configUrl) throws ComponentException { - if (configUrl == null) { - throw new IllegalArgumentException("configUrl cannot be null"); - } - Document document = null; - try { - document = UtilXml.readXmlDocument(configUrl, true); - } catch (SAXException e) { - throw new ComponentException("Error reading the component config file: " + configUrl, e); - } catch (ParserConfigurationException e) { - throw new ComponentException("Error reading the component config file: " + configUrl, e); - } catch (IOException e) { - throw new ComponentException("Error reading the component config file: " + configUrl, e); - } - Element root = document.getDocumentElement(); - List<? extends Element> toLoad = UtilXml.childElementList(root); - List<ComponentDef> componentsFromConfig = null; - if (!toLoad.isEmpty()) { - componentsFromConfig = new ArrayList<ComponentDef>(toLoad.size()); - Map<String, ? extends Object> systemProps = UtilGenerics.<String, Object> checkMap(System.getProperties()); - for (Element element : toLoad) { - String nodeName = element.getNodeName(); - String name = null; - String location = null; - int type = SINGLE_COMPONENT; - if ("load-component".equals(nodeName)) { - name = element.getAttribute("component-name"); - location = FlexibleStringExpander.expandString(element.getAttribute("component-location"), systemProps); - } else if ("load-components".equals(nodeName)) { - location = FlexibleStringExpander.expandString(element.getAttribute("parent-directory"), systemProps); - type = COMPONENT_DIRECTORY; - } else { - throw new ComponentException("Invalid element '" + nodeName + "' found in component config file " + configUrl); - } - componentsFromConfig.add(new ComponentDef(name, location, type)); - } + Document document = parseDocumentFromUrl(configUrl); + List<? extends Element> toLoad = UtilXml.childElementList(document.getDocumentElement()); + List<ComponentDef> componentsFromConfig = new ArrayList<ComponentDef>(); + + for (Element element : toLoad) { + componentsFromConfig.add(retrieveComponentDefFromElement(element, configUrl)); } return Collections.unmodifiableList(componentsFromConfig); } @@ -108,12 +66,44 @@ public class ComponentLoaderConfig { public static class ComponentDef { public String name; public final String location; - public final int type; + public final ComponentType type; - private ComponentDef(String name, String location, int type) { + private ComponentDef(String name, String location, ComponentType type) { this.name = name; this.location = location; this.type = type; } } + + private static Document parseDocumentFromUrl(URL configUrl) throws ComponentException { + if (configUrl == null) { + throw new ComponentException("configUrl cannot be null"); + } + try { + return UtilXml.readXmlDocument(configUrl, true); + } catch (SAXException | ParserConfigurationException | IOException e) { + throw new ComponentException("Error reading the component config file: " + configUrl, e); + } + } + + private static ComponentDef retrieveComponentDefFromElement(Element element, URL configUrl) throws ComponentException { + Map<String, ? extends Object> systemProps = UtilGenerics.<String, Object> checkMap(System.getProperties()); + String nodeName = element.getNodeName(); + + String name = null; + String location = null; + ComponentType type = null; + + if ("load-component".equals(nodeName)) { + name = element.getAttribute("component-name"); + location = FlexibleStringExpander.expandString(element.getAttribute("component-location"), systemProps); + type = ComponentType.SINGLE_COMPONENT; + } else if ("load-components".equals(nodeName)) { + location = FlexibleStringExpander.expandString(element.getAttribute("parent-directory"), systemProps); + type = ComponentType.COMPONENT_DIRECTORY; + } else { + throw new ComponentException("Invalid element '" + nodeName + "' found in component-load file " + configUrl); + } + return new ComponentDef(name, location, type); + } } Modified: ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java?rev=1772256&r1=1772255&r2=1772256&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java (original) +++ ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java Thu Dec 1 19:29:23 2016 @@ -31,24 +31,25 @@ import org.apache.ofbiz.base.component.C import org.apache.ofbiz.base.component.ComponentLoaderConfig; import org.apache.ofbiz.base.start.Classpath; import org.apache.ofbiz.base.start.NativeLibClassLoader; +import org.apache.ofbiz.base.start.Start; import org.apache.ofbiz.base.start.StartupCommand; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.FileUtil; -import org.apache.ofbiz.base.util.UtilValidate; /** * ComponentContainer - StartupContainer implementation for Components - * <p/> - * Example ofbiz-container.xml configuration: - * <pre> - * <container name="component-container" class="org.apache.ofbiz.base.component.ComponentContainer"/> - * </pre> + * + * The purpose of this container is to load the classpath for all components + * defined in OFBiz. This container must run before any other containers to + * allow components to access any necessary resources. Furthermore, the + * ComponentContainer also builds up the <code>ComponentConfigCache</code> + * to keep track of all loaded components + * */ public class ComponentContainer implements Container { public static final String module = ComponentContainer.class.getName(); - protected String configFileLocation = null; private String name; private final AtomicBoolean loaded = new AtomicBoolean(false); @@ -58,23 +59,16 @@ public class ComponentContainer implemen throw new ContainerException("Components already loaded, cannot start"); } this.name = name; - this.configFileLocation = configFile; - // get the config for this container - ContainerConfig.Configuration cc = ContainerConfig.getConfiguration(name, configFileLocation); - - // check for an override loader config - String loaderConfig = null; - if (cc.getProperty("loader-config") != null) { - loaderConfig = cc.getProperty("loader-config").value; - } - - // load the components + // load the components from framework/base/config/component-load.xml (root components) try { - loadComponents(loaderConfig); - } catch (ComponentException e) { + for (ComponentLoaderConfig.ComponentDef def: ComponentLoaderConfig.getRootComponents()) { + loadComponentFromConfig(Start.getInstance().getConfig().ofbizHome, def); + } + } catch (IOException | ComponentException e) { throw new ContainerException(e); } + Debug.logInfo("All components loaded", module); } /** @@ -84,165 +78,185 @@ public class ComponentContainer implemen return loaded.get(); } - public void loadComponents(String loaderConfig) throws ComponentException { - // get the components to load - List<ComponentLoaderConfig.ComponentDef> components = ComponentLoaderConfig.getRootComponents(loaderConfig); - 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); - } + /** + * Checks if <code>ComponentDef.type</code> is a directory or a single component. + * If it is a directory, load the directory, otherwise load a single component + * + * @param parentPath: the parent path of what is being loaded + * @param def: the component or directory loader definition + * @throws IOException + */ + private void loadComponentFromConfig(String parentPath, ComponentLoaderConfig.ComponentDef def) throws IOException { + String location = def.location.startsWith("/") ? def.location : parentPath + "/" + def.location; + + if (def.type.equals(ComponentLoaderConfig.ComponentType.COMPONENT_DIRECTORY)) { + loadComponentDirectory(location); + } else if (def.type.equals(ComponentLoaderConfig.ComponentType.SINGLE_COMPONENT)) { + ComponentConfig config = retrieveComponentConfig(def.name, location); + if (config != null) { + loadComponent(config); } - } catch (MalformedURLException e) { - throw new ComponentException(e.getMessage(), e); - } catch (IOException e) { - throw new ComponentException(e.getMessage(), e); } - Debug.logInfo("All components loaded", module); } - private void loadComponentFromConfig(String parentPath, ComponentLoaderConfig.ComponentDef def) throws IOException { - String location; - if (def.location.startsWith("/")) { - location = def.location; + /** + * Checks to see if the directory contains a load file (component-load.xml) and + * then delegates loading to the appropriate method + * + * @param directoryName: the name of component directory to load + * @throws IOException + */ + private void loadComponentDirectory(String directoryName) throws IOException { + Debug.logInfo("Auto-Loading component directory : [" + directoryName + "]", module); + + File directoryPath = FileUtil.getFile(directoryName); + if (directoryPath.exists() && directoryPath.isDirectory()) { + File componentLoadFile = new File(directoryPath, ComponentLoaderConfig.COMPONENT_LOAD_XML_FILENAME); + if (componentLoadFile != null && componentLoadFile.exists()) { + loadComponentsInDirectoryUsingLoadFile(directoryPath, componentLoadFile); + } else { + loadComponentsInDirectory(directoryPath); + } } else { - location = parentPath + "/" + def.location; + Debug.logError("Auto-Load Component directory not found : " + directoryName, module); } - if (def.type == ComponentLoaderConfig.SINGLE_COMPONENT) { - ComponentConfig config = null; - try { - config = ComponentConfig.getComponentConfig(def.name, location); - if (UtilValidate.isEmpty(def.name)) { - def.name = config.getGlobalName(); + + } + + /** + * load components residing in a directory only if they exist in the component + * load file (component-load.xml) and they are sorted in order from top to bottom + * in the load file + * + * @param directoryPath: the absolute path of the directory + * @param componentLoadFile: the name of the load file (i.e. component-load.xml) + * @throws IOException + */ + private void loadComponentsInDirectoryUsingLoadFile(File directoryPath, File componentLoadFile) throws IOException { + URL configUrl = null; + try { + configUrl = componentLoadFile.toURI().toURL(); + List<ComponentLoaderConfig.ComponentDef> componentsToLoad = ComponentLoaderConfig.getComponentsFromConfig(configUrl); + if (componentsToLoad != null) { + for (ComponentLoaderConfig.ComponentDef def: componentsToLoad) { + loadComponentFromConfig(directoryPath.toString(), def); } - } catch (ComponentException e) { - Debug.logError("Cannot load component : " + def.name + " @ " + def.location + " : " + e.getMessage(), module); - } - if (config == null) { - Debug.logError("Cannot load component : " + def.name + " @ " + def.location, module); - } else { - this.loadComponent(config); } - } else if (def.type == ComponentLoaderConfig.COMPONENT_DIRECTORY) { - this.loadComponentDirectory(location); + } catch (MalformedURLException e) { + Debug.logError(e, "Unable to locate URL for component loading file: " + componentLoadFile.getAbsolutePath(), module); + } catch (ComponentException e) { + Debug.logError(e, "Unable to load components from URL: " + configUrl.toExternalForm(), module); } } - 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()) { - Debug.logError("Auto-Load Component directory not found : " + directoryName, module); - } else { - File componentLoadConfig = new File(parentPath, ComponentLoaderConfig.COMPONENT_LOAD_XML_FILENAME); - if (componentLoadConfig != null && componentLoadConfig.exists()) { - URL configUrl = null; - try { - configUrl = componentLoadConfig.toURI().toURL(); - List<ComponentLoaderConfig.ComponentDef> componentsToLoad = ComponentLoaderConfig.getComponentsFromConfig(configUrl); - if (componentsToLoad != null) { - for (ComponentLoaderConfig.ComponentDef def: componentsToLoad) { - this.loadComponentFromConfig(parentPath.toString(), def); - } - } - } catch (MalformedURLException e) { - Debug.logError(e, "Unable to locate URL for component loading file: " + componentLoadConfig.getAbsolutePath(), module); - } catch (ComponentException e) { - Debug.logError(e, "Unable to load components from URL: " + configUrl.toExternalForm(), module); - } - } else { - String[] fileNames = parentPath.list(); - Arrays.sort(fileNames); - for (String sub: fileNames) { - try { - File componentPath = FileUtil.getFile(parentPath.getCanonicalPath() + File.separator + sub); - if (componentPath.isDirectory() && !sub.equals("CVS") && !sub.equals(".svn")) { - // make sure we have a component configuration file - String componentLocation = componentPath.getCanonicalPath(); - File configFile = FileUtil.getFile(componentLocation.concat(File.separator).concat(ComponentConfig.OFBIZ_COMPONENT_XML_FILENAME)); - if (configFile.exists()) { - ComponentConfig config = null; - try { - // pass null for the name, will default to the internal component name - config = ComponentConfig.getComponentConfig(null, componentLocation); - } catch (ComponentException e) { - Debug.logError(e, "Cannot load component : " + componentPath.getName() + " @ " + componentLocation + " : " + e.getMessage(), module); - } - if (config == null) { - Debug.logError("Cannot load component : " + componentPath.getName() + " @ " + componentLocation, module); - } else { - loadComponent(config); - } - } - } - } catch (IOException ioe) { - Debug.logError(ioe, module); - } + /** + * Load all components in a directory because it does not contain + * a load-components.xml file. The components are sorted alphabetically + * for loading purposes + * + * @param directoryPath: the absolute path of the directory + * @throws IOException + */ + private void loadComponentsInDirectory(File directoryPath) throws IOException { + String[] sortedComponentNames = directoryPath.list(); + Arrays.sort(sortedComponentNames); + + for (String componentName: sortedComponentNames) { + File componentPath = FileUtil.getFile(directoryPath.getCanonicalPath() + File.separator + componentName); + String componentLocation = componentPath.getCanonicalPath(); + File configFile = FileUtil.getFile(componentLocation.concat(File.separator).concat(ComponentConfig.OFBIZ_COMPONENT_XML_FILENAME)); + + if (componentPath.isDirectory() && !componentName.startsWith(".") && configFile.exists()) { + ComponentConfig config = retrieveComponentConfig(null, componentLocation); + if (config != null) { + loadComponent(config); } } } } + /** + * Fetch the <code>ComponentConfig</code> for a certain component + * + * @param name: component name + * @param location: directory location of the component + * @return The component configuration + */ + private ComponentConfig retrieveComponentConfig(String name, String location) { + ComponentConfig config = null; + try { + config = ComponentConfig.getComponentConfig(name, location); + } catch (ComponentException e) { + Debug.logError("Cannot load component : " + name + " @ " + location + " : " + e.getMessage(), module); + } + if (config == null) { + Debug.logError("Cannot load component : " + name + " @ " + location, module); + } + return config; + } + + /** + * Load a single component by adding all its classpath entries to + * the classloader + * + * @param config: the component configuration + * @throws IOException + */ private void loadComponent(ComponentConfig config) throws IOException { - // make sure the component is enabled if (!config.enabled()) { Debug.logInfo("Not loading component [" + config.getComponentName() + "] because it is disabled", module); return; } + + NativeLibClassLoader classloader = (NativeLibClassLoader) Thread.currentThread().getContextClassLoader(); + Classpath classPath = buildClasspathFromComponentConfig(config); + + for (URL url : classPath.getUrls()) { + classloader.addURL(url); + } + for (File folder : classPath.getNativeFolders()) { + classloader.addNativeClassPath(folder); + } + + Debug.logInfo("Loaded component : [" + config.getComponentName() + "]", module); + } + + /** + * Construct a <code>Classpath</code> object for a certain component based + * on its configuration defined in <code>ComponentConfig</code> + * + * @param config: the component configuration + * @return the constructed classpath + * @throws IOException + */ + private Classpath buildClasspathFromComponentConfig(ComponentConfig config) throws IOException { + Classpath classPath = new Classpath(); + String configRoot = config.getRootLocation().replace('\\', '/'); + configRoot = configRoot.endsWith("/") ? configRoot : configRoot + "/"; 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 (ComponentConfig.ClasspathInfo cp: classpathInfos) { + String location = cp.location.replace('\\', '/'); + if (!"jar".equals(cp.type) && !"dir".equals(cp.type)) { + Debug.logError("Classpath type '" + cp.type + "' is not supported; '" + location + "' not loaded", module); + continue; } - for (File folder : classPath.getNativeFolders()) { - classloader.addNativeClassPath(folder); + + location = location.startsWith("/") ? location.substring(1) : location; + String dirLoc = location.endsWith("/*") ? location.substring(0, location.length() - 2) : location; + File path = FileUtil.getFile(configRoot + dirLoc); + + if (path.exists()) { + classPath.addComponent(configRoot + location); + if (path.isDirectory() && "dir".equals(cp.type)) { + classPath.addFilesFromPath(path); + } + } else { + Debug.logWarning("Location '" + configRoot + dirLoc + "' does not exist", module); } } - Debug.logInfo("Loaded component : [" + config.getComponentName() + "]", module); + return classPath; } - /** * @see org.apache.ofbiz.base.container.Container#stop() */ Modified: ofbiz/trunk/framework/testtools/ofbiz-component.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/testtools/ofbiz-component.xml?rev=1772256&r1=1772255&r2=1772256&view=diff ============================================================================== --- ofbiz/trunk/framework/testtools/ofbiz-component.xml (original) +++ ofbiz/trunk/framework/testtools/ofbiz-component.xml Thu Dec 1 19:29:23 2016 @@ -31,6 +31,4 @@ <service-resource type="model" loader="main" location="servicedef/services.xml"/> <container name="testtools-container" loaders="test" class="org.apache.ofbiz.testtools.TestRunContainer"/> - <container name="testtools-container" loaders="testlist" class="org.apache.ofbiz.testtools.TestListContainer"/> - </ofbiz-component> \ No newline at end of file |
Free forum by Nabble | Edit this page |