JAMES-1738 Import Onami-test code in order to not depend on a SNAPSHOT
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/a37176fb Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/a37176fb Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/a37176fb Branch: refs/heads/master Commit: a37176fb07ed3f3c0b106340db5c31b20c7137f4 Parents: e8ef39c Author: Benoit Tellier <[email protected]> Authored: Wed Oct 5 12:38:20 2016 +0200 Committer: Benoit Tellier <[email protected]> Committed: Wed Oct 5 14:57:39 2016 +0200 ---------------------------------------------------------------------- mpt/onami-test/pom.xml | 82 +++ .../james/mpt/onami/test/GuiceMockModule.java | 182 +++++++ .../james/mpt/onami/test/MockEngineFactory.java | 66 +++ .../james/mpt/onami/test/OnamiRunner.java | 510 +++++++++++++++++++ .../apache/james/mpt/onami/test/OnamiSuite.java | 464 +++++++++++++++++ .../mpt/onami/test/annotation/GuiceModules.java | 42 ++ .../test/annotation/GuiceProvidedModules.java | 44 ++ .../james/mpt/onami/test/annotation/Mock.java | 77 +++ .../onami/test/annotation/MockFramework.java | 40 ++ .../mpt/onami/test/annotation/MockObjType.java | 48 ++ .../mpt/onami/test/annotation/MockType.java | 39 ++ .../onami/test/guice/MockMembersInjector.java | 79 +++ .../mpt/onami/test/guice/MockTypeListener.java | 87 ++++ .../handler/GuiceInjectableClassHandler.java | 84 +++ .../onami/test/handler/GuiceModuleHandler.java | 77 +++ .../handler/GuiceProvidedModuleHandler.java | 137 +++++ .../test/handler/MockFrameworkHandler.java | 72 +++ .../mpt/onami/test/handler/MockHandler.java | 178 +++++++ .../james/mpt/onami/test/mock/MockEngine.java | 50 ++ .../test/mock/framework/EasyMockFramework.java | 65 +++ .../test/mock/framework/MockitoFramework.java | 55 ++ .../test/reflection/AnnotationHandler.java | 45 ++ .../mpt/onami/test/reflection/ClassHandler.java | 33 ++ .../mpt/onami/test/reflection/ClassVisitor.java | 110 ++++ .../mpt/onami/test/reflection/FieldHandler.java | 34 ++ .../onami/test/reflection/HandleException.java | 66 +++ .../onami/test/reflection/MethodHandler.java | 34 ++ .../mpt/onami/test/AbstractEmptyTestCase.java | 42 ++ .../mpt/onami/test/AbstractMockTestCase.java | 40 ++ .../mpt/onami/test/AbstractMockitoTestCase.java | 45 ++ .../james/mpt/onami/test/AbstractTestCase.java | 83 +++ .../test/InjectDependingMockObjectTestCase.java | 87 ++++ .../test/InjectFromSuperClassTestCase.java | 57 +++ .../test/InjectJSR330ModuleClassTestCase.java | 54 ++ .../onami/test/InjectMockObjectTestCase.java | 97 ++++ .../onami/test/InjectModuleClassTestCase.java | 53 ++ .../onami/test/InjectStaticSimpleTestCase.java | 70 +++ .../james/mpt/onami/test/MockTypeTestCase.java | 43 ++ .../onami/test/MockitoFrameworkTestCase.java | 60 +++ .../james/mpt/onami/test/OnamiSuiteTest.java | 29 ++ .../mpt/onami/test/ServiceMockProviderTest.java | 43 ++ .../apache/james/mpt/onami/test/SimpleTest.java | 56 ++ .../mpt/onami/test/data/ComplexModule.java | 41 ++ .../mpt/onami/test/data/HelloWordAnnotated.java | 46 ++ .../james/mpt/onami/test/data/HelloWorld.java | 65 +++ .../james/mpt/onami/test/data/Service.java | 29 ++ .../james/mpt/onami/test/data/ServiceImpl.java | 36 ++ .../onami/test/data/ServiceMockProvider.java | 33 ++ .../mpt/onami/test/data/ServiceModule.java | 35 ++ .../james/mpt/onami/test/data/SimpleModule.java | 34 ++ .../mpt/onami/test/data/TelephonService.java | 27 + .../onami/test/data/TelephonServiceImpl.java | 31 ++ .../mpt/onami/test/data/TestAnnotation.java | 32 ++ .../mpt/onami/test/data/TestAnnotation2.java | 32 ++ .../apache/james/mpt/onami/test/data/WhoIm.java | 37 ++ .../test/guice/MockAnnotatedWithTestCase.java | 76 +++ .../test/guice/TestCustomInjectionTest.java | 82 +++ .../src/test/resources/log4j.properties | 46 ++ mpt/pom.xml | 1 + 59 files changed, 4342 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/pom.xml ---------------------------------------------------------------------- diff --git a/mpt/onami-test/pom.xml b/mpt/onami-test/pom.xml new file mode 100644 index 0000000..930450d --- /dev/null +++ b/mpt/onami-test/pom.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>apache-james-mpt</artifactId> + <groupId>org.apache.james</groupId> + <version>3.0.0-beta5-SNAPSHOT</version> + </parent> + + <artifactId>apache-james-mpt-onami-test</artifactId> + <packaging>jar</packaging> + + <name>Apache James :: MPT :: Onami-test</name> + <description>MPT tooling from Onami project</description> + + <dependencies> + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>3.2</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>16.0.1</version> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.9.5</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/GuiceMockModule.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/GuiceMockModule.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/GuiceMockModule.java new file mode 100644 index 0000000..645e57f --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/GuiceMockModule.java @@ -0,0 +1,182 @@ +/**************************************************************** + * 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.mpt.onami.test; + +import static com.google.common.base.Preconditions.checkState; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.annotation.Mock; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +/** + * <p> + * This class creates the binding for all mock objects found. + * </p> + * <p> + * Method {@link GuiceMockModule#configure()} creates a binding for each {@link Mock} annotation found. The binding will + * be created <b>if and only if</b> there is no types conflict between {@link Mock} caught. + * <p> + * <p> + * <b>A type conflict</b> is detected if two or more field are annotated with the same {@link Mock} and no different + * {@link Mock#annotatedWith} parameter are specified, or two o more equals {@link Mock#annotatedWith} parameter are + * specified for the same type field. + * </p> + * <p> + * If a conflict is detected the binding will not create for the conflicted type, moreover the field will be injected + * into the test class. + * </p> + */ +public class GuiceMockModule + extends AbstractModule +{ + + private static final Logger LOGGER = Logger.getLogger( GuiceMockModule.class.getName() ); + + final Map<Field, Object> mockedFields; + + /** + * Costructor. + * + * @param mockedFields the map of mock fileds. + */ + + public GuiceMockModule( final Map<Field, Object> mockedFields ) + { + this.mockedFields = mockedFields; + } + + @SuppressWarnings( "unchecked" ) + @Override + protected void configure() + { + final Multimap<Type, Field> fieldsByType = HashMultimap.create(); + + for ( final Entry<Field, Object> entry : this.mockedFields.entrySet() ) + { + fieldsByType.put( entry.getKey().getGenericType(), entry.getKey() ); + } + + for ( final Type type : fieldsByType.keySet() ) + { + final Collection<Field> fields = fieldsByType.get( type ); + + boolean isTypeConflicts = false; + if ( fields.size() != 1 ) + { + isTypeConflicts = checkTypeConflict( fields ); + } + + checkState( !isTypeConflicts, " Found multiple annotation @%s for type: %s; binding skipped!.", + Mock.class.getSimpleName(), type ); + for ( final Field field : fields ) + { + final TypeLiteral literal = TypeLiteral.get( type ); + final Mock annoBy = field.getAnnotation( Mock.class ); + final Object mock = this.mockedFields.get( field ); + if ( annoBy.annotatedWith() != Mock.NoAnnotation.class ) + { + bind( literal ).annotatedWith( annoBy.annotatedWith() ).toInstance( mock ); + } + else if ( !"".equals( annoBy.namedWith() ) ) + { + bind( literal ).annotatedWith( Names.named( annoBy.namedWith() ) ).toInstance( mock ); + } + else + { + bind( literal ).toInstance( mock ); + } + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Created binding for: " + type + " " + annoBy ); + } + } + } + } + + /** + * @param fields + * @return + */ + private boolean checkTypeConflict( Collection<Field> fields ) + { + final List<Class<?>> listAnnotatedType = new ArrayList<Class<?>>(); + final List<String> listNamedType = new ArrayList<String>(); + int numOfSimpleType = 0; + + for ( Field field : fields ) + { + final Mock annoBy = field.getAnnotation( Mock.class ); + + if ( annoBy.annotatedWith() == Mock.NoAnnotation.class && "".equals( annoBy.namedWith() ) ) + { + numOfSimpleType++; + } + if ( numOfSimpleType > 1 ) + { + LOGGER.finer( "Found multiple simple type" ); + return true; + } + + if ( annoBy.annotatedWith() != Mock.NoAnnotation.class ) + { + if ( !listAnnotatedType.contains( annoBy.annotatedWith() ) ) + { + listAnnotatedType.add( annoBy.annotatedWith() ); + } + else + { + // found two fields with same annotation + LOGGER.finer( "Found multiple annotatedBy type" ); + return true; + } + } + + if ( !"".equals( annoBy.namedWith() ) ) + { + if ( !listNamedType.contains( annoBy.namedWith() ) ) + { + listNamedType.add( annoBy.namedWith() ); + } + else + { + // found two fields with same named annotation + LOGGER.finer( "Found multiple namedWith type" ); + return true; + } + } + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/MockEngineFactory.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/MockEngineFactory.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/MockEngineFactory.java new file mode 100644 index 0000000..ad10daf --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/MockEngineFactory.java @@ -0,0 +1,66 @@ +/**************************************************************** + * 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.mpt.onami.test; + +import org.apache.james.mpt.onami.test.annotation.MockType; +import org.apache.james.mpt.onami.test.mock.MockEngine; +import org.apache.james.mpt.onami.test.mock.framework.EasyMockFramework; +import org.apache.james.mpt.onami.test.mock.framework.MockitoFramework; + +/** + * Factory class to create the mock framework. + * + * @see org.apache.onami.test.annotation.MockFramework + */ +final class MockEngineFactory +{ + + /** + * Hidden constructor, this class must not be instantiated directly. + */ + private MockEngineFactory() + { + // do nothing + } + + /** + * Mock factory constructor. <br> + * Supported framewors: <li> {@link MockType}.EASY_MOCK <li> {@link MockType}.MOCKITO <br> + * + * @see MockType + * @param type of mock framework to create. + * @return An instance of mock framework. + */ + public static MockEngine getMockEngine(MockType type ) + { + switch ( type ) + { + case EASY_MOCK: + return new EasyMockFramework(); + + case MOCKITO: + return new MockitoFramework(); + + default: + throw new IllegalArgumentException( "Unrecognized MockType '" + type.name() + "'" ); + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiRunner.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiRunner.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiRunner.java new file mode 100644 index 0000000..3ca9f6c --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiRunner.java @@ -0,0 +1,510 @@ +/**************************************************************** + * 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.mpt.onami.test; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.annotation.GuiceModules; +import org.apache.james.mpt.onami.test.annotation.GuiceProvidedModules; +import org.apache.james.mpt.onami.test.annotation.Mock; +import org.apache.james.mpt.onami.test.annotation.MockFramework; +import org.apache.james.mpt.onami.test.annotation.MockType; +import org.apache.james.mpt.onami.test.guice.MockTypeListener; +import org.apache.james.mpt.onami.test.handler.GuiceInjectableClassHandler; +import org.apache.james.mpt.onami.test.handler.GuiceModuleHandler; +import org.apache.james.mpt.onami.test.handler.GuiceProvidedModuleHandler; +import org.apache.james.mpt.onami.test.handler.MockFrameworkHandler; +import org.apache.james.mpt.onami.test.handler.MockHandler; +import org.apache.james.mpt.onami.test.mock.MockEngine; +import org.apache.james.mpt.onami.test.reflection.ClassVisitor; +import org.apache.james.mpt.onami.test.reflection.HandleException; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.matcher.Matchers; +import com.google.inject.util.Modules; + +/** + * <p> + * It's a {@link BlockJUnit4ClassRunner} runner. + * </p> + * <p> + * This class creates a Google Guice {@link Injector} configured by {@link GuiceModules} annotation (only fr modules + * with default constructor) and {@link GuiceProvidedModules} annotation and {@link Mock}. + * </p> + * <p> + * <b>Example #1:</b> <br> + * + * <pre> + * + * @org.junit.runner.RunWith( OnamiRunner.class ) + * @GuiceModules( SimpleModule.class ) + * public class AcmeTestCase + * { + * + * @GuiceProvidedModules + * static public Module getProperties() + * { + +import org.apache.onami.test.reflection.AnnotationHandler; +import org.apache.onami.test.reflection.HandleException; + * ... + * return Modules.combine(new ComplexModule( loadProperies() ), ... ); + * } + * + * </pre> + * + * </p> + * <p> + * <b>Example #2:</b> <br> + * + * <pre> + * + * @org.junit.runner.RunWith( OnamiRunner.class ) + * public class AcmeTestCase + * extends com.google.inject.AbstractModule + * { + * + * public void configure() + * { + * // Configure your proper modules + * ... + * bind( Service.class ).annotatedWith( TestAnnotation.class ).to( ServiceTestImpl.class ); + * ... + * } + * + * @Mock + * private AnotherService serviceMock; + * + * @Inject + * private Service serviceTest; + * + * @org.junit.Test + * public void test() + * { + * assertNotNull( serviceMock ); + * assertNotNull( serviceTest ); + * } + * </pre> + * + * </p> + * + * @see GuiceMockModule + */ +public class OnamiRunner + extends BlockJUnit4ClassRunner +{ + + private static final Logger LOGGER = Logger.getLogger( OnamiRunner.class.getName() ); + + private Injector injector; + + private final List<Module> allModules; + + private final Map<Field, Object> mocked = new HashMap<Field, Object>( 1 ); + + private MockType mockFramework = MockType.EASY_MOCK; + + /** + * OnamiRunner constructor to create the core JUnice class. + * + * @see org.junit.runner.RunWith + * @param klass The test case class to run. + * @throws org.junit.runners.model.InitializationError if any error occurs. + */ + public OnamiRunner( Class<?> klass ) + throws InitializationError + { + super( klass ); + + try + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "Inizializing injector for test class: " + klass.getName() ); + } + + this.allModules = inizializeInjector( klass ); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "done..." ); + } + } + catch ( Exception e ) + { + final List<Throwable> throwables = new LinkedList<Throwable>(); + throwables.add( e ); + throw new InitializationError( throwables ); + } + } + + /** + * OnamiRunner constructor to create the runner needed + * by the OnamiSuite class. + * + * @see org.junit.runner.RunWith + * @param suite The suite test case class to run. + * @param test The test case class to run. + * @throws org.junit.runners.model.InitializationError if any error occurs. + */ + public OnamiRunner( Class<?> suite, Class<?> test ) + throws InitializationError + { + super( test ); + + try + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "Inizializing injector for test class: " + test.getName() ); + } + + this.allModules = inizializeInjector( suite, test ); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "done..." ); + } + } + catch ( Exception e ) + { + final List<Throwable> throwables = new LinkedList<Throwable>(); + throwables.add( e ); + throw new InitializationError( throwables ); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void run( final RunNotifier notifier ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ### Run test case: " + getTestClass().getJavaClass() + " ### " ); + LOGGER.finer( " #### Creating injector ####" ); + } + + this.injector = createInjector( allModules ); + super.run( notifier ); + this.flush(); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ### End test case: " + getTestClass().getJavaClass().getName() + " ### " ); + } + } + + /** + * {@inheritDoc} + */ + private void flush() + { + this.injector = null; + this.allModules.clear(); + this.mocked.clear(); + } + + @Override + protected void runChild( FrameworkMethod method, RunNotifier notifier ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " +++ invoke test method: " + method.getName() + " +++ " ); + } + + super.runChild( method, notifier ); + resetAllResetAfterMocks(); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " --- end test method: " + method.getName() + " --- " ); + } + } + + /** + * Creates test instance via Google-Guice to inject all not-static dependencies. + * @return The instance of the test case. + * @throws Exception when an error occurs. + */ + @Override + protected Object createTest() + throws Exception + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Create and inject test class: " + getTestClass().getJavaClass() ); + } + return this.injector.getInstance( getTestClass().getJavaClass() ); + } + + /** + * Shortcut to create the Injector given a list of Modules. + * + * @param modules the list of modules have to be load + * @return an Injector instance built using the input Module list + */ + protected Injector createInjector( List<Module> modules ) + { + return Guice.createInjector( modules ); + } + + /** + * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock} + * and {@ OnamiSuite}. + * + * @param <T> whatever input type is accepted + * @param suite the input suite to be analyzed + * @param test the input class has to be analyzed + * @return a List of Guice Modules built after input class analysis. + * @throws IllegalAccessException when a n error occurs. + * @throws InstantiationException when a n error occurs. + * @throws HandleException when a n error occurs. + */ + protected <T> List<Module> inizializeInjector( Class<?> suite, Class<T> test) + throws HandleException, InstantiationException, IllegalAccessException + { + final List<Module> modules = inizializeInjector(test); + Module m = visitClass( suite ); + if ( m != null ) + { + modules.add( m ); + } + return modules; + } + + /** + * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock}. + * + * @param <T> whatever input type is accepted + * @param clazz the input class has to be analyzed + * @return a List of Guice Modules built after input class analysis. + * @throws IllegalAccessException when a n error occurs. + * @throws InstantiationException when a n error occurs. + * @throws HandleException when a n error occurs. + */ + protected <T> List<Module> inizializeInjector( Class<T> clazz ) + throws HandleException, InstantiationException, IllegalAccessException + { + final List<Module> modules = new ArrayList<Module>(); + Module m = visitClass( clazz ); + if ( m != null ) + { + modules.add( m ); + } + return modules; + } + + private void resetAllResetAfterMocks() + { + for ( Entry<Field, Object> entry : mocked.entrySet() ) + { + final Mock mockAnnotation = entry.getKey().getAnnotation( Mock.class ); + if ( mockAnnotation.resetAfter() ) + { + MockEngine mockEngine = MockEngineFactory.getMockEngine( mockFramework ); + mockEngine.resetMock( entry.getValue() ); + } + } + } + + /** + * @throws HandleException + * @throws IllegalAccessException + * @throws InstantiationException + */ + private <T> Module visitClass( final Class<T> clazz ) + throws HandleException, InstantiationException, IllegalAccessException + { + try + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Start introspecting class: " + clazz.getName() ); + } + final List<Module> allModules = new ArrayList<Module>(); + + // Setup the handlers + final GuiceProvidedModuleHandler guiceProvidedModuleHandler = new GuiceProvidedModuleHandler(); + final GuiceModuleHandler guiceModuleHandler = new GuiceModuleHandler(); + final GuiceInjectableClassHandler<Inject> guiceInjectableClassHandler = new GuiceInjectableClassHandler<com.google.inject.Inject>(); + final GuiceInjectableClassHandler<javax.inject.Inject> jsr330InjectableClassHandler = new GuiceInjectableClassHandler<javax.inject.Inject>(); + + final MockHandler mockHandler = new MockHandler(); + final MockFrameworkHandler mockFrameworkHandler = new MockFrameworkHandler(); + + // Visit class and super-classes + new ClassVisitor() + .registerHandler( GuiceProvidedModules.class, guiceProvidedModuleHandler ) + .registerHandler( GuiceModules.class, guiceModuleHandler ) + .registerHandler( Mock.class, mockHandler ) + .registerHandler( MockFramework.class, mockFrameworkHandler ) + .registerHandler( com.google.inject.Inject.class, guiceInjectableClassHandler ) + .registerHandler( javax.inject.Inject.class, jsr330InjectableClassHandler ) + .visit( clazz ); + + // Retrieve mock framework + if ( mockFrameworkHandler.getMockType() != null ) + { + this.mockFramework = mockFrameworkHandler.getMockType(); + } + + // retrieve the modules founded + allModules.addAll( guiceProvidedModuleHandler.getModules() ); + allModules.addAll( guiceModuleHandler.getModules() ); + MockEngine engine = MockEngineFactory.getMockEngine( this.mockFramework ); + this.mocked.putAll( mockHandler.getMockedObject( engine ) ); + if ( !this.mocked.isEmpty() ) + { + // Replace all real module binding with Mocked moduled. + Module m = Modules.override( allModules ).with( new GuiceMockModule( this.mocked ) ); + allModules.clear(); + allModules.add( m ); + } + + // Add only clasess that have got the Inject annotation + final Class<?>[] guiceInjectableClasses = guiceInjectableClassHandler.getClasses(); + final Class<?>[] jsr330InjectableClasses = jsr330InjectableClassHandler.getClasses(); + + final AbstractModule statcInjector = new AbstractModule() + { + @Override + protected void configure() + { + // inject all STATIC dependencies + if ( guiceInjectableClasses.length != 0 ) + { + requestStaticInjection( guiceInjectableClasses ); + } + + if ( jsr330InjectableClasses.length != 0 ) + { + requestStaticInjection( jsr330InjectableClasses ); + } + + + } + }; + if ( guiceInjectableClasses.length != 0 || jsr330InjectableClasses.length != 0 ) + { + allModules.add( statcInjector ); + } + + // Check if the class is itself a Google Module. + if ( Module.class.isAssignableFrom( getTestClass().getJavaClass() ) ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " creating module from test class " + getTestClass().getJavaClass() ); + } + final Module classModule = (Module) getTestClass().getJavaClass().newInstance(); + allModules.add( classModule ); + } + + // create MockTypeListenerModule + if ( this.mocked.size() != 0 ) + { + final AbstractModule mockTypeListenerModule = new AbstractModule() + { + @Override + protected void configure() + { + bindListener( Matchers.any(), new MockTypeListener( mocked ) ); + } + }; + + // BEGIN patch for issue: google-guice: #452 + for ( Entry<Field, Object> entry : mocked.entrySet() ) + { + final Field field = entry.getKey(); + final Object mock = entry.getValue(); + if ( Modifier.isStatic( field.getModifiers() ) ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " inject static mock field: " + field.getName() ); + } + + AccessController.doPrivileged( new PrivilegedAction<Void>() + { + + public Void run() + { + field.setAccessible( true ); + return null; + } + + } ); + field.set( field.getDeclaringClass(), mock ); + } + } + // END patch for issue: google-guice: #452 + + allModules.add( mockTypeListenerModule ); + } + + if ( allModules.size() != 0 ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + StringBuilder builder = new StringBuilder(); + builder.append( " Collected modules: " ); + builder.append( "\n" ); + for ( Module module : allModules ) + { + builder.append( " " ).append( module ); + builder.append( "\n" ); + } + LOGGER.finer( builder.toString() ); + } + return Modules.combine( allModules ); + } + return null; + } + finally + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ...done" ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiSuite.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiSuite.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiSuite.java new file mode 100644 index 0000000..cb7835e --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/OnamiSuite.java @@ -0,0 +1,464 @@ +/**************************************************************** + * 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.mpt.onami.test; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.annotation.GuiceModules; +import org.apache.james.mpt.onami.test.annotation.GuiceProvidedModules; +import org.apache.james.mpt.onami.test.annotation.Mock; +import org.apache.james.mpt.onami.test.annotation.MockFramework; +import org.apache.james.mpt.onami.test.annotation.MockType; +import org.apache.james.mpt.onami.test.guice.MockTypeListener; +import org.apache.james.mpt.onami.test.handler.GuiceInjectableClassHandler; +import org.apache.james.mpt.onami.test.handler.GuiceModuleHandler; +import org.apache.james.mpt.onami.test.handler.GuiceProvidedModuleHandler; +import org.apache.james.mpt.onami.test.handler.MockFrameworkHandler; +import org.apache.james.mpt.onami.test.handler.MockHandler; +import org.apache.james.mpt.onami.test.mock.MockEngine; +import org.apache.james.mpt.onami.test.reflection.ClassVisitor; +import org.apache.james.mpt.onami.test.reflection.HandleException; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.matcher.Matchers; +import com.google.inject.util.Modules; + +/** + * <p> + * It's a {@link Suite} runner. + * </p> + * <p> + * This class creates a Google Guice {@link Injector} configured by {@link GuiceModules} annotation (only fr modules + * with default constructor) and {@link GuiceProvidedModules} annotation and {@link Mock}. + * </p> + * <p> + * <b>Example #1:</b> <br> + * + * <pre> + * + * @org.junit.runner.RunWith( OnamiSuite.class ) + * @GuiceModules( SimpleModule.class ) + * @SuiteClasses({ .class }) + * public class AcmeTestCase + * { + * + * @GuiceProvidedModules + * static public Module getProperties() + * { + * ... + * return Modules.combine(new ComplexModule( loadProperies() ), ... ); + * } + * + * </pre> + * + * </p> + * <p> + * <b>Example #2:</b> <br> + * + * <pre> + * + * @org.junit.runner.RunWith( OnamiSuite.class ) + * public class AcmeTestCase + * extends com.google.inject.AbstractModule + * { + * + * public void configure() + * { + * // Configure your proper modules + * ... + * bind( Service.class ).annotatedWith( TestAnnotation.class ).to( ServiceTestImpl.class ); + * ... + * } + * + * @Mock + * private AnotherService serviceMock; + * + * @Inject + * private Service serviceTest; + * + * @org.junit.Test + * public void test() + * { + * assertNotNull( serviceMock ); + * assertNotNull( serviceTest ); + * } + * </pre> + * + * </p> + * + * @see GuiceMockModule + */ +public class OnamiSuite + extends Suite +{ + + private static final Logger LOGGER = Logger.getLogger( OnamiSuite.class.getName() ); + + private Injector injector; + + private final List<Module> allModules; + + private final Map<Field, Object> mocked = new HashMap<Field, Object>( 1 ); + + private MockType mockFramework = MockType.EASY_MOCK; + + private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError { + SuiteClasses annotation= klass.getAnnotation(SuiteClasses.class); + if (annotation == null) + throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName())); + return annotation.value(); + } + + /** + * OnamiRunner constructor to create the core JUnice class. + * + * @see org.junit.runner.RunWith + * @param klass The test case class to run. + * @throws org.junit.runners.model.InitializationError if any error occurs. + */ + public OnamiSuite( Class<?> klass, RunnerBuilder builder ) + throws InitializationError + { + this(builder, klass, getAnnotatedClasses(klass)); + + } + + /** + * Called by this class and subclasses once the classes making up the suite have been determined + * + * @param builder builds runners for classes in the suite + * @param klass the root of the suite + * @param suiteClasses the classes in the suite + * @throws InitializationError + */ + protected OnamiSuite( RunnerBuilder builder, Class<?> suite, Class<?>[] suiteClasses ) + throws InitializationError + { + super( suite, runners( suite, suiteClasses ) ); + try + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "Inizializing injector for siote class: " + suite.getName() ); + } + + this.allModules = inizializeInjector( suite ); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( "done..." ); + } + } + catch ( Exception e ) + { + final List<Throwable> throwables = new LinkedList<Throwable>(); + throwables.add( e ); + throw new InitializationError( throwables ); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void run( final RunNotifier notifier ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ### Run test case: " + getTestClass().getJavaClass() + " ### " ); + LOGGER.finer( " #### Creating injector ####" ); + } + + this.injector = createInjector( allModules ); + super.run( notifier ); + this.flush(); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ### End test case: " + getTestClass().getJavaClass().getName() + " ### " ); + } + } + + private static List<Runner> runners( Class<?> suite, Class<?>[] children ) throws InitializationError { + ArrayList<Runner> runners= new ArrayList<Runner>(); + for (Class<?> each : children) { + Runner childRunner= new OnamiRunner( suite, each ); + if (childRunner != null) + runners.add(childRunner); + } + return runners; + } + + /** + * {@inheritDoc} + */ + private void flush() + { + this.injector = null; + this.allModules.clear(); + this.mocked.clear(); + } + + @Override + protected void runChild( Runner runner, RunNotifier notifier ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " +++ invoke runner: " + runner + " +++ " ); + } + + super.runChild( runner, notifier ); + resetAllResetAfterMocks(); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " --- end runner: " + runner + " --- " ); + } + } + + /** + * Shortcut to create the Injector given a list of Modules. + * + * @param modules the list of modules have to be load + * @return an Injector instance built using the input Module list + */ + protected Injector createInjector( List<Module> modules ) + { + return Guice.createInjector( modules ); + } + + /** + * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock}. + * + * @param <T> whatever input type is accepted + * @param clazz the input class has to be analyzed + * @return a List of Guice Modules built after input class analysis. + * @throws IllegalAccessException when a n error occurs. + * @throws InstantiationException when a n error occurs. + * @throws HandleException when a n error occurs. + */ + protected <T> List<Module> inizializeInjector( Class<T> clazz ) + throws HandleException, InstantiationException, IllegalAccessException + { + final List<Module> modules = new ArrayList<Module>(); + Module m = visitClass( clazz ); + if ( m != null ) + { + modules.add( m ); + } + return modules; + } + + private void resetAllResetAfterMocks() + { + for ( Entry<Field, Object> entry : mocked.entrySet() ) + { + final Mock mockAnnotation = entry.getKey().getAnnotation( Mock.class ); + if ( mockAnnotation.resetAfter() ) + { + MockEngine mockEngine = MockEngineFactory.getMockEngine( mockFramework ); + mockEngine.resetMock( entry.getValue() ); + } + } + } + + /** + * @throws HandleException + * @throws IllegalAccessException + * @throws InstantiationException + */ + private <T> Module visitClass( final Class<T> clazz ) + throws HandleException, InstantiationException, IllegalAccessException + { + try + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Start introspecting class: " + clazz.getName() ); + } + final List<Module> allModules = new ArrayList<Module>(); + + // Setup the handlers + final GuiceProvidedModuleHandler guiceProvidedModuleHandler = new GuiceProvidedModuleHandler(); + final GuiceModuleHandler guiceModuleHandler = new GuiceModuleHandler(); + final GuiceInjectableClassHandler<Inject> guiceInjectableClassHandler = new GuiceInjectableClassHandler<Inject>(); + final GuiceInjectableClassHandler<javax.inject.Inject> jsr330InjectableClassHandler = new GuiceInjectableClassHandler<javax.inject.Inject>(); + + final MockHandler mockHandler = new MockHandler(); + final MockFrameworkHandler mockFrameworkHandler = new MockFrameworkHandler(); + + // Visit class and super-classes + new ClassVisitor() + .registerHandler( GuiceProvidedModules.class, guiceProvidedModuleHandler ) + .registerHandler( GuiceModules.class, guiceModuleHandler ) + .registerHandler( Mock.class, mockHandler ) + .registerHandler( MockFramework.class, mockFrameworkHandler ) + .registerHandler( Inject.class, guiceInjectableClassHandler ) + .registerHandler( javax.inject.Inject.class, jsr330InjectableClassHandler ) + .visit( clazz ); + + // Retrieve mock framework + if ( mockFrameworkHandler.getMockType() != null ) + { + this.mockFramework = mockFrameworkHandler.getMockType(); + } + + // retrieve the modules founded + allModules.addAll( guiceProvidedModuleHandler.getModules() ); + allModules.addAll( guiceModuleHandler.getModules() ); + MockEngine engine = MockEngineFactory.getMockEngine( this.mockFramework ); + this.mocked.putAll( mockHandler.getMockedObject( engine ) ); + if ( !this.mocked.isEmpty() ) + { + // Replace all real module binding with Mocked moduled. + Module m = Modules.override( allModules ).with( new GuiceMockModule( this.mocked ) ); + allModules.clear(); + allModules.add( m ); + } + + // Add only clasess that have got the Inject annotation + final Class<?>[] guiceInjectableClasses = guiceInjectableClassHandler.getClasses(); + final Class<?>[] jsr330InjectableClasses = jsr330InjectableClassHandler.getClasses(); + + final AbstractModule statcInjector = new AbstractModule() + { + @Override + protected void configure() + { + // inject all STATIC dependencies + if ( guiceInjectableClasses.length != 0 ) + { + requestStaticInjection( guiceInjectableClasses ); + } + + if ( jsr330InjectableClasses.length != 0 ) + { + requestStaticInjection( jsr330InjectableClasses ); + } + + + } + }; + if ( guiceInjectableClasses.length != 0 || jsr330InjectableClasses.length != 0 ) + { + allModules.add( statcInjector ); + } + + // Check if the class is itself a Google Module. + if ( Module.class.isAssignableFrom( getTestClass().getJavaClass() ) ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " creating module from test class " + getTestClass().getJavaClass() ); + } + final Module classModule = (Module) getTestClass().getJavaClass().newInstance(); + allModules.add( classModule ); + } + + // create MockTypeListenerModule + if ( this.mocked.size() != 0 ) + { + final AbstractModule mockTypeListenerModule = new AbstractModule() + { + @Override + protected void configure() + { + bindListener( Matchers.any(), new MockTypeListener( mocked ) ); + } + }; + + // BEGIN patch for issue: google-guice: #452 + for ( Entry<Field, Object> entry : mocked.entrySet() ) + { + final Field field = entry.getKey(); + final Object mock = entry.getValue(); + if ( Modifier.isStatic( field.getModifiers() ) ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " inject static mock field: " + field.getName() ); + } + + AccessController.doPrivileged( new PrivilegedAction<Void>() + { + + public Void run() + { + field.setAccessible( true ); + return null; + } + + } ); + field.set( field.getDeclaringClass(), mock ); + } + } + // END patch for issue: google-guice: #452 + + allModules.add( mockTypeListenerModule ); + } + + if ( allModules.size() != 0 ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + StringBuilder builder = new StringBuilder(); + builder.append( " Collected modules: " ); + builder.append( "\n" ); + for ( Module module : allModules ) + { + builder.append( " " ).append( module ); + builder.append( "\n" ); + } + LOGGER.finer( builder.toString() ); + } + return Modules.combine( allModules ); + } + return null; + } + finally + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " ...done" ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceModules.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceModules.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceModules.java new file mode 100644 index 0000000..fe98e07 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceModules.java @@ -0,0 +1,42 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.google.inject.Module; + +/** + * Annotate your class to define a list of Google Guice {@link Module} whit default constructor. + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.TYPE ) +public @interface GuiceModules +{ + + /** + * List of Google Guice {@link Module}. + */ + Class<? extends Module>[] value(); + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceProvidedModules.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceProvidedModules.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceProvidedModules.java new file mode 100644 index 0000000..bd36d22 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/GuiceProvidedModules.java @@ -0,0 +1,44 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p> + * Annotate a <b>public static</b> method to create a Google Guice {@link com.google.inject.Module} provider. + * </p> + * <p> + * The method return type must be one of: + * <ul> + * <li>com.google.inject.Module</li> + * <li>Iterable<com.google.inject.Module></li> + * <li>com.google.inject.Module[]</li> + * </p> + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.METHOD ) +public @interface GuiceProvidedModules +{ + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/Mock.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/Mock.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/Mock.java new file mode 100644 index 0000000..5695e51 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/Mock.java @@ -0,0 +1,77 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotate your filed into which {@link org.apache.onami.test.GuiceMockModule} will create and inject the mock object. + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.FIELD ) +@Inherited +public @interface Mock +{ + + /** + * Annotation class used to mark that no annotation binding is defined. + */ + public static @interface NoAnnotation + { + } + + /** + * Indicates if this mock object has to be resetted after each test method Default: true + */ + boolean resetAfter() default true; + + /** + * The name of the method that provides to mock creation. + */ + String providedBy() default ""; + + /** + * The {@link Class} that contains the method {@link Mock#providedBy()}. By default: the filed declaring class. + */ + Class<?> providerClass() default Object.class; + + /** + * Specifies an annotation {@link Class} that will be used in the <em>Google Guice</em> binder to execute the literal + * annotating binding. + */ + Class<? extends Annotation> annotatedWith() default NoAnnotation.class; + + /** + * Specifies an {@link String} annotation that will be used in the <em>Google Guice</em> binder to execute the + * literal annotating binding via {@link com.google.inject.name.Named} class. + */ + String namedWith() default ""; + + /** + * Specifies TODO + */ + MockObjType type() default MockObjType.DEFAULT; + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockFramework.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockFramework.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockFramework.java new file mode 100644 index 0000000..d695453 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockFramework.java @@ -0,0 +1,40 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotate test class to specify you favorite mock framework. + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.TYPE ) +public @interface MockFramework +{ + + /** + * Type of mock that JUnice has to create. + */ + MockType value(); + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockObjType.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockObjType.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockObjType.java new file mode 100644 index 0000000..e3e4eac --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockObjType.java @@ -0,0 +1,48 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +/** + * Enumeration class to specifies the preferred mock object. + */ +public enum MockObjType +{ + + /** + * @see EasyMock.createMock + */ + EASY_MOCK_NORMAL, + + /** + * @see EasyMock.createStrictMock + */ + EASY_MOCK_STRICT, + + /** + * @see EasyMock.createNiceMock + */ + EASY_MOCK_NICE, + + /** + * Use default mock creation mode + */ + DEFAULT + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockType.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockType.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockType.java new file mode 100644 index 0000000..57f2810 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/annotation/MockType.java @@ -0,0 +1,39 @@ +/**************************************************************** + * 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.mpt.onami.test.annotation; + +/** + * Enumeration class to specifies your preferred mock framework. + * + * @see MockFramework + */ +public enum MockType +{ + /** + * Identify the Easy Mock framework + */ + EASY_MOCK, + + /** + * Identify the Mockito framework + */ + MOCKITO + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockMembersInjector.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockMembersInjector.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockMembersInjector.java new file mode 100644 index 0000000..d8f05ce --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockMembersInjector.java @@ -0,0 +1,79 @@ +/**************************************************************** + * 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.mpt.onami.test.guice; + +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; + +import com.google.inject.MembersInjector; + +/** + * Class to inject via google-guice mock members into test cases classes. + * + * @param <T> type to inject members of + */ +public class MockMembersInjector<T> + implements MembersInjector<T> +{ + + private final Field field; + + private final Map<Field, Object> mockedObjects; + + /** + * Create a new instance. + * + * @param field the field that has to be injected. + * @param mockedObjects the map of mocked object. + */ + public MockMembersInjector( final Field field, Map<Field, Object> mockedObjects ) + { + this.field = field; + this.mockedObjects = mockedObjects; + AccessController.doPrivileged( new PrivilegedAction<Void>() + { + + public Void run() + { + field.setAccessible( true ); + return null; + } + + } ); + } + + /** + * {@inheritDoc} + */ + public void injectMembers( T t ) + { + try + { + field.set( t, mockedObjects.get( field ) ); + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockTypeListener.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockTypeListener.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockTypeListener.java new file mode 100644 index 0000000..427fab8 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/guice/MockTypeListener.java @@ -0,0 +1,87 @@ +/**************************************************************** + * 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.mpt.onami.test.guice; + +import java.lang.reflect.Field; +import java.util.Map; + +import org.apache.james.mpt.onami.test.annotation.Mock; +import org.apache.james.mpt.onami.test.reflection.AnnotationHandler; +import org.apache.james.mpt.onami.test.reflection.ClassVisitor; +import org.apache.james.mpt.onami.test.reflection.HandleException; + +import com.google.inject.TypeLiteral; +import com.google.inject.spi.TypeEncounter; +import com.google.inject.spi.TypeListener; + +/** + * <p> + * {@link TypeListener} implementation. + * </p> + * <p> + * Creates a specific {@link MockMembersInjector} for each {@link Mock} annotation found. + * </p> + * + * @see MockMembersInjector + * @see Mock + */ +public class MockTypeListener + implements TypeListener +{ + + private final Map<Field, Object> mockedObjects; + + /** + * Creates a new {@code MockTypeListener} instance given a map of mocked objects. + * + * @param mockedObjects a map of mocked objects + */ + public MockTypeListener( Map<Field, Object> mockedObjects ) + { + this.mockedObjects = mockedObjects; + } + + /** + * {@inheritDoc} + */ + public <I> void hear( final TypeLiteral<I> typeLiteral, final TypeEncounter<I> typeEncounter ) + { + try + { + new ClassVisitor() + .registerHandler( Mock.class, new AnnotationHandler<Mock, Field>() + { + + public void handle( Mock annotation, Field field ) + throws HandleException + { + typeEncounter.register( new MockMembersInjector<I>( field, mockedObjects ) ); + } + + } ) + .visit( typeLiteral.getRawType() ); + } + catch ( HandleException e ) + { + typeEncounter.addError( e ); + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceInjectableClassHandler.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceInjectableClassHandler.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceInjectableClassHandler.java new file mode 100644 index 0000000..936e4ed --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceInjectableClassHandler.java @@ -0,0 +1,84 @@ +/**************************************************************** + * 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.mpt.onami.test.handler; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Member; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.reflection.AnnotationHandler; +import org.apache.james.mpt.onami.test.reflection.HandleException; + +/** + * Handler class to handle all {@link com.google.inject.Inject} and {@link javax.inject.Inject} annotations. + * + * @param <A> whatever annotation type + * @see org.apache.onami.test.reflection.ClassVisitor + */ +public final class GuiceInjectableClassHandler<A extends Annotation> + implements AnnotationHandler<A, AccessibleObject> +{ + + private static final Logger LOGGER = Logger.getLogger( GuiceInjectableClassHandler.class.getName() ); + + /** + * Contains the guice injectable classes founded, after inspection. + */ + protected final Set<Class<?>> classes = new HashSet<Class<?>>(); + + /** + * Return all {@link Class} that contains at last one {@link com.google.inject.Inject} or + * {@link javax.inject.Inject} annotation. + * + * @return {@link Class} array. + */ + public Class<?>[] getClasses() + { + return classes.toArray( new Class<?>[classes.size()] ); + } + + /** + * {@inheritDoc} + */ + public void handle( A annotation, AccessibleObject element ) + throws HandleException + { + Class<?> type = null; + + if ( element instanceof Member ) + { + type = ( (Member) element ).getDeclaringClass(); + } + + if ( type != null && !classes.contains( type ) ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Found injectable type: " + type ); + } + classes.add( type ); + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceModuleHandler.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceModuleHandler.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceModuleHandler.java new file mode 100644 index 0000000..718604d --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceModuleHandler.java @@ -0,0 +1,77 @@ +/**************************************************************** + * 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.mpt.onami.test.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.annotation.GuiceModules; +import org.apache.james.mpt.onami.test.reflection.ClassHandler; +import org.apache.james.mpt.onami.test.reflection.HandleException; + +import com.google.inject.Module; + +/** + * Handler class to handle all {@link GuiceModules} annotations. + * + * @see org.apache.onami.test.reflection.ClassVisitor + */ +public final class GuiceModuleHandler + implements ClassHandler<GuiceModules> +{ + + private static final Logger LOGGER = Logger.getLogger( GuiceModuleHandler.class.getName() ); + + private final List<Module> modules = new ArrayList<Module>(); + + /** + * @return the modules + */ + public List<Module> getModules() + { + return modules; + } + + /** + * {@inheritDoc} + */ + public void handle( GuiceModules annotation, Class<?> element ) + throws HandleException + { + for ( Class<? extends Module> module : annotation.value() ) + { + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Try to create module: " + module ); + } + try + { + modules.add( module.newInstance() ); + } + catch ( Exception e ) + { + throw new HandleException( e ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/a37176fb/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceProvidedModuleHandler.java ---------------------------------------------------------------------- diff --git a/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceProvidedModuleHandler.java b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceProvidedModuleHandler.java new file mode 100644 index 0000000..9c7b365 --- /dev/null +++ b/mpt/onami-test/src/main/java/org/apache/james/mpt/onami/test/handler/GuiceProvidedModuleHandler.java @@ -0,0 +1,137 @@ +/**************************************************************** + * 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.mpt.onami.test.handler; + +import static java.lang.String.format; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.james.mpt.onami.test.annotation.GuiceProvidedModules; +import org.apache.james.mpt.onami.test.reflection.HandleException; +import org.apache.james.mpt.onami.test.reflection.MethodHandler; + +import com.google.inject.Module; +import com.google.inject.TypeLiteral; + +/** + * Handler class to handle all {@link GuiceProvidedModules} annotations. + * + * @see org.apache.onami.test.reflection.ClassVisitor + * @see GuiceProvidedModules + */ +public final class GuiceProvidedModuleHandler + implements MethodHandler<GuiceProvidedModules> +{ + + private static final Logger LOGGER = Logger.getLogger( GuiceProvidedModuleHandler.class.getName() ); + + private final List<Module> modules = new ArrayList<Module>(); + + /** + * @return the guiceProviderModuleRegistry + */ + public List<Module> getModules() + { + return modules; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings( "unchecked" ) + public void handle( GuiceProvidedModules annotation, Method method ) + throws HandleException + { + final Class<?> returnType = method.getReturnType(); + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( format( " Found %s annotated method, checking if return type '%s' is one of ( %s | Iterable<%s> | %s[] )", + GuiceProvidedModules.class.getSimpleName(), + returnType.getName(), + Module.class.getName(), + Module.class.getName(), + Module.class.getName() ) ); + } + + if ( !Modifier.isPublic( method.getModifiers() ) || !Modifier.isStatic( method.getModifiers() ) ) + { + throw new HandleException( "Impossible to invoke method: " + method + ", it has to be static and public" ); + } + + final Class<?> type = method.getDeclaringClass(); + + try + { + if ( Module.class.isAssignableFrom( returnType ) ) + { + modules.add( (Module) method.invoke( type ) ); + } + else if ( new TypeLiteral<Iterable<Module>>() + { + }.getRawType().isAssignableFrom( returnType ) ) + { + addModules( (Iterable<Module>) method.invoke( type ) ); + } + else if ( new TypeLiteral<Module[]>() + { + }.getRawType().isAssignableFrom( returnType ) ) + { + addModules( (Module[]) method.invoke( type ) ); + } + else + { + throw new ClassCastException( format( " Incompatible return type: %s.\nThe return type must be one of ( %s | Iterable<%s> | %s[] )", + returnType.getName(), + Module.class.getName(), + Module.class.getName(), + Module.class.getName() ) ); + } + + if ( LOGGER.isLoggable( Level.FINER ) ) + { + LOGGER.finer( " Invoked method: " + method.toGenericString() ); + } + } + catch ( Exception e ) + { + throw new HandleException( e ); + } + } + + private void addModules( Iterable<Module> modules ) + { + for ( Module module : modules ) + { + this.modules.add( module ); + } + } + + private void addModules( Module... modules ) + { + Collections.addAll( this.modules, modules ); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
