This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 897debed28864e03088a7ec4f6bd78b0c2cbb08c Author: Benoit Tellier <[email protected]> AuthorDate: Thu Sep 19 14:45:47 2019 +0700 JAMES-2886 Generify Guice loader --- server/container/guice/guice-utils/pom.xml | 20 ++++ .../java/org/apache/james/utils/ClassName.java | 68 ++++++++++++++ .../apache/james/utils/ExtendedClassLoader.java | 4 +- .../james/utils/FullyQualifiedClassName.java} | 41 +++++---- .../java/org/apache/james/utils/NamingScheme.java} | 38 +++----- .../java/org/apache/james/utils/PackageName.java | 80 ++++++++++++++++ .../java/org/apache/james/utils/ClassNameTest.java | 102 +++++++++++++++++++++ .../james/utils/FullyQualifiedClassNameTest.java} | 54 ++++++----- .../org/apache/james/utils/NamingSchemeTest.java | 78 ++++++++++++++++ .../org/apache/james/utils/PackageNameTest.java | 72 +++++++++++++++ .../org/apache/james/utils/GuiceGenericLoader.java | 30 +++--- .../org/apache/james/utils/GuiceMailetLoader.java | 10 +- .../org/apache/james/utils/GuiceMatcherLoader.java | 10 +- 13 files changed, 511 insertions(+), 96 deletions(-) diff --git a/server/container/guice/guice-utils/pom.xml b/server/container/guice/guice-utils/pom.xml index 7948e4e..4b8b922 100644 --- a/server/container/guice/guice-utils/pom.xml +++ b/server/container/guice/guice-utils/pom.xml @@ -47,6 +47,26 @@ <artifactId>throwing-lambdas</artifactId> </dependency> <dependency> + <groupId>nl.jqno.equalsverifier</groupId> + <artifactId>equalsverifier</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-launcher</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> diff --git a/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ClassName.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ClassName.java new file mode 100644 index 0000000..83217e8 --- /dev/null +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ClassName.java @@ -0,0 +1,68 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.utils; + +import java.util.Objects; + +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; + +public class ClassName { + private final String name; + + public ClassName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isEmpty(), "A class name can not be empty"); + Preconditions.checkArgument(!name.startsWith(String.valueOf(PackageName.PART_SEPARATOR)), "A class name can not start with '.'"); + Preconditions.checkArgument(!name.endsWith(String.valueOf(PackageName.PART_SEPARATOR)), "A class name can not end with '.'"); + Splitter.on(PackageName.PART_SEPARATOR) + .split(name) + .forEach(part -> Preconditions.checkArgument(!part.isEmpty(), "Package part can not be empty within a class name")); + + this.name = name; + } + + public String getName() { + return name; + } + + FullyQualifiedClassName appendPackage(PackageName aPackage) { + return new FullyQualifiedClassName(aPackage.getName() + "." + name); + } + + FullyQualifiedClassName asFullyQualified() { + return new FullyQualifiedClassName(name); + } + + @Override + public final boolean equals(Object o) { + if (o instanceof ClassName) { + ClassName className = (ClassName) o; + + return Objects.equals(this.name, className.name); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(name); + } +} diff --git a/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java index 5b98666..5602a68 100644 --- a/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java @@ -73,7 +73,7 @@ public class ExtendedClassLoader { } @SuppressWarnings("unchecked") - public <T> Class<T> locateClass(String className) throws ClassNotFoundException { - return (Class<T>) urlClassLoader.loadClass(className); + public <T> Class<T> locateClass(FullyQualifiedClassName className) throws ClassNotFoundException { + return (Class<T>) urlClassLoader.loadClass(className.getName()); } } diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/FullyQualifiedClassName.java similarity index 55% copy from server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java copy to server/container/guice/guice-utils/src/main/java/org/apache/james/utils/FullyQualifiedClassName.java index db8959ad..64c421d 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/FullyQualifiedClassName.java @@ -19,35 +19,36 @@ package org.apache.james.utils; -import javax.mail.MessagingException; +import java.util.Objects; -import org.apache.james.mailetcontainer.api.MatcherLoader; -import org.apache.mailet.Matcher; -import org.apache.mailet.MatcherConfig; +import com.google.common.base.Preconditions; -import com.google.inject.Inject; -import com.google.inject.Injector; +public class FullyQualifiedClassName { + private final String name; -public class GuiceMatcherLoader implements MatcherLoader { + FullyQualifiedClassName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isEmpty(), "A class name can not be empty"); - private static final String STANDARD_PACKAGE = "org.apache.james.transport.matchers."; - - private final GuiceGenericLoader<Matcher> genericLoader; + this.name = name; + } - @Inject - public GuiceMatcherLoader(Injector injector, ExtendedClassLoader extendedClassLoader) { - this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, STANDARD_PACKAGE); + public String getName() { + return name; } @Override - public Matcher getMatcher(MatcherConfig config) throws MessagingException { - try { - Matcher result = genericLoader.instanciate(config.getMatcherName()); - result.init(config); - return result; - } catch (Exception e) { - throw new MessagingException("Can not load matcher " + config.getMatcherName(), e); + public final boolean equals(Object o) { + if (o instanceof FullyQualifiedClassName) { + FullyQualifiedClassName className = (FullyQualifiedClassName) o; + + return Objects.equals(this.name, className.name); } + return false; } + @Override + public final int hashCode() { + return Objects.hash(name); + } } diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/NamingScheme.java similarity index 54% copy from server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java copy to server/container/guice/guice-utils/src/main/java/org/apache/james/utils/NamingScheme.java index db8959ad..4042a2e 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/NamingScheme.java @@ -19,35 +19,25 @@ package org.apache.james.utils; -import javax.mail.MessagingException; +import java.util.stream.Stream; -import org.apache.james.mailetcontainer.api.MatcherLoader; -import org.apache.mailet.Matcher; -import org.apache.mailet.MatcherConfig; +public interface NamingScheme { + Stream<FullyQualifiedClassName> toFullyQualifiedClassNames(ClassName className); -import com.google.inject.Inject; -import com.google.inject.Injector; + NamingScheme IDENTITY = className -> Stream.of(className.asFullyQualified()); -public class GuiceMatcherLoader implements MatcherLoader { + class OptionalPackagePrefix implements NamingScheme { + private final PackageName packageName; - private static final String STANDARD_PACKAGE = "org.apache.james.transport.matchers."; - - private final GuiceGenericLoader<Matcher> genericLoader; - - @Inject - public GuiceMatcherLoader(Injector injector, ExtendedClassLoader extendedClassLoader) { - this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, STANDARD_PACKAGE); - } + public OptionalPackagePrefix(PackageName packageName) { + this.packageName = packageName; + } - @Override - public Matcher getMatcher(MatcherConfig config) throws MessagingException { - try { - Matcher result = genericLoader.instanciate(config.getMatcherName()); - result.init(config); - return result; - } catch (Exception e) { - throw new MessagingException("Can not load matcher " + config.getMatcherName(), e); + @Override + public Stream<FullyQualifiedClassName> toFullyQualifiedClassNames(ClassName className) { + return Stream.of( + className.asFullyQualified(), + className.appendPackage(packageName)); } } - } diff --git a/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/PackageName.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/PackageName.java new file mode 100644 index 0000000..188fcd8 --- /dev/null +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/PackageName.java @@ -0,0 +1,80 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.utils; + +import java.util.Objects; + +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; + +public class PackageName { + static final char PART_SEPARATOR = '.'; + + public static PackageName of(String value) { + Preconditions.checkNotNull(value); + String sanitizedValue = sanitize(value); + Preconditions.checkArgument(!hasEmptyParts(sanitizedValue), + "PackageName can not contain empty parts: " + sanitizedValue); + + return new PackageName(sanitizedValue); + } + + private static boolean hasEmptyParts(String sanitizedValue) { + return Splitter.on(PART_SEPARATOR) + .splitToList(sanitizedValue) + .stream() + .anyMatch(String::isEmpty); + } + + private static String sanitize(String value) { + if (value.endsWith(String.valueOf(PART_SEPARATOR))) { + return value.substring(0, value.length() - 1); + } + return value; + } + + private final String name; + + private PackageName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isEmpty(), "Name should not be empty"); + + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof PackageName) { + PackageName className = (PackageName) o; + + return Objects.equals(this.name, className.name); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(name); + } +} diff --git a/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/ClassNameTest.java b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/ClassNameTest.java new file mode 100644 index 0000000..111a8e9 --- /dev/null +++ b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/ClassNameTest.java @@ -0,0 +1,102 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class ClassNameTest { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(ClassName.class) + .verify(); + } + + @Test + void constructorShouldThrowWhenNull() { + assertThatThrownBy(() -> new ClassName(null)) + .isInstanceOf(NullPointerException.class); + } + + @Test + void constructorShouldThrowWhenEmpty() { + assertThatThrownBy(() -> new ClassName("")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void constructorShouldThrowWhenStartWithDot() { + assertThatThrownBy(() -> new ClassName(".MyClass")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void constructorShouldThrowWhenEndWithDot() { + assertThatThrownBy(() -> new ClassName("MyClass.")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void constructorShouldThrowWhenEmptyPackagePart() { + assertThatThrownBy(() -> new ClassName("part..MyClass")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void getNameShouldReturnSuppliedValue() { + String name = "org.apache.MyClass"; + assertThat(new ClassName(name).getName()) + .isEqualTo(name); + } + + @Test + void getNameShouldReturnSuppliedValueWhenNoPackage() { + String name = "MyClass"; + assertThat(new ClassName(name).getName()) + .isEqualTo(name); + } + + @Test + void asFullyQualifiedShouldReturnCorrespondingFullyQualifiedClassName() { + String name = "org.apache.MyClass"; + assertThat(new ClassName(name).asFullyQualified()) + .isEqualTo(new FullyQualifiedClassName(name)); + } + + @Test + void appendPackageShouldAddPackageInFullyQualifiedClassName() { + String name = "MyClass"; + String packageName = "org.apache"; + assertThat(new ClassName(name).appendPackage(PackageName.of(packageName))) + .isEqualTo(new FullyQualifiedClassName("org.apache.MyClass")); + } + + @Test + void appendPackageShouldAddPackageInFullyQualifiedClassNameWhenAPackagePartAlreadyExists() { + String name = "part.MyClass"; + String packageName = "org.apache"; + assertThat(new ClassName(name).appendPackage(PackageName.of(packageName))) + .isEqualTo(new FullyQualifiedClassName("org.apache.part.MyClass")); + } +} \ No newline at end of file diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/FullyQualifiedClassNameTest.java similarity index 52% copy from server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java copy to server/container/guice/guice-utils/src/test/java/org/apache/james/utils/FullyQualifiedClassNameTest.java index db8959ad..6dff3dd 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java +++ b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/FullyQualifiedClassNameTest.java @@ -19,35 +19,43 @@ package org.apache.james.utils; -import javax.mail.MessagingException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; -import org.apache.james.mailetcontainer.api.MatcherLoader; -import org.apache.mailet.Matcher; -import org.apache.mailet.MatcherConfig; +import org.junit.jupiter.api.Test; -import com.google.inject.Inject; -import com.google.inject.Injector; +import nl.jqno.equalsverifier.EqualsVerifier; -public class GuiceMatcherLoader implements MatcherLoader { - - private static final String STANDARD_PACKAGE = "org.apache.james.transport.matchers."; +class FullyQualifiedClassNameTest { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(FullyQualifiedClassName.class) + .verify(); + } - private final GuiceGenericLoader<Matcher> genericLoader; + @Test + void constructorShouldThrowWhenNull() { + assertThatThrownBy(() -> new FullyQualifiedClassName(null)) + .isInstanceOf(NullPointerException.class); + } - @Inject - public GuiceMatcherLoader(Injector injector, ExtendedClassLoader extendedClassLoader) { - this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, STANDARD_PACKAGE); + @Test + void constructorShouldThrowWhenEmpty() { + assertThatThrownBy(() -> new FullyQualifiedClassName("")) + .isInstanceOf(IllegalArgumentException.class); } - @Override - public Matcher getMatcher(MatcherConfig config) throws MessagingException { - try { - Matcher result = genericLoader.instanciate(config.getMatcherName()); - result.init(config); - return result; - } catch (Exception e) { - throw new MessagingException("Can not load matcher " + config.getMatcherName(), e); - } + @Test + void getNameShouldReturnSuppliedValue() { + String name = "org.apache.MyClass"; + assertThat(new FullyQualifiedClassName(name).getName()) + .isEqualTo(name); } -} + @Test + void getNameShouldReturnSuppliedValueWhenOnlyAClassName() { + String name = "MyClass"; + assertThat(new FullyQualifiedClassName(name).getName()) + .isEqualTo(name); + } +} \ No newline at end of file diff --git a/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/NamingSchemeTest.java b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/NamingSchemeTest.java new file mode 100644 index 0000000..22a3dc6 --- /dev/null +++ b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/NamingSchemeTest.java @@ -0,0 +1,78 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.utils; + +import static org.apache.james.utils.NamingScheme.IDENTITY; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class NamingSchemeTest { + public static final String PACKAGE = "org.apache.james"; + public static final NamingScheme.OptionalPackagePrefix PACKAGE_PREFIX = new NamingScheme.OptionalPackagePrefix(PackageName.of(PACKAGE)); + + @Nested + class IdentityTest { + @Test + void asFullyQualifiedShouldPromoteNameToFullyQualifiedClass() { + String name = "org.MyClass"; + ClassName className = new ClassName(name); + + assertThat(IDENTITY.toFullyQualifiedClassNames(className)) + .containsExactly(new FullyQualifiedClassName(name)); + } + + @Test + void asFullyQualifiedShouldPromoteNameToFullyQualifiedClassWhenNoPackagePart() { + String name = "MyClass"; + ClassName className = new ClassName(name); + + assertThat(IDENTITY.toFullyQualifiedClassNames(className)) + .containsExactly(new FullyQualifiedClassName(name)); + } + } + + @Nested + class OptionalPackagePrefixTest { + + @Test + void asFullyQualifiedShouldPromoteNameToFullyQualifiedClass() { + String name = "org.MyClass"; + ClassName className = new ClassName(name); + + assertThat(PACKAGE_PREFIX.toFullyQualifiedClassNames(className)) + .containsExactly( + new FullyQualifiedClassName("org.MyClass"), + new FullyQualifiedClassName("org.apache.james.org.MyClass")); + } + + @Test + void asFullyQualifiedShouldPromoteNameToFullyQualifiedClassWhenNoPackagePart() { + String name = "MyClass"; + ClassName className = new ClassName(name); + + assertThat(PACKAGE_PREFIX.toFullyQualifiedClassNames(className)) + .containsExactly( + new FullyQualifiedClassName("MyClass"), + new FullyQualifiedClassName("org.apache.james.MyClass")); + } + } +} \ No newline at end of file diff --git a/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/PackageNameTest.java b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/PackageNameTest.java new file mode 100644 index 0000000..cce1a01 --- /dev/null +++ b/server/container/guice/guice-utils/src/test/java/org/apache/james/utils/PackageNameTest.java @@ -0,0 +1,72 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class PackageNameTest { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(PackageName.class) + .verify(); + } + + @Test + void ofShouldThrowWhenNull() { + assertThatThrownBy(() -> PackageName.of(null)) + .isInstanceOf(NullPointerException.class); + } + + @Test + void ofShouldThrowWhenEmpty() { + assertThatThrownBy(() -> PackageName.of("")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void getNameShouldReturnSuppliedValue() { + String name = "org.apache.MyClass"; + assertThat(PackageName.of(name).getName()) + .isEqualTo(name); + } + + @Test + void ofShouldThrowWhenStartingDot() { + assertThatThrownBy(() -> PackageName.of(".org.apache.MyClass")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void ofShouldSanitizeEndingDot() { + assertThat(PackageName.of("org.apache.MyClass.").getName()) + .isEqualTo("org.apache.MyClass"); + } + + @Test + void ofShouldThrowWhenDoubleDot() { + assertThatThrownBy(() -> PackageName.of("org.apache..MyClass")) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceGenericLoader.java b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceGenericLoader.java index cdd6d41..d8c6188 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceGenericLoader.java +++ b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceGenericLoader.java @@ -19,42 +19,38 @@ package org.apache.james.utils; -import java.util.Optional; - -import org.apache.james.util.OptionalUtils; +import java.util.stream.Stream; import com.google.inject.Injector; public class GuiceGenericLoader<T> { private final Injector injector; - private final String defaultPackageName; + private final NamingScheme namingScheme; private final ExtendedClassLoader extendedClassLoader; - public GuiceGenericLoader(Injector injector, ExtendedClassLoader extendedClassLoader, String defaultPackageName) { + public GuiceGenericLoader(Injector injector, ExtendedClassLoader extendedClassLoader, NamingScheme namingScheme) { this.injector = injector; - this.defaultPackageName = defaultPackageName; + this.namingScheme = namingScheme; this.extendedClassLoader = extendedClassLoader; } - - public T instanciate(String className) throws Exception { + public T instanciate(ClassName className) throws Exception { Class<T> clazz = locateClass(className); return injector.getInstance(clazz); } - private Class<T> locateClass(String className) throws ClassNotFoundException { - return OptionalUtils.orSuppliers( - () -> tryLocateClass(className), - () -> tryLocateClass(defaultPackageName + className), - () -> tryLocateClass(defaultPackageName + "." + className)) - .orElseThrow(() -> new ClassNotFoundException(className)); + private Class<T> locateClass(ClassName className) throws ClassNotFoundException { + return namingScheme.toFullyQualifiedClassNames(className) + .flatMap(this::tryLocateClass) + .findFirst() + .orElseThrow(() -> new ClassNotFoundException(className.getName())); } - private Optional<Class<T>> tryLocateClass(String className) { + private Stream<Class<T>> tryLocateClass(FullyQualifiedClassName className) { try { - return Optional.of(extendedClassLoader.locateClass(className)); + return Stream.of(extendedClassLoader.locateClass(className)); } catch (ClassNotFoundException e) { - return Optional.empty(); + return Stream.empty(); } } diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMailetLoader.java b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMailetLoader.java index 096aaee..ac6296d 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMailetLoader.java +++ b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMailetLoader.java @@ -34,15 +34,15 @@ import com.google.inject.Inject; import com.google.inject.Injector; public class GuiceMailetLoader implements MailetLoader { - - private static final String STANDARD_PACKAGE = "org.apache.james.transport.mailets."; + private static final PackageName STANDARD_PACKAGE = PackageName.of("org.apache.james.transport.mailets."); + private static final NamingScheme MAILET_NAMING_SCHEME = new NamingScheme.OptionalPackagePrefix(STANDARD_PACKAGE); private final GuiceGenericLoader<Mailet> genericLoader; private final Map<Class<? extends Mailet>, MailetConfig> configurationOverrides; @Inject public GuiceMailetLoader(Injector injector, ExtendedClassLoader extendedClassLoader, Set<MailetConfigurationOverride> mailetConfigurationOverrides) { - this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, STANDARD_PACKAGE); + this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, MAILET_NAMING_SCHEME); this.configurationOverrides = mailetConfigurationOverrides.stream() .collect(Guavate.toImmutableMap( MailetConfigurationOverride::getClazz, @@ -52,7 +52,8 @@ public class GuiceMailetLoader implements MailetLoader { @Override public Mailet getMailet(MailetConfig config) throws MessagingException { try { - Mailet result = genericLoader.instanciate(config.getMailetName()); + ClassName className = new ClassName(config.getMailetName()); + Mailet result = genericLoader.instanciate(className); result.init(resolveConfiguration(result, config)); return result; } catch (Exception e) { @@ -64,5 +65,4 @@ public class GuiceMailetLoader implements MailetLoader { return Optional.ofNullable(configurationOverrides.get(result.getClass())) .orElse(providedConfiguration); } - } diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java index db8959ad..6d2f874 100644 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java +++ b/server/container/guice/mailet/src/main/java/org/apache/james/utils/GuiceMatcherLoader.java @@ -29,25 +29,25 @@ import com.google.inject.Inject; import com.google.inject.Injector; public class GuiceMatcherLoader implements MatcherLoader { - - private static final String STANDARD_PACKAGE = "org.apache.james.transport.matchers."; + private static final PackageName STANDARD_PACKAGE = PackageName.of("org.apache.james.transport.matchers."); + private static final NamingScheme MATCHER_NAMING_SCHEME = new NamingScheme.OptionalPackagePrefix(STANDARD_PACKAGE); private final GuiceGenericLoader<Matcher> genericLoader; @Inject public GuiceMatcherLoader(Injector injector, ExtendedClassLoader extendedClassLoader) { - this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, STANDARD_PACKAGE); + this.genericLoader = new GuiceGenericLoader<>(injector, extendedClassLoader, MATCHER_NAMING_SCHEME); } @Override public Matcher getMatcher(MatcherConfig config) throws MessagingException { try { - Matcher result = genericLoader.instanciate(config.getMatcherName()); + ClassName className = new ClassName(config.getMatcherName()); + Matcher result = genericLoader.instanciate(className); result.init(config); return result; } catch (Exception e) { throw new MessagingException("Can not load matcher " + config.getMatcherName(), e); } } - } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
