Author: jleroux
Date: Wed Sep 5 16:23:04 2018 New Revision: 1840139 URL: http://svn.apache.org/viewvc?rev=1840139&view=rev Log: Implemented: Implement Depends on support for Component Loading. (OFBIZ-10368) Components are loaded in the order they are found (i.e. alphabetic or creation date). Here is a feature which supports in ofbiz-component to create a series of dependency for component loading, before loading a particular component. Here we can define dependency for a component like Component ebaystore is dependent on Component ebay (even multiple dependencies for a single component is also supported). We can declare it in this fashion in ofbiz-component.xml file. <ofbiz-component name="ebaystore" enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-component.xsd"> <depends-on component-name="ebay"/> Now we can declare dependency and if any anomaly is found loading of components will stop. Thanks: Modified: ofbiz/ofbiz-framework/trunk/framework/base/dtd/ofbiz-component.xsd ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java Modified: ofbiz/ofbiz-framework/trunk/framework/base/dtd/ofbiz-component.xsd URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/base/dtd/ofbiz-component.xsd?rev=1840139&r1=1840138&r2=1840139&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/base/dtd/ofbiz-component.xsd (original) +++ ofbiz/ofbiz-framework/trunk/framework/base/dtd/ofbiz-component.xsd Wed Sep 5 16:23:04 2018 @@ -43,21 +43,26 @@ under the License. <xs:attributeGroup ref="attlist.depends-on"> <xs:annotation> <xs:documentation> - This is yet unimplemented. It's not a trivial implementation because at the moment components are loaded - in the order they are found (i.e. alphabetic or creation date). - While this feature would require them all to be located first and then reordered and loaded. - So, for now, simply follow below guidelines. + Alter the way components are loaded. + By default components are loaded in the order they are found (i.e. alphabetic or creation date). For the plugins, all components will be loaded after the OFBiz components, including, in this order, those in: - framework - themes - applications + framework + themes + applications + The plugins Auto-Loading feature also loads all components in the order they are found (i.e. alphabetic or creation date). + + Using depends-on allows to create a series of dependencies for component loading, before loading a particular component. + For instance we can define dependency for a component like component ebaystore is dependent on component ebay + (even multiple dependencies for a single component is also supported). - The plugins Auto-Loading feature loads all components in the order they are found (i.e. alphabetic or creation date). - - If you need a specific loading order of these components then you need to disable the Auto-Loading feature - by creating a component-load.xml file in the plugins directory and use the load-component tag to load - your components in the order you want (just use the component-load.xml file in the application folder as a template). + We can declare it in this fashion in ofbiz-component.xml file (beware ebaystore is disabled by default) + <![CDATA[ + <ofbiz-component name="ebaystore" enabled="true" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-component.xsd"> + <depends-on component-name="ebay"/> + ]]> </xs:documentation> </xs:annotation> </xs:attributeGroup> Modified: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java?rev=1840139&r1=1840138&r2=1840139&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java (original) +++ ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java Wed Sep 5 16:23:04 2018 @@ -340,6 +340,7 @@ public final class ComponentConfig { private final boolean enabled; private final Map<String, ResourceLoaderInfo> resourceLoaderInfos; private final List<ClasspathInfo> classpathInfos; + private final List<DependsOnInfo> dependsOnInfos; private final List<EntityResourceInfo> entityResourceInfos; private final List<ServiceResourceInfo> serviceResourceInfos; private final List<TestSuiteInfo> testSuiteInfos; @@ -390,6 +391,19 @@ public final class ComponentConfig { } else { this.resourceLoaderInfos = Collections.emptyMap(); } + + childElements = UtilXml.childElementList(ofbizComponentElement, "depends-on"); + if (!childElements.isEmpty()) { + List<DependsOnInfo> dependsOnList = new ArrayList<>(childElements.size()); + for (Element curElement : childElements) { + DependsOnInfo dependsOnInfo = new DependsOnInfo(this, curElement); + dependsOnList.add(dependsOnInfo); + } + this.dependsOnInfos = Collections.unmodifiableList(dependsOnList); + } else { + this.dependsOnInfos = Collections.emptyList(); + } + // classpath - classpathInfos childElements = UtilXml.childElementList(ofbizComponentElement, "classpath"); if (!childElements.isEmpty()) { @@ -529,6 +543,10 @@ public final class ComponentConfig { return this.globalName; } + public List<DependsOnInfo> getDependsOn() { + return this.dependsOnInfos; + } + public List<KeystoreInfo> getKeystoreInfos() { return this.keystoreInfos; } @@ -677,6 +695,15 @@ public final class ComponentConfig { } } + public static final class DependsOnInfo extends ResourceInfo { + public final String componentName; + + private DependsOnInfo(ComponentConfig componentConfig, Element element) { + super(componentConfig, element); + this.componentName = element.getAttribute("component-name"); + } + } + /** * An object that models the <code><keystore></code> element. * Modified: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java?rev=1840139&r1=1840138&r2=1840139&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java (original) +++ ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/container/ComponentContainer.java Wed Sep 5 16:23:04 2018 @@ -25,9 +25,14 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; + +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; - +import java.util.stream.Collectors; import org.apache.ofbiz.base.component.ComponentConfig; import org.apache.ofbiz.base.component.ComponentException; import org.apache.ofbiz.base.component.ComponentLoaderConfig; @@ -36,6 +41,7 @@ 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 @@ -54,6 +60,7 @@ public class ComponentContainer implemen private String name; private final AtomicBoolean loaded = new AtomicBoolean(false); private final List<Classpath> componentsClassPath = new ArrayList<>(); + private static Map<String, List<ComponentConfig.DependsOnInfo>> toBeLoadedComponents = new HashMap<>(); @Override public void init(List<StartupCommand> ofbizCommands, String name, String configFile) throws ContainerException { @@ -110,8 +117,10 @@ public class ComponentContainer implemen * @param parentPath the parent path of what is being loaded * @param def the component or directory loader definition * @throws IOException + * @throws ContainerException + * @throws ComponentException */ - private void loadComponentFromConfig(String parentPath, ComponentLoaderConfig.ComponentDef def) throws IOException { + private void loadComponentFromConfig(String parentPath, ComponentLoaderConfig.ComponentDef def) throws IOException, ContainerException, ComponentException { String location = def.location.startsWith("/") ? def.location : parentPath + "/" + def.location; if (def.type.equals(ComponentLoaderConfig.ComponentType.COMPONENT_DIRECTORY)) { @@ -130,8 +139,10 @@ public class ComponentContainer implemen * * @param directoryName the name of component directory to load * @throws IOException + * @throws ContainerException + * @throws ComponentException */ - private void loadComponentDirectory(String directoryName) throws IOException { + private void loadComponentDirectory(String directoryName) throws IOException, ContainerException, ComponentException { Debug.logInfo("Auto-Loading component directory : [" + directoryName + "]", module); File directoryPath = FileUtil.getFile(directoryName); @@ -156,8 +167,9 @@ public class ComponentContainer implemen * @param directoryPath the absolute path of the directory * @param componentLoadFile the name of the load file (i.e. component-load.xml) * @throws IOException + * @throws ContainerException */ - private void loadComponentsInDirectoryUsingLoadFile(File directoryPath, File componentLoadFile) throws IOException { + private void loadComponentsInDirectoryUsingLoadFile(File directoryPath, File componentLoadFile) throws IOException, ContainerException { URL configUrl = null; try { configUrl = componentLoadFile.toURI().toURL(); @@ -179,9 +191,11 @@ public class ComponentContainer implemen * * @param directoryPath the absolute path of the directory * @throws IOException + * @throws ComponentException */ - private void loadComponentsInDirectory(File directoryPath) throws IOException { + private void loadComponentsInDirectory(File directoryPath) throws IOException, ComponentException { String[] sortedComponentNames = directoryPath.list(); + List<ComponentConfig> componentConfigs = new ArrayList<>(); if (sortedComponentNames == null) { throw new IllegalArgumentException("sortedComponentNames is null, directory path is invalid " + directoryPath.getPath()); } @@ -194,8 +208,46 @@ public class ComponentContainer implemen if (componentPath.isDirectory() && !componentName.startsWith(".") && configFile.exists()) { ComponentConfig config = retrieveComponentConfig(null, componentLocation); - if (config != null) { - loadComponent(config); + componentConfigs.add(config); + } + } + for (ComponentConfig componentConfig : componentConfigs) { + if (componentConfig != null) { + loadComponent(componentConfig); + } + } + loadComponentWithDependency(); + } + + /** + * Checks dependency for unloaded components and add them into + * componentsClassPath + * + * @throws IOException + * @throws ComponentException + */ + private void loadComponentWithDependency() throws IOException, ComponentException { + while (true) { + if (UtilValidate.isEmpty(toBeLoadedComponents)) { + return; + } else { + for (Map.Entry<String, List<ComponentConfig.DependsOnInfo>> entries : toBeLoadedComponents.entrySet()) { + ComponentConfig config = retrieveComponentConfig(entries.getKey(), null); + if (config.enabled()) { + List<ComponentConfig.DependsOnInfo> dependencyList = checkDependencyForComponent(config); + if (UtilValidate.isNotEmpty(dependencyList)) { + toBeLoadedComponents.replace(config.getComponentName(), dependencyList); + String msg = "Not loading component [" + config.getComponentName() + "] because it's dependent Component is not loaded [ " + dependencyList + "]"; + Debug.logInfo(msg, module); + } + if (UtilValidate.isEmpty(dependencyList)) { + componentsClassPath.add(buildClasspathFromComponentConfig(config)); + toBeLoadedComponents.replace(config.getComponentName(), dependencyList); + Debug.logInfo("Added class path for component : [" + config.getComponentName() + "]", module); + } + } else { + Debug.logInfo("Not loading component [" + config.getComponentName() + "] because it's disabled", module); + } } } } @@ -227,15 +279,52 @@ public class ComponentContainer implemen * * @param config the component configuration * @throws IOException + * @throws ComponentException */ - private void loadComponent(ComponentConfig config) throws IOException { + private void loadComponent(ComponentConfig config) throws IOException, ComponentException { if (config.enabled()) { - Classpath classpath = buildClasspathFromComponentConfig(config); - componentsClassPath.add(classpath); - Debug.logInfo("Added class path for component : [" + config.getComponentName() + "]", module); + List<ComponentConfig.DependsOnInfo> dependencyList = checkDependencyForComponent(config); + if (UtilValidate.isEmpty(dependencyList)) { + componentsClassPath.add(buildClasspathFromComponentConfig(config)); + Debug.logInfo("Added class path for component : [" + config.getComponentName() + "]", module); + } } else { - Debug.logInfo("Not loading component [" + config.getComponentName() + "] because it is disabled", module); + Debug.logInfo("Not loading component [" + config.getComponentName() + "] because it's disabled", module); + } + } + + /** + * Check for components loaded and Removes loaded components dependency + * from list of unloaded components + * + * @param config the component configuration + * @throws IOException + * @throws ComponentException + * + */ + private List<ComponentConfig.DependsOnInfo> checkDependencyForComponent(ComponentConfig config) throws IOException, ComponentException { + List<ComponentConfig.DependsOnInfo> dependencyList = new ArrayList<>(config.getDependsOn()); + if (UtilValidate.isNotEmpty(dependencyList)) { + Set<ComponentConfig.DependsOnInfo> resolvedDependencyList = new HashSet<>(); + for (ComponentConfig.DependsOnInfo dependency : dependencyList) { + Debug.logInfo("Component : " + config.getComponentName() + " is Dependent on " + dependency.componentName, module); + ComponentConfig componentConfig = ComponentConfig.getComponentConfig(String.valueOf(dependency.componentName)); + Classpath dependentComponentClasspath = buildClasspathFromComponentConfig(componentConfig); + componentsClassPath.forEach(componentClassPath -> { + if (Arrays.equals(componentClassPath.toString().split(":"), dependentComponentClasspath.toString().split(":"))) { + resolvedDependencyList.add(dependency); + } + }); + } + resolvedDependencyList.forEach(resolvedDependency -> Debug.logInfo("Resolved : " + resolvedDependency.componentName + " Dependency for Component " + config.getComponentName(), module)); + dependencyList.removeAll(resolvedDependencyList); + if (UtilValidate.isEmpty(dependencyList)) { + toBeLoadedComponents.remove(config.getComponentName()); + } else { + toBeLoadedComponents.put(config.getComponentName(), dependencyList); + } } + return dependencyList; } /** |
Free forum by Nabble | Edit this page |