diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginLoader.java b/scm-core/src/main/java/sonia/scm/plugin/PluginLoader.java index 70d401be5e..d5789391e2 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/PluginLoader.java +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginLoader.java @@ -82,4 +82,12 @@ public interface PluginLoader * @return */ public Collection getInstalledPlugins(); + + /** + * Method description + * + * + * @return + */ + public ClassLoader getUberClassLoader(); } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java b/scm-core/src/main/java/sonia/scm/plugin/PluginWrapper.java similarity index 55% rename from scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java rename to scm-core/src/main/java/sonia/scm/plugin/PluginWrapper.java index b01da86a32..ba33f44273 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginWrapper.java @@ -33,33 +33,86 @@ package sonia.scm.plugin; //~--- JDK imports ------------------------------------------------------------ -import java.io.IOException; - -import java.util.Set; +import java.nio.file.Path; /** + * Wrapper for a {@link Plugin}. The wrapper holds the directory and the + * {@link ClassLoader}, which is able to load plugin classes. * * @author Sebastian Sdorra + * @since 2.0.0 */ -public class BlacklistDependencyFilter extends AbstractDependencyFilter +public final class PluginWrapper { - /** Field description */ - private static final String BLACKLIST = "/config/blacklist.list"; + /** + * Constructs a new plugin wrapper. + * + * @param plugin wrapped plugin + * @param classLoader plugin class loader + * @param directory plugin directory + */ + public PluginWrapper(Plugin plugin, ClassLoader classLoader, Path directory) + { + this.plugin = plugin; + this.classLoader = classLoader; + this.directory = directory; + } - //~--- methods -------------------------------------------------------------- + //~--- get methods ---------------------------------------------------------- /** - * Method description + * Returns plugin class loader. * * - * @return - * - * @throws IOException + * @return plugin class loader */ - @Override - protected Set loadExcludeSet() throws IOException + public ClassLoader getClassLoader() { - return DependencyFilters.loadDependencySet(BLACKLIST); + return classLoader; } + + /** + * Returns plugin directory. + * + * + * @return plugin directory + */ + public Path getDirectory() + { + return directory; + } + + /** + * Returns the id of the plugin. + * + * + * @return id of plugin + */ + public String getId() + { + return plugin.getInformation().getId(); + } + + /** + * Returns the plugin. + * + * + * @return plugin + */ + public Plugin getPlugin() + { + return plugin; + } + + //~--- fields --------------------------------------------------------------- + + /** plugin class loader */ + private final ClassLoader classLoader; + + /** plugin directory */ + private final Path directory; + + /** plugin */ + private final Plugin plugin; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/BrowseCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/BrowseCommandRequest.java index b996a10030..2f7c007959 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/BrowseCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/BrowseCommandRequest.java @@ -189,7 +189,7 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest * * @since 1.26 */ - boolean isDisableLastCommit() + public boolean isDisableLastCommit() { return disableLastCommit; } @@ -202,7 +202,7 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest * * @since 1.26 */ - boolean isDisableSubRepositoryDetection() + public boolean isDisableSubRepositoryDetection() { return disableSubRepositoryDetection; } @@ -215,7 +215,7 @@ public final class BrowseCommandRequest extends FileBaseCommandRequest * * @since 1.26 */ - boolean isRecursive() + public boolean isRecursive() { return recursive; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/DiffCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/DiffCommandRequest.java index 90b913b97e..5cfd57f71b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/DiffCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/DiffCommandRequest.java @@ -119,7 +119,7 @@ public final class DiffCommandRequest extends FileBaseCommandRequest * * @since 1.34 */ - DiffFormat getFormat() + public DiffFormat getFormat() { return format; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/FileBaseCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/FileBaseCommandRequest.java index 69b6262d7c..aec2b7087a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/FileBaseCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/FileBaseCommandRequest.java @@ -154,7 +154,7 @@ public abstract class FileBaseCommandRequest * * @return */ - String getPath() + public String getPath() { return path; } @@ -165,7 +165,7 @@ public abstract class FileBaseCommandRequest * * @return */ - String getRevision() + public String getRevision() { return revision; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/LogCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/LogCommandRequest.java index 21391e4b3a..1637a92c16 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/LogCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/LogCommandRequest.java @@ -212,7 +212,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - String getBranch() + public String getBranch() { return branch; } @@ -223,7 +223,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - String getEndChangeset() + public String getEndChangeset() { return endChangeset; } @@ -234,7 +234,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - int getPagingLimit() + public int getPagingLimit() { return pagingLimit; } @@ -245,7 +245,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - int getPagingStart() + public int getPagingStart() { return pagingStart; } @@ -256,7 +256,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - String getPath() + public String getPath() { return path; } @@ -267,7 +267,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - String getStartChangeset() + public String getStartChangeset() { return startChangeset; } @@ -278,7 +278,7 @@ public final class LogCommandRequest implements Serializable, Resetable * * @return */ - boolean isPagingUnlimited() + public boolean isPagingUnlimited() { return pagingLimit < 0; } diff --git a/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java b/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java index 80998ef693..98fa4955d5 100644 --- a/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java +++ b/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java @@ -31,6 +31,10 @@ package sonia.scm.util; +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Preconditions; + /** * Util methods for {@link ClassLoader}s. * @@ -46,6 +50,38 @@ public final class ClassLoaders */ private ClassLoaders() {} + //~--- methods -------------------------------------------------------------- + + /** + * Executes a {@link Runnable} with the given {@link ClassLoader} as context + * ClassLoader ({@link Thread#setContextClassLoader(ClassLoader)}). + * + * + * @param classLoader ClassLoader for context + * @param runnable runnable + * + * @since 2.0.0 + */ + public static void executeInContext(ClassLoader classLoader, + Runnable runnable) + { + Preconditions.checkNotNull(classLoader, "ClassLoader is required"); + Preconditions.checkNotNull(runnable, "runnable is required"); + + ClassLoader ctxCl = Thread.currentThread().getContextClassLoader(); + + Thread.currentThread().setContextClassLoader(ctxCl); + + try + { + runnable.run(); + } + finally + { + Thread.currentThread().setContextClassLoader(ctxCl); + } + } + //~--- get methods ---------------------------------------------------------- /** diff --git a/scm-maven-plugins/scm-annotation-processor/src/main/java/sonia/scm/annotation/ScmAnnotationProcessor.java b/scm-maven-plugins/scm-annotation-processor/src/main/java/sonia/scm/annotation/ScmAnnotationProcessor.java index 595009d104..49e154f04e 100644 --- a/scm-maven-plugins/scm-annotation-processor/src/main/java/sonia/scm/annotation/ScmAnnotationProcessor.java +++ b/scm-maven-plugins/scm-annotation-processor/src/main/java/sonia/scm/annotation/ScmAnnotationProcessor.java @@ -101,7 +101,7 @@ import javax.xml.transform.stream.StreamResult; */ @SuppressWarnings({ "Since16", "Since15" }) @MetaInfServices(Processor.class) -@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedAnnotationTypes("*") public final class ScmAnnotationProcessor extends AbstractProcessor { diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index b006b484ea..99672b02bb 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -23,10 +23,18 @@ + + javax.servlet + servlet-api + ${servlet.version} + provided + + sonia.scm scm-core 2.0.0-SNAPSHOT + provided @@ -37,6 +45,15 @@ 2.0.0-SNAPSHOT provided + + + + + sonia.scm + scm-test + 2.0.0-SNAPSHOT + test + @@ -67,8 +84,12 @@ sonia.scm.maven - scm-maven-plugin - 2.0.0-SNAPSHOT + smp-maven-plugin + 1.0.0-SNAPSHOT + true + + true + fix-descriptor diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 325d3378c1..b57e395d26 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -13,6 +13,7 @@ scm-git-plugin 2.0.0-SNAPSHOT scm-git-plugin + smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index d6d79a87cb..a790b69756 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -13,17 +13,11 @@ scm-hg-plugin 2.0.0-SNAPSHOT scm-hg-plugin + smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial - - - javax.servlet - servlet-api - ${servlet.version} - provided - com.aragost.javahg @@ -31,23 +25,6 @@ 0.8-SNAPSHOT - - - - com.google.guava - guava - ${guava.version} - - - - - - sonia.scm - scm-test - 2.0.0-SNAPSHOT - test - - diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIExceptionHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIExceptionHandler.java index 71d766072d..1b8bf6bed2 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIExceptionHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIExceptionHandler.java @@ -53,6 +53,8 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; +import java.util.Locale; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -99,7 +101,8 @@ public class HgCGIExceptionHandler */ public HgCGIExceptionHandler() { - this.bundle = Bundle.getBundle(BUNDLE_PATH); + this.bundle = Bundle.getBundle(BUNDLE_PATH, Locale.ENGLISH, + HgCGIExceptionHandler.class.getClassLoader()); } //~--- methods -------------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 9b6e0df608..441d8122f6 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -13,6 +13,7 @@ scm-svn-plugin 2.0.0-SNAPSHOT scm-svn-plugin + smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 3c39cd377f..492fbf8c7d 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -55,25 +55,7 @@ scm-dao-xml 2.0.0-SNAPSHOT - - - sonia.scm.plugins - scm-hg-plugin - 2.0.0-SNAPSHOT - - - - sonia.scm.plugins - scm-svn-plugin - 2.0.0-SNAPSHOT - - - - sonia.scm.plugins - scm-git-plugin - 2.0.0-SNAPSHOT - - + @@ -220,44 +202,6 @@ compiler ${mustache.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-asynchttpclient - ${aether.version} - - - - org.sonatype.aether - aether-connector-file - ${aether.version} - @@ -364,7 +308,6 @@ - @@ -388,7 +331,6 @@ true - org.apache.maven.plugins @@ -408,6 +350,42 @@ + + sonia.scm.maven + smp-maven-plugin + 1.0.0-SNAPSHOT + + + + sonia.scm.plugins + scm-hg-plugin + 2.0.0-SNAPSHOT + smp + + + sonia.scm.plugins + scm-svn-plugin + 2.0.0-SNAPSHOT + smp + + + sonia.scm.plugins + scm-git-plugin + 2.0.0-SNAPSHOT + smp + + + + + + compile + + copy-core-plugins + + + + + org.apache.maven.plugins maven-antrun-plugin @@ -452,7 +430,7 @@ - + sonia.maven change-env diff --git a/scm-webapp/src/main/java/sonia/scm/ClassOverrides.java b/scm-webapp/src/main/java/sonia/scm/ClassOverrides.java index 3cc8ce47ef..b727a75fc0 100644 --- a/scm-webapp/src/main/java/sonia/scm/ClassOverrides.java +++ b/scm-webapp/src/main/java/sonia/scm/ClassOverrides.java @@ -30,6 +30,7 @@ */ + package sonia.scm; //~--- non-JDK imports -------------------------------------------------------- @@ -42,6 +43,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.util.AssertUtil; +import sonia.scm.util.ClassLoaders; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ @@ -50,7 +52,6 @@ import java.io.IOException; import java.net.URL; -import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; @@ -87,42 +88,54 @@ public class ClassOverrides implements Iterable * Method description * * + * + * @param classLoader * @return * */ - public static ClassOverrides findOverrides() + public static ClassOverrides findOverrides(ClassLoader classLoader) { - ClassOverrides overrides = new ClassOverrides(); + final ClassOverrides overrides = new ClassOverrides(); try { - Enumeration overridesEnm = - getClassLoader().getResources(OVERRIDE_PATH); - JAXBContext context = JAXBContext.newInstance(ClassOverrides.class); + final Enumeration overridesEnm = + classLoader.getResources(OVERRIDE_PATH); + final JAXBContext context = JAXBContext.newInstance(ClassOverrides.class); - while (overridesEnm.hasMoreElements()) + ClassLoaders.executeInContext(classLoader, new Runnable() { - URL overrideUrl = overridesEnm.nextElement(); - if (logger.isInfoEnabled()) + @Override + public void run() { - logger.info("load override from {}", overrideUrl.toExternalForm()); - } + while (overridesEnm.hasMoreElements()) + { + URL overrideUrl = overridesEnm.nextElement(); - try - { - ClassOverrides co = - (ClassOverrides) context.createUnmarshaller().unmarshal( - overrideUrl); + if (logger.isInfoEnabled()) + { + logger.info("load override from {}", + overrideUrl.toExternalForm()); + } - overrides.append(co); + try + { + ClassOverrides co = + (ClassOverrides) context.createUnmarshaller().unmarshal( + overrideUrl); + + overrides.append(co); + } + catch (JAXBException ex) + { + logger.error( + "could not load ".concat(overrideUrl.toExternalForm()), ex); + } + } } - catch (Exception ex) - { - logger.error("could not load ".concat(overrideUrl.toExternalForm()), - ex); - } - } + }); + } catch (IOException ex) { @@ -136,28 +149,6 @@ public class ClassOverrides implements Iterable return overrides; } - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - private static ClassLoader getClassLoader() - { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - if (classLoader == null) - { - classLoader = ClassOverrides.class.getClassLoader(); - } - - return classLoader; - } - - //~--- methods -------------------------------------------------------------- - /** * Method description * @@ -207,7 +198,7 @@ public class ClassOverrides implements Iterable { if (moduleClasses == null) { - moduleClasses = new ArrayList>(); + moduleClasses = Lists.newArrayList(); } return moduleClasses; @@ -227,7 +218,7 @@ public class ClassOverrides implements Iterable if (Util.isNotEmpty(moduleClasses)) { modules = Lists.transform(moduleClasses, - new Function, Module>() + new Function, Module>() { @Override public Module apply(Class moduleClass) @@ -238,11 +229,11 @@ public class ClassOverrides implements Iterable { module = moduleClass.newInstance(); } - catch (Exception ex) + catch (IllegalAccessException | InstantiationException ex) { logger.error( - "could not create module instance of ".concat( - moduleClass.getName()), ex); + "could not create module instance of ".concat( + moduleClass.getName()), ex); } return module; @@ -292,7 +283,7 @@ public class ClassOverrides implements Iterable { if (overrides == null) { - overrides = new ArrayList(); + overrides = Lists.newArrayList(); } return overrides; diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index 784b2ea11d..66e0590d6d 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -46,6 +46,7 @@ import org.apache.shiro.guice.web.ShiroWebModule; import sonia.scm.cache.CacheManager; import sonia.scm.group.GroupManager; import sonia.scm.plugin.DefaultPluginLoader; +import sonia.scm.plugin.PluginWrapper; import sonia.scm.repository.HealthCheckContextListener; import sonia.scm.repository.RepositoryManager; import sonia.scm.store.StoreFactory; @@ -57,6 +58,7 @@ import sonia.scm.web.security.AuthenticationManager; //~--- JDK imports ------------------------------------------------------------ import java.util.List; +import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -68,6 +70,21 @@ import javax.servlet.ServletContextEvent; public class ScmContextListener extends GuiceServletContextListener { + /** + * Constructs ... + * + * + * @param parent + * @param plugins + */ + public ScmContextListener(ClassLoader parent, Set plugins) + { + this.parent = parent; + this.plugins = plugins; + } + + //~--- methods -------------------------------------------------------------- + /** * Method description * @@ -150,6 +167,17 @@ public class ScmContextListener extends GuiceServletContextListener //~--- get methods ---------------------------------------------------------- + /** + * Method description + * + * + * @return + */ + public Set getPlugins() + { + return plugins; + } + /** * Method description * @@ -181,9 +209,10 @@ public class ScmContextListener extends GuiceServletContextListener */ private Injector getDefaultInjector(ServletContext servletContext) { - DefaultPluginLoader pluginLoader = new DefaultPluginLoader(); + DefaultPluginLoader pluginLoader = new DefaultPluginLoader(parent, plugins); - ClassOverrides overrides = ClassOverrides.findOverrides(); + ClassOverrides overrides = + ClassOverrides.findOverrides(pluginLoader.getUberClassLoader()); ScmServletModule main = new ScmServletModule(pluginLoader, overrides); List moduleList = Lists.newArrayList(); @@ -214,6 +243,12 @@ public class ScmContextListener extends GuiceServletContextListener //~--- fields --------------------------------------------------------------- + /** Field description */ + private final ClassLoader parent; + + /** Field description */ + private final Set plugins; + /** Field description */ private Injector globalInjector; diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index dd0c3538a8..d091e39486 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -35,6 +35,7 @@ package sonia.scm; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.Maps; import com.google.inject.Provider; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; @@ -71,7 +72,6 @@ import sonia.scm.plugin.PluginManager; import sonia.scm.repository.DefaultRepositoryManager; import sonia.scm.repository.DefaultRepositoryProvider; import sonia.scm.repository.HealthCheckContextListener; -import sonia.scm.repository.LastModifiedUpdateListener; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryManager; @@ -140,9 +140,7 @@ import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.spi.container.servlet.ServletContainer; -import java.util.HashMap; import java.util.Map; -import java.util.Set; /** * @@ -360,10 +358,11 @@ public class ScmServletModule extends JerseyServletModule bind(TemplateEngineFactory.class); // bind events - bind(LastModifiedUpdateListener.class); - + // bind(LastModifiedUpdateListener.class); + // jersey - Map params = new HashMap(); + Map params = Maps.newHashMap(); + /* * params.put("com.sun.jersey.spi.container.ContainerRequestFilters", * "com.sun.jersey.api.container.filter.LoggingFilter"); @@ -375,13 +374,13 @@ public class ScmServletModule extends JerseyServletModule params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_REDIRECT, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE.toString()); - + /* * TODO remove UriExtensionsConfig and PackagesResourceConfig * to stop jersey classpath scanning */ params.put(ServletContainer.RESOURCE_CONFIG_CLASS, - UriExtensionsConfig.class.getName()); + UriExtensionsConfig.class.getName()); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "unbound"); serve(PATTERN_RESTAPI).with(GuiceContainer.class, params); } diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java new file mode 100644 index 0000000000..8a11d2a43c --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java @@ -0,0 +1,263 @@ +/** + * 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; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Charsets; +import com.google.common.base.Strings; +import com.google.common.io.Resources; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContext; +import sonia.scm.ScmContextListener; +import sonia.scm.plugin.PluginException; +import sonia.scm.plugin.PluginLoadException; +import sonia.scm.plugin.PluginWrapper; +import sonia.scm.plugin.Plugins; +import sonia.scm.util.ClassLoaders; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URL; + +import java.util.List; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * + * @author Sebastian Sdorra + */ +public class BootstrapContextListener implements ServletContextListener +{ + + /** Field description */ + private static final String DIRECTORY_PLUGINS = "plugins"; + + /** Field description */ + private static final String PLUGIN_DIRECTORY = "/WEB-INF/plugins/"; + + /** + * the logger for BootstrapContextListener + */ + private static final Logger logger = + LoggerFactory.getLogger(BootstrapContextListener.class); + + /** Field description */ + private static final String PLUGIN_COREINDEX = + PLUGIN_DIRECTORY.concat("plugin.idx"); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + contextListener.contextDestroyed(sce); + + for (PluginWrapper plugin : contextListener.getPlugins()) + { + ClassLoader pcl = plugin.getClassLoader(); + + if (pcl instanceof Closeable) + { + try + { + ((Closeable) pcl).close(); + } + catch (IOException ex) + { + logger.warn("could not close plugin classloader", ex); + } + } + } + + contextListener = null; + } + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextInitialized(ServletContextEvent sce) + { + ServletContext context = sce.getServletContext(); + List lines = readCorePluginIndex(context); + + File pluginDirectory = getPluginDirectory(); + + copyCorePlugins(context, pluginDirectory, lines); + + ClassLoader cl = + ClassLoaders.getContextClassLoader(BootstrapContextListener.class); + + try + { + Set plugins = Plugins.collectPlugins(cl, + pluginDirectory.toPath()); + + contextListener = new ScmContextListener(cl, plugins); + } + catch (IOException ex) + { + throw new PluginLoadException("could not load plugins", ex); + } + + contextListener.contextInitialized(sce); + } + + /** + * Method description + * + * + * @param context + * @param pluginDirectory + * @param name + * + * @throws IOException + */ + private void copyCorePlugin(ServletContext context, File pluginDirectory, + String name) + throws IOException + { + URL url = context.getResource(PLUGIN_DIRECTORY.concat(name)); + File file = new File(pluginDirectory, name); + + try (OutputStream output = new FileOutputStream(file)) + { + Resources.copy(url, output); + } + } + + /** + * Method description + * + * + * @param context + * @param pluginDirectory + * @param lines + */ + private void copyCorePlugins(ServletContext context, File pluginDirectory, + List lines) + { + IOUtil.mkdirs(pluginDirectory); + + for (String line : lines) + { + line = line.trim(); + + if (!Strings.isNullOrEmpty(line)) + { + try + { + copyCorePlugin(context, pluginDirectory, line); + } + catch (IOException ex) + { + logger.error("could not copy core plugin", ex); + } + } + } + } + + /** + * Method description + * + * + * @param context + * + * @return + */ + private List readCorePluginIndex(ServletContext context) + { + List lines; + + try + { + URL index = context.getResource(PLUGIN_COREINDEX); + + if (index == null) + { + throw new PluginException("no core plugin index found"); + } + + lines = Resources.readLines(index, Charsets.UTF_8); + } + catch (IOException ex) + { + throw new PluginException("could not load core plugin index", ex); + } + + return lines; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private File getPluginDirectory() + { + File baseDirectory = SCMContext.getContext().getBaseDirectory(); + + return new File(baseDirectory, DIRECTORY_PLUGINS); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private ScmContextListener contextListener; +} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java deleted file mode 100644 index d68552db94..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapFilter.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * 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; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -/** - * - * @author Sebastian Sdorra - */ -public class BootstrapFilter implements Filter -{ - - /** Field description */ - public static final String FILTER = "com.google.inject.servlet.GuiceFilter"; - - /** the logger for BootstrapFilter */ - private static final Logger logger = - LoggerFactory.getLogger(BootstrapFilter.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - @Override - public void destroy() - { - ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); - - try - { - if (classLoader != null) - { - Thread.currentThread().setContextClassLoader(classLoader); - } - - logger.debug("destroy guice filter"); - - guiceFilter.destroy(); - } - finally - { - Thread.currentThread().setContextClassLoader(oldClassLoader); - } - } - - /** - * Method description - * - * - * @param request - * @param response - * @param chain - * - * @throws IOException - * @throws ServletException - */ - @Override - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) - throws IOException, ServletException - { - ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); - - try - { - if (classLoader != null) - { - Thread.currentThread().setContextClassLoader(classLoader); - } - - guiceFilter.doFilter(request, response, chain); - } - finally - { - Thread.currentThread().setContextClassLoader(oldClassLoader); - } - } - - /** - * Method description - * - * - * @param filterConfig - * - * @throws ServletException - */ - @Override - public void init(FilterConfig filterConfig) throws ServletException - { - classLoader = - BootstrapUtil.getClassLoader(filterConfig.getServletContext()); - - if (classLoader != null) - { - logger.info("loading GuiceFilter with ScmBootstrapClassLoader"); - Thread.currentThread().setContextClassLoader(classLoader); - guiceFilter = BootstrapUtil.loadClass(classLoader, Filter.class, FILTER); - } - - if (guiceFilter == null) - { - logger.info("fallback to default classloader for GuiceFilter"); - guiceFilter = BootstrapUtil.loadClass(Filter.class, FILTER); - } - - guiceFilter.init(filterConfig); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ClassLoader classLoader; - - /** Field description */ - private Filter guiceFilter; -} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java deleted file mode 100644 index 6658c25b05..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapListener.java +++ /dev/null @@ -1,302 +0,0 @@ -/** - * 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; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.collect.Lists; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.SCMContext; -import sonia.scm.SCMContextProvider; -import sonia.scm.util.ClassLoaders; -import sonia.scm.util.IOUtil; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.Closeable; -import java.io.File; - -import java.net.MalformedURLException; -import java.net.URL; - -import java.util.List; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import javax.xml.bind.JAXB; - -/** - * - * @author Sebastian Sdorra - */ -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"; - - /** the logger for BootstrapListener */ - private static final Logger logger = - LoggerFactory.getLogger(BootstrapListener.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param sce - */ - @Override - public void contextDestroyed(ServletContextEvent sce) - { - if (scmContextListener != null) - { - logger.info("destroy scm context listener"); - scmContextListener.contextDestroyed(sce); - } - - ServletContext servletContext = sce.getServletContext(); - ClassLoader classLoader = BootstrapUtil.getClassLoader(servletContext); - - if (classLoader != null) - { - if (classLoader instanceof Closeable) - { - logger.info("close plugin class loader"); - IOUtil.close((Closeable) classLoader); - } - - logger.debug("remove plugin class loader from servlet context"); - BootstrapUtil.removeClassLoader(servletContext); - } - else - { - logger.debug("plugin class loader is not available"); - } - } - - /** - * Method description - * - * - * @param sce - */ - @Override - public void contextInitialized(ServletContextEvent sce) - { - SCMContextProvider context = SCMContext.getContext(); - - if (logger.isInfoEnabled()) - { - logger.info("start scm-manager {} in stage: {}", context.getVersion(), - context.getStage()); - } - - ClassLoader classLoader = createClassLoader(context); - - if (classLoader != null) - { - if (logger.isInfoEnabled()) - { - logger.info("try to use ScmBootstrapClassLoader"); - } - - scmContextListener = BootstrapUtil.loadClass(classLoader, - ServletContextListener.class, LISTENER); - BootstrapUtil.setClassLoader(sce.getServletContext(), classLoader); - } - - if (scmContextListener == null) - { - if (logger.isWarnEnabled()) - { - logger.warn("fallback to default classloader"); - } - - scmContextListener = - BootstrapUtil.loadClass(ServletContextListener.class, LISTENER); - } - - initializeContext(classLoader, scmContextListener, sce); - } - - /** - * Method description - * - * - * @param context - * - * @return - */ - private ClassLoader createClassLoader(SCMContextProvider context) - { - ClassLoader classLoader = null; - File pluginDirectory = new File(context.getBaseDirectory(), - PLUGIN_DIRECTORY); - - if (pluginDirectory.exists()) - { - File classpathFile = new File(pluginDirectory, PLUGIN_CLASSPATHFILE); - - if (classpathFile.exists()) - { - try - { - Classpath classpath = JAXB.unmarshal(classpathFile, Classpath.class); - - if (classpath != null) - { - classLoader = createClassLoader(pluginDirectory, classpath); - } - else if (logger.isErrorEnabled()) - { - logger.error("classloader is null"); - } - } - catch (Exception ex) - { - logger.error("could not load classpath from plugin folder", ex); - } - } - } - else if (logger.isDebugEnabled()) - { - logger.debug("no plugin directory found"); - } - - return classLoader; - } - - /** - * Method description - * - * - * @param pluginDirectory - * @param classpath - * - * @return - */ - private ClassLoader createClassLoader(File pluginDirectory, - Classpath classpath) - { - if (logger.isDebugEnabled()) - { - logger.debug("create classloader from plugin classpath"); - } - - List classpathURLs = Lists.newLinkedList(); - - for (String path : classpath) - { - if (path.startsWith("/")) - { - path = path.substring(1); - } - - File file = new File(pluginDirectory, path); - - if (file.exists()) - { - try - { - URL url = file.toURI().toURL(); - - if (logger.isDebugEnabled()) - { - logger.debug("append {} to classpath", url.toExternalForm()); - } - - classpathURLs.add(url); - } - catch (MalformedURLException ex) - { - logger.error("could not append url to classpath", ex); - } - } - else if (logger.isErrorEnabled()) - { - logger.error("plugin file {} does not exists", file); - } - } - - return BootstrapUtil.createClassLoader(classpathURLs, - ClassLoaders.getContextClassLoader(BootstrapListener.class)); - } - - /** - * Method description - * - * - * @param classLoader - * @param listener - * @param sce - */ - private void initializeContext(ClassLoader classLoader, - ServletContextListener listener, ServletContextEvent sce) - { - ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); - - try - { - if (classLoader != null) - { - Thread.currentThread().setContextClassLoader(classLoader); - } - - logger.info("initialize scm context listener"); - listener.contextInitialized(sce); - } - finally - { - Thread.currentThread().setContextClassLoader(oldClassLoader); - } - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ServletContextListener scmContextListener; -} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java deleted file mode 100644 index 366d7971ef..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapUtil.java +++ /dev/null @@ -1,254 +0,0 @@ -/** - * 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; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.Strings; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.plugin.ChildFirstPluginClassLoader; -import sonia.scm.plugin.DefaultPluginClassLoader; - -//~--- JDK imports ------------------------------------------------------------ - -import java.net.URL; - -import java.util.List; - -import javax.servlet.ServletContext; - -/** - * - * @author Sebastian Sdorra - */ -public final class BootstrapUtil -{ - - /** Field description */ - public static final String CLASSLOADER = "sonia.scm.BoostrapClassLoader"; - - /** Field description */ - private static final String STRATEGY = - "sonia.scm.plugin.classloader.strategy"; - - /** Field description */ - private static final String STRATEGY_CHILDFIRST = "child-first"; - - /** Field description */ - private static final String STRATEGY_PARENTFIRST = "parent-first"; - - /** the logger for BootstrapUtil */ - private static final Logger logger = - LoggerFactory.getLogger(BootstrapUtil.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - private BootstrapUtil() {} - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param classpathURLs - * @param parent - * - * @return - */ - public static ClassLoader createClassLoader(List classpathURLs, - ClassLoader parent) - { - ClassLoader classLoader = null; - URL[] urls = classpathURLs.toArray(new URL[classpathURLs.size()]); - String strategy = System.getProperty(STRATEGY); - - if (!Strings.isNullOrEmpty(strategy)) - { - if (STRATEGY_CHILDFIRST.equals(strategy)) - { - logger.info("using {} as plugin classloading strategy", - STRATEGY_CHILDFIRST); - classLoader = new ChildFirstPluginClassLoader(urls, parent); - } - else if (!STRATEGY_PARENTFIRST.equals(strategy)) - { - logger.warn("unknown plugin classloading strategy {}", strategy); - } - } - - if (classLoader == null) - { - logger.info("using {} as plugin classloading strategy", - STRATEGY_PARENTFIRST); - classLoader = new DefaultPluginClassLoader(urls, parent); - } - - return classLoader; - } - - /** - * Method description - * - * - * @param classLoader - * @param clazz - * @param - * - * @return - */ - @SuppressWarnings("unchecked") - public static T loadClass(ClassLoader classLoader, Class clazz) - { - T instance = null; - - try - { - instance = (T) classLoader.loadClass(clazz.getName()).newInstance(); - } - catch (Exception ex) - { - logger.error("could not load class ".concat(clazz.getName()), ex); - } - - return instance; - } - - /** - * Method description - * - * - * @param classLoader - * @param clazz - * @param className - * @param - * - * @return - */ - @SuppressWarnings("unchecked") - public static T loadClass(ClassLoader classLoader, Class clazz, - String className) - { - T instance = null; - - try - { - instance = (T) classLoader.loadClass(className).newInstance(); - } - catch (Exception ex) - { - logger.error("could not load class ".concat(className), ex); - } - - return instance; - } - - /** - * Method description - * - * - * - * @param clazz - * @param className - * @param - * - * @return - */ - @SuppressWarnings("unchecked") - public static T loadClass(Class clazz, String className) - { - T instance = null; - - try - { - instance = (T) Class.forName(className).newInstance(); - } - catch (Exception ex) - { - logger.error("could not load class ".concat(className), ex); - } - - return instance; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param context - * - * @return - */ - public static ClassLoader getClassLoader(ServletContext context) - { - return (ClassLoader) context.getAttribute(CLASSLOADER); - } - - //~--- set methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param context - * @param classLoader - */ - public static void setClassLoader(ServletContext context, - ClassLoader classLoader) - { - context.setAttribute(CLASSLOADER, classLoader); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param context - */ - public static void removeClassLoader(ServletContext context) - { - context.removeAttribute(CLASSLOADER); - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java b/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java deleted file mode 100644 index ef15c38000..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/boot/Classpath.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * 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/AbstractDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java deleted file mode 100644 index d448358b64..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java +++ /dev/null @@ -1,155 +0,0 @@ -/** - * 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.Throwables; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.artifact.Artifact; -import org.sonatype.aether.graph.DependencyFilter; -import org.sonatype.aether.graph.DependencyNode; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.List; -import java.util.Set; - -/** - * - * @author Sebastian Sdorra - */ -public abstract class AbstractDependencyFilter implements DependencyFilter -{ - - /** - * the logger for AbstractDependencyFilter - */ - private static final Logger logger = - LoggerFactory.getLogger(AbstractDependencyFilter.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @return - * - * @throws IOException - */ - protected abstract Set loadExcludeSet() throws IOException; - - /** - * Method description - * - * - * @param node - * @param parents - * - * @return - */ - @Override - public boolean accept(DependencyNode node, List parents) - { - boolean result = true; - - if ((node != null) && (node.getDependency() != null)) - { - Artifact artifact = node.getDependency().getArtifact(); - - if (artifact != null) - { - String id = getId(artifact); - - result = !getExludeSet().contains(id); - - if (!result && logger.isDebugEnabled()) - { - logger.debug("exlcude dependency {} because it is blacklisted", id); - } - } - } - - return result; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - private Set getExludeSet() - { - if (exludeSet == null) - { - try - { - exludeSet = loadExcludeSet(); - } - catch (IOException ex) - { - throw Throwables.propagate(ex); - } - } - - return exludeSet; - } - - /** - * Method description - * - * - * @param artifact - * - * @return - */ - private String getId(Artifact artifact) - { - return artifact.getGroupId().concat(":").concat(artifact.getArtifactId()); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private Set exludeSet; -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java b/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java deleted file mode 100644 index 6a27d5758f..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java +++ /dev/null @@ -1,240 +0,0 @@ -/** - * 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.MavenRepositorySystemSession; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.RepositorySystemSession; -import org.sonatype.aether.collection.CollectRequest; -import org.sonatype.aether.collection.DependencyCollectionException; -import org.sonatype.aether.collection.DependencyGraphTransformer; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.graph.DependencyFilter; -import org.sonatype.aether.graph.DependencyNode; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.LocalRepositoryManager; -import org.sonatype.aether.repository.Proxy; -import org.sonatype.aether.repository.RemoteRepository; -import org.sonatype.aether.repository.RepositoryPolicy; -import org.sonatype.aether.resolution.DependencyRequest; -import org.sonatype.aether.resolution.DependencyResolutionException; -import org.sonatype.aether.util.artifact.DefaultArtifact; -import org.sonatype.aether.util.artifact.JavaScopes; -import org.sonatype.aether.util.filter.AndDependencyFilter; -import org.sonatype.aether.util.filter.DependencyFilterUtils; -import org.sonatype.aether.util.graph.transformer - .ChainedDependencyGraphTransformer; -import org.sonatype.aether.util.graph.transformer.ConflictMarker; -import org.sonatype.aether.util.graph.transformer.JavaDependencyContextRefiner; -import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator; -import org.sonatype.aether.util.graph.transformer - .NearestVersionConflictResolver; - -import sonia.scm.config.ScmConfiguration; -import sonia.scm.net.Proxies; - -/** - * - * @author Sebastian Sdorra - */ -public final class Aether -{ - - /** Field description */ - private static final DependencyFilter FILTER = - new AndDependencyFilter( - new CoreDependencyFilter(), - new BlacklistDependencyFilter() - ); - - /** - * the logger for Aether - */ - private static final Logger logger = LoggerFactory.getLogger(Aether.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - private Aether() {} - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param gav - * - * @return - */ - public static Dependency createDependency(String gav) - { - return new Dependency(new DefaultArtifact(gav), JavaScopes.RUNTIME); - } - - /** - * Method description - * - * - * @return - */ - public static DependencyFilter createDependencyFilter() - { - return DependencyFilterUtils.andFilter( - DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME), FILTER); - } - - /** - * Method description - * - * - * @param configuration - * @param pluginRepository - * - * @return - */ - public static RemoteRepository createRemoteRepository( - ScmConfiguration configuration, PluginRepository pluginRepository) - { - RemoteRepository remoteRepository = - new RemoteRepository(pluginRepository.getId(), "default", - pluginRepository.getUrl()); - - if (Proxies.isEnabled(configuration, remoteRepository.getHost())) - { - Proxy proxy = DefaultProxySelector.createProxy(configuration); - - if (logger.isDebugEnabled()) - { - logger.debug("enable proxy {} for {}", proxy.getHost(), - pluginRepository.getUrl()); - } - - remoteRepository.setProxy(proxy); - } - - return remoteRepository; - } - - /** - * Method description - * - * - * @return - */ - public static RepositorySystem createRepositorySystem() - { - return new AetherServiceLocator().getService(RepositorySystem.class); - } - - /** - * Method description - * - * - * @param system - * @param localRepository - * @param configuration - * - * @return - */ - public static RepositorySystemSession createRepositorySystemSession( - RepositorySystem system, LocalRepository localRepository, - ScmConfiguration configuration) - { - MavenRepositorySystemSession session = new MavenRepositorySystemSession(); - - session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN); - - if (configuration.isEnableProxy()) - { - logger.debug("enable proxy selector to collect dependencies"); - session.setProxySelector(new DefaultProxySelector(configuration)); - } - - LocalRepositoryManager localRepositoryManager = - system.newLocalRepositoryManager(localRepository); - - session.setLocalRepositoryManager(localRepositoryManager); - - // create graph transformer to resolve dependency conflicts - //J- - DependencyGraphTransformer dgt = new ChainedDependencyGraphTransformer( - new ConflictMarker(), - new JavaEffectiveScopeCalculator(), - new NearestVersionConflictResolver(), - new JavaDependencyContextRefiner() - ); - //J+ - - session.setDependencyGraphTransformer(dgt); - - return session; - } - - /** - * Method description - * - * - * @param system - * @param session - * @param request - * - * - * @return - * @throws DependencyCollectionException - * @throws DependencyResolutionException - */ - public static DependencyNode resolveDependencies(RepositorySystem system, - RepositorySystemSession session, CollectRequest request) - throws DependencyCollectionException, DependencyResolutionException - { - DependencyNode node = system.collectDependencies(session, - request).getRoot(); - DependencyRequest dr = new DependencyRequest(node, - Aether.createDependencyFilter()); - - system.resolveDependencies(session, dr); - - return node; - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java deleted file mode 100644 index 67bf4e8a40..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java +++ /dev/null @@ -1,197 +0,0 @@ -/** - * 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 org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.RepositorySystemSession; -import org.sonatype.aether.collection.CollectRequest; -import org.sonatype.aether.collection.DependencyCollectionException; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.graph.DependencyNode; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.RemoteRepository; -import org.sonatype.aether.resolution.DependencyResolutionException; -import org.sonatype.aether.util.graph.PreorderNodeListGenerator; - -import sonia.scm.config.ScmConfiguration; - -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - -/** - * - * @author Sebastian Sdorra - */ -public class AetherDependencyResolver -{ - - /** - * the logger for AetherDependencyResolver - */ - private static final Logger logger = - LoggerFactory.getLogger(AetherDependencyResolver.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param configuration - * @param system - * @param localRepository - * @param remoteRepositories - */ - public AetherDependencyResolver(ScmConfiguration configuration, - RepositorySystem system, LocalRepository localRepository, - List remoteRepositories) - { - this.configuration = configuration; - this.system = system; - this.localRepository = localRepository; - this.remoteRepositories = remoteRepositories; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public String createClassPath() - { - PreorderNodeListGenerator nodeListGenerator = - new PreorderNodeListGenerator(); - - for (DependencyNode node : resolvedNodes) - { - node.accept(nodeListGenerator); - } - - return nodeListGenerator.getClassPath(); - } - - /** - * Method description - * - * - * @param dependency - * @param dependencies - * - * @throws DependencyCollectionException - * @throws DependencyResolutionException - */ - public void resolveDependencies(Dependency dependency, - List dependencies) - throws DependencyCollectionException, DependencyResolutionException - { - resolveDependency(new CollectRequest(dependency, dependencies, - remoteRepositories)); - } - - /** - * Method description - * - * - * @param request - * - * @throws DependencyCollectionException - * @throws DependencyResolutionException - */ - private void resolveDependency(CollectRequest request) - throws DependencyCollectionException, DependencyResolutionException - { - DependencyNode node = Aether.resolveDependencies(system, getSession(), - request); - - if (logger.isTraceEnabled()) - { - StringDependencyGraphDumper dumper = new StringDependencyGraphDumper(); - - node.accept(dumper); - logger.trace(dumper.getGraphAsString()); - } - - resolvedNodes.add(node); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - private RepositorySystemSession getSession() - { - if (session == null) - { - session = Aether.createRepositorySystemSession(system, localRepository, - configuration); - } - - return session; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ScmConfiguration configuration; - - /** Field description */ - private LocalRepository localRepository; - - /** Field description */ - private List remoteRepositories; - - /** Field description */ - private List resolvedNodes = Lists.newArrayList(); - - /** Field description */ - private RepositorySystemSession session; - - /** Field description */ - private RepositorySystem system; -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java deleted file mode 100644 index f719ebecfc..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java +++ /dev/null @@ -1,366 +0,0 @@ -/** - * 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 org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.RepositorySystem; -import org.sonatype.aether.graph.Dependency; -import org.sonatype.aether.repository.LocalRepository; -import org.sonatype.aether.repository.RemoteRepository; - -import sonia.scm.ConfigurationException; -import sonia.scm.SCMContextProvider; -import sonia.scm.boot.BootstrapListener; -import sonia.scm.boot.Classpath; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.util.IOUtil; -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.File; - -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; - -/** - * - * @author Sebastian Sdorra - */ -public class AetherPluginHandler -{ - - /** the logger for AetherPluginHandler */ - private static final Logger logger = - LoggerFactory.getLogger(AetherPluginHandler.class); - - /** Field description */ - private static final Object LOCK = new Object(); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * - * @param pluginManager - * @param context - * @param configuration - */ - public AetherPluginHandler(PluginManager pluginManager, - SCMContextProvider context, ScmConfiguration configuration) - { - this.pluginManager = pluginManager; - this.configuration = configuration; - localRepositoryDirectory = new File(context.getBaseDirectory(), - BootstrapListener.PLUGIN_DIRECTORY); - - try - { - jaxbContext = JAXBContext.newInstance(Classpath.class); - } - catch (JAXBException ex) - { - throw new ConfigurationException( - "could not create jaxb context for classpath file", ex); - } - - classpathFile = new File(localRepositoryDirectory, - BootstrapListener.PLUGIN_CLASSPATHFILE); - - if (classpathFile.exists()) - { - try - { - classpath = - (Classpath) jaxbContext.createUnmarshaller().unmarshal(classpathFile); - } - catch (JAXBException ex) - { - logger.error("could not read classpath file", ex); - } - } - - IOUtil.mkdirs(localRepositoryDirectory); - repositorySystem = Aether.createRepositorySystem(); - localRepository = new LocalRepository(localRepositoryDirectory); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param gav - */ - public void install(String gav) - { - synchronized (LOCK) - { - doInstall(gav); - } - } - - /** - * TODO: remove dependencies and remove files - * - * - * - * @param id - */ - public void uninstall(String id) - { - synchronized (LOCK) - { - doUninstall(id); - } - } - - //~--- set methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param repositories - */ - public void setPluginRepositories(Collection repositories) - { - remoteRepositories = Lists.newArrayList(); - - for (PluginRepository repository : repositories) - { - remoteRepositories.add(Aether.createRemoteRepository(configuration, - repository)); - } - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param dependency - * @param dependencies - * @param localDependencies - */ - private void collectDependencies(Dependency dependency, - List localDependencies) - { - try - { - AetherDependencyResolver resolver = - new AetherDependencyResolver(configuration, repositorySystem, - localRepository, remoteRepositories); - - resolver.resolveDependencies(dependency, localDependencies); - - if (classpath == null) - { - classpath = new Classpath(); - } - - Set classpathSet = createClasspathSet(resolver.createClassPath()); - - classpath.setPathSet(classpathSet); - storeClasspath(); - } - catch (Exception ex) - { - throw new PluginException( - "could not collect dependencies or store classpath file", ex); - } - } - - /** - * Method description - * - * - * @param classpathString - * - * @return - */ - private Set createClasspathSet(String classpathString) - { - if (logger.isDebugEnabled()) - { - logger.debug("set new plugin classpath: {}", classpathString); - } - - Set classpathSet = new LinkedHashSet(); - - if (Util.isNotEmpty(classpathString)) - { - String[] classpathParts = classpathString.split(File.pathSeparator); - int prefixLength = localRepositoryDirectory.getAbsolutePath().length(); - - for (String classpathPart : classpathParts) - { - classpathSet.add(classpathPart.substring(prefixLength)); - } - } - - return classpathSet; - } - - /** - * Method description - * - * - * @param gav - */ - private void doInstall(String gav) - { - if (logger.isInfoEnabled()) - { - logger.info("try to install plugin with gav: {}", gav); - } - - Dependency dependency = Aether.createDependency(gav); - List dependencies = getInstalledDependencies(null); - - collectDependencies(dependency, dependencies); - } - - /** - * Method description - * - * - * @param id - */ - private void doUninstall(String id) - { - if (logger.isInfoEnabled()) - { - logger.info("try to uninstall plugin: {}", id); - } - - if (classpath != null) - { - List dependencies = getInstalledDependencies(id); - - collectDependencies(null, dependencies); - } - } - - /** - * Method description - * - * - * @throws JAXBException - */ - private void storeClasspath() throws JAXBException - { - Marshaller marshaller = jaxbContext.createMarshaller(); - - marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - marshaller.marshal(classpath, classpathFile); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * - * @param skipId - * @return - */ - private List getInstalledDependencies(String skipId) - { - List dependencies = Lists.newArrayList(); - Collection installed = - pluginManager.get(new StatePluginPredicate(PluginState.INSTALLED)); - - if (installed != null) - { - for (PluginInformation plugin : installed) - { - String id = plugin.getId(); - - if (Util.isNotEmpty(id) && ((skipId == null) ||!id.equals(skipId))) - { - dependencies.add(Aether.createDependency(id)); - } - } - } - - return dependencies; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private Classpath classpath; - - /** Field description */ - private File classpathFile; - - /** Field description */ - private ScmConfiguration configuration; - - /** Field description */ - private JAXBContext jaxbContext; - - /** Field description */ - private LocalRepository localRepository; - - /** Field description */ - private File localRepositoryDirectory; - - /** Field description */ - private PluginManager pluginManager; - - /** Field description */ - private List remoteRepositories; - - /** Field description */ - private RepositorySystem repositorySystem; -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java deleted file mode 100644 index 79038a4102..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherServiceLocator.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * 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.slf4j.LoggerFactory; - -import org.sonatype.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.sonatype.aether.connector.file.FileRepositoryConnectorFactory; -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.impl.internal.Slf4jLogger; -import org.sonatype.aether.spi.connector.RepositoryConnectorFactory; -import org.sonatype.aether.spi.log.Logger; - -/** - * - * @author Sebastian Sdorra - */ -public class AetherServiceLocator extends DefaultServiceLocator -{ - - /** Field description */ - private static final String LOGGER_NAME = "org.sonatype.aether"; - - /** Field description */ - private static final Slf4jLogger logger = - new Slf4jLogger(LoggerFactory.getLogger(LOGGER_NAME)); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - public AetherServiceLocator() - { - setServices(Logger.class, logger); - addService(VersionResolver.class, DefaultVersionResolver.class); - addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class); - addService(ArtifactDescriptorReader.class, - DefaultArtifactDescriptorReader.class); - addService(RepositoryConnectorFactory.class, - AsyncRepositoryConnectorFactory.class); - addService(RepositoryConnectorFactory.class, - FileRepositoryConnectorFactory.class); - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java deleted file mode 100644 index 528cc19ef5..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * 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; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.Set; - -/** - * - * @author Sebastian Sdorra - */ -public class CoreDependencyFilter extends AbstractDependencyFilter -{ - - /** Field description */ - private static final String CORE_DEPENDENCIES = "/config/dependencies.list"; - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @return - * - * @throws IOException - */ - @Override - protected Set loadExcludeSet() throws IOException - { - return DependencyFilters.loadDependencySet(CORE_DEPENDENCIES); - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java index 0e55355d0b..b7765af570 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java @@ -46,8 +46,6 @@ import com.google.inject.Module; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.util.ClassLoaders; - //~--- JDK imports ------------------------------------------------------------ import java.io.IOException; @@ -83,24 +81,33 @@ public class DefaultPluginLoader implements PluginLoader /** * Constructs ... * + * @param parent + * @param wrappedPlugins */ - public DefaultPluginLoader() + public DefaultPluginLoader(ClassLoader parent, + Set wrappedPlugins) { - ClassLoader classLoader = - ClassLoaders.getContextClassLoader(DefaultPluginLoader.class); + this.uberClassLoader = new UberClassLoader(parent, wrappedPlugins); try { JAXBContext context = JAXBContext.newInstance(ScmModule.class, Plugin.class); - modules = getInstalled(classLoader, context, PATH_MODULECONFIG); - plugins = getInstalled(classLoader, context, PATH_PLUGINCONFIG); + modules = getInstalled(parent, context, PATH_MODULECONFIG); + + // hidden plugins ??? + Set ips = getInstalled(parent, context, PATH_PLUGINCONFIG); + Builder builder = ImmutableSet.builder(); + + builder.addAll(ips); + builder.addAll(Plugins.unwrap(wrappedPlugins)); + plugins = builder.build(); appendExtensions(multiple, single, extensions, modules); appendExtensions(multiple, single, extensions, plugins); } - catch (Exception ex) + catch (IOException | JAXBException ex) { throw Throwables.propagate(ex); } @@ -171,6 +178,18 @@ public class DefaultPluginLoader implements PluginLoader return plugins; } + /** + * Method description + * + * + * @return + */ + @Override + public ClassLoader getUberClassLoader() + { + return uberClassLoader; + } + //~--- methods -------------------------------------------------------------- /** @@ -259,6 +278,9 @@ public class DefaultPluginLoader implements PluginLoader //~--- fields --------------------------------------------------------------- + /** Field description */ + private final ClassLoader uberClassLoader; + /** Field description */ private Set modules; 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 7f60494263..d5638c340a 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -86,6 +86,7 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; /** + * TODO replace aether stuff * * @author Sebastian Sdorra */ @@ -199,7 +200,7 @@ public class DefaultPluginManager implements PluginManager PluginCenter center = getPluginCenter(); - pluginHandler.install(id); + // pluginHandler.install(id); for (PluginInformation plugin : center.getPlugins()) { @@ -248,7 +249,7 @@ public class DefaultPluginManager implements PluginManager throw new PluginConditionFailedException(condition); } - AetherPluginHandler aph = new AetherPluginHandler(this, context, + /*AetherPluginHandler aph = new AetherPluginHandler(this, context, configuration); Collection repositories = Sets.newHashSet(new PluginRepository("package-repository", @@ -256,7 +257,7 @@ public class DefaultPluginManager implements PluginManager aph.setPluginRepositories(repositories); - aph.install(plugin.getInformation().getId()); + aph.install(plugin.getInformation().getId());*/ plugin.getInformation().setState(PluginState.INSTALLED); installedPlugins.put(plugin.getInformation().getId(), plugin); @@ -301,12 +302,12 @@ public class DefaultPluginManager implements PluginManager throw new PluginNotInstalledException(id.concat(" is not install")); } - if (pluginHandler == null) + /*if (pluginHandler == null) { getPluginCenter(); } - pluginHandler.uninstall(id); + pluginHandler.uninstall(id);*/ installedPlugins.remove(id); preparePlugins(getPluginCenter()); } @@ -643,13 +644,13 @@ public class DefaultPluginManager implements PluginManager preparePlugins(center); cache.put(PluginCenter.class.getName(), center); - if (pluginHandler == null) + /*if (pluginHandler == null) { pluginHandler = new AetherPluginHandler(this, SCMContext.getContext(), configuration); } - pluginHandler.setPluginRepositories(center.getRepositories()); + pluginHandler.setPluginRepositories(center.getRepositories());*/ } catch (Exception ex) { @@ -767,9 +768,6 @@ public class DefaultPluginManager implements PluginManager /** Field description */ private final Map installedPlugins; - /** Field description */ - private AetherPluginHandler pluginHandler; - /** Field description */ private Unmarshaller unmarshaller; } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java deleted file mode 100644 index fd3ad16507..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultProxySelector.java +++ /dev/null @@ -1,128 +0,0 @@ -/** - * 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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.sonatype.aether.repository.Authentication; -import org.sonatype.aether.repository.Proxy; -import org.sonatype.aether.repository.ProxySelector; -import org.sonatype.aether.repository.RemoteRepository; - -import sonia.scm.config.ScmConfiguration; -import sonia.scm.util.Util; - -/** - * - * @author Sebastian Sdorra - */ -public class DefaultProxySelector implements ProxySelector -{ - - /** - * the logger for DefaultProxySelector - */ - private static final Logger logger = - LoggerFactory.getLogger(DefaultProxySelector.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param configuration - */ - public DefaultProxySelector(ScmConfiguration configuration) - { - this.configuration = configuration; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * - * @param configuration - * @return - */ - public static Proxy createProxy(ScmConfiguration configuration) - { - Authentication authentication = null; - String username = configuration.getProxyUser(); - String password = configuration.getProxyPassword(); - - if (Util.isNotEmpty(username) || Util.isNotEmpty(password)) - { - authentication = new Authentication(Util.nonNull(username), - Util.nonNull(password)); - } - - return new Proxy(Proxy.TYPE_HTTP, configuration.getProxyServer(), - configuration.getProxyPort(), authentication); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param repository - * - * @return - */ - @Override - public Proxy getProxy(RemoteRepository repository) - { - Proxy proxy = createProxy(configuration); - - if (logger.isDebugEnabled()) - { - logger.debug("enable proxy {} for {}", proxy.getHost(), - repository.getUrl()); - } - - return proxy; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private ScmConfiguration configuration; -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java new file mode 100644 index 0000000000..52fb75b5d7 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java @@ -0,0 +1,467 @@ +/** + * 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.ImmutableSet; +import com.google.common.collect.Sets; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.io.ZipUnArchiver; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.FileNotFoundException; +import java.io.IOException; + +import java.net.URL; + +import java.nio.file.DirectoryStream; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.Files; +import java.nio.file.Path; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +/** + * + * @author Sebastian Sdorra + */ +public final class PluginProcessor +{ + + /** Field description */ + private static final String DESCRIPTOR = "META-INF/scm/plugin.xml"; + + /** Field description */ + private static final String DIRECTORY_CLASSES = "classes"; + + /** Field description */ + private static final String DIRECTORY_DEPENDENCIES = "lib"; + + /** Field description */ + private static final String DIRECTORY_LINK = ".link"; + + /** Field description */ + private static final String DIRECTORY_METAINF = "META-INF"; + + /** Field description */ + private static final String DIRECTORY_WEBINF = "WEB-INF"; + + /** Field description */ + private static final String EXTENSION_PLUGIN = ".smp"; + + /** Field description */ + private static final String GLOB_JAR = "*.jar"; + + /** + * the logger for PluginProcessor + */ + private static final Logger logger = + LoggerFactory.getLogger(PluginProcessor.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param pluginDirectory + */ + public PluginProcessor(Path pluginDirectory) + { + this.pluginDirectory = pluginDirectory; + + try + { + this.context = JAXBContext.newInstance(Plugin.class); + } + catch (JAXBException ex) + { + throw new PluginLoadException("could not create jaxb context", ex); + } + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param parentClassLoader + * @param directory + * + * @return + * + * @throws IOException + */ + private static DefaultPluginClassLoader createClassLoader( + ClassLoader parentClassLoader, Path directory) + throws IOException + { + List urls = new ArrayList<>(); + + Path metaDir = directory.resolve(DIRECTORY_METAINF); + + if (!Files.exists(metaDir)) + { + throw new FileNotFoundException("could not find META-INF directory"); + } + + Path linkDir = directory.resolve(DIRECTORY_LINK); + + if (!Files.exists(linkDir)) + { + Files.createDirectory(linkDir); + } + + Path linkMetaDir = linkDir.resolve(DIRECTORY_METAINF); + + if (!Files.exists(linkMetaDir)) + { + Files.deleteIfExists(linkMetaDir); + Files.createSymbolicLink(linkMetaDir, linkMetaDir.relativize(metaDir)); + } + + urls.add(linkDir.toUri().toURL()); + + Path webinfDir = directory.resolve(DIRECTORY_WEBINF); + + if (Files.exists(webinfDir)) + { + Path classesDir = webinfDir.resolve(DIRECTORY_CLASSES); + + if (Files.exists(classesDir)) + { + urls.add(classesDir.toUri().toURL()); + } + + Path libDir = webinfDir.resolve(DIRECTORY_DEPENDENCIES); + + if (Files.exists(libDir)) + { + for (Path f : Files.newDirectoryStream(libDir, GLOB_JAR)) + { + urls.add(f.toUri().toURL()); + } + } + } + + System.out.println(urls); + + //J- + return new DefaultPluginClassLoader( + urls.toArray(new URL[urls.size()]), + parentClassLoader + ); + //J+ + } + + /** + * Method description + * + * + * @param directory + * @param filter + * + * @return + * + * @throws IOException + */ + private static DirectoryStream stream(Path directory, + Filter filter) + throws IOException + { + return Files.newDirectoryStream(directory, filter); + } + + /** + * Method description + * + * + * @param classLoader + * @return + * + * @throws IOException + */ + public Set collectPlugins(ClassLoader classLoader) + throws IOException + { + logger.info("collect plugins"); + + Set archives = collect(pluginDirectory, new PluginArchiveFilter()); + + if (logger.isDebugEnabled()) + { + logger.debug("extract {} archives", archives.size()); + } + + extract(archives); + + Set directories = collect(pluginDirectory, new DirectoryFilter()); + + if (logger.isDebugEnabled()) + { + logger.debug("process {} directories", directories.size()); + } + + Set pluginWrappers = createPluginWrappers(classLoader, + directories); + + if (logger.isDebugEnabled()) + { + logger.debug("collected {} plugins", pluginWrappers.size()); + } + + return ImmutableSet.copyOf(pluginWrappers); + } + + /** + * Method description + * + * + * @param directory + * @param filter + * + * @return + * + * @throws IOException + */ + private Set collect(Path directory, Filter filter) + throws IOException + { + Set paths; + + try (DirectoryStream stream = stream(directory, filter)) + { + paths = ImmutableSet.copyOf(stream); + } + + return paths; + } + + /** + * Method description + * + * + * + * @param classLoader + * @param descriptor + * + * @return + */ + private Plugin createPlugin(ClassLoader classLoader, Path descriptor) + { + ClassLoader ctxcl = Thread.currentThread().getContextClassLoader(); + + Thread.currentThread().setContextClassLoader(classLoader); + + try + { + return (Plugin) context.createUnmarshaller().unmarshal( + descriptor.toFile()); + } + catch (JAXBException ex) + { + throw new PluginLoadException( + "could not load plugin desriptor ".concat(descriptor.toString()), ex); + } + finally + { + Thread.currentThread().setContextClassLoader(ctxcl); + } + } + + /** + * Method description + * + * + * @param classLoader + * @param directory + * + * @return + * + * @throws IOException + */ + private PluginWrapper createPluginWrapper(ClassLoader classLoader, + Path directory) + throws IOException + { + PluginWrapper wrapper = null; + Path descriptor = directory.resolve(DESCRIPTOR); + + if (Files.exists(descriptor)) + { + ClassLoader cl = createClassLoader(classLoader, directory); + + Plugin plugin = createPlugin(cl, descriptor); + + wrapper = new PluginWrapper(plugin, cl, directory); + } + + return wrapper; + } + + /** + * Method description + * + * + * + * @param classLoader + * @param directories + * + * @return + * + * @throws IOException + */ + private Set createPluginWrappers(ClassLoader classLoader, + Iterable directories) + throws IOException + { + Set plugins = Sets.newHashSet(); + + for (Path directory : directories) + { + PluginWrapper plugin = createPluginWrapper(classLoader, directory); + + if (plugin != null) + { + plugins.add(plugin); + } + } + + return plugins; + } + + /** + * Method description + * + * + * @param archives + * + * @throws IOException + */ + private void extract(Iterable archives) throws IOException + { + logger.debug("extract archives"); + + for (Path archive : archives) + { + logger.trace("extract archive {}", archive); + + String filename = archive.getFileName().toString(); + Path directory = pluginDirectory.resolve(filename.substring(0, + filename.lastIndexOf('.'))); + + IOUtil.extract(archive.toFile(), directory.toFile(), + ZipUnArchiver.EXTENSION); + Files.delete(archive); + } + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 14/06/04 + * @author Enter your name here... + */ + private static class DirectoryFilter implements DirectoryStream.Filter + { + + /** + * Method description + * + * + * @param entry + * + * @return + * + * @throws IOException + */ + @Override + public boolean accept(Path entry) throws IOException + { + return Files.isDirectory(entry); + } + } + + + /** + * Class description + * + * + * @version Enter version here..., 14/06/04 + * @author Enter your name here... + */ + private static class PluginArchiveFilter + implements DirectoryStream.Filter + { + + /** + * Method description + * + * + * @param entry + * + * @return + * + * @throws IOException + */ + @Override + public boolean accept(Path entry) throws IOException + { + return Files.isRegularFile(entry) + && entry.getFileName().toString().endsWith(EXTENSION_PLUGIN); + } + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private final JAXBContext context; + + /** Field description */ + private final Path pluginDirectory; +} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java b/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java new file mode 100644 index 0000000000..d27f01645d --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java @@ -0,0 +1,106 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + + + +package sonia.scm.plugin; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.nio.file.Path; + +import java.util.Set; + +import javax.servlet.ServletContext; + +/** + * + * @author Sebastian Sdorra + */ +public final class Plugins +{ + + /** Field description */ + private static final String CONTEXT_VAR = "sonia.scm.plugins"; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + */ + private Plugins() {} + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param classLoader + * @param directory + * + * @return + * + * @throws IOException + */ + public static Set collectPlugins(ClassLoader classLoader, + Path directory) + throws IOException + { + PluginProcessor processor = new PluginProcessor(directory); + + return processor.collectPlugins(classLoader); + } + + /** + * Method description + * + * + * @param wrapped + * + * @return + */ + public static Iterable unwrap(Iterable wrapped) + { + return Iterables.transform(wrapped, new Unwrap()); + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 14/06/05 + * @author Enter your name here... + */ + private static class Unwrap implements Function + { + + /** + * Method description + * + * + * @param wrapper + * + * @return + */ + @Override + public Plugin apply(PluginWrapper wrapper) + { + return wrapper.getPlugin(); + } + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java b/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java deleted file mode 100644 index 5bfcdebd23..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/plugin/StringDependencyGraphDumper.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * 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.graph.DependencyNode; -import org.sonatype.aether.graph.DependencyVisitor; - -/** - * - * @author Sebastian Sdorra - */ -public class StringDependencyGraphDumper implements DependencyVisitor -{ - - /** Field description */ - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - public void reset() - { - buffer = new StringBuilder(); - } - - /** - * Method description - * - * - * @param node - * - * @return - */ - @Override - public boolean visitEnter(DependencyNode node) - { - buffer.append(currentIndent).append(node).append(LINE_SEPARATOR); - - if (currentIndent.length() <= 0) - { - currentIndent = "+- "; - } - else - { - currentIndent = "| " + currentIndent; - } - - return true; - } - - /** - * Method description - * - * - * @param node - * - * @return - */ - @Override - public boolean visitLeave(DependencyNode node) - { - currentIndent = currentIndent.substring(3, currentIndent.length()); - - return true; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public String getGraphAsString() - { - return buffer.toString(); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private StringBuilder buffer = new StringBuilder(); - - /** Field description */ - private String currentIndent = ""; -} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/UberClassLoader.java b/scm-webapp/src/main/java/sonia/scm/plugin/UberClassLoader.java new file mode 100644 index 0000000000..6906afc7d4 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/UberClassLoader.java @@ -0,0 +1,202 @@ +/** + * 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.Maps; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.lang.ref.WeakReference; + +import java.net.URL; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.ConcurrentMap; + +/** + * {@link ClassLoader} which is able to load classes and resources from all + * plugins. + * + * @author Sebastian Sdorra + */ +public final class UberClassLoader extends ClassLoader +{ + + /** + * Constructs ... + * + * + * @param parent + * @param plugins + */ + public UberClassLoader(ClassLoader parent, Iterable plugins) + { + super(parent); + this.plugins = plugins; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * + * @return + * + * @throws ClassNotFoundException + */ + @Override + protected Class findClass(String name) throws ClassNotFoundException + { + Class clazz = getFromCache(name); + + if (clazz == null) + { + for (PluginWrapper plugin : plugins) + { + ClassLoader cl = plugin.getClassLoader(); + + // load class could be slow, perhaps we should call + // find class via reflection ??? + clazz = cl.loadClass(name); + + if (clazz != null) + { + cache.put(name, new WeakReference>(clazz)); + + break; + } + } + } + + return clazz; + } + + /** + * Method description + * + * + * @param name + * + * @return + */ + @Override + protected URL findResource(String name) + { + URL url = null; + + for (PluginWrapper plugin : plugins) + { + ClassLoader cl = plugin.getClassLoader(); + + url = cl.getResource(name); + + if (url != null) + { + break; + } + } + + return url; + } + + /** + * Method description + * + * + * @param name + * + * @return + * + * @throws IOException + */ + @Override + protected Enumeration findResources(String name) throws IOException + { + List urls = Lists.newArrayList(); + + for (PluginWrapper plugin : plugins) + { + ClassLoader cl = plugin.getClassLoader(); + + urls.addAll(Collections.list(cl.getResources(name))); + } + + return Collections.enumeration(urls); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * + * @return + */ + private Class getFromCache(String name) + { + Class clazz = null; + WeakReference> ref = cache.get(name); + + if (ref != null) + { + clazz = ref.get(); + + if (clazz == null) + { + cache.remove(name); + } + } + + return clazz; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private final ConcurrentMap>> cache = + Maps.newConcurrentMap(); + + /** Field description */ + private final Iterable plugins; +} diff --git a/scm-webapp/src/main/java/sonia/scm/resources/AbstractResource.java b/scm-webapp/src/main/java/sonia/scm/resources/AbstractResource.java index 6fc79b543f..b3b7facb34 100644 --- a/scm-webapp/src/main/java/sonia/scm/resources/AbstractResource.java +++ b/scm-webapp/src/main/java/sonia/scm/resources/AbstractResource.java @@ -30,6 +30,7 @@ */ + package sonia.scm.resources; //~--- non-JDK imports -------------------------------------------------------- @@ -37,7 +38,7 @@ package sonia.scm.resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.boot.BootstrapUtil; +import sonia.scm.plugin.PluginLoader; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; @@ -72,14 +73,16 @@ public abstract class AbstractResource implements Resource * * * @param servletContext + * @param pluginLoader * @param resources * @param resourceHandlers */ public AbstractResource(ServletContext servletContext, - List resources, - List resourceHandlers) + PluginLoader pluginLoader, List resources, + List resourceHandlers) { this.servletContext = servletContext; + this.pluginLoader = pluginLoader; this.resources = resources; this.resourceHandlers = resourceHandlers; } @@ -128,7 +131,7 @@ public abstract class AbstractResource implements Resource * @throws IOException */ private void appendResource(OutputStream stream, String resource) - throws IOException + throws IOException { InputStream input = getResourceAsStream(resource); @@ -152,7 +155,7 @@ public abstract class AbstractResource implements Resource * @throws IOException */ private void appendResource(InputStream input, OutputStream stream) - throws IOException + throws IOException { if (input != null) { @@ -180,7 +183,7 @@ public abstract class AbstractResource implements Resource private InputStream getResourceAsStream(String resource) { InputStream input = null; - ClassLoader classLoader = BootstrapUtil.getClassLoader(servletContext); + ClassLoader classLoader = pluginLoader.getUberClassLoader(); if (classLoader != null) { @@ -204,6 +207,9 @@ public abstract class AbstractResource implements Resource //~--- fields --------------------------------------------------------------- + /** Field description */ + private final PluginLoader pluginLoader; + /** Field description */ protected List resourceHandlers; diff --git a/scm-webapp/src/main/java/sonia/scm/resources/DefaultResource.java b/scm-webapp/src/main/java/sonia/scm/resources/DefaultResource.java index b2906e4fbf..f88f6a407c 100644 --- a/scm-webapp/src/main/java/sonia/scm/resources/DefaultResource.java +++ b/scm-webapp/src/main/java/sonia/scm/resources/DefaultResource.java @@ -46,6 +46,7 @@ import java.io.OutputStream; import java.util.List; import javax.servlet.ServletContext; +import sonia.scm.plugin.PluginLoader; /** * @@ -65,12 +66,12 @@ public class DefaultResource extends AbstractResource * * @throws IOException */ - public DefaultResource(ServletContext servletContext, List resources, + public DefaultResource(ServletContext servletContext, PluginLoader pluginLoader, List resources, List resourceHandlers, ResourceType type) throws IOException { - super(servletContext, resources, resourceHandlers); + super(servletContext, pluginLoader, resources, resourceHandlers); this.type = type; ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/scm-webapp/src/main/java/sonia/scm/resources/DefaultResourceManager.java b/scm-webapp/src/main/java/sonia/scm/resources/DefaultResourceManager.java index 854cb405b0..4e5c99c98d 100644 --- a/scm-webapp/src/main/java/sonia/scm/resources/DefaultResourceManager.java +++ b/scm-webapp/src/main/java/sonia/scm/resources/DefaultResourceManager.java @@ -30,10 +30,12 @@ */ + package sonia.scm.resources; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.Lists; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -46,7 +48,6 @@ import sonia.scm.plugin.PluginLoader; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -79,8 +80,7 @@ public class DefaultResourceManager extends AbstractResourceManager */ @Inject public DefaultResourceManager(ServletContext servletContext, - PluginLoader pluginLoader, - Set resourceHandlers) + PluginLoader pluginLoader, Set resourceHandlers) { super(servletContext, pluginLoader, resourceHandlers); } @@ -100,12 +100,12 @@ public class DefaultResourceManager extends AbstractResourceManager try { - Resource resource = new DefaultResource(servletContext, resources, - new ArrayList(resourceHandlers), + Resource resource = new DefaultResource(servletContext, pluginLoader, + resources, Lists.newArrayList(resourceHandlers), ResourceType.SCRIPT); resourceMap.put(new ResourceKey(resource.getName(), ResourceType.SCRIPT), - resource); + resource); } catch (IOException ex) { diff --git a/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResource.java b/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResource.java index 0050d2d360..13184d9d17 100644 --- a/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResource.java +++ b/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResource.java @@ -30,10 +30,12 @@ */ + package sonia.scm.resources; //~--- non-JDK imports -------------------------------------------------------- +import sonia.scm.plugin.PluginLoader; import sonia.scm.util.HttpUtil; //~--- JDK imports ------------------------------------------------------------ @@ -58,17 +60,17 @@ public class DevelopmentResource extends AbstractResource * * * @param servletContext + * @param pluginLoader * @param resources * @param resourceHandlers * @param name * @param type */ public DevelopmentResource(ServletContext servletContext, - List resources, - List resourceHandlers, - String name, ResourceType type) + PluginLoader pluginLoader, List resources, + List resourceHandlers, String name, ResourceType type) { - super(servletContext, resources, resourceHandlers); + super(servletContext, pluginLoader, resources, resourceHandlers); this.type = type; if (name.startsWith(HttpUtil.SEPARATOR_PATH)) diff --git a/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResourceManager.java b/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResourceManager.java index 1788c6d76d..114295626d 100644 --- a/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResourceManager.java +++ b/scm-webapp/src/main/java/sonia/scm/resources/DevelopmentResourceManager.java @@ -30,6 +30,7 @@ */ + package sonia.scm.resources; //~--- non-JDK imports -------------------------------------------------------- @@ -72,8 +73,7 @@ public class DevelopmentResourceManager extends AbstractResourceManager */ @Inject public DevelopmentResourceManager(ServletContext servletContext, - PluginLoader pluginLoader, - Set resourceHandlers) + PluginLoader pluginLoader, Set resourceHandlers) { super(servletContext, pluginLoader, resourceHandlers); } @@ -94,12 +94,12 @@ public class DevelopmentResourceManager extends AbstractResourceManager for (String script : scripts) { - Resource resource = new DevelopmentResource(servletContext, + Resource resource = new DevelopmentResource(servletContext, pluginLoader, Arrays.asList(script), Collections.EMPTY_LIST, script, ResourceType.SCRIPT); resourceMap.put(new ResourceKey(resource.getName(), ResourceType.SCRIPT), - resource); + resource); } for (ResourceHandler handler : resourceHandlers) @@ -113,9 +113,9 @@ public class DevelopmentResourceManager extends AbstractResourceManager name = PREFIX_HANDLER.concat(name); resourceMap.put(new ResourceKey(name, ResourceType.SCRIPT), - new DevelopmentResource(servletContext, - Collections.EMPTY_LIST, Arrays.asList(handler), name, - ResourceType.SCRIPT)); + new DevelopmentResource(servletContext, pluginLoader, + Collections.EMPTY_LIST, Arrays.asList(handler), name, + ResourceType.SCRIPT)); } } } diff --git a/scm-webapp/src/main/webapp/WEB-INF/web.xml b/scm-webapp/src/main/webapp/WEB-INF/web.xml index b8a21e834f..ea7311f05b 100644 --- a/scm-webapp/src/main/webapp/WEB-INF/web.xml +++ b/scm-webapp/src/main/webapp/WEB-INF/web.xml @@ -38,12 +38,12 @@ metadata-complete="true"> - sonia.scm.boot.BootstrapListener + sonia.scm.boot.BootstrapContextListener guiceFilter - sonia.scm.boot.BootstrapFilter + com.google.inject.servlet.GuiceFilter