001// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.ioc.junit;
016
017import java.lang.reflect.InvocationTargetException;
018import java.lang.reflect.Method;
019import java.lang.reflect.Modifier;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.List;
023
024import org.apache.tapestry5.ioc.RegistryBuilder;
025import org.junit.runners.model.InitializationError;
026
027/**
028 * Helper class used by the {@link TapestryIOCJUnit4ClassRunner} to manage the test registry
029 */
030public class TestRegistryManager {
031        private final Registry annotation;
032        private final List<Method> moduleDefFactories;
033        
034        private org.apache.tapestry5.ioc.Registry registry;
035        
036        public TestRegistryManager(Class<?> type) throws InitializationError {
037                super();
038                
039                Registry annotation = type.getAnnotation(Registry.class);
040                if (annotation == null) {
041                        throw new InitializationError(type.getName() + " does not specify a @Registry");
042                }
043                
044                this.annotation = annotation;
045                this.moduleDefFactories = findModuleDefFactories(type);
046        }
047        
048        protected List<Method> findModuleDefFactories(Class<?> type) throws InitializationError {
049                List<Method> factoryMethods = new ArrayList<Method>();
050                for (Method method : type.getMethods()) {
051                        if (method.getAnnotation(ModuleDef.class) != null) {
052                                validateModuleDefMethod(method);
053                                factoryMethods.add(method);
054                        }
055                }
056                return factoryMethods.isEmpty() ? Collections.<Method> emptyList() : factoryMethods;
057        }
058
059        protected void validateModuleDefMethod(Method method) throws InitializationError {
060                int modifiers = method.getModifiers();
061                if (method.getParameterTypes().length != 0
062                                || !Modifier.isStatic(modifiers)
063                                || !Modifier.isPublic(modifiers)) {
064
065                        throw new InitializationError(
066                                        String.format("@ModuleDef method %s must be public static and accept no arguments",
067                                        method.getName()));
068                }
069                if (!org.apache.tapestry5.ioc.def.ModuleDef.class.isAssignableFrom(method.getReturnType())) {
070                        throw new InitializationError(
071                                        String.format("@ModuleDef method %s return type %s is not valid",
072                                        method.getName(), method.getReturnType().getName()));
073                }
074        }
075
076        /**
077         * Get the existing registry or create one if required.
078         * @return The test Registry
079         * @throws Exception
080         */
081        public org.apache.tapestry5.ioc.Registry getOrCreateRegistry() throws Exception {
082                if (registry == null) {
083                        RegistryBuilder builder = new RegistryBuilder();
084                        if (annotation.modules() != null) {
085                                builder.add(annotation.modules());
086                        }
087                        for (Method moduleDefFactory : moduleDefFactories) {
088                                try {
089                                        org.apache.tapestry5.ioc.def.ModuleDef moduleDef =
090                                                        (org.apache.tapestry5.ioc.def.ModuleDef) moduleDefFactory.invoke(null);
091                                        
092                                        builder.add(moduleDef);
093                                } catch (InvocationTargetException e) {
094                                        if (e.getTargetException() instanceof Exception) {
095                                                throw (Exception) e.getTargetException();
096                                        }
097                                        throw e;
098                                }
099                        }
100                        registry = builder.build();
101                        registry.performRegistryStartup();
102                }
103                return registry;
104        }
105        
106        /**
107         * Notify that the current test method has completed
108         */
109        public void afterTestMethod() {
110                if (annotation.shutdown() == RegistryShutdownType.AFTER_METHOD) {
111                        shutdownRegistry();
112                }
113        }
114
115        /**
116         * Notify that the current test class has completed
117         */
118        public void afterTestClass() {
119                if (annotation.shutdown() == RegistryShutdownType.AFTER_CLASS) {
120                        shutdownRegistry();
121                }
122        }
123        
124        protected void shutdownRegistry() {
125                try {
126                        registry.shutdown();
127                } finally {
128                        registry = null;
129                }
130        }
131}