CCM NG: Some cleanup

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3589 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-08-26 18:22:28 +00:00
parent fb1ecd04b0
commit 98d1f02f21
8 changed files with 0 additions and 773 deletions

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public interface ModuleDescriptor {
/**
* Called by the {@link ModuleManager} after the database tables for the
* module have been created. Use this method to create initial or example
* data.
*/
void prepare();
/**
* Called by the {@link ModuleManager} when a module is removed from the
* installation. If necessary clean up the data of the module in the
* implementation of this method.
*/
void uninstall();
/**
* Called each time the CCM application is started. Use an implementation of
* this method for creating static instances or for integrity checking.
*/
void init();
/**
* Called each time the CCM application stops.
*/
void shutdown();
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules;
import com.arsdigita.runtime.RegistryConfig;
import java.util.Arrays;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class ModuleManager {
@Inject
private transient Instance<ModuleDescriptor> modules;
/**
* Checks for new or upgraded modules and executes database migrations if
* necessary. If a new module is installed the database tables for this
* module are generated first. After that the {@code prepare()} method of
* the module is called (see {@link ModuleDescriptor#prepare()}).
*/
public void loadModules() {
}
/**
* Checks if a module is already installed.
*
* @param moduleDescriptor The descriptor of the module.
*
* @return {@code true} if the module is already installed, {@code false}
* otherwise.
*/
private boolean isInstalled(final ModuleDescriptor moduleDescriptor) {
final RegistryConfig registryConfig = new RegistryConfig();
registryConfig.load();
final String[] packages = registryConfig.getPackages();
final List<String> packageList = Arrays.asList(packages);
return packageList.contains(ModuleUtil.getModuleName(moduleDescriptor));
}
/**
* Called to uninstall a module. First the {@code uninstal()} method of the
* module is called (see {@link ModuleDescriptor#uninstall()}). After that
* the database tables of the module are removed.
*
* @param module The module to uninstall.
*/
public void uninstallModule(final ModuleDescriptor module) {
}
/**
* Initialises all modules by calling their {@code init()} method (see
* {@link ModuleDescriptor#init()}.
*/
public void initModules() {
}
/**
* Shutdown all modules by calling their {@link shutdown()} method (see
* {@link ModuleDescriptor#shutdown()}).
*/
public void shutdownModules() {
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules;
import org.libreccm.modules.annotations.Module;
import org.libreccm.modules.annotations.RequiredModule;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class ModuleUtil {
private ModuleUtil() {
//Nothing
}
private static Module getModuleAnnotation(
final ModuleDescriptor module) {
final Module annotation = module.getClass().getAnnotation(Module.class);
if (annotation == null) {
throw new IllegalArgumentException(String.format(
"The provided implementation of the "
+ "org.libreccm.modules.Module interface, \"%s\", is not"
+ "annotated with org.libreccm.modules.annotations.Module",
module.getClass().getName()));
} else {
return annotation;
}
}
public static String getModuleName(final ModuleDescriptor module) {
return getModuleAnnotation(module).name();
}
public static String getVersion(final ModuleDescriptor module) {
return getModuleAnnotation(module).version();
}
public static RequiredModule[] getRequiredModules(final ModuleDescriptor module) {
return getModuleAnnotation(module).requiredModules();
}
public static String getModuleName(
final Class<? extends ModuleDescriptor> module) {
final Module annotation = module.getAnnotation(Module.class);
if (annotation == null) {
throw new IllegalArgumentException(String.format(
"The provided implementation of the "
+ "org.libreccm.modules.Module interface, \"%s\", is not"
+ "annotated with org.libreccm.modules.annotations.Module",
module.getClass().getName()));
} else {
return annotation.name();
}
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules.annotations;
import org.libreccm.modules.ModuleDescriptor;
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
/**
* Annotate an implementation of the {@link ModuleDescriptor} interface with
* this annotation to use it as a module.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Module {
@Nonbinding String name() default "";
@Nonbinding String version() default "";
@Nonbinding RequiredModule[] requiredModules() default {};
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules.annotations;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public @interface RequiredModule {
Class<? extends org.libreccm.modules.ModuleDescriptor> module();
String minVersion() default "";
String maxVersion() default "";
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules.dependencytree;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DependencyException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>DependencyException</code> without detail message.
*/
public DependencyException() {
super();
}
/**
* Constructs an instance of <code>DependencyException</code> with the specified detail message.
*
* @param msg The detail message.
*/
public DependencyException(final String msg) {
super(msg);
}
/**
* Constructs an instance of <code>DependencyException</code> which wraps the
* specified exception.
*
* @param exception The exception to wrap.
*/
public DependencyException(final Exception exception) {
super(exception);
}
/**
* Constructs an instance of <code>DependencyException</code> with the specified message which also wraps the
* specified exception.
*
* @param msg The detail message.
* @param exception The exception to wrap.
*/
public DependencyException(final String msg, final Exception exception) {
super(msg, exception);
}
}

View File

@ -1,268 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules.dependencytree;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.libreccm.modules.ModuleDescriptor;
import org.libreccm.modules.ModuleUtil;
import org.libreccm.modules.annotations.RequiredModule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.inject.Instance;
/**
* This class implements topological sorting to determine the order in which the
* modules are loaded and initialised.
*
* The class is used by creating an instance with the parameterless constructor.
* To create the tree/graph call the
* {@link #generateTree(javax.enterprise.inject.Instance)} method. With the
* returned list of nodes call the the {@link #orderModules(java.util.List)}
* method. The list returned by {@link #orderModules(java.util.List)} contains
* all modules in order.
*
* More information about topological sorting:
* <a href="https://en.wikipedia.org/wiki/Topological_sorting">https://en.wikipedia.org/wiki/Topological_sorting</a>
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DependencyTreeManager {
private static final Logger LOGGER = LogManager.getLogger(
DependencyTreeManager.class);
public List<TreeNode> generateTree(final Instance<ModuleDescriptor> modules)
throws DependencyException {
LOGGER.info("Starting to generate dependency tree...");
final Map<String, TreeNode> nodes = new HashMap<>();
for (final ModuleDescriptor module : modules) {
createTreeNode(module, nodes);
}
for (final ModuleDescriptor module : modules) {
addDependencyRelations(module, nodes);
}
final List<TreeNode> nodeList = new ArrayList<>();
for (final Map.Entry<String, TreeNode> entry : nodes.entrySet()) {
nodeList.add(entry.getValue());
}
LOGGER.info("Dependency tree generated.");
return nodeList;
}
public List<TreeNode> orderModules(final List<TreeNode> dependencyTree)
throws DependencyException {
LOGGER.info("Creating an ordered list from the dependency tree...");
final List<TreeNode> orderedModules = new ArrayList<>();
final List<TreeNode> resolvedModules = new ArrayList<>();
LOGGER.info("Looking for modules which do not depend on any other "
+ "modules...");
for (final TreeNode node : dependencyTree) {
if (node.getDependsOn().isEmpty()) {
LOGGER.info(
"\tModule \"{}\" does not depend on any other module",
ModuleUtil.getModuleName(node.getModule()));
resolvedModules.add(node);
}
}
LOGGER.info("Ordering remaining nodes...");
while (!resolvedModules.isEmpty()) {
final TreeNode current = resolvedModules.remove(0);
LOGGER.info("\tProcessing node for module \"{}\"...",
ModuleUtil.getModuleName(current.getModule()));
orderedModules.add(current);
for (final TreeNode dependent : current.getDependentModules()) {
dependent.removeDependsOn(current);
if (dependent.getDependsOn().isEmpty()) {
resolvedModules.add(dependent);
}
}
}
if (orderedModules.size() == dependencyTree.size()) {
LOGGER.info("Dependency graph proceessed successfully. "
+ "Modules in order:");
for (final TreeNode node : orderedModules) {
LOGGER.info("\t{}", ModuleUtil.getModuleName(node.getModule()));
}
return orderedModules;
} else {
LOGGER.fatal("The dependency graph has a least one cycle.");
throw new DependencyException(
"The dependency graph has a least one cycle.");
}
}
private void createTreeNode(final ModuleDescriptor module,
final Map<String, TreeNode> nodes) {
final TreeNode node = new TreeNode(module);
LOGGER.info("Creating node for module \"{}\"...",
ModuleUtil.getModuleName(module));
nodes.put(ModuleUtil.getModuleName(module), node);
}
private void addDependencyRelations(final ModuleDescriptor module,
final Map<String, TreeNode> nodes)
throws DependencyException {
LOGGER.info("Adding dependency relations for module \"{}\"...",
ModuleUtil.getModuleName(module));
final String moduleName = ModuleUtil.getModuleName(module);
if (!nodes.containsKey(moduleName)) {
LOGGER.fatal("Modules nodes map does contain an entry for \"{}\". "
+ "That should not happen.",
ModuleUtil.getModuleName(module));
throw new IllegalArgumentException(String.format(
"The nodes map does not contain a node for module \"%s\". "
+ "That should not happen.",
moduleName));
}
final TreeNode node = nodes.get(moduleName);
LOGGER.info("Processing required modules for module \"{}\"...",
ModuleUtil.getModuleName(module));
for (final RequiredModule requiredModule : ModuleUtil
.getRequiredModules(
module)) {
LOGGER.info("\tModule \"{}\" requires module \"{}\".",
ModuleUtil.getModuleName(module),
ModuleUtil.getModuleName(requiredModule.module()));
if (!nodes.containsKey(ModuleUtil.getModuleName(requiredModule
.module()))) {
LOGGER.fatal("Required module \"{}\" no found.",
ModuleUtil.getModuleName(requiredModule.module()));
throw new DependencyException(String.format(
"Module \"%s\" depends on module \"%s\" but the dependency "
+ "tree does contain an entry for module \"%s\".",
ModuleUtil.getModuleName(module),
ModuleUtil.getModuleName(requiredModule.module()),
ModuleUtil.getModuleName(requiredModule.module())));
}
final TreeNode dependencyNode = nodes.get(ModuleUtil.getModuleName(
requiredModule.module()));
//Check version
if (!validateVersion(ModuleUtil.getVersion(dependencyNode
.getModule()),
requiredModule.minVersion(),
requiredModule.maxVersion())) {
throw new DependencyException(String.format(
"The required module is avialable but in the correct "
+ "version. "
+ "Available version: \"%s\"; "
+ "minimal required version: \"%s\"; "
+ "maximum required version: \"%s\"",
ModuleUtil.getVersion(dependencyNode.getModule()),
requiredModule.minVersion(),
requiredModule.maxVersion()));
}
node.addDependsOn(dependencyNode);
dependencyNode.addDependentModule(node);
}
}
/**
* Helper method for checking if an dependency is available in the required
* version.
*
* @param availableVersion The available version. Can't be {@code null} or
* empty.
* @param minRequiredVersion The minimal version required. Can be
* {@code null} or empty.
* @param maxRequiredVersion The maximum version required. Can be
* {@code null} or empty.
*
* @return {@code true} if the available version is in the required range,
* {@code false} if not.
*/
//The names are fine. Shorter names would be less readable. Also removing
//the parentheses in the ifs would make the conditions less readable.
@SuppressWarnings({"PMD.LongVariable",
"PMD.UselessParentheses",
"PMD.CyclomaticComplexity"})
private boolean validateVersion(final String availableVersion,
final String minRequiredVersion,
final String maxRequiredVersion) {
if (availableVersion == null || availableVersion.isEmpty()) {
throw new IllegalArgumentException("No available version specified.");
}
if ((minRequiredVersion == null || minRequiredVersion.isEmpty())
&& (maxRequiredVersion == null || maxRequiredVersion.isEmpty())) {
return true;
} else if ((minRequiredVersion != null && !minRequiredVersion.isEmpty())
&& (maxRequiredVersion == null || maxRequiredVersion
.isEmpty())) {
final ComparableVersion minVersion = new ComparableVersion(
minRequiredVersion);
final ComparableVersion version = new ComparableVersion(
availableVersion);
return minVersion.compareTo(version) <= 0;
} else if ((minRequiredVersion == null || minRequiredVersion.isEmpty())
&& (maxRequiredVersion != null && !maxRequiredVersion
.isEmpty())) {
final ComparableVersion maxVersion = new ComparableVersion(
maxRequiredVersion);
final ComparableVersion version = new ComparableVersion(
availableVersion);
return version.compareTo(maxVersion) <= 0;
} else {
final ComparableVersion minVersion = new ComparableVersion(
minRequiredVersion);
final ComparableVersion maxVersion = new ComparableVersion(
(maxRequiredVersion));
final ComparableVersion version = new ComparableVersion(
availableVersion);
return minVersion.compareTo(version) <= 0 && version.compareTo(
maxVersion) <= 0;
}
}
}

View File

@ -1,132 +0,0 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.modules.dependencytree;
import org.libreccm.modules.ModuleDescriptor;
import org.libreccm.modules.ModuleUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* Represents a node in the dependency tree.
*
* @see DependencyTreeManager
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class TreeNode {
private ModuleDescriptor module;
private List<TreeNode> dependentModules;
private List<TreeNode> dependsOn;
public TreeNode() {
super();
dependentModules = new ArrayList<>();
dependsOn = new ArrayList<>();
}
public TreeNode(final ModuleDescriptor module) {
this();
this.module = module;
}
public ModuleDescriptor getModule() {
return module;
}
public void setModule(final ModuleDescriptor module) {
this.module = module;
}
public List<TreeNode> getDependentModules() {
return Collections.unmodifiableList(dependentModules);
}
void setDependentModules(final List<TreeNode> dependentModules) {
this.dependentModules = dependentModules;
}
void addDependentModule(final TreeNode node) {
dependentModules.add(node);
}
void removeDependentModule(final TreeNode node) {
dependentModules.remove(node);
}
public List<TreeNode> getDependsOn() {
return Collections.unmodifiableList(dependsOn);
}
void setDependsOn(final List<TreeNode> dependsOn) {
this.dependsOn = dependsOn;
}
void addDependsOn(final TreeNode node) {
dependsOn.add(node);
}
void removeDependsOn(final TreeNode node) {
dependsOn.remove(node);
}
@Override
public int hashCode() {
int hash = 5;
final String moduleName = ModuleUtil.getModuleName(module);
final String version = ModuleUtil.getVersion(module);
hash = 37 * hash + Objects.hashCode(moduleName);
hash = 37 * hash + Objects.hashCode(version);
return hash;
}
@Override
public boolean equals(final Object object) {
if (object == null) {
return false;
}
if (!(object instanceof TreeNode)) {
return false;
}
final TreeNode other = (TreeNode) object;
final String name = ModuleUtil.getModuleName(module);
final String otherName = ModuleUtil.getModuleName(other.getModule());
if (!name.equals(otherName)) {
return false;
}
final String version = ModuleUtil.getVersion(module);
final String otherVersion = ModuleUtil.getVersion(other.getModule());
return version.equals(otherVersion);
}
}