From 07c4190ff78d48896cd743aa1404ea6b43cc011f Mon Sep 17 00:00:00 2001 From: Adrien LAUER Date: Mon, 29 Jun 2020 13:53:36 +0200 Subject: [PATCH] Switch from specs to predicates for plugins --- .../CommandLineHandlerSpecification.java | 7 +-- .../seed/cli/internal/CommandLinePlugin.java | 5 +- core/pom.xml | 2 +- .../seed/core/internal/CorePlugin.java | 21 +++----- .../core/internal/el/ELHandlerPredicate.java | 31 +++++++++++ .../seed/core/internal/el/ELInterceptor.java | 18 +++---- .../seed/core/internal/el/ELModule.java | 9 ++-- .../seed/core/internal/el/ELPlugin.java | 22 +++----- .../lifecycle/LifecycleExtension.java | 16 +++--- .../internal/lifecycle/LifecycleManager.java | 4 ++ .../internal/lifecycle/LifecyclePlugin.java | 44 ++++++++------- .../internal/utils/SpecificationBuilder.java | 50 ----------------- ...java => ConstraintValidatorPredicate.java} | 11 ++-- .../internal/validation/ValidationPlugin.java | 8 +-- pom.xml | 6 +-- ...fication.java => HttpMethodPredicate.java} | 11 ++-- ...ation.java => JaxRsProviderPredicate.java} | 11 ++-- ...ation.java => JaxRsResourcePredicate.java} | 11 ++-- ...cification.java => JsonHomePredicate.java} | 13 ++--- ...elSpecification.java => RelPredicate.java} | 13 ++--- .../seed/rest/internal/ResourceScanner.java | 5 +- .../seed/rest/internal/RestPlugin.java | 13 ++--- ...t.java => JaxRsResourcePredicateTest.java} | 20 +++---- ...onTest.java => JsonHomePredicateTest.java} | 14 ++--- .../seed/rest/internal/RestPluginTest.java | 36 ++++++------- .../security/internal/SecurityModule.java | 15 ++++-- .../security/internal/SecurityPlugin.java | 23 ++++---- .../internal/ShiroSecuritySupport.java | 24 ++++++--- .../ConfigurationRoleMapping.java | 53 +++++++++++++++---- .../internal/SecurityProviderTest.java | 3 +- specs/pom.xml | 7 ++- .../org/seedstack/seed/LifecycleListener.java | 15 ++++++ testing/junit4/pom.xml | 2 +- 33 files changed, 298 insertions(+), 245 deletions(-) create mode 100644 core/src/main/java/org/seedstack/seed/core/internal/el/ELHandlerPredicate.java delete mode 100644 core/src/main/java/org/seedstack/seed/core/internal/utils/SpecificationBuilder.java rename core/src/main/java/org/seedstack/seed/core/internal/validation/{ConstraintValidatorSpecification.java => ConstraintValidatorPredicate.java} (70%) rename rest/core/src/main/java/org/seedstack/seed/rest/internal/{HttpMethodSpecification.java => HttpMethodPredicate.java} (70%) rename rest/core/src/main/java/org/seedstack/seed/rest/internal/{JaxRsProviderSpecification.java => JaxRsProviderPredicate.java} (67%) rename rest/core/src/main/java/org/seedstack/seed/rest/internal/{JaxRsResourceSpecification.java => JaxRsResourcePredicate.java} (84%) rename rest/core/src/main/java/org/seedstack/seed/rest/internal/{JsonHomeSpecification.java => JsonHomePredicate.java} (76%) rename rest/core/src/main/java/org/seedstack/seed/rest/internal/{RelSpecification.java => RelPredicate.java} (75%) rename rest/core/src/test/java/org/seedstack/seed/rest/internal/{JaxRsResourceSpecificationTest.java => JaxRsResourcePredicateTest.java} (65%) rename rest/core/src/test/java/org/seedstack/seed/rest/internal/{JsonHomeSpecificationTest.java => JsonHomePredicateTest.java} (72%) diff --git a/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLineHandlerSpecification.java b/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLineHandlerSpecification.java index fe442a2e5..db55e6ebe 100644 --- a/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLineHandlerSpecification.java +++ b/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLineHandlerSpecification.java @@ -5,14 +5,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.cli.internal; import java.lang.reflect.Modifier; -import org.kametic.specifications.AbstractSpecification; +import java.util.function.Predicate; import org.seedstack.seed.cli.CommandLineHandler; import org.seedstack.shed.reflect.ClassPredicates; -class CommandLineHandlerSpecification extends AbstractSpecification> { +class CommandLineHandlerSpecification implements Predicate> { static CommandLineHandlerSpecification INSTANCE = new CommandLineHandlerSpecification(); private CommandLineHandlerSpecification() { @@ -20,7 +21,7 @@ private CommandLineHandlerSpecification() { } @Override - public boolean isSatisfiedBy(Class candidate) { + public boolean test(Class candidate) { return ClassPredicates.classIsAssignableFrom(CommandLineHandler.class) .and(ClassPredicates.classIsInterface().negate()) .and(ClassPredicates.classModifierIs(Modifier.ABSTRACT).negate()) diff --git a/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLinePlugin.java b/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLinePlugin.java index 1d08fb024..01e9500c4 100644 --- a/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLinePlugin.java +++ b/cli/src/main/java/org/seedstack/seed/cli/internal/CommandLinePlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.cli.internal; import io.nuun.kernel.api.plugin.InitState; @@ -43,7 +44,7 @@ public void setup(SeedRuntime seedRuntime) { @Override public Collection classpathScanRequests() { - return classpathScanRequestBuilder().specification(CommandLineHandlerSpecification.INSTANCE).build(); + return classpathScanRequestBuilder().predicate(CommandLineHandlerSpecification.INSTANCE).build(); } @Override @@ -54,7 +55,7 @@ public InitState initialize(InitContext initContext) { return InitState.INITIALIZED; } - Collection> cliHandlerCandidates = initContext.scannedTypesBySpecification() + Collection> cliHandlerCandidates = initContext.scannedTypesByPredicate() .get(CommandLineHandlerSpecification.INSTANCE); for (Class candidate : cliHandlerCandidates) { CliCommand cliCommand = candidate.getAnnotation(CliCommand.class); diff --git a/core/pom.xml b/core/pom.xml index 0b3652bc8..35a2d251f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -31,7 +31,7 @@ ${project.version} - io.nuun + io.nuun.kernel kernel-core diff --git a/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java b/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java index f5db9d7f6..daa4c117f 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal; import static org.seedstack.shed.misc.PriorityUtils.sortByPriority; @@ -21,9 +22,7 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Provider; -import org.kametic.specifications.Specification; import org.seedstack.seed.SeedInterceptor; -import org.seedstack.seed.core.internal.utils.SpecificationBuilder; import org.seedstack.shed.misc.PriorityUtils; import org.seedstack.shed.reflect.Classes; import org.slf4j.Logger; @@ -39,12 +38,6 @@ public class CorePlugin extends AbstractSeedPlugin { static final String AUTODETECT_BINDINGS_KERNEL_PARAM = "seedstack.autodetectBindings"; static final String AUTODETECT_INTERCEPTORS_KERNEL_PARAM = "seedstack.autodetectInterceptors"; private static final String SEEDSTACK_PACKAGE = "org.seedstack"; - private static final Specification> installSpecification = new SpecificationBuilder<>( - InstallResolver.INSTANCE).build(); - private static final Specification> bindSpecification = new SpecificationBuilder<>( - BindResolver.INSTANCE).build(); - private static final Specification> providerSpecification = new SpecificationBuilder<>( - ProvideResolver.INSTANCE).build(); private final Set> modules = new HashSet<>(); private final Set> overridingModules = new HashSet<>(); private final List methodInterceptors = new ArrayList<>(); @@ -64,9 +57,9 @@ public String pluginPackageRoot() { @Override public Collection classpathScanRequests() { return classpathScanRequestBuilder() - .specification(installSpecification) - .specification(bindSpecification) - .specification(providerSpecification) + .predicate(InstallResolver.INSTANCE) + .predicate(BindResolver.INSTANCE) + .predicate(ProvideResolver.INSTANCE) .subtypeOf(SeedInterceptor.class) .build(); } @@ -91,7 +84,7 @@ public InitState initialize(InitContext initContext) { @SuppressWarnings("unchecked") private void detectModules(InitContext initContext) { - initContext.scannedTypesBySpecification().get(installSpecification) + initContext.scannedTypesByPredicate().get(InstallResolver.INSTANCE) .stream() .filter(Module.class::isAssignableFrom) .forEach(candidate -> InstallResolver.INSTANCE.apply(candidate).ifPresent(annotation -> { @@ -107,7 +100,7 @@ private void detectModules(InitContext initContext) { @SuppressWarnings("unchecked") private void detectBindings(InitContext initContext) { - initContext.scannedTypesBySpecification().get(bindSpecification) + initContext.scannedTypesByPredicate().get(BindResolver.INSTANCE) .forEach(candidate -> BindResolver.INSTANCE.apply(candidate).ifPresent(annotation -> { if (annotation.override()) { overridingBindings.add(new BindingDefinition<>( @@ -127,7 +120,7 @@ private void detectBindings(InitContext initContext) { @SuppressWarnings("unchecked") private void detectProviders(InitContext initContext) { - initContext.scannedTypesBySpecification().get(providerSpecification) + initContext.scannedTypesByPredicate().get(ProvideResolver.INSTANCE) .forEach(candidate -> ProvideResolver.INSTANCE.apply(candidate).ifPresent(annotation -> { if (annotation.override()) { overridingBindings.add(new ProviderDefinition<>((Class>) candidate)); diff --git a/core/src/main/java/org/seedstack/seed/core/internal/el/ELHandlerPredicate.java b/core/src/main/java/org/seedstack/seed/core/internal/el/ELHandlerPredicate.java new file mode 100644 index 000000000..184e470fb --- /dev/null +++ b/core/src/main/java/org/seedstack/seed/core/internal/el/ELHandlerPredicate.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2013-2020, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.internal.el; + +import static org.seedstack.shed.reflect.ClassPredicates.classImplements; +import static org.seedstack.shed.reflect.ClassPredicates.classModifierIs; + +import java.lang.reflect.Modifier; +import java.util.function.Predicate; +import org.seedstack.seed.el.spi.ELHandler; + +class ELHandlerPredicate implements Predicate> { + static ELHandlerPredicate INSTANCE = new ELHandlerPredicate(); + + private ELHandlerPredicate() { + // no instantiation allowed + } + + @Override + public boolean test(Class candidate) { + return classImplements(ELHandler.class) + .and(classModifierIs(Modifier.ABSTRACT).negate()) + .test(candidate); + } +} diff --git a/core/src/main/java/org/seedstack/seed/core/internal/el/ELInterceptor.java b/core/src/main/java/org/seedstack/seed/core/internal/el/ELInterceptor.java index 9285f44eb..9f112542f 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/el/ELInterceptor.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/el/ELInterceptor.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.el; import com.google.inject.Injector; @@ -21,21 +22,14 @@ import org.seedstack.seed.el.spi.ELHandler; class ELInterceptor implements MethodInterceptor { - - private Class annotationClass; - - private ELBinder.ExecutionPolicy policy; - - // Get a map of annotation handler + private final Class annotationClass; + private final ELBinder.ExecutionPolicy policy; @Inject - private Map, Class> elMap; - + private Map, Class>> elMap; @Inject private ELService elService; - @Inject private ELContextBuilder elContextBuilder; - @Inject private Injector injector; @@ -46,8 +40,8 @@ class ELInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { - Class handlerClass = elMap.get(this.annotationClass); - ELHandler ELHandler = injector.getInstance(handlerClass); + Class> handlerClass = elMap.get(this.annotationClass); + ELHandler ELHandler = injector.getInstance(handlerClass); // The policy defines if the EL is evaluated before the method, after or both. diff --git a/core/src/main/java/org/seedstack/seed/core/internal/el/ELModule.java b/core/src/main/java/org/seedstack/seed/core/internal/el/ELModule.java index faa91bf04..7eb639e4a 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/el/ELModule.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/el/ELModule.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.el; import com.google.common.collect.ImmutableMap; @@ -19,9 +20,9 @@ class ELModule extends AbstractModule { private final ExpressionFactory expressionFactory; - private final Map, Class> elMap; + private final Map, Class>> elMap; - ELModule(ExpressionFactory expressionFactory, Map, Class> elMap) { + ELModule(ExpressionFactory expressionFactory, Map, Class>> elMap) { this.expressionFactory = expressionFactory; this.elMap = elMap; } @@ -32,7 +33,7 @@ protected void configure() { bind(ELService.class).to(ELServiceInternal.class); bind(ELContextBuilder.class).to(ELContextBuilderImpl.class); - for (Class elHandlerClass : elMap.values()) { + for (Class> elHandlerClass : elMap.values()) { bind(elHandlerClass); } @@ -41,6 +42,6 @@ protected void configure() { } private static class AnnotationHandlersTypeLiteral - extends TypeLiteral, Class>> { + extends TypeLiteral, Class>>> { } } diff --git a/core/src/main/java/org/seedstack/seed/core/internal/el/ELPlugin.java b/core/src/main/java/org/seedstack/seed/core/internal/el/ELPlugin.java index c7865b767..3db5d7c7b 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/el/ELPlugin.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/el/ELPlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.el; import io.nuun.kernel.api.plugin.InitState; @@ -19,7 +20,6 @@ import javax.el.ELContext; import javax.el.ExpressionFactory; import net.jodah.typetools.TypeResolver; -import org.kametic.specifications.Specification; import org.seedstack.seed.SeedException; import org.seedstack.seed.core.internal.AbstractSeedPlugin; import org.seedstack.seed.el.spi.ELHandler; @@ -32,7 +32,6 @@ public class ELPlugin extends AbstractSeedPlugin { static final Class JUEL_CONTEXT_CLASS; private static final Object EXPRESSION_FACTORY; private static final Logger LOGGER = LoggerFactory.getLogger(ELPlugin.class); - private final Specification> specificationELHandlers = classImplements(ELHandler.class); private ELModule elModule; static { @@ -106,36 +105,31 @@ public String name() { @Override public Collection classpathScanRequests() { - return classpathScanRequestBuilder().specification(specificationELHandlers).build(); + return classpathScanRequestBuilder().predicate(ELHandlerPredicate.INSTANCE).build(); } @SuppressWarnings("unchecked") @Override public InitState initialize(InitContext initContext) { if (isEnabled()) { - Map, Class> elMap = new HashMap<>(); - - // Scan all the ExpressionLanguageHandler - Map>> scannedTypesBySpecification = initContext - .scannedTypesBySpecification(); - Collection> elHandlerClasses = scannedTypesBySpecification.get(specificationELHandlers); + Map, Class>> elMap = new HashMap<>(); - // Look for their type parameters - for (Class elHandlerClass : elHandlerClasses) { + // Scan all the ExpressionLanguageHandler and look for their type parameters + for (Class elHandlerClass : initContext.scannedTypesByPredicate().get(ELHandlerPredicate.INSTANCE)) { Class typeParameterClass = (Class) TypeResolver.resolveRawArguments( - ELHandler.class, (Class) elHandlerClass)[0]; + ELHandler.class, (Class>) elHandlerClass)[0]; // transform this type parameters in a map of annotation, ExpressionHandler if (elMap.get(typeParameterClass) != null) { throw SeedException.createNew(ExpressionLanguageErrorCode.EL_ANNOTATION_IS_ALREADY_BIND) .put("annotation", typeParameterClass.getSimpleName()) .put("handler", elHandlerClass); } - elMap.put(typeParameterClass, (Class) elHandlerClass); + elMap.put(typeParameterClass, (Class>) elHandlerClass); } elModule = new ELModule((ExpressionFactory) EXPRESSION_FACTORY, elMap); } else { - LOGGER.debug("Java EL is not present in the classpath, EL support disabled"); + LOGGER.info("Java EL is not present in the classpath, EL support disabled"); } return InitState.INITIALIZED; diff --git a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleExtension.java b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleExtension.java index cab4ad3cf..cec5fba7f 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleExtension.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleExtension.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.lifecycle; import io.nuun.kernel.spi.KernelExtension; @@ -26,22 +27,23 @@ public void starting(Collection lifecycleManagers) { // this phase is not supported by LifecycleManager } + @Override + public void injected(Collection lifecycleManagers) { + lifecycleManagers.forEach(LifecycleManager::starting); + } + @Override public void started(Collection lifecycleManagers) { - for (LifecycleManager lifecycleManager : lifecycleManagers) { - lifecycleManager.started(); - } + lifecycleManagers.forEach(LifecycleManager::started); } @Override public void stopping(Collection lifecycleManagers) { - for (LifecycleManager lifecycleManager : lifecycleManagers) { - lifecycleManager.stopping(); - } + lifecycleManagers.forEach(LifecycleManager::stopping); } @Override public void stopped(Collection lifecycleManagers) { - // this phase is not supported by LifecycleManager + lifecycleManagers.forEach(LifecycleManager::stopped); } } diff --git a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleManager.java b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleManager.java index a42ab3c34..2746ce8e3 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleManager.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecycleManager.java @@ -11,10 +11,14 @@ import java.lang.reflect.Method; interface LifecycleManager { + void starting(); + void started(); void stopping(); + void stopped(); + void registerPreDestroy(Object o, Method m); void registerAutoCloseable(AutoCloseable autoCloseable); diff --git a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecyclePlugin.java b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecyclePlugin.java index de6be61d6..aa1cd838d 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecyclePlugin.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/lifecycle/LifecyclePlugin.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.function.Consumer; import javax.inject.Inject; import org.seedstack.seed.Ignore; import org.seedstack.seed.LifecycleListener; @@ -71,21 +72,15 @@ public Object nativeUnitModule() { } @Override - public void started() { - List sortedLifecycleListeners = new ArrayList<>(this.lifecycleListeners); - sortByPriority(sortedLifecycleListeners, PriorityUtils::priorityOfClassOf); + public void starting() { + // Lifecycle listeners starting() + invokeLifecycleListeners("starting", LifecycleListener::starting); + } - for (LifecycleListener lifecycleListener : sortedLifecycleListeners) { - try { - LOGGER.info("Invoking lifecycle method: {}.started()", lifecycleListener.getClass().getName()); - lifecycleListener.started(); - } catch (Exception e) { - throw SeedException - .wrap(e, CoreErrorCode.ERROR_IN_LIFECYCLE_LISTENER) - .put("lifecycleListenerClass", lifecycleListener.getClass().getCanonicalName()) - .put("phase", "start"); - } - } + @Override + public void started() { + // Lifecycle listeners started() + invokeLifecycleListeners("started", LifecycleListener::started); } @Override @@ -97,15 +92,28 @@ public void stopping() { preDestroyMethods.forEach(DelayedCall::proceed); // Lifecycle listeners stopping() + invokeLifecycleListeners("stopping", LifecycleListener::stopping); + } + + @Override + public void stopped() { + // Lifecycle listeners stopping() + invokeLifecycleListeners("stopped", LifecycleListener::stopped); + } + + private void invokeLifecycleListeners(String phase, Consumer consumer) { List sortedLifecycleListeners = new ArrayList<>(this.lifecycleListeners); sortByPriority(sortedLifecycleListeners, PriorityUtils::priorityOfClassOf); + for (LifecycleListener lifecycleListener : sortedLifecycleListeners) { try { - LOGGER.info("Invoking lifecycle method: {}.stopping()", lifecycleListener.getClass().getName()); - lifecycleListener.stopping(); + LOGGER.info("Invoking lifecycle method: {}.{}()", lifecycleListener.getClass().getName(), phase); + consumer.accept(lifecycleListener); } catch (Exception e) { - LOGGER.error("An exception occurred in lifecycle method: {}.stopping()", - lifecycleListener.getClass().getName(), e); + throw SeedException + .wrap(e, CoreErrorCode.ERROR_IN_LIFECYCLE_LISTENER) + .put("lifecycleListenerClass", lifecycleListener.getClass().getCanonicalName()) + .put("phase", phase); } } } diff --git a/core/src/main/java/org/seedstack/seed/core/internal/utils/SpecificationBuilder.java b/core/src/main/java/org/seedstack/seed/core/internal/utils/SpecificationBuilder.java deleted file mode 100644 index 7b9caba16..000000000 --- a/core/src/main/java/org/seedstack/seed/core/internal/utils/SpecificationBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2013-2020, The SeedStack authors - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.seedstack.seed.core.internal.utils; - -import java.util.function.Predicate; -import org.kametic.specifications.AbstractSpecification; -import org.kametic.specifications.Specification; - -public class SpecificationBuilder { - private Predicate predicate; - - public SpecificationBuilder(Predicate predicate) { - this.predicate = predicate; - } - - @SafeVarargs - public final SpecificationBuilder and(Predicate... others) { - for (Predicate other : others) { - predicate = predicate.and(other); - } - return this; - } - - @SafeVarargs - public final SpecificationBuilder or(Predicate... others) { - for (Predicate other : others) { - predicate = predicate.or(other); - } - return this; - } - - public final SpecificationBuilder negate() { - predicate = predicate.negate(); - return this; - } - - public Specification build() { - return new AbstractSpecification() { - @Override - public boolean isSatisfiedBy(T candidate) { - return predicate.test(candidate); - } - }; - } -} diff --git a/core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorSpecification.java b/core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorPredicate.java similarity index 70% rename from core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorSpecification.java rename to core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorPredicate.java index 58cad190c..f06f59fc9 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorSpecification.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/validation/ConstraintValidatorPredicate.java @@ -5,22 +5,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.validation; import java.lang.reflect.Modifier; +import java.util.function.Predicate; import javax.validation.ConstraintValidator; -import org.kametic.specifications.AbstractSpecification; import org.seedstack.shed.reflect.ClassPredicates; -class ConstraintValidatorSpecification extends AbstractSpecification> { - static ConstraintValidatorSpecification INSTANCE = new ConstraintValidatorSpecification(); +class ConstraintValidatorPredicate implements Predicate> { + static ConstraintValidatorPredicate INSTANCE = new ConstraintValidatorPredicate(); - private ConstraintValidatorSpecification() { + private ConstraintValidatorPredicate() { // no instantiation allowed } @Override - public boolean isSatisfiedBy(Class candidate) { + public boolean test(Class candidate) { return ClassPredicates.classIsAssignableFrom(ConstraintValidator.class) .and(ClassPredicates.classIsInterface().negate()) .and(ClassPredicates.classModifierIs(Modifier.ABSTRACT).negate()) diff --git a/core/src/main/java/org/seedstack/seed/core/internal/validation/ValidationPlugin.java b/core/src/main/java/org/seedstack/seed/core/internal/validation/ValidationPlugin.java index dcf342826..8bc2881aa 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/validation/ValidationPlugin.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/validation/ValidationPlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal.validation; import com.google.inject.Injector; @@ -42,7 +43,7 @@ public String name() { public Collection classpathScanRequests() { if (isValidationEnabled()) { return classpathScanRequestBuilder() - .specification(ConstraintValidatorSpecification.INSTANCE) + .predicate(ConstraintValidatorPredicate.INSTANCE) .build(); } else { return new ArrayList<>(); @@ -52,9 +53,8 @@ public Collection classpathScanRequests() { @Override protected InitState initialize(InitContext initContext) { if (isValidationEnabled()) { - Collection> constraintValidatorCandidates = initContext.scannedTypesBySpecification() - .get(ConstraintValidatorSpecification.INSTANCE); - for (Class candidate : constraintValidatorCandidates) { + for (Class candidate : initContext.scannedTypesByPredicate() + .get(ConstraintValidatorPredicate.INSTANCE)) { if (ConstraintValidator.class.isAssignableFrom(candidate)) { LOGGER.debug("Detected constraint validator {}", candidate.getCanonicalName()); constraintValidators.add(candidate.asSubclass(ConstraintValidator.class)); diff --git a/pom.xml b/pom.xml index 057ee2773..64a42fd0c 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ pom - 1.0.M9 + 1.0.M10-SNAPSHOT 3.24.1-GA 1.1.6 3.1.5 @@ -60,7 +60,7 @@ - io.nuun + io.nuun.kernel kernel-specs ${nuun-kernel.version} @@ -75,7 +75,7 @@ - io.nuun + io.nuun.kernel kernel-core ${nuun-kernel.version} diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodSpecification.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodPredicate.java similarity index 70% rename from rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodSpecification.java rename to rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodPredicate.java index 4d869eed6..08afda5c8 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodSpecification.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/HttpMethodPredicate.java @@ -5,22 +5,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.function.Predicate; import javax.ws.rs.HttpMethod; -import org.kametic.specifications.AbstractSpecification; -class HttpMethodSpecification extends AbstractSpecification { - static final HttpMethodSpecification INSTANCE = new HttpMethodSpecification(); +class HttpMethodPredicate implements Predicate { + static final HttpMethodPredicate INSTANCE = new HttpMethodPredicate(); - private HttpMethodSpecification() { + private HttpMethodPredicate() { // no instantiation allowed } @Override - public boolean isSatisfiedBy(Method candidate) { + public boolean test(Method candidate) { for (Annotation annotation : candidate.getDeclaredAnnotations()) { if (annotation.annotationType().getAnnotation(HttpMethod.class) != null) { return true; diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderSpecification.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderPredicate.java similarity index 67% rename from rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderSpecification.java rename to rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderPredicate.java index be7d0b930..ab4297829 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderSpecification.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsProviderPredicate.java @@ -5,24 +5,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; +import java.util.function.Predicate; import javax.ws.rs.ext.Provider; -import org.kametic.specifications.AbstractSpecification; import org.seedstack.shed.reflect.AnnotationPredicates; /** * Matches classes annotated by {@link javax.ws.rs.ext.Provider}. */ -class JaxRsProviderSpecification extends AbstractSpecification> { - static final JaxRsProviderSpecification INSTANCE = new JaxRsProviderSpecification(); +class JaxRsProviderPredicate implements Predicate> { + static final JaxRsProviderPredicate INSTANCE = new JaxRsProviderPredicate(); - private JaxRsProviderSpecification() { + private JaxRsProviderPredicate() { // no instantiation allowed } @Override - public boolean isSatisfiedBy(Class candidate) { + public boolean test(Class candidate) { return AnnotationPredicates.elementAnnotatedWith(Provider.class, false).test(candidate); } } diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecification.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicate.java similarity index 84% rename from rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecification.java rename to rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicate.java index 1ada26c82..6e72c697c 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecification.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicate.java @@ -5,11 +5,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import java.lang.reflect.Modifier; +import java.util.function.Predicate; import javax.ws.rs.Path; -import org.kametic.specifications.AbstractSpecification; import org.seedstack.shed.reflect.AnnotationPredicates; import org.seedstack.shed.reflect.ClassPredicates; @@ -28,15 +29,15 @@ * class or interface annotations is not supported. * */ -class JaxRsResourceSpecification extends AbstractSpecification> { - static final JaxRsResourceSpecification INSTANCE = new JaxRsResourceSpecification(); +class JaxRsResourcePredicate implements Predicate> { + static final JaxRsResourcePredicate INSTANCE = new JaxRsResourcePredicate(); - private JaxRsResourceSpecification() { + private JaxRsResourcePredicate() { // not instantiation allowed } @Override - public boolean isSatisfiedBy(Class candidate) { + public boolean test(Class candidate) { return ClassPredicates .classModifierIs(Modifier.ABSTRACT).negate() .and(AnnotationPredicates.elementAnnotatedWith(Path.class, false)) diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomeSpecification.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomePredicate.java similarity index 76% rename from rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomeSpecification.java rename to rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomePredicate.java index e6c5d2d34..fd2a40444 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomeSpecification.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/JsonHomePredicate.java @@ -5,10 +5,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import java.lang.reflect.Method; -import org.kametic.specifications.AbstractSpecification; +import java.util.function.Predicate; import org.seedstack.seed.rest.Rel; /** @@ -22,16 +23,16 @@ *
  • If the annotated is not found on the method, the declaring class is checked.
  • * */ -class JsonHomeSpecification extends AbstractSpecification { - static JsonHomeSpecification INSTANCE = new JsonHomeSpecification(); +class JsonHomePredicate implements Predicate { + static JsonHomePredicate INSTANCE = new JsonHomePredicate(); - private JsonHomeSpecification() { + private JsonHomePredicate() { // no instantiation allowed } @Override - public boolean isSatisfiedBy(Method method) { - if (!HttpMethodSpecification.INSTANCE.isSatisfiedBy(method)) { + public boolean test(Method method) { + if (!HttpMethodPredicate.INSTANCE.test(method)) { return false; } Rel rootRel = method.getDeclaringClass().getAnnotation(Rel.class); diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/RelSpecification.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/RelPredicate.java similarity index 75% rename from rest/core/src/main/java/org/seedstack/seed/rest/internal/RelSpecification.java rename to rest/core/src/main/java/org/seedstack/seed/rest/internal/RelPredicate.java index 6a22c378c..70225d1b8 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/RelSpecification.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/RelPredicate.java @@ -5,10 +5,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import java.lang.reflect.Method; -import org.kametic.specifications.AbstractSpecification; +import java.util.function.Predicate; import org.seedstack.seed.rest.Rel; /** @@ -22,16 +23,16 @@ *
  • If the annotated is not found on the method, the declaring class is checked.
  • * */ -class RelSpecification extends AbstractSpecification { - static RelSpecification INSTANCE = new RelSpecification(); +class RelPredicate implements Predicate { + static RelPredicate INSTANCE = new RelPredicate(); - private RelSpecification() { + private RelPredicate() { // no instantiation allowed } @Override - public boolean isSatisfiedBy(Method method) { - if (!HttpMethodSpecification.INSTANCE.isSatisfiedBy(method)) { + public boolean test(Method method) { + if (!HttpMethodPredicate.INSTANCE.test(method)) { return false; } Rel rootRel = method.getDeclaringClass().getAnnotation(Rel.class); diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/ResourceScanner.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/ResourceScanner.java index c8c9232d4..67b1ef09c 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/ResourceScanner.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/ResourceScanner.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import com.damnhandy.uri.template.UriTemplate; @@ -62,7 +63,7 @@ ResourceScanner scan(final Collection> classes) { private void collectHttpMethodsWithRel(Class aClass) { for (Method method : aClass.getDeclaredMethods()) { - if (RelSpecification.INSTANCE.isSatisfiedBy(method)) { + if (RelPredicate.INSTANCE.test(method)) { Rel relAnnotation = RESTReflect.findRel(method); if (relAnnotation == null || "".equals(relAnnotation.value())) { throw new IllegalStateException("Missing rel value on " + method.toGenericString()); @@ -124,7 +125,7 @@ private void buildJsonHomeResources() { private Resource buildJsonHomeResource(String baseParam, String rel, Method method) { Resource currentResource = null; - if (JsonHomeSpecification.INSTANCE.isSatisfiedBy(method)) { + if (JsonHomePredicate.INSTANCE.test(method)) { String path = RESTReflect.findPath(method); if (path == null) { diff --git a/rest/core/src/main/java/org/seedstack/seed/rest/internal/RestPlugin.java b/rest/core/src/main/java/org/seedstack/seed/rest/internal/RestPlugin.java index 974f2672f..66904348a 100644 --- a/rest/core/src/main/java/org/seedstack/seed/rest/internal/RestPlugin.java +++ b/rest/core/src/main/java/org/seedstack/seed/rest/internal/RestPlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import com.fasterxml.jackson.jaxrs.base.JsonMappingExceptionMapper; @@ -21,10 +22,10 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import javax.servlet.ServletContext; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Variant; -import org.kametic.specifications.Specification; import org.seedstack.seed.core.SeedRuntime; import org.seedstack.seed.core.internal.AbstractSeedPlugin; import org.seedstack.seed.core.internal.init.ValidationManager; @@ -70,19 +71,19 @@ protected void setup(SeedRuntime seedRuntime) { @Override public Collection classpathScanRequests() { return classpathScanRequestBuilder() - .specification(JaxRsResourceSpecification.INSTANCE) - .specification(JaxRsProviderSpecification.INSTANCE) + .predicate(JaxRsResourcePredicate.INSTANCE) + .predicate(JaxRsProviderPredicate.INSTANCE) .build(); } @Override public InitState initialize(InitContext initContext) { ServletContext servletContext = seedRuntime.contextAs(ServletContext.class); - Map>> scannedClasses = initContext.scannedTypesBySpecification(); + Map>, Collection>> scannedClasses = initContext.scannedTypesByPredicate(); restConfig = getConfiguration(RestConfig.class); - resources = scannedClasses.get(JaxRsResourceSpecification.INSTANCE); - providers = scannedClasses.get(JaxRsProviderSpecification.INSTANCE); + resources = scannedClasses.get(JaxRsResourcePredicate.INSTANCE); + providers = scannedClasses.get(JaxRsProviderPredicate.INSTANCE); if (servletContext != null) { addJacksonProviders(providers); diff --git a/rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecificationTest.java b/rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicateTest.java similarity index 65% rename from rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecificationTest.java rename to rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicateTest.java index 63c97f7aa..a36859586 100644 --- a/rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourceSpecificationTest.java +++ b/rest/core/src/test/java/org/seedstack/seed/rest/internal/JaxRsResourcePredicateTest.java @@ -14,21 +14,21 @@ import org.junit.Test; @Ignore // Tells nuun to not scan the test class -public class JaxRsResourceSpecificationTest { - private JaxRsResourceSpecification underTest = JaxRsResourceSpecification.INSTANCE; +public class JaxRsResourcePredicateTest { + private JaxRsResourcePredicate underTest = JaxRsResourcePredicate.INSTANCE; @Test public void valid_resource_specification() { - Assertions.assertThat(underTest.isSatisfiedBy(AbstractResource.class)).isFalse(); + Assertions.assertThat(underTest.test(AbstractResource.class)).isFalse(); - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource1.class)).isTrue(); - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource2.class)).isTrue(); - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource3.class)).isTrue(); + Assertions.assertThat(underTest.test(ValidResource1.class)).isTrue(); + Assertions.assertThat(underTest.test(ValidResource2.class)).isTrue(); + Assertions.assertThat(underTest.test(ValidResource3.class)).isTrue(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource1.class)).isFalse(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource2.class)).isFalse(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource3.class)).isFalse(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource4.class)).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource1.class)).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource2.class)).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource3.class)).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource4.class)).isFalse(); } interface InterfaceResource { diff --git a/rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomeSpecificationTest.java b/rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomePredicateTest.java similarity index 72% rename from rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomeSpecificationTest.java rename to rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomePredicateTest.java index 26b2b3d57..f93a7b7d9 100644 --- a/rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomeSpecificationTest.java +++ b/rest/core/src/test/java/org/seedstack/seed/rest/internal/JsonHomePredicateTest.java @@ -14,22 +14,22 @@ import org.junit.Test; import org.seedstack.seed.rest.Rel; -public class JsonHomeSpecificationTest { - private JsonHomeSpecification underTest = JsonHomeSpecification.INSTANCE; +public class JsonHomePredicateTest { + private JsonHomePredicate underTest = JsonHomePredicate.INSTANCE; @Test public void valid_json_entry_point_specification() throws NoSuchMethodException { - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource1.class.getMethod("post"))).isTrue(); - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource2.class.getMethod("post"))).isTrue(); + Assertions.assertThat(underTest.test(ValidResource1.class.getMethod("post"))).isTrue(); + Assertions.assertThat(underTest.test(ValidResource2.class.getMethod("post"))).isTrue(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource1.class.getMethod("post"))).isFalse(); - Assertions.assertThat(underTest.isSatisfiedBy(InvalidResource2.class.getMethod("post"))).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource1.class.getMethod("post"))).isFalse(); + Assertions.assertThat(underTest.test(InvalidResource2.class.getMethod("post"))).isFalse(); } @Test @org.junit.Ignore public void valid_json_home_on_interface() throws NoSuchMethodException { - Assertions.assertThat(underTest.isSatisfiedBy(ValidResource3.class.getMethod("post"))).isTrue(); + Assertions.assertThat(underTest.test(ValidResource3.class.getMethod("post"))).isTrue(); } static interface InterfaceResource1 { diff --git a/rest/core/src/test/java/org/seedstack/seed/rest/internal/RestPluginTest.java b/rest/core/src/test/java/org/seedstack/seed/rest/internal/RestPluginTest.java index 817fbc155..26807d13e 100644 --- a/rest/core/src/test/java/org/seedstack/seed/rest/internal/RestPluginTest.java +++ b/rest/core/src/test/java/org/seedstack/seed/rest/internal/RestPluginTest.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.rest.internal; import static org.assertj.core.api.Assertions.assertThat; @@ -16,6 +17,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import javax.servlet.ServletContext; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; @@ -25,7 +27,6 @@ import mockit.Mocked; import mockit.Tested; import org.junit.Test; -import org.kametic.specifications.Specification; import org.seedstack.coffig.Coffig; import org.seedstack.coffig.provider.CompositeProvider; import org.seedstack.seed.Application; @@ -58,39 +59,38 @@ public void testName() { @Test public void testRequestScanForJaxRsClasses() { - assertScanSpecification(JaxRsProviderSpecification.INSTANCE); - assertScanSpecification(JaxRsResourceSpecification.INSTANCE); + assertScanPredicate(JaxRsProviderPredicate.INSTANCE); + assertScanPredicate(JaxRsResourcePredicate.INSTANCE); } - private void assertScanSpecification(Specification> specification) { - boolean scanSpecification = false; + private void assertScanPredicate(Predicate> predicate) { + boolean scanPredicate = false; for (ClasspathScanRequest classpathScanRequest : underTest.classpathScanRequests()) { - if (classpathScanRequest.specification == specification) { - scanSpecification = true; + if (classpathScanRequest.classPredicate == predicate) { + scanPredicate = true; break; } } - assertThat(scanSpecification).isTrue(); + assertThat(scanPredicate).isTrue(); } @Test public void testWithoutServletContext() { givenConfiguration(); givenSpecifications( - new Pair<>(JaxRsResourceSpecification.INSTANCE, MyResource.class), - new Pair<>(JaxRsProviderSpecification.INSTANCE, MyProvider.class) + new Pair<>(JaxRsResourcePredicate.INSTANCE, MyResource.class), + new Pair<>(JaxRsProviderPredicate.INSTANCE, MyProvider.class) ); InitState init = underTest.init(initContext); assertThat(init).isEqualTo(InitState.INITIALIZED); } - @SuppressWarnings("unchecked") @Test public void testInitGetJaxRsClasses() { givenConfiguration(); givenSpecifications( - new Pair(JaxRsResourceSpecification.INSTANCE, MyResource.class), - new Pair(JaxRsProviderSpecification.INSTANCE, MyProvider.class) + new Pair<>(JaxRsResourcePredicate.INSTANCE, MyResource.class), + new Pair<>(JaxRsProviderPredicate.INSTANCE, MyProvider.class) ); underTest.provideContainerContext(SeedRuntime.builder() @@ -107,13 +107,13 @@ public void testInitGetJaxRsClasses() { } @SafeVarargs - private final void givenSpecifications(Pair>, Class>... specEntries) { - final Map>> specsMap = new HashMap<>(); - for (Pair>, Class> specEntry : specEntries) { + private final void givenSpecifications(Pair>, Class>... specEntries) { + final Map>, Collection>> specsMap = new HashMap<>(); + for (Pair>, Class> specEntry : specEntries) { specsMap.put(specEntry.getValue0(), Lists.newArrayList(specEntry.getValue1())); } new Expectations() {{ - initContext.scannedTypesBySpecification(); + initContext.scannedTypesByPredicate(); result = specsMap; }}; } @@ -146,7 +146,7 @@ private static class MyResource { private static class MyProvider { } - class Pair { + static class Pair { private final T1 t1; private final T2 t2; diff --git a/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityModule.java b/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityModule.java index fac2fd2ba..fdf5c5339 100644 --- a/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityModule.java +++ b/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityModule.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.security.internal; import com.google.inject.AbstractModule; @@ -17,7 +18,6 @@ import com.google.inject.spi.PrivateElements; import java.util.Collection; import java.util.Map; -import org.apache.commons.lang.ArrayUtils; import org.apache.shiro.event.EventBus; import org.apache.shiro.mgt.SecurityManager; import org.seedstack.seed.SeedException; @@ -93,18 +93,27 @@ private ModuleWithoutSecurityManager(PrivateElements privateElements) { @Override protected void configure() { for (Element element : privateElements.getElements()) { - if (element instanceof Binding && ArrayUtils.contains(excludedKeys, ((Binding) element).getKey())) { + if (element instanceof Binding && isExcluded(((Binding) element).getKey())) { continue; } element.applyTo(binder()); } for (Key exposedKey : privateElements.getExposedKeys()) { - if (ArrayUtils.contains(excludedKeys, exposedKey)) { + if (isExcluded(exposedKey)) { continue; } expose(exposedKey); } } + + private static boolean isExcluded(Key valueToFind) { + for (Key key : excludedKeys) { + if (valueToFind != null && valueToFind.equals(key)) { + return true; + } + } + return false; + } } } diff --git a/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityPlugin.java b/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityPlugin.java index 232845675..a453d4089 100644 --- a/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityPlugin.java +++ b/security/core/src/main/java/org/seedstack/seed/security/internal/SecurityPlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.security.internal; import static org.seedstack.shed.misc.PriorityUtils.sortByPriority; @@ -45,7 +46,6 @@ public class SecurityPlugin extends AbstractSeedPlugin { private final Set securityProviders = new HashSet<>(); private final List> crudActionResolvers = new ArrayList<>(); private SecurityConfigurer securityConfigurer; - private boolean elAvailable; @Override public String name() { @@ -54,18 +54,18 @@ public String name() { @Override public Collection> dependencies() { - return Lists.newArrayList(ELPlugin.class, SecurityProvider.class); + return Lists.newArrayList(SecurityProvider.class); } @Override public Collection classpathScanRequests() { return classpathScanRequestBuilder() - .descendentTypeOf(Realm.class) - .descendentTypeOf(RoleMapping.class) - .descendentTypeOf(RolePermissionResolver.class) - .descendentTypeOf(Scope.class) - .descendentTypeOf(PrincipalCustomizer.class) - .descendentTypeOf(CrudActionResolver.class) + .subtypeOf(Realm.class) + .subtypeOf(RoleMapping.class) + .subtypeOf(RolePermissionResolver.class) + .subtypeOf(Scope.class) + .subtypeOf(PrincipalCustomizer.class) + .subtypeOf(CrudActionResolver.class) .build(); } @@ -73,15 +73,12 @@ public Collection classpathScanRequests() { @SuppressWarnings({"unchecked"}) public InitState initialize(InitContext initContext) { SecurityConfig securityConfig = getConfiguration(SecurityConfig.class); - Map, Collection>> scannedClasses = initContext.scannedSubTypesByAncestorClass(); + Map, Collection>> scannedClasses = initContext.scannedSubTypesByParentClass(); configureScopes(scannedClasses.get(Scope.class)); configureCrudActionResolvers(scannedClasses.get(CrudActionResolver.class)); securityProviders.addAll(initContext.dependencies(SecurityProvider.class)); - - elAvailable = initContext.dependency(ELPlugin.class).isFunctionMappingAvailable(); - securityConfigurer = new SecurityConfigurer( securityConfig, scannedClasses, @@ -149,7 +146,7 @@ public Object nativeUnitModule() { return new SecurityModule( securityConfigurer, scopeClasses, - elAvailable, + ELPlugin.isFunctionMappingAvailable(), securityProviders, crudActionResolvers); } diff --git a/security/core/src/main/java/org/seedstack/seed/security/internal/ShiroSecuritySupport.java b/security/core/src/main/java/org/seedstack/seed/security/internal/ShiroSecuritySupport.java index 194d5174c..98d65ba2c 100644 --- a/security/core/src/main/java/org/seedstack/seed/security/internal/ShiroSecuritySupport.java +++ b/security/core/src/main/java/org/seedstack/seed/security/internal/ShiroSecuritySupport.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.security.internal; import java.util.ArrayList; @@ -14,7 +15,6 @@ import java.util.HashSet; import java.util.Set; import javax.inject.Inject; -import org.apache.commons.lang.ArrayUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.mgt.SecurityManager; @@ -104,7 +104,7 @@ public boolean isPermitted(String permission) { @Override public boolean isPermitted(String permission, Scope... scopes) { - if (ArrayUtils.isEmpty(scopes)) { + if (scopes == null || scopes.length == 0) { return isPermitted(permission); } boolean isPermitted = true; @@ -121,8 +121,12 @@ public boolean isPermittedAll(String... permissions) { @Override public boolean isPermittedAny(String... permissions) { - boolean[] bools = SecurityUtils.getSubject().isPermitted(permissions); - return ArrayUtils.contains(bools, true); + for (boolean bool : SecurityUtils.getSubject().isPermitted(permissions)) { + if (bool) { + return true; + } + } + return false; } @Override @@ -137,7 +141,7 @@ public void checkPermission(String permission) { @Override public void checkPermission(String permission, Scope... scopes) { try { - if (ArrayUtils.isEmpty(scopes)) { + if (scopes == null || scopes.length == 0) { checkPermission(permission); } else { for (Scope scope : scopes) { @@ -170,7 +174,7 @@ public boolean hasRole(String roleIdentifier) { @Override public boolean hasRole(String roleIdentifier, Scope... scopes) { - if (ArrayUtils.isEmpty(scopes)) { + if (scopes == null || scopes.length == 0) { return hasRole(roleIdentifier); } Role role = null; @@ -194,8 +198,12 @@ public boolean hasAllRoles(String... roleIdentifiers) { @Override public boolean hasAnyRole(String... roleIdentifiers) { - boolean[] hasRoles = SecurityUtils.getSubject().hasRoles(Arrays.asList(roleIdentifiers)); - return ArrayUtils.contains(hasRoles, true); + for (boolean hasRole : SecurityUtils.getSubject().hasRoles(Arrays.asList(roleIdentifiers))) { + if (hasRole) { + return true; + } + } + return false; } @Override diff --git a/security/core/src/main/java/org/seedstack/seed/security/internal/authorization/ConfigurationRoleMapping.java b/security/core/src/main/java/org/seedstack/seed/security/internal/authorization/ConfigurationRoleMapping.java index 61320ceee..4955172a4 100644 --- a/security/core/src/main/java/org/seedstack/seed/security/internal/authorization/ConfigurationRoleMapping.java +++ b/security/core/src/main/java/org/seedstack/seed/security/internal/authorization/ConfigurationRoleMapping.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.security.internal.authorization; import static org.seedstack.shed.reflect.ReflectUtils.makeAccessible; @@ -17,7 +18,6 @@ import java.util.Map; import java.util.Set; import javax.inject.Inject; -import org.apache.commons.lang.StringUtils; import org.seedstack.seed.SeedException; import org.seedstack.seed.security.Role; import org.seedstack.seed.security.RoleMapping; @@ -34,7 +34,7 @@ *
      *     admin = ADMIN, DEV
      * 
    - * + *

    * Means that the admin local role will be given to any identified subject to which the realm(s) have given the ADMIN * or DEV role. *

    @@ -44,7 +44,7 @@ *

      *     reader = *
      * 
    - * + *

    * Means that every identified subject will have the reader role. *

    * This implementation handles simple scopes: @@ -52,7 +52,7 @@ *

      *     admin = ADMIN.{SCOPE}, DEV
      * 
    - * + *

    * Means that subjects having the ADMIN.FR role from the realm(s) (like an LDAP directory) will be given the titi * local role within the FR scope only. */ @@ -161,14 +161,14 @@ void readConfiguration(SecurityConfig securityConfig) { */ private String findScope(String wildcard, String wildcardAuth, String auth) { String scope; - String before = StringUtils.substringBefore(wildcardAuth, wildcard); - String after = StringUtils.substringAfter(wildcardAuth, wildcard); - if (StringUtils.startsWith(wildcardAuth, wildcard)) { - scope = StringUtils.substringBefore(auth, after); - } else if (StringUtils.endsWith(wildcardAuth, wildcard)) { - scope = StringUtils.substringAfter(auth, before); + String before = substringBefore(wildcardAuth, wildcard); + String after = substringAfter(wildcardAuth, wildcard); + if (wildcardAuth.startsWith(wildcard)) { + scope = substringBefore(auth, after); + } else if (wildcardAuth.endsWith(wildcard)) { + scope = substringAfter(auth, before); } else { - scope = StringUtils.substringBetween(auth, before, after); + scope = substringBetween(auth, before, after); } return scope; } @@ -176,4 +176,35 @@ private String findScope(String wildcard, String wildcardAuth, String auth) { private String convertToRegex(String value, String wildcard) { return String.format("\\Q%s\\E", value.replace(wildcard, "\\E.*\\Q")); } + + private String substringBefore(String str, String sep) { + int idx = str.indexOf(sep); + if (idx == -1) { + return str; + } else { + return str.substring(0, idx); + } + } + + private String substringAfter(String str, String sep) { + int idx = str.indexOf(sep); + if (idx == -1) { + return str; + } else { + return str.substring(idx + sep.length()); + } + } + + private String substringBetween(String str, String start, String end) { + String result = str; + int idx = str.indexOf(start); + if (idx != -1) { + result = result.substring(idx + start.length()); + } + idx = result.indexOf(end); + if (idx != -1) { + result = result.substring(0, idx); + } + return result; + } } diff --git a/security/core/src/test/java/org/seedstack/seed/security/internal/SecurityProviderTest.java b/security/core/src/test/java/org/seedstack/seed/security/internal/SecurityProviderTest.java index e2a902999..0da9e12ee 100644 --- a/security/core/src/test/java/org/seedstack/seed/security/internal/SecurityProviderTest.java +++ b/security/core/src/test/java/org/seedstack/seed/security/internal/SecurityProviderTest.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.security.internal; import static org.junit.Assert.assertTrue; @@ -56,7 +57,7 @@ InitContext buildCoherentInitContext() { Collection> realms = new ArrayList<>(); realms.add(ConfigurationRealm.class); types.put(Realm.class, realms); - when(initContext.scannedSubTypesByAncestorClass()).thenReturn(types); + when(initContext.scannedSubTypesByParentClass()).thenReturn(types); ApplicationProvider applicationProvider = mock(ApplicationProvider.class); SecurityConfig securityConfig = mock(SecurityConfig.class); diff --git a/specs/pom.xml b/specs/pom.xml index a38f0144c..a06391d34 100644 --- a/specs/pom.xml +++ b/specs/pom.xml @@ -21,9 +21,14 @@ - io.nuun + io.nuun.kernel kernel-specs + + javax.inject + javax.inject + ${javax.inject.version} + org.seedstack.shed shed diff --git a/specs/src/main/java/org/seedstack/seed/LifecycleListener.java b/specs/src/main/java/org/seedstack/seed/LifecycleListener.java index 7903cf61d..11815ef04 100644 --- a/specs/src/main/java/org/seedstack/seed/LifecycleListener.java +++ b/specs/src/main/java/org/seedstack/seed/LifecycleListener.java @@ -5,13 +5,21 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed; /** * Any class implementing this interface will be registered as an application lifecycle listener. As the application * starts and stops, these callbacks will be invoked to allow for executing startup and/or shutdown code. + * LifecycleListeners are singletons and injected. */ public interface LifecycleListener { + /** + * This method is called by SeedStack just after the application has initialized but is not started yet. + */ + default void starting() { + // no-op + } /** * This method is called by SeedStack just after the application has started up. @@ -26,4 +34,11 @@ default void started() { default void stopping() { // no-op } + + /** + * This method is called by SeedStack just after the application has been shut down. + */ + default void stopped() { + // no-op + } } diff --git a/testing/junit4/pom.xml b/testing/junit4/pom.xml index 9cbc6226d..b6e5e19a1 100644 --- a/testing/junit4/pom.xml +++ b/testing/junit4/pom.xml @@ -37,7 +37,7 @@ - io.nuun + io.nuun.kernel kernel-core test