Skip to content
Permalink
Browse files

Improved: Refactor ‘ComponentLoaderConfig’ class

(OFBIZ-11192)

This redefines the ‘ComponentLoaderConfig#ComponentDef’ class by
removing its unused name attribute.

The ‘java.nio.file’ API has been used to represent the relative path
of a component location.

Various cleanups and Javadoc added.


git-svn-id: https://svn.apache.org/repos/asf/ofbiz/ofbiz-framework/trunk@1867394 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
mthl committed Sep 23, 2019
1 parent 6a89860 commit e3acbf65413bd4b1bd045fb43217e9a4ab4db41e
@@ -1,4 +1,4 @@
/*******************************************************************************
/*
* 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
@@ -15,11 +15,13 @@
* 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;

import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -36,9 +38,17 @@
import org.xml.sax.SAXException;

/**
* ComponentLoaderConfig - Component Loader configuration utility class
* to handle component-load.xml files
* This class is a module for manipulating component loader files.
*
* <p> The component loader files are named {@code component-load.xml}
* and are present either in the classpath when defining the top-level component
* directories or inside those component directories when defining the loading order
* of the enabled simple components inside those directories.
*
* Simple components are directories containing a component configuration file
* named {@code ofbiz-component.xml} and mapped to a {@link ComponentConfig} object.
*
* @see ComponentConfig
*/
public final class ComponentLoaderConfig {

@@ -47,34 +57,105 @@

public enum ComponentType { SINGLE_COMPONENT, COMPONENT_DIRECTORY }

private ComponentLoaderConfig() { }

/**
* Provides the list of root directory components defined in the classpath.
*
* @return the list of root directory components.
* @throws ComponentException if the main {@code component-load.xml} file is either invalid
* or refer to non-existent component directory.
*/
public static List<ComponentDef> getRootComponents() throws ComponentException {
URL xmlUrl = UtilURL.fromResource(COMPONENT_LOAD_XML_FILENAME);
return getComponentsFromConfig(xmlUrl);
}

/**
* Collects the component definitions from a {@code component-load.xml} file
*
* @param configUrl the location of the {@code component-load.xml} file
* @return a list of component definitions
* @throws ComponentException when the {@code component-load.xml} file is invalid.
*/
public static List<ComponentDef> getComponentsFromConfig(URL configUrl) throws ComponentException {
Document document = parseDocumentFromUrl(configUrl);
List<? extends Element> toLoad = UtilXml.childElementList(document.getDocumentElement());
List<ComponentDef> componentsFromConfig = new ArrayList<>();

for (Element element : toLoad) {
componentsFromConfig.add(retrieveComponentDefFromElement(element, configUrl));
componentsFromConfig.add(ComponentDef.of(element, configUrl));
}
return Collections.unmodifiableList(componentsFromConfig);
}

/**
* Represents a simple component or a component directory.
*/
public static class ComponentDef {
public String name;
public final String location;
/** The location of the component. */
public final Path location;
/** The type of component. */
public final ComponentType type;

private ComponentDef(String name, String location, ComponentType type) {
this.name = name;
/**
* Constructs a component definition.
*
* @param location the location of the component
* @param type the type of the component
*/
private ComponentDef(Path location, ComponentType type) {
this.location = location;
this.type = type;
}

@Override
public String toString() {
return String.format("ComponentDef [location=%s, type=%s]", location, type);
}

/**
* Converts a string based location to a proper {@code Path}.
*
* @param location the string based location
* @return the corresponding {@code Path} object.
*/
private static Path locationToPath(String location) {
Map<String, ?> systemProps = UtilGenerics.cast(System.getProperties());
return Paths.get(FlexibleStringExpander.expandString(location, systemProps));
}

/**
* Constructs a component definition object from an XML element.
*
* @param element an XML element which must have either a "load-component" or "load-components" label.
* @param configUrl the location of the file containing the XML element
* @return the corresponding component definition object.
* @throws ComponentException when {@code element} has an invalid label.
*/
private static ComponentDef of(Element element, URL configUrl) throws ComponentException {
String nodeName = element.getNodeName();
switch (nodeName) {
case "load-component":
return new ComponentDef(locationToPath(element.getAttribute("component-location")),
ComponentType.SINGLE_COMPONENT);
case "load-components":
return new ComponentDef(locationToPath(element.getAttribute("parent-directory")),
ComponentType.COMPONENT_DIRECTORY);
default:
throw new ComponentException(
String.format("Invalid element '%s' found in component-load file %s", nodeName, configUrl));
}
}
}

/**
* Parses a {@code component-load.xml} resource.
*
* @param configUrl the {@code component-load.xml} resource.
* @return the parsed XML document
* @throws ComponentException when {@code configUrl} is {@code null} or is invalid.
*/
private static Document parseDocumentFromUrl(URL configUrl) throws ComponentException {
if (configUrl == null) {
throw new ComponentException("configUrl cannot be null");
@@ -85,25 +166,4 @@ private static Document parseDocumentFromUrl(URL configUrl) throws ComponentExce
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.cast(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);
}
}
@@ -117,12 +117,12 @@ private static void loadClassPathForAllComponents(List<Classpath> componentsClas
* @throws ComponentException
*/
private void loadComponentFromConfig(String parentPath, ComponentLoaderConfig.ComponentDef def) throws IOException, ContainerException, ComponentException {
String location = def.location.startsWith("/") ? def.location : parentPath + "/" + def.location;
String location = def.location.startsWith("/") ? def.location.toString() : 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);
ComponentConfig config = retrieveComponentConfig(null, location);
if (config != null) {
loadComponent(config);
}

0 comments on commit e3acbf6

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