Skip to content
Permalink
Browse files

Reverted: "Fixed: Remove dependency management from ‘ComponentContain…

…er’"

(OFBIZ-11275)

This reverts commit 3d3533c.

‘./gradlew cleanAll loadAll’ do not work anymore.
  • Loading branch information
mthl committed Nov 8, 2019
1 parent 03b69b3 commit a521de9ad8a0b5a0f9ceadab348c46d7961ff89a
@@ -309,7 +309,7 @@ checkstyle {
// the sum of errors that were present before introducing the
// ‘checkstyle’ tool present in the framework and in the official
// plugins.
tasks.checkstyleMain.maxErrors = 37776
tasks.checkstyleMain.maxErrors = 37779
// Currently there are a lot of errors so we need to temporarily
// hide them to avoid polluting the terminal output.
showViolations = false
@@ -0,0 +1,44 @@
/*******************************************************************************
* 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.
*******************************************************************************/
package org.apache.ofbiz.base.component;

/**
* Component Already Loaded Exception
*
*/
@SuppressWarnings("serial")
public class AlreadyLoadedException extends ComponentException {

public AlreadyLoadedException() {
super();
}

public AlreadyLoadedException(String str) {
super(str);
}

public AlreadyLoadedException(Throwable nested) {
super(nested);
}

public AlreadyLoadedException(String str, Throwable nested) {
super(str, nested);
}
}

@@ -18,9 +18,6 @@
*******************************************************************************/
package org.apache.ofbiz.base.component;

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;

import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
@@ -43,7 +40,6 @@
import org.apache.ofbiz.base.location.FlexibleLocation;
import org.apache.ofbiz.base.util.Assert;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.Digraph;
import org.apache.ofbiz.base.util.KeyStoreUtil;
import org.apache.ofbiz.base.util.UtilURL;
import org.apache.ofbiz.base.util.UtilValidate;
@@ -95,16 +91,6 @@ public static Boolean componentExists(String componentName) {
return componentConfigCache.values();
}

/**
* Sorts the cached component configurations.
*
* @throws ComponentException when a component configuration contains an invalid dependency
* or if the dependency graph contains a cycle.
*/
public static void sortDependencies() throws ComponentException {
componentConfigCache.sort();
}

public static Stream<ComponentConfig> components() {
return componentConfigCache.values().stream();
}
@@ -695,8 +681,6 @@ public String toString() {
private final Map<String, ComponentConfig> componentConfigs = new LinkedHashMap<>();
// Root location mapped to global name.
private final Map<String, String> componentLocations = new HashMap<>();
/** Sorted component configurations (based on depends-on declaration if ofbiz-component.xml). */
private List<ComponentConfig> componentConfigsSorted;

private synchronized ComponentConfig fromGlobalName(String globalName) {
return componentConfigs.get(globalName);
@@ -717,49 +701,8 @@ synchronized ComponentConfig put(ComponentConfig config) {
return componentConfigs.put(globalName, config);
}

/**
* Provides a sequence of cached component configurations.
*
* <p>the order of the sequence is arbitrary unless the {@link #sort())} has been invoked beforehand.
*
* @return the list of cached component configurations
*/
synchronized List<ComponentConfig> values() {
// When the configurations have not been sorted use arbitrary order.
List<ComponentConfig> res = (componentConfigsSorted == null)
? new ArrayList<>(componentConfigs.values())
: componentConfigsSorted;
return Collections.unmodifiableList(res);
}

/**
* Provides the stored dependencies as component configurations.
*
* <p>Handle invalid dependencies by creating dummy component configurations.
*
* @param the component configuration containing dependencies
* @return a collection of component configurations dependencies.
*/
private Collection<ComponentConfig> componentConfigDeps(ComponentConfig cc) {
return cc.getDependsOn().stream()
.map(dep -> {
ComponentConfig storedCc = componentConfigs.get(dep);
return (storedCc != null) ? storedCc : new Builder().globalName(dep).create();
})
.collect(Collectors.toList());
}

/**
* Sorts the component configurations based on their “depends-on” XML elements.
*/
synchronized void sort() throws ComponentException {
Map<ComponentConfig, Collection<ComponentConfig>> graphSpec = componentConfigs.values().stream()
.collect(toMap(identity(), this::componentConfigDeps));
try {
componentConfigsSorted = new Digraph<>(graphSpec).sort();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new ComponentException("failed to initialize components", e);
}
synchronized Collection<ComponentConfig> values() {
return Collections.unmodifiableList(new ArrayList<>(componentConfigs.values()));
}
}

@@ -26,7 +26,13 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -38,6 +44,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.UtilValidate;

/**
* ComponentContainer - StartupContainer implementation for Components
@@ -55,6 +62,9 @@

private String name;
private final AtomicBoolean loaded = new AtomicBoolean(false);
/** The set of ready components in their inverse dependency order. */
private final LinkedHashSet<ComponentConfig> readyComponents = new LinkedHashSet<>();
private static Map<String, List<String>> toBeLoadedComponents = new ConcurrentHashMap<>();

@Override
public void init(List<StartupCommand> ofbizCommands, String name, String configFile) throws ContainerException {
@@ -79,12 +89,11 @@ void init(String name, Path ofbizHome) throws ContainerException {
for (ComponentDef def: ComponentLoaderConfig.getRootComponents()) {
loadComponent(ofbizHome, def);
}
ComponentConfig.sortDependencies();
} catch (IOException | ComponentException e) {
throw new ContainerException(e);
}
String fmt = "Added class path for component : [%s]";
List<Classpath> componentsClassPath = ComponentConfig.components()
List<Classpath> componentsClassPath = readyComponents.stream()
.peek(cmpnt -> Debug.logInfo(String.format(fmt, cmpnt.getComponentName()), module))
.map(cmpnt -> buildClasspathFromComponentConfig(cmpnt))
.collect(Collectors.toList());
@@ -125,15 +134,19 @@ private static void loadClassPathForAllComponents(List<Classpath> componentsClas
* @param dir the location where the component should be loaded
* @param component a single component or a component directory definition
* @throws IOException when component directory loading fails.
* @throws ComponentException when retrieving component configuration files fails.
*/
private void loadComponent(Path dir, ComponentDef component) throws IOException {
private void loadComponent(Path dir, ComponentDef component) throws IOException, ComponentException {
Path location = component.location.isAbsolute() ? component.location : dir.resolve(component.location);
switch (component.type) {
case COMPONENT_DIRECTORY:
loadComponentDirectory(location);
break;
case SINGLE_COMPONENT:
retrieveComponentConfig(null, location);
ComponentConfig config = retrieveComponentConfig(null, location);
if (config != null) {
loadSingleComponent(config);
}
break;
}
}
@@ -144,8 +157,9 @@ private void loadComponent(Path dir, ComponentDef component) throws IOException
*
* @param directoryName the name of component directory to load
* @throws IOException
* @throws ComponentException
*/
private void loadComponentDirectory(Path directoryName) throws IOException {
private void loadComponentDirectory(Path directoryName) throws IOException, ComponentException {
Debug.logInfo("Auto-Loading component directory : [" + directoryName + "]", module);
if (Files.exists(directoryName) && Files.isDirectory(directoryName)) {
Path componentLoad = directoryName.resolve(ComponentLoaderConfig.COMPONENT_LOAD_XML_FILENAME);
@@ -191,15 +205,56 @@ private void loadComponentsInDirectoryUsingLoadFile(Path directoryPath, Path com
* for loading purposes
*
* @param directoryPath a valid absolute path of a component directory
* @throws IOException if an I/O error occurs when opening the directory
* @throws IOException
* @throws ComponentException
*/
private static void loadComponentsInDirectory(Path directoryPath) throws IOException {
private void loadComponentsInDirectory(Path directoryPath) throws IOException, ComponentException {
try (Stream<Path> paths = Files.list(directoryPath)) {
paths.sorted()
List<ComponentConfig> componentConfigs = paths.sorted()
.map(cmpnt -> directoryPath.resolve(cmpnt).toAbsolutePath().normalize())
.filter(Files::isDirectory)
.filter(dir -> Files.exists(dir.resolve(ComponentConfig.OFBIZ_COMPONENT_XML_FILENAME)))
.forEach(componentDir -> retrieveComponentConfig(null, componentDir));
.map(componentDir -> retrieveComponentConfig(null, componentDir))
.filter(Objects::nonNull)
.collect(Collectors.toList());

for (ComponentConfig cmpnt : componentConfigs) {
loadSingleComponent(cmpnt);
}
}
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<String>> entries : toBeLoadedComponents.entrySet()) {
ComponentConfig config = retrieveComponentConfig(entries.getKey(), null);
if (config.enabled()) {
List<String> 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)) {
readyComponents.add(config);
toBeLoadedComponents.replace(config.getComponentName(), dependencyList);
}
} else {
Debug.logInfo("Not loading component [" + config.getComponentName() + "] because it's disabled", module);
}
}
}
}
}

@@ -223,6 +278,53 @@ private static ComponentConfig retrieveComponentConfig(String name, Path locatio
return config;
}

/**
* Load a single component by adding all its classpath entries to
* the list of classpaths to be loaded
*
* @param config the component configuration
* @throws ComponentException
*/
private void loadSingleComponent(ComponentConfig config) throws ComponentException {
if (config.enabled()) {
List<String> dependencyList = checkDependencyForComponent(config);
if (UtilValidate.isEmpty(dependencyList)) {
readyComponents.add(config);
}
} else {
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 ComponentException
*/
private List<String> checkDependencyForComponent(ComponentConfig config) throws ComponentException {
List<String> dependencyList = new ArrayList<>(config.getDependsOn());
if (UtilValidate.isNotEmpty(dependencyList)) {
Set<String> resolvedDependencyList = new HashSet<>();
for (String dependency : dependencyList) {
Debug.logInfo("Component : " + config.getComponentName() + " is Dependent on " + dependency, module);
ComponentConfig componentConfig = ComponentConfig.getComponentConfig(String.valueOf(dependency));
if (readyComponents.contains(componentConfig)) {
resolvedDependencyList.add(dependency);
}
}
resolvedDependencyList.forEach(resolvedDependency -> Debug.logInfo("Resolved : " + resolvedDependency + " 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;
}

/**
* Constructs a {@code Classpath} object for a specific component definition.
*
@@ -35,6 +35,7 @@
import org.apache.ofbiz.base.start.StartupException;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;


@@ -60,6 +61,7 @@ public void cleanUp() throws IOException {
}
}

@Ignore("Dependency declarations do not impact the components order")
@Test
public void testCheckDependencyForComponent() throws ContainerException, StartupException, MalformedURLException {
ComponentContainer containerObj = new ComponentContainer();

0 comments on commit a521de9

Please sign in to comment.
You can’t perform that action at this time.