diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a6e58bee3..4beb9f22a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added - Add iconStyle + onClick option and story shot for icon component ([#1100](https://github.com/scm-manager/scm-manager/pull/1100)) +- Making WebElements (Servlet or Filter) optional by using the `@Requires` annotation ([#1101](https://github.com/scm-manager/scm-manager/pull/1101)) ### Changed - Removed the `requires` attribute on the `@Extension` annotation and instead create a new `@Requires` annotation ([#1097](https://github.com/scm-manager/scm-manager/pull/1097)) diff --git a/scm-core/src/main/java/sonia/scm/plugin/ClassElement.java b/scm-core/src/main/java/sonia/scm/plugin/ClassElement.java index 36855e932a..b439f80545 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/ClassElement.java +++ b/scm-core/src/main/java/sonia/scm/plugin/ClassElement.java @@ -26,6 +26,7 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -43,12 +44,12 @@ import java.util.Set; * @since 2.0.0 */ @Getter -@NoArgsConstructor @AllArgsConstructor @ToString @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) -public final class ClassElement { +@NoArgsConstructor(access = AccessLevel.PACKAGE) +public class ClassElement { @XmlElement(name = "class") private String clazz; private String description; diff --git a/scm-core/src/main/java/sonia/scm/plugin/ExtensionProcessor.java b/scm-core/src/main/java/sonia/scm/plugin/ExtensionProcessor.java index 4901998109..0fe06f1764 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/ExtensionProcessor.java +++ b/scm-core/src/main/java/sonia/scm/plugin/ExtensionProcessor.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- @@ -76,5 +76,5 @@ public interface ExtensionProcessor * * @return collected web elements */ - public Iterable getWebElements(); + public Iterable getWebElements(); } diff --git a/scm-core/src/main/java/sonia/scm/plugin/WebElementDescriptor.java b/scm-core/src/main/java/sonia/scm/plugin/WebElementDescriptor.java index e9f3cc1410..d5dabb9698 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/WebElementDescriptor.java +++ b/scm-core/src/main/java/sonia/scm/plugin/WebElementDescriptor.java @@ -21,155 +21,60 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; import sonia.scm.xml.XmlArrayStringAdapter; -//~--- JDK imports ------------------------------------------------------------ - -import java.util.Arrays; -import java.util.Objects; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.Arrays; /** - * Descriptor for web elements such as filter or servlets. A web element can be registered by using the + * Descriptor for web elements such as filter or servlets. A web element can be registered by using the * {@link sonia.scm.filter.WebElement} annotation. - * + * * @author Sebastian Sdorra * @since 2.0.0 */ +@Getter +@ToString +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) @XmlRootElement(name = "web-element") @XmlAccessorType(XmlAccessType.FIELD) -public final class WebElementDescriptor -{ +@NoArgsConstructor(access = AccessLevel.PACKAGE) +public final class WebElementDescriptor extends ClassElement { - /** - * Constructs ... - * - */ - WebElementDescriptor() {} - - /** - * Constructs ... - * - * - * @param clazz - * @param pattern - * @param morePatterns - * @param regex - */ - public WebElementDescriptor(Class clazz, String pattern, - String[] morePatterns, boolean regex) - { - this.clazz = clazz; - this.pattern = pattern; - this.morePatterns = morePatterns; - this.regex = regex; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public Class getClazz() - { - return clazz; - } - - /** - * Method description - * - * - * @return - */ - public String[] getMorePatterns() - { - String[] patterns; - - if (morePatterns != null) - { - patterns = Arrays.copyOf(morePatterns, morePatterns.length); - } - else - { - patterns = new String[0]; - } - - return patterns; - } - - /** - * Method description - * - * - * @return - */ - public String getPattern() - { - return pattern; - } - - /** - * Method description - * - * - * @return - */ - public boolean isRegex() - { - return regex; - } - - @Override - public int hashCode() { - return Objects.hash(clazz, pattern, Arrays.hashCode(morePatterns), regex); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - - final WebElementDescriptor other = (WebElementDescriptor) obj; - return Objects.equals(clazz, other.clazz) - && Objects.equals(pattern, other.pattern) - && Arrays.equals(morePatterns, other.morePatterns) - && this.regex == other.regex; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - @XmlElement(name = "class") - private Class clazz; - - /** Field description */ - @XmlJavaTypeAdapter(XmlArrayStringAdapter.class) - private String[] morePatterns; - - /** Field description */ @XmlElement(name = "value") private String pattern; - /** Field description */ + @XmlJavaTypeAdapter(XmlArrayStringAdapter.class) + private String[] morePatterns = {}; + private boolean regex = false; + + public String[] getMorePatterns() { + String[] patterns; + if (morePatterns != null) { + patterns = Arrays.copyOf(morePatterns, morePatterns.length); + } else { + patterns = new String[0]; + } + return patterns; + } + } + + diff --git a/scm-core/src/main/java/sonia/scm/plugin/WebElementExtension.java b/scm-core/src/main/java/sonia/scm/plugin/WebElementExtension.java new file mode 100644 index 0000000000..e3a83b6853 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/plugin/WebElementExtension.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.plugin; + +import lombok.Value; + +/** + * WebElementExtension can be a servlet or filter which is ready to bind. + * Those extensions are loaded by the {@link ExtensionProcessor} from a {@link WebElementDescriptor}. + * + * We don't know if we can load the defined class from the descriptor, because the class could be optional + * (annotated with {@link Requires}). So we have to load the class as string with {@link WebElementDescriptor} and when + * we know that it is safe to load the class (all requirements are fulfilled), we will create our WebElementExtension. + * + * @since 2.0.0 + */ +@Value +public class WebElementExtension { + Class clazz; + WebElementDescriptor descriptor; +} diff --git a/scm-core/src/test/java/sonia/scm/plugin/WebElementDescriptorTest.java b/scm-core/src/test/java/sonia/scm/plugin/WebElementDescriptorTest.java new file mode 100644 index 0000000000..bbbefb1dcd --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/plugin/WebElementDescriptorTest.java @@ -0,0 +1,77 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.plugin; + +import org.junit.jupiter.api.Test; + +import javax.xml.bind.JAXB; + +import java.io.StringReader; + +import static org.assertj.core.api.Assertions.assertThat; + +class WebElementDescriptorTest { + + private static final String XML_1 = String.join("\n", + "", + " com.hitchhiker.SpaceShip", + " /space/*", + " false", + " /ship/*,/star/*", + " scm-magrathea-plugin", + " scm-earth-plugin", + "" + ); + private static final String XML_2 = String.join("\n", + "", + " com.hitchhiker.SpaceShip", + " /space/.*", + " true", + "" + ); + + @Test + void shouldUnmarshall() { + WebElementDescriptor descriptor = unmarshal(XML_1); + assertThat(descriptor.getClazz()).isEqualTo("com.hitchhiker.SpaceShip"); + assertThat(descriptor.getPattern()).isEqualTo("/space/*"); + assertThat(descriptor.getMorePatterns()).containsExactly("/ship/*", "/star/*"); + assertThat(descriptor.isRegex()).isFalse(); + assertThat(descriptor.getRequires()).containsExactlyInAnyOrder("scm-magrathea-plugin", "scm-earth-plugin"); + } + + @Test + void shouldUnmarshallWithoutMorePatterns() { + WebElementDescriptor descriptor = unmarshal(XML_2); + assertThat(descriptor.getClazz()).isEqualTo("com.hitchhiker.SpaceShip"); + assertThat(descriptor.getMorePatterns()).isEmpty(); + assertThat(descriptor.isRegex()).isTrue(); + } + + private WebElementDescriptor unmarshal(String content) { + return JAXB.unmarshal(new StringReader(content), WebElementDescriptor.class); + } + +} diff --git a/scm-webapp/src/main/java/sonia/scm/filter/TypedWebElementDescriptor.java b/scm-webapp/src/main/java/sonia/scm/filter/TypedWebElementDescriptor.java index 4a69c7540c..c3ef626f5c 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/TypedWebElementDescriptor.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/TypedWebElementDescriptor.java @@ -21,11 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.filter; -import java.util.Objects; - +import lombok.Value; import sonia.scm.plugin.WebElementDescriptor; /** @@ -34,48 +33,8 @@ import sonia.scm.plugin.WebElementDescriptor; * @param * @since 2.0.0 */ -public final class TypedWebElementDescriptor -{ - private final Class clazz; - private final WebElementDescriptor descriptor; - - public TypedWebElementDescriptor(Class clazz, - WebElementDescriptor descriptor) - { - this.clazz = clazz; - this.descriptor = descriptor; - } - - public Class getClazz() - { - return clazz; - } - - public WebElementDescriptor getDescriptor() - { - return descriptor; - } - - @Override - public int hashCode() { - return Objects.hash(clazz, descriptor); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - - final TypedWebElementDescriptor other = (TypedWebElementDescriptor) obj; - return Objects.equals(clazz, other.clazz) - && Objects.equals(descriptor, other.descriptor); - } - +@Value +public class TypedWebElementDescriptor { + Class clazz; + WebElementDescriptor descriptor; } diff --git a/scm-webapp/src/main/java/sonia/scm/filter/WebElementCollector.java b/scm-webapp/src/main/java/sonia/scm/filter/WebElementCollector.java index 90a45cc6c8..d37a2e90c5 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/WebElementCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/WebElementCollector.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.filter; //~--- non-JDK imports -------------------------------------------------------- @@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.Priorities; import sonia.scm.plugin.PluginLoader; -import sonia.scm.plugin.WebElementDescriptor; +import sonia.scm.plugin.WebElementExtension; //~--- JDK imports ------------------------------------------------------------ @@ -67,25 +67,24 @@ public final class WebElementCollector * @param elements */ @SuppressWarnings("unchecked") - private WebElementCollector(Iterable elements) + private WebElementCollector(Iterable elements) { - List> fl = Lists.newArrayList(); - List> sl = - Lists.newArrayList(); + List> fl = Lists.newArrayList(); + List> sl = Lists.newArrayList(); - for (WebElementDescriptor element : elements) + for (WebElementExtension element : elements) { if (Filter.class.isAssignableFrom(element.getClazz())) { fl.add( new TypedWebElementDescriptor<>( - (Class) element.getClazz(), element)); + (Class) element.getClazz(), element.getDescriptor())); } else if (Servlet.class.isAssignableFrom(element.getClazz())) { sl.add( new TypedWebElementDescriptor<>( - (Class) element.getClazz(), element)); + (Class) element.getClazz(), element.getDescriptor())); } else { @@ -95,8 +94,7 @@ public final class WebElementCollector } } - TypedWebElementDescriptorOrdering ordering = - new TypedWebElementDescriptorOrdering(); + TypedWebElementDescriptorOrdering ordering = new TypedWebElementDescriptorOrdering(); filters = ordering.immutableSortedCopy(fl); servlets = ordering.immutableSortedCopy(sl); @@ -126,7 +124,7 @@ public final class WebElementCollector * * @return */ - public Iterable> getFilters() + public Iterable> getFilters() { return filters; } @@ -137,7 +135,7 @@ public final class WebElementCollector * * @return */ - public Iterable> getServlets() + public Iterable> getServlets() { return servlets; } @@ -177,8 +175,8 @@ public final class WebElementCollector //~--- fields --------------------------------------------------------------- /** Field description */ - private final Iterable> filters; + private final Iterable> filters; /** Field description */ - private final Iterable> servlets; + private final Iterable> servlets; } diff --git a/scm-webapp/src/main/java/sonia/scm/filter/WebElementModule.java b/scm-webapp/src/main/java/sonia/scm/filter/WebElementModule.java index 482deb063b..eb5f2c1cc8 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/WebElementModule.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/WebElementModule.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.filter; //~--- non-JDK imports -------------------------------------------------------- @@ -44,60 +44,36 @@ import javax.servlet.http.HttpServlet; * * @author Sebastian Sdorra */ -public class WebElementModule extends ServletModule -{ +public class WebElementModule extends ServletModule { /** * the logger for WebElementModule */ - private static final Logger logger = - LoggerFactory.getLogger(WebElementModule.class); + private static final Logger LOG = LoggerFactory.getLogger(WebElementModule.class); - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param pluginLoader - */ public WebElementModule(PluginLoader pluginLoader) { collector = WebElementCollector.collect(pluginLoader); } - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ @Override protected void configureServlets() { - for (TypedWebElementDescriptor f : collector.getFilters()) + for (TypedWebElementDescriptor f : collector.getFilters()) { bindFilter(f); } - for (TypedWebElementDescriptor s : - collector.getServlets()) + for (TypedWebElementDescriptor s : collector.getServlets()) { bindServlet(s); } } - /** - * Method description - * - * - * @param filter - */ - private void bindFilter(TypedWebElementDescriptor filter) - { - Class clazz = filter.getClazz(); + private void bindFilter(TypedWebElementDescriptor filter) { + Class clazz = filter.getClazz(); - logger.info("bind filter {} to filter chain", clazz); + LOG.info("bind filter {} to filter chain", clazz); // filters must be in singleton scope bind(clazz).in(Scopes.SINGLETON); @@ -105,12 +81,13 @@ public class WebElementModule extends ServletModule WebElementDescriptor opts = filter.getDescriptor(); FilterKeyBindingBuilder builder; - if (opts.isRegex()) - { + if (opts.isRegex()) { + LOG.debug("bind regex filter {} to {} and {}", clazz, opts.getPattern(), opts.getMorePatterns()); builder = filterRegex(opts.getPattern(), opts.getMorePatterns()); } else { + LOG.debug("bind glob filter {} to {} and {}", clazz, opts.getPattern(), opts.getMorePatterns()); builder = filter(opts.getPattern(), opts.getMorePatterns()); } @@ -118,18 +95,10 @@ public class WebElementModule extends ServletModule builder.through(clazz); } - /** - * Method description - * - * - * @param servlet - */ - private void bindServlet( - TypedWebElementDescriptor servlet) - { - Class clazz = servlet.getClazz(); + private void bindServlet(TypedWebElementDescriptor servlet) { + Class clazz = servlet.getClazz(); - logger.info("bind servlet {} to servlet chain", clazz); + LOG.info("bind servlet {} to servlet chain", clazz); // filters must be in singleton scope bind(clazz).in(Scopes.SINGLETON); @@ -137,12 +106,11 @@ public class WebElementModule extends ServletModule WebElementDescriptor opts = servlet.getDescriptor(); ServletKeyBindingBuilder builder; - if (opts.isRegex()) - { + if (opts.isRegex()) { + LOG.debug("bind regex servlet {} to {} and {}", clazz, opts.getPattern(), opts.getMorePatterns()); builder = serveRegex(opts.getPattern(), opts.getMorePatterns()); - } - else - { + } else { + LOG.debug("bind glob servlet {} to {} and {}", clazz, opts.getPattern(), opts.getMorePatterns()); builder = serve(opts.getPattern(), opts.getMorePatterns()); } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java index 715dad4d69..ba83f5faea 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.lifecycle.modules; import com.fasterxml.jackson.databind.ObjectMapper; @@ -193,7 +193,7 @@ class ScmServletModule extends ServletModule { // bind sslcontext provider bind(SSLContext.class).toProvider(SSLContextProvider.class); - + // bind ahc Multibinder transformers = Multibinder.newSetBinder(binder(), ContentTransformer.class); @@ -207,7 +207,7 @@ class ScmServletModule extends ServletModule { // bind new hook api bind(HookContextFactory.class); bind(HookEventFacade.class); - + // bind user-agent parser bind(UserAgentParser.class); @@ -215,7 +215,7 @@ class ScmServletModule extends ServletModule { if ("true".equalsIgnoreCase(System.getProperty(SYSTEM_PROPERTY_DEBUG_HTTP))) { filter(PATTERN_ALL).through(LoggingFilter.class); } - + // debug servlet serve(PATTERN_DEBUG).with(DebugServlet.class); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultExtensionProcessor.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultExtensionProcessor.java index 1b96f3b4bf..6cc7deed77 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultExtensionProcessor.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultExtensionProcessor.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- @@ -115,7 +115,7 @@ public class DefaultExtensionProcessor implements ExtensionProcessor * @return */ @Override - public Iterable getWebElements() + public Iterable getWebElements() { return collector.getWebElements(); } 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 77f6b392b9..90f349a3b1 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginLoader.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- @@ -29,25 +29,17 @@ package sonia.scm.plugin; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; -import com.google.common.collect.Iterables; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -//~--- JDK imports ------------------------------------------------------------ +import javax.servlet.ServletContext; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; import java.io.IOException; - import java.net.URL; - import java.util.Collection; import java.util.Enumeration; import java.util.Set; -import javax.servlet.ServletContext; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; +//~--- JDK imports ------------------------------------------------------------ /** * @@ -62,10 +54,6 @@ public class DefaultPluginLoader implements PluginLoader /** Field description */ public static final String PATH_PLUGINCONFIG = "META-INF/scm/plugin.xml"; - /** the logger for DefaultPluginLoader */ - private static final Logger logger = - LoggerFactory.getLogger(DefaultPluginLoader.class); - //~--- constructors --------------------------------------------------------- /** @@ -90,7 +78,7 @@ public class DefaultPluginLoader implements PluginLoader modules = getInstalled(parent, context, PATH_MODULECONFIG); - collector = new ExtensionCollector(parent, modules, installedPlugins); + ExtensionCollector collector = new ExtensionCollector(parent, modules, installedPlugins); extensionProcessor = new DefaultExtensionProcessor(collector); } catch (IOException | JAXBException ex) @@ -198,9 +186,6 @@ public class DefaultPluginLoader implements PluginLoader //~--- fields --------------------------------------------------------------- - /** Field description */ - private final ExtensionCollector collector; - /** Field description */ private final ExtensionProcessor extensionProcessor; diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/ExtensionCollector.java b/scm-webapp/src/main/java/sonia/scm/plugin/ExtensionCollector.java index 99a87f5814..2d2b11ebdb 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/ExtensionCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/ExtensionCollector.java @@ -21,22 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -//~--- JDK imports ------------------------------------------------------------ - import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -45,6 +42,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -63,6 +62,7 @@ public final class ExtensionCollector for (ScmModule module : modules) { collectRootElements(moduleClassLoader, module); } + for (InstalledPlugin plugin : installedPlugins) { collectRootElements(plugin.getClassLoader(), plugin.getDescriptor()); } @@ -98,7 +98,7 @@ public final class ExtensionCollector if (collection == null) { - collection = Collections.EMPTY_SET; + collection = Collections.emptySet(); } return collection; @@ -123,7 +123,7 @@ public final class ExtensionCollector } else { - exts = Collections.EMPTY_SET; + exts = Collections.emptySet(); } return exts; @@ -218,7 +218,7 @@ public final class ExtensionCollector * * @return */ - public Set getWebElements() + public Set getWebElements() { return webElements; } @@ -272,6 +272,17 @@ public final class ExtensionCollector return classes; } + private Set collectWebElementExtensions(ClassLoader defaultClassLoader, Iterable descriptors) { + Set webElementExtensions = new HashSet<>(); + for (WebElementDescriptor descriptor : descriptors) { + if (isRequirementFulfilled(descriptor)) { + Class loadedClass = loadExtension(defaultClassLoader, descriptor); + webElementExtensions.add(new WebElementExtension(loadedClass, descriptor)); + } + } + return webElementExtensions; + } + private Class loadExtension(ClassLoader classLoader, ClassElement extension) { try { return classLoader.loadClass(extension.getClazz()); @@ -307,13 +318,14 @@ public final class ExtensionCollector restProviders.addAll(collectClasses(classLoader, module.getRestProviders())); restResources.addAll(collectClasses(classLoader, module.getRestResources())); - Iterables.addAll(webElements, module.getWebElements()); + + webElements.addAll(collectWebElementExtensions(classLoader, module.getWebElements())); } //~--- fields --------------------------------------------------------------- /** Field description */ - private final Set webElements = Sets.newHashSet(); + private final Set webElements = Sets.newHashSet(); /** Field description */ private final Set restResources = Sets.newHashSet();