mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 06:25:45 +01:00
build plugin tree
This commit is contained in:
@@ -226,7 +226,7 @@ public class DefaultPluginLoader implements PluginLoader
|
|||||||
{
|
{
|
||||||
injectionModules.add((Module) extensionClass.newInstance());
|
injectionModules.add((Module) extensionClass.newInstance());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (IllegalAccessException | InstantiationException ex)
|
||||||
{
|
{
|
||||||
logger.error("could not create instance of module", ex);
|
logger.error("could not create instance of module", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
191
scm-webapp/src/main/java/sonia/scm/plugin/PluginNode.java
Normal file
191
scm-webapp/src/main/java/sonia/scm/plugin/PluginNode.java
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||||
|
* nor the names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public final class PluginNode
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param plugin
|
||||||
|
*/
|
||||||
|
public PluginNode(ExplodedSmp plugin)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
public void addChild(PluginNode node)
|
||||||
|
{
|
||||||
|
this.children.add(node);
|
||||||
|
node.addParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
private void addParent(PluginNode node)
|
||||||
|
{
|
||||||
|
this.parents.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public PluginNode getChild(final String id)
|
||||||
|
{
|
||||||
|
return Iterables.find(children, new Predicate<PluginNode>()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(PluginNode node)
|
||||||
|
{
|
||||||
|
return node.getId().equals(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<PluginNode> getChildren()
|
||||||
|
{
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return plugin.getPlugin().getInformation().getId(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<PluginNode> getParents()
|
||||||
|
{
|
||||||
|
return parents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ExplodedSmp getPlugin()
|
||||||
|
{
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public PluginWrapper getWrapper()
|
||||||
|
{
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- set methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param wrapper
|
||||||
|
*/
|
||||||
|
public void setWrapper(PluginWrapper wrapper)
|
||||||
|
{
|
||||||
|
this.wrapper = wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final List<PluginNode> parents = Lists.newArrayList();
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final List<PluginNode> children = Lists.newArrayList();
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final ExplodedSmp plugin;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private PluginWrapper wrapper;
|
||||||
|
}
|
||||||
@@ -37,7 +37,6 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.ImmutableList.Builder;
|
import com.google.common.collect.ImmutableList.Builder;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Ordering;
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ public final class PluginProcessor
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private static DefaultPluginClassLoader createClassLoader(
|
private DefaultPluginClassLoader createClassLoader(
|
||||||
ClassLoader parentClassLoader, Path directory)
|
ClassLoader parentClassLoader, Path directory)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@@ -256,17 +255,97 @@ public final class PluginProcessor
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ExplodedSmp> smps = Lists.transform(dirs, new PathTransformer());
|
List<ExplodedSmp> smps = Lists.transform(dirs, new PathTransformer());
|
||||||
Iterable<ExplodedSmp> smpOrdered = Ordering.natural().sortedCopy(smps);
|
|
||||||
|
|
||||||
Set<PluginWrapper> pluginWrappers = createPluginWrappers(classLoader,
|
logger.trace("start building plugin tree");
|
||||||
smpOrdered);
|
|
||||||
|
List<PluginNode> rootNodes = new PluginTree(smps).getRootNodes();
|
||||||
|
|
||||||
|
logger.trace("create plugin wrappers and build classloaders");
|
||||||
|
|
||||||
|
Set<PluginWrapper> wrappers = createPluginWrappers(classLoader, rootNodes);
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("collected {} plugins", pluginWrappers.size());
|
logger.debug("collected {} plugins", wrappers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImmutableSet.copyOf(pluginWrappers);
|
return ImmutableSet.copyOf(wrappers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param plugins
|
||||||
|
* @param classLoader
|
||||||
|
* @param node
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void appendPluginWrapper(Set<PluginWrapper> plugins,
|
||||||
|
ClassLoader classLoader, PluginNode node)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
ExplodedSmp smp = node.getPlugin();
|
||||||
|
|
||||||
|
List<ClassLoader> parents = Lists.newArrayList();
|
||||||
|
|
||||||
|
for (PluginNode parent : node.getParents())
|
||||||
|
{
|
||||||
|
PluginWrapper wrapper = parent.getWrapper();
|
||||||
|
|
||||||
|
if (wrapper != null)
|
||||||
|
{
|
||||||
|
parents.add(wrapper.getClassLoader());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
throw new PluginLoadException(
|
||||||
|
String.format(
|
||||||
|
"parent %s of plugin %s is not ready", parent.getId(), node.getId()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginWrapper plugin =
|
||||||
|
createPluginWrapper(createParentPluginClassLoader(classLoader, parents),
|
||||||
|
smp.getPath());
|
||||||
|
|
||||||
|
if (plugin != null)
|
||||||
|
{
|
||||||
|
plugins.add(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param plugins
|
||||||
|
* @param classLoader
|
||||||
|
* @param nodes
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void appendPluginWrappers(Set<PluginWrapper> plugins,
|
||||||
|
ClassLoader classLoader, List<PluginNode> nodes)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO fix plugin loading order
|
||||||
|
for (PluginNode node : nodes)
|
||||||
|
{
|
||||||
|
appendPluginWrapper(plugins, classLoader, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PluginNode node : nodes)
|
||||||
|
{
|
||||||
|
appendPluginWrappers(plugins, classLoader, node.getChildren());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -366,6 +445,37 @@ public final class PluginProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param root
|
||||||
|
* @param parents
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ClassLoader createParentPluginClassLoader(ClassLoader root,
|
||||||
|
List<ClassLoader> parents)
|
||||||
|
{
|
||||||
|
ClassLoader result;
|
||||||
|
int size = parents.size();
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
result = root;
|
||||||
|
}
|
||||||
|
else if (size == 1)
|
||||||
|
{
|
||||||
|
result = parents.get(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = new MultiParentClassLoader(parents);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -407,26 +517,19 @@ public final class PluginProcessor
|
|||||||
*
|
*
|
||||||
* @param classLoader
|
* @param classLoader
|
||||||
* @param smps
|
* @param smps
|
||||||
|
* @param rootNodes
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private Set<PluginWrapper> createPluginWrappers(ClassLoader classLoader,
|
private Set<PluginWrapper> createPluginWrappers(ClassLoader classLoader,
|
||||||
Iterable<ExplodedSmp> smps)
|
List<PluginNode> rootNodes)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
Set<PluginWrapper> plugins = Sets.newHashSet();
|
Set<PluginWrapper> plugins = Sets.newHashSet();
|
||||||
|
|
||||||
for (ExplodedSmp smp : smps)
|
appendPluginWrappers(plugins, classLoader, rootNodes);
|
||||||
{
|
|
||||||
PluginWrapper plugin = createPluginWrapper(classLoader, smp.getPath());
|
|
||||||
|
|
||||||
if (plugin != null)
|
|
||||||
{
|
|
||||||
plugins.add(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|||||||
210
scm-webapp/src/main/java/sonia/scm/plugin/PluginTree.java
Normal file
210
scm-webapp/src/main/java/sonia/scm/plugin/PluginTree.java
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||||
|
* nor the names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Ordering;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public final class PluginTree
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the logger for PluginTree
|
||||||
|
*/
|
||||||
|
private static final Logger logger =
|
||||||
|
LoggerFactory.getLogger(PluginTree.class);
|
||||||
|
|
||||||
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param smps
|
||||||
|
*/
|
||||||
|
public PluginTree(ExplodedSmp... smps)
|
||||||
|
{
|
||||||
|
this(Arrays.asList(smps));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param smps
|
||||||
|
*/
|
||||||
|
public PluginTree(List<ExplodedSmp> smps)
|
||||||
|
{
|
||||||
|
Iterable<ExplodedSmp> smpOrdered = Ordering.natural().sortedCopy(smps);
|
||||||
|
|
||||||
|
for (ExplodedSmp smp : smpOrdered)
|
||||||
|
{
|
||||||
|
Plugin plugin = smp.getPlugin();
|
||||||
|
PluginCondition condition = plugin.getCondition();
|
||||||
|
|
||||||
|
if ((condition == null) || condition.isSupported())
|
||||||
|
{
|
||||||
|
Set<String> dependencies = plugin.getDependencies();
|
||||||
|
|
||||||
|
if ((dependencies == null) || dependencies.isEmpty())
|
||||||
|
{
|
||||||
|
rootNodes.add(new PluginNode(smp));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendNode(rootNodes, dependencies, smp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
throw new PluginConditionFailedException(
|
||||||
|
condition,
|
||||||
|
String.format(
|
||||||
|
"could not load plugin %s, the plugin condition does not match",
|
||||||
|
plugin.getInformation().getId()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<PluginNode> getRootNodes()
|
||||||
|
{
|
||||||
|
return rootNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nodes
|
||||||
|
* @param dependencies
|
||||||
|
* @param smp
|
||||||
|
*/
|
||||||
|
private void appendNode(List<PluginNode> nodes, Set<String> dependencies,
|
||||||
|
ExplodedSmp smp)
|
||||||
|
{
|
||||||
|
PluginNode child = new PluginNode(smp);
|
||||||
|
|
||||||
|
for (String dependency : dependencies)
|
||||||
|
{
|
||||||
|
if (!appendNode(nodes, child, dependency))
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
throw new PluginNotInstalledException(
|
||||||
|
String.format(
|
||||||
|
"dependency %s of %s is not installed",
|
||||||
|
dependency,
|
||||||
|
child.getId()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nodes
|
||||||
|
* @param child
|
||||||
|
* @param dependency
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean appendNode(List<PluginNode> nodes, PluginNode child,
|
||||||
|
String dependency)
|
||||||
|
{
|
||||||
|
logger.debug("check for {} {}", dependency, child.getId());
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
|
||||||
|
for (PluginNode node : nodes)
|
||||||
|
{
|
||||||
|
if (node.getId().equals(dependency))
|
||||||
|
{
|
||||||
|
logger.debug("add plugin {} as child of {}", child.getId(),
|
||||||
|
node.getId());
|
||||||
|
node.addChild(child);
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (appendNode(node.getChildren(), child, dependency))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final List<PluginNode> rootNodes = Lists.newArrayList();
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||||
|
* nor the names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public class PluginProcessorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temp = new TemporaryFolder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildPluginTree() throws IOException
|
||||||
|
{
|
||||||
|
PluginProcessor processor = new PluginProcessor(temp.newFolder().toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
268
scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java
Normal file
268
scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||||
|
* nor the names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public class PluginTreeTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Test(expected = PluginConditionFailedException.class)
|
||||||
|
public void testPluginConditionFailed() throws IOException
|
||||||
|
{
|
||||||
|
PluginCondition condition = new PluginCondition("999",
|
||||||
|
new ArrayList<String>(), "hit");
|
||||||
|
Plugin plugin = new Plugin(createInfo("a", "b", "1"), null, condition,
|
||||||
|
null);
|
||||||
|
ExplodedSmp smp = createSmp(plugin);
|
||||||
|
|
||||||
|
new PluginTree(smp).getRootNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Test(expected = PluginNotInstalledException.class)
|
||||||
|
public void testPluginNotInstalled() throws IOException
|
||||||
|
{
|
||||||
|
new PluginTree(createSmpWithDependency("b", "a")).getRootNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRootNotes() throws IOException
|
||||||
|
{
|
||||||
|
List<ExplodedSmp> smps = createSmps("a", "b", "c");
|
||||||
|
List<String> nodes = unwrapIds(new PluginTree(smps).getRootNodes());
|
||||||
|
|
||||||
|
assertThat(nodes, containsInAnyOrder("a:a", "b:b", "c:c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSimpleDependencies() throws IOException
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
ExplodedSmp[] smps = new ExplodedSmp[] {
|
||||||
|
createSmpWithDependency("a"),
|
||||||
|
createSmpWithDependency("b", "a"),
|
||||||
|
createSmpWithDependency("c", "a", "b")
|
||||||
|
};
|
||||||
|
//J+
|
||||||
|
|
||||||
|
PluginTree tree = new PluginTree(smps);
|
||||||
|
List<PluginNode> rootNodes = tree.getRootNodes();
|
||||||
|
|
||||||
|
assertThat(unwrapIds(rootNodes), containsInAnyOrder("a:a"));
|
||||||
|
|
||||||
|
PluginNode a = rootNodes.get(0);
|
||||||
|
|
||||||
|
assertThat(unwrapIds(a.getChildren()), containsInAnyOrder("b:b", "c:c"));
|
||||||
|
|
||||||
|
PluginNode b = a.getChild("b:b");
|
||||||
|
|
||||||
|
assertThat(unwrapIds(b.getChildren()), containsInAnyOrder("c:c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param groupId
|
||||||
|
* @param artifactId
|
||||||
|
* @param version
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private PluginInformation createInfo(String groupId, String artifactId,
|
||||||
|
String version)
|
||||||
|
{
|
||||||
|
PluginInformation info = new PluginInformation();
|
||||||
|
|
||||||
|
info.setGroupId(groupId);
|
||||||
|
info.setArtifactId(artifactId);
|
||||||
|
info.setVersion(version);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param plugin
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private ExplodedSmp createSmp(Plugin plugin) throws IOException
|
||||||
|
{
|
||||||
|
return new ExplodedSmp(tempFolder.newFile().toPath(), plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private ExplodedSmp createSmp(String name) throws IOException
|
||||||
|
{
|
||||||
|
return createSmp(new Plugin(createInfo(name, name, "1.0.0"), null, null,
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param dependencies
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private ExplodedSmp createSmpWithDependency(String name,
|
||||||
|
String... dependencies)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
Set<String> dependencySet = new HashSet<>();
|
||||||
|
|
||||||
|
for (String d : dependencies)
|
||||||
|
{
|
||||||
|
dependencySet.add(d.concat(":").concat(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin plugin = new Plugin(createInfo(name, name, "1"), null, null,
|
||||||
|
dependencySet);
|
||||||
|
|
||||||
|
return createSmp(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param names
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private List<ExplodedSmp> createSmps(String... names) throws IOException
|
||||||
|
{
|
||||||
|
List<ExplodedSmp> smps = Lists.newArrayList();
|
||||||
|
|
||||||
|
for (String name : names)
|
||||||
|
{
|
||||||
|
smps.add(createSmp(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return smps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nodes
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<String> unwrapIds(List<PluginNode> nodes)
|
||||||
|
{
|
||||||
|
return Lists.transform(nodes, new Function<PluginNode, String>()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply(PluginNode input)
|
||||||
|
{
|
||||||
|
return input.getId();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user