diff --git a/scm-core/src/main/java/sonia/scm/plugin/Plugin.java b/scm-core/src/main/java/sonia/scm/plugin/Plugin.java
index b8d8a5b623..bf72e5650d 100644
--- a/scm-core/src/main/java/sonia/scm/plugin/Plugin.java
+++ b/scm-core/src/main/java/sonia/scm/plugin/Plugin.java
@@ -35,8 +35,6 @@ package sonia.scm.plugin;
//~--- JDK imports ------------------------------------------------------------
-import java.net.URL;
-
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
index 127ce74056..05b5c6c98b 100644
--- a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
+++ b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
@@ -89,6 +89,21 @@ public class PluginInformation
return groupId;
}
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getId()
+ {
+ StringBuilder id = new StringBuilder(groupId);
+
+ id.append(":").append(artifactId).append(":");
+
+ return id.append(version).toString();
+ }
+
/**
* Method description
*
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index ac2530eb07..52b4dd4d77 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -101,6 +101,64 @@
${ehcache.version}
+
+
+
+ org.sonatype.aether
+ aether-api
+ ${aether.version}
+
+
+
+ org.sonatype.aether
+ aether-impl
+ ${aether.version}
+
+
+
+ org.apache.maven
+ maven-aether-provider
+ ${maven.version}
+
+
+ plexus-component-annotations
+ org.codehaus.plexus
+
+
+
+
+
+ org.sonatype.aether
+ aether-connector-wagon
+ ${aether.version}
+
+
+
+ org.apache.maven.wagon
+ wagon-provider-api
+ ${wagon.version}
+
+
+
+ org.apache.maven.wagon
+ wagon-http-lightweight
+ ${wagon.version}
+
+
+ nekohtml
+ nekohtml
+
+
+ nekohtml
+ xercesMinimal
+
+
+ commons-logging
+ commons-logging
+
+
+
+
@@ -116,6 +174,24 @@
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.1
+
+
+ compile
+
+ list
+
+
+ runtime
+ ${project.build.directory}/classes/config/dependencies.list
+
+
+
+
+
org.mortbay.jetty
maven-jetty-plugin
@@ -147,6 +223,12 @@
scm-webapp
+
+ 1.8
+ 1.0-beta-7
+ 3.0.1
+
+
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AvailablePluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AvailablePluginResource.java
index b3e1e1c887..56259b7fb0 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AvailablePluginResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AvailablePluginResource.java
@@ -46,9 +46,12 @@ import sonia.scm.plugin.PluginManager;
import java.util.Collection;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
/**
*
@@ -71,6 +74,25 @@ public class AvailablePluginResource
this.pluginManager = pluginManager;
}
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param id
+ *
+ * @return
+ */
+ @POST
+ @Path("{id}")
+ public Response install(@PathParam("id") String id)
+ {
+ pluginManager.install(id);
+
+ return Response.ok().build();
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java
index a6ece57fe9..90d2f2e0e3 100644
--- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java
+++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java
@@ -47,12 +47,19 @@ import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
+import javax.xml.bind.JAXB;
+
/**
*
* @author Sebastian Sdorra
@@ -63,6 +70,9 @@ public class BootstrapListener implements ServletContextListener
/** Field description */
public static final String LISTENER = "sonia.scm.ScmContextListener";
+ /** Field description */
+ public static final String PLUGIN_CLASSPATHFILE = "classpath.xml";
+
/** Field description */
public static final String PLUGIN_DIRECTORY = "plugins";
@@ -102,32 +112,23 @@ public class BootstrapListener implements ServletContextListener
if (pluginDirectory.exists())
{
- try
- {
- File[] jarFiles = pluginDirectory.listFiles(new JarFilenameFilter());
+ File classpathFile = new File(pluginDirectory, PLUGIN_CLASSPATHFILE);
- if (Util.isNotEmpty(jarFiles))
+ if (classpathFile.exists())
+ {
+ try
{
- int size = jarFiles.length;
- URL[] urls = new URL[size];
+ Classpath classpath = JAXB.unmarshal(classpathFile, Classpath.class);
- for (int i = 0; i < size; i++)
+ if (classpath != null)
{
- urls[i] = jarFiles[i].toURI().toURL();
-
- if (logger.isDebugEnabled())
- {
- logger.debug("added jar {} to classpath",
- urls[i].toExternalForm());
- }
+ classLoader = createClassLoader(pluginDirectory, classpath);
}
-
- classLoader = new URLClassLoader(urls, getParentClassLoader());
}
- }
- catch (IOException ex)
- {
- logger.error(ex.getMessage(), ex);
+ catch (Exception ex)
+ {
+ logger.error(ex.getMessage(), ex);
+ }
}
}
@@ -150,6 +151,51 @@ public class BootstrapListener implements ServletContextListener
scmContextListener.contextInitialized(sce);
}
+ /**
+ * Method description
+ *
+ *
+ * @param pluginDirectory
+ * @param classpath
+ *
+ * @return
+ */
+ private ClassLoader createClassLoader(File pluginDirectory,
+ Classpath classpath)
+ {
+ List classpathURLs = new LinkedList();
+
+ for (String path : classpath)
+ {
+ if (path.startsWith("/"))
+ {
+ path = path.substring(1);
+ }
+
+ File file = new File(pluginDirectory, path);
+
+ if (file.exists())
+ {
+ try
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("append {} to classpath", file.getPath());
+ }
+
+ classpathURLs.add(file.toURI().toURL());
+ }
+ catch (MalformedURLException ex)
+ {
+ logger.error(ex.getMessage(), ex);
+ }
+ }
+ }
+
+ return new URLClassLoader(classpathURLs.toArray(new URL[0]),
+ getParentClassLoader());
+ }
+
//~--- get methods ----------------------------------------------------------
/**
@@ -170,35 +216,6 @@ public class BootstrapListener implements ServletContextListener
return classLoader;
}
- //~--- inner classes --------------------------------------------------------
-
- /**
- * Class description
- *
- *
- * @version Enter version here..., 2010-12-09
- * @author Sebastian Sdorra
- */
- private static class JarFilenameFilter implements FilenameFilter
- {
-
- /**
- * Method description
- *
- *
- * @param file
- * @param name
- *
- * @return
- */
- @Override
- public boolean accept(File file, String name)
- {
- return name.endsWith(".jar");
- }
- }
-
-
//~--- fields ---------------------------------------------------------------
/** Field description */
diff --git a/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java b/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java
new file mode 100644
index 0000000000..ef15c38000
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java
@@ -0,0 +1,131 @@
+/**
+ * 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.boot;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@XmlRootElement(name = "classpath")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Classpath implements Iterable
+{
+
+ /**
+ * Constructs ...
+ *
+ */
+ public Classpath() {}
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param path
+ */
+ public void add(String path)
+ {
+ pathSet.add(path);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param file
+ */
+ public void add(File file)
+ {
+ pathSet.add(file.getPath());
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public Iterator iterator()
+ {
+ return pathSet.iterator();
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public Set getPathSet()
+ {
+ return pathSet;
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param pathSet
+ */
+ public void setPathSet(Set pathSet)
+ {
+ this.pathSet = pathSet;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ @XmlElement(name = "path")
+ private Set pathSet = new LinkedHashSet();
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java
new file mode 100644
index 0000000000..be1d4203c8
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java
@@ -0,0 +1,155 @@
+/**
+ * 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 org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.graph.DependencyNode;
+
+import sonia.scm.util.Util;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Set;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class AetherDependencyFilter implements DependencyFilter
+{
+
+ /** Field description */
+ public static final String EXCLUDE_LIST = "/config/dependencies.list";
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ public AetherDependencyFilter()
+ {
+ loadExcludes();
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param node
+ * @param parents
+ *
+ * @return
+ */
+ @Override
+ public boolean accept(DependencyNode node, List parents)
+ {
+ Artifact artifact = node.getDependency().getArtifact();
+
+ return !exludeSet.contains(getId(artifact));
+ }
+
+ /**
+ * Method description
+ *
+ */
+ private void loadExcludes()
+ {
+ Scanner scanner = null;
+
+ try
+ {
+ scanner = new Scanner(
+ AetherDependencyFilter.class.getResourceAsStream(EXCLUDE_LIST));
+
+ while (scanner.hasNextLine())
+ {
+ parseLine(scanner.nextLine());
+ }
+ }
+ finally
+ {
+ scanner.close();
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param line
+ */
+ private void parseLine(String line)
+ {
+ line = line.trim();
+
+ if (Util.isNotEmpty(line))
+ {
+ String[] parts = line.split(":");
+
+ if (parts.length >= 2)
+ {
+ exludeSet.add(parts[0].concat(":").concat(parts[1]));
+ }
+ }
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param artifact
+ *
+ * @return
+ */
+ private String getId(Artifact artifact)
+ {
+ return artifact.getGroupId().concat(":").concat(artifact.getArtifactId());
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private Set exludeSet = new HashSet();
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java
new file mode 100644
index 0000000000..9db4b38ff5
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java
@@ -0,0 +1,282 @@
+/**
+ * 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 org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
+import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
+import org.apache.maven.repository.internal.DefaultVersionResolver;
+import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.providers.http.LightweightHttpWagon;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.sonatype.aether.RepositorySystem;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.connector.wagon.WagonProvider;
+import org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.impl.ArtifactDescriptorReader;
+import org.sonatype.aether.impl.VersionRangeResolver;
+import org.sonatype.aether.impl.VersionResolver;
+import org.sonatype.aether.impl.internal.DefaultServiceLocator;
+import org.sonatype.aether.repository.LocalRepository;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.spi.connector.RepositoryConnectorFactory;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+import sonia.scm.ConfigurationException;
+import sonia.scm.SCMContextProvider;
+import sonia.scm.boot.BootstrapListener;
+import sonia.scm.boot.Classpath;
+import sonia.scm.util.IOUtil;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class AetherPluginHandler
+{
+
+ /** Field description */
+ public static final String PLUGIN_SCOPE = "runtime";
+
+ /** the logger for AetherPluginHandler */
+ private static final Logger logger =
+ LoggerFactory.getLogger(AetherPluginHandler.class);
+
+ /** Field description */
+ private static final DependencyFilter FILTER = new AetherDependencyFilter();
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param context
+ */
+ public AetherPluginHandler(SCMContextProvider context)
+ {
+ localRepositoryDirectory = new File(context.getBaseDirectory(),
+ BootstrapListener.PLUGIN_DIRECTORY);
+
+ try
+ {
+ jaxbContext = JAXBContext.newInstance(Classpath.class);
+ }
+ catch (JAXBException ex)
+ {
+ throw new ConfigurationException(ex);
+ }
+
+ classpathFile = new File(localRepositoryDirectory,
+ BootstrapListener.PLUGIN_CLASSPATHFILE);
+
+ if (classpathFile.exists())
+ {
+ try
+ {
+ classpath =
+ (Classpath) jaxbContext.createUnmarshaller().unmarshal(classpathFile);
+ }
+ catch (JAXBException ex)
+ {
+ logger.error(ex.getMessage(), ex);
+ }
+ }
+
+ IOUtil.mkdirs(localRepositoryDirectory);
+ repositorySystem = createRepositorySystem();
+ localRepository = new LocalRepository(localRepositoryDirectory);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param gav
+ */
+ public void install(String gav)
+ {
+ if (logger.isInfoEnabled())
+ {
+ logger.info("try to install plugin with gav: {}", gav);
+ }
+
+ Dependency dependency = new Dependency(new DefaultArtifact(gav),
+ PLUGIN_SCOPE);
+ CollectRequest request = new CollectRequest(dependency, remoteRepositories);
+ MavenRepositorySystemSession session = new MavenRepositorySystemSession();
+
+ session.setLocalRepositoryManager(
+ repositorySystem.newLocalRepositoryManager(localRepository));
+
+ try
+ {
+
+ /*
+ * DependencyNode node = repositorySystem.collectDependencies(session,
+ * request).getRoot();
+ */
+ List artifacts =
+ repositorySystem.resolveDependencies(session, request, FILTER);
+
+ synchronized (Classpath.class)
+ {
+ if (classpath == null)
+ {
+ classpath = new Classpath();
+ }
+
+ for (ArtifactResult result : artifacts)
+ {
+ File file = result.getArtifact().getFile();
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("added {} to classpath", file.getPath());
+ }
+
+ classpath.add(
+ file.getAbsolutePath().substring(
+ localRepositoryDirectory.getAbsolutePath().length()));
+ }
+
+ Marshaller marshaller = jaxbContext.createMarshaller();
+
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ marshaller.marshal(classpath, classpathFile);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new PluginLoadException(ex);
+ }
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repositories
+ */
+ public void setPluginRepositories(Collection repositories)
+ {
+ remoteRepositories = new ArrayList();
+
+ for (PluginRepository repository : repositories)
+ {
+ remoteRepositories.add(new RemoteRepository(repository.getId(),
+ "default", repository.getUrl()));
+ }
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ private RepositorySystem createRepositorySystem()
+ {
+ DefaultServiceLocator locator = new DefaultServiceLocator();
+
+ locator.addService(VersionResolver.class, DefaultVersionResolver.class);
+ locator.addService(VersionRangeResolver.class,
+ DefaultVersionRangeResolver.class);
+ locator.addService(ArtifactDescriptorReader.class,
+ DefaultArtifactDescriptorReader.class);
+ locator.setServices(WagonProvider.class, new WagonProvider()
+ {
+ @Override
+ public Wagon lookup(String roleHint) throws Exception
+ {
+ return new LightweightHttpWagon();
+ }
+ @Override
+ public void release(Wagon wagon) {}
+ });
+ locator.addService(RepositoryConnectorFactory.class,
+ WagonRepositoryConnectorFactory.class);
+
+ return locator.getService(RepositorySystem.class);
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private Classpath classpath;
+
+ /** Field description */
+ private File classpathFile;
+
+ /** Field description */
+ private JAXBContext jaxbContext;
+
+ /** Field description */
+ private LocalRepository localRepository;
+
+ /** Field description */
+ private File localRepositoryDirectory;
+
+ /** Field description */
+ private List remoteRepositories;
+
+ /** Field description */
+ private RepositorySystem repositorySystem;
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
index 75c4866992..81f948ed72 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
@@ -42,6 +42,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ConfigurationException;
+import sonia.scm.SCMContext;
import sonia.scm.cache.CacheManager;
import sonia.scm.cache.SimpleCache;
import sonia.scm.config.ScmConfiguration;
@@ -100,9 +101,7 @@ public class DefaultPluginManager implements PluginManager
if (info != null)
{
- String id = getPluginId(info);
-
- installedPlugins.put(id, plugin.getInformation());
+ installedPlugins.put(info.getId(), plugin.getInformation());
}
}
@@ -128,7 +127,12 @@ public class DefaultPluginManager implements PluginManager
@Override
public void install(String id)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ if (pluginHandler == null)
+ {
+ getPluginCenter();
+ }
+
+ pluginHandler.install(id);
}
/**
@@ -156,7 +160,19 @@ public class DefaultPluginManager implements PluginManager
@Override
public PluginInformation get(String id)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ PluginInformation result = null;
+
+ for (PluginInformation info : getPluginCenter().getPlugins())
+ {
+ if (id.equals(info.getId()))
+ {
+ result = info;
+
+ break;
+ }
+ }
+
+ return result;
}
/**
@@ -195,44 +211,37 @@ public class DefaultPluginManager implements PluginManager
if (center == null)
{
- if (logger.isInfoEnabled())
+ synchronized (DefaultPluginManager.class)
{
- logger.info("fetch plugin informations from {}",
- configuration.getPluginUrl());
- }
+ if (logger.isInfoEnabled())
+ {
+ logger.info("fetch plugin informations from {}",
+ configuration.getPluginUrl());
+ }
- try
- {
- center = (PluginCenter) unmarshaller.unmarshal(
- new URL(configuration.getPluginUrl()));
- cache.put(PluginCenter.class.getName(), center);
- }
- catch (Exception ex)
- {
- throw new PluginLoadException(ex);
+ try
+ {
+ center = (PluginCenter) unmarshaller.unmarshal(
+ new URL(configuration.getPluginUrl()));
+ cache.put(PluginCenter.class.getName(), center);
+
+ if (pluginHandler == null)
+ {
+ pluginHandler = new AetherPluginHandler(SCMContext.getContext());
+ }
+
+ pluginHandler.setPluginRepositories(center.getRepositories());
+ }
+ catch (Exception ex)
+ {
+ throw new PluginLoadException(ex);
+ }
}
}
return center;
}
- /**
- * Method description
- *
- *
- * @param info
- *
- * @return
- */
- private String getPluginId(PluginInformation info)
- {
- StringBuilder id = new StringBuilder(info.getGroupId());
-
- id.append(":").append(info.getArtifactId()).append(":");
-
- return id.append(info.getVersion()).toString();
- }
-
//~--- fields ---------------------------------------------------------------
/** Field description */
@@ -244,6 +253,9 @@ public class DefaultPluginManager implements PluginManager
/** Field description */
private Map installedPlugins;
+ /** Field description */
+ private AetherPluginHandler pluginHandler;
+
/** Field description */
private Unmarshaller unmarshaller;
}
diff --git a/scm-webapp/src/main/resources/config/ehcache.xml b/scm-webapp/src/main/resources/config/ehcache.xml
index 528780bea1..fa5e5e1456 100644
--- a/scm-webapp/src/main/resources/config/ehcache.xml
+++ b/scm-webapp/src/main/resources/config/ehcache.xml
@@ -104,19 +104,18 @@
overflowToDisk="true"
timeToIdleSeconds="1200"
timeToLiveSeconds="2400"
- diskPersistent="true"
+ diskPersistent="false"
diskExpiryThreadIntervalSeconds="2400"
/>