mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 16:35:45 +01:00
support requires annotation on WebElements
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -76,5 +76,5 @@ public interface ExtensionProcessor
|
||||
*
|
||||
* @return collected web elements
|
||||
*/
|
||||
public Iterable<WebElementDescriptor> getWebElements();
|
||||
public Iterable<WebElementExtension> getWebElements();
|
||||
}
|
||||
|
||||
@@ -26,18 +26,20 @@ 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
|
||||
@@ -46,130 +48,33 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
* @author Sebastian Sdorra
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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",
|
||||
"<web-element>",
|
||||
" <class>com.hitchhiker.SpaceShip</class>",
|
||||
" <value>/space/*</value>",
|
||||
" <regex>false</regex>",
|
||||
" <morePatterns>/ship/*,/star/*</morePatterns>",
|
||||
" <requires>scm-magrathea-plugin</requires>",
|
||||
" <requires>scm-earth-plugin</requires>",
|
||||
"</web-element>"
|
||||
);
|
||||
private static final String XML_2 = String.join("\n",
|
||||
"<web-element>",
|
||||
" <class>com.hitchhiker.SpaceShip</class>",
|
||||
" <value>/space/.*</value>",
|
||||
" <regex>true</regex>",
|
||||
"</web-element>"
|
||||
);
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,25 @@ public final class WebElementCollector
|
||||
* @param elements
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private WebElementCollector(Iterable<WebElementDescriptor> elements)
|
||||
private WebElementCollector(Iterable<WebElementExtension> elements)
|
||||
{
|
||||
List<TypedWebElementDescriptor<? extends Filter>> fl = Lists.newArrayList();
|
||||
List<TypedWebElementDescriptor<? extends HttpServlet>> sl =
|
||||
Lists.newArrayList();
|
||||
|
||||
for (WebElementDescriptor element : elements)
|
||||
for (WebElementExtension element : elements)
|
||||
{
|
||||
if (Filter.class.isAssignableFrom(element.getClazz()))
|
||||
{
|
||||
fl.add(
|
||||
new TypedWebElementDescriptor<>(
|
||||
(Class<? extends Filter>) element.getClazz(), element));
|
||||
(Class<? extends Filter>) element.getClazz(), element.getDescriptor()));
|
||||
}
|
||||
else if (Servlet.class.isAssignableFrom(element.getClazz()))
|
||||
{
|
||||
sl.add(
|
||||
new TypedWebElementDescriptor<>(
|
||||
(Class<? extends HttpServlet>) element.getClazz(), element));
|
||||
(Class<? extends HttpServlet>) element.getClazz(), element.getDescriptor()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DefaultExtensionProcessor implements ExtensionProcessor
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Iterable<WebElementDescriptor> getWebElements()
|
||||
public Iterable<WebElementExtension> getWebElements()
|
||||
{
|
||||
return collector.getWebElements();
|
||||
}
|
||||
|
||||
@@ -28,15 +28,12 @@ package sonia.scm.plugin;
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -218,7 +218,7 @@ public final class ExtensionCollector
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<WebElementDescriptor> getWebElements()
|
||||
public Set<WebElementExtension> getWebElements()
|
||||
{
|
||||
return webElements;
|
||||
}
|
||||
@@ -272,6 +272,17 @@ public final class ExtensionCollector
|
||||
return classes;
|
||||
}
|
||||
|
||||
private Set<WebElementExtension> collectWebElementExtensions(ClassLoader defaultClassLoader, Iterable<WebElementDescriptor> descriptors) {
|
||||
Set<WebElementExtension> 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<WebElementDescriptor> webElements = Sets.newHashSet();
|
||||
private final Set<WebElementExtension> webElements = Sets.newHashSet();
|
||||
|
||||
/** Field description */
|
||||
private final Set<Class> restResources = Sets.newHashSet();
|
||||
|
||||
Reference in New Issue
Block a user