TestApplicationBootstrapper.java
001 /*
002  * Copyright 2008-2014 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package org.codehaus.griffon.runtime.core;
017 
018 import griffon.core.GriffonApplication;
019 import griffon.core.injection.Module;
020 import griffon.core.test.TestCaseAware;
021 import griffon.inject.BindTo;
022 import griffon.util.AnnotationUtils;
023 import org.codehaus.griffon.runtime.core.injection.AbstractModule;
024 import org.codehaus.griffon.runtime.core.injection.AnnotatedBindingBuilder;
025 import org.codehaus.griffon.runtime.core.injection.LinkedBindingBuilder;
026 import org.codehaus.griffon.runtime.core.injection.SingletonBindingBuilder;
027 
028 import javax.annotation.Nonnull;
029 import javax.inject.Named;
030 import javax.inject.Provider;
031 import javax.inject.Qualifier;
032 import javax.inject.Singleton;
033 import java.lang.annotation.Annotation;
034 import java.lang.reflect.Field;
035 import java.lang.reflect.Method;
036 import java.util.ArrayList;
037 import java.util.Collection;
038 import java.util.Collections;
039 import java.util.List;
040 
041 import static griffon.util.AnnotationUtils.named;
042 import static griffon.util.GriffonNameUtils.getPropertyName;
043 import static griffon.util.GriffonNameUtils.isBlank;
044 
045 /**
046  @author Andres Almiray
047  @since 2.0.0
048  */
049 public class TestApplicationBootstrapper extends DefaultApplicationBootstrapper implements TestCaseAware {
050     private static final String METHOD_MODULES = "modules";
051     private static final String METHOD_MODULE_OVERRIDES = "moduleOverrides";
052     private Object testCase;
053 
054     public TestApplicationBootstrapper(@Nonnull GriffonApplication application) {
055         super(application);
056     }
057 
058     public void setTestCase(@Nonnull Object testCase) {
059         this.testCase = testCase;
060     }
061 
062     @Nonnull
063     @Override
064     protected List<Module> loadModules() {
065         List<Module> modules = doCollectModulesFromMethod();
066         if (!modules.isEmpty()) {
067             return modules;
068         }
069         modules = super.loadModules();
070         doCollectOverridingModules(modules);
071         doCollectModulesFromInnerClasses(modules);
072         doCollectModulesFromFields(modules);
073         return modules;
074     }
075 
076 
077     @SuppressWarnings("unchecked")
078     private List<Module> doCollectModulesFromMethod() {
079         Method method = null;
080         try {
081             method = testCase.getClass().getDeclaredMethod(METHOD_MODULES);
082             method.setAccessible(true);
083         catch (NoSuchMethodException e) {
084             return Collections.emptyList();
085         }
086 
087         try {
088             return (List<Module>method.invoke(testCase);
089         catch (Exception e) {
090             throw new IllegalArgumentException("An error occurred while initializing modules from " + testCase.getClass().getName() "." + METHOD_MODULES, e);
091         }
092     }
093 
094     @SuppressWarnings("unchecked")
095     private void doCollectOverridingModules(final @Nonnull Collection<Module> modules) {
096         Method method = null;
097         try {
098             method = testCase.getClass().getDeclaredMethod(METHOD_MODULE_OVERRIDES);
099             method.setAccessible(true);
100         catch (NoSuchMethodException e) {
101             return;
102         }
103 
104         try {
105             List<Module> overrides = (List<Module>method.invoke(testCase);
106             modules.addAll(overrides);
107         catch (Exception e) {
108             throw new IllegalArgumentException("An error occurred while initializing modules from " + testCase.getClass().getName() "." + METHOD_MODULE_OVERRIDES, e);
109         }
110     }
111 
112     private void doCollectModulesFromInnerClasses(final @Nonnull Collection<Module> modules) {
113         modules.add(new InnerClassesModule());
114     }
115 
116     private void doCollectModulesFromFields(final @Nonnull Collection<Module> modules) {
117         modules.add(new FieldsModule());
118     }
119 
120     @Nonnull
121     protected List<Annotation> harvestQualifiers(@Nonnull Class<?> clazz) {
122         List<Annotation> list = new ArrayList<>();
123         Annotation[] annotations = clazz.getAnnotations();
124         for (Annotation annotation : annotations) {
125             if (AnnotationUtils.isAnnotatedWith(annotation, Qualifier.class)) {
126                 if (BindTo.class.isAssignableFrom(annotation.getClass())) {
127                     continue;
128                 }
129 
130                 // special case for @Named
131                 if (Named.class.isAssignableFrom(annotation.getClass())) {
132                     Named named = (Namedannotation;
133                     if (isBlank(named.value())) {
134                         list.add(named(getPropertyName(clazz)));
135                         continue;
136                     }
137                 }
138                 list.add(annotation);
139             }
140         }
141         return list;
142     }
143 
144     @Nonnull
145     protected List<Annotation> harvestQualifiers(@Nonnull Field field) {
146         List<Annotation> list = new ArrayList<>();
147         Annotation[] annotations = field.getAnnotations();
148         for (Annotation annotation : annotations) {
149             if (AnnotationUtils.isAnnotatedWith(annotation, Qualifier.class)) {
150                 if (BindTo.class.isAssignableFrom(annotation.getClass())) {
151                     continue;
152                 }
153 
154                 // special case for @Named
155                 if (Named.class.isAssignableFrom(annotation.getClass())) {
156                     Named named = (Namedannotation;
157                     if (isBlank(named.value())) {
158                         list.add(named(getPropertyName(field.getName())));
159                         continue;
160                     }
161                 }
162                 list.add(annotation);
163             }
164         }
165         return list;
166     }
167 
168     private class InnerClassesModule extends AbstractModule {
169         @Override
170         @SuppressWarnings("unchecked")
171         protected void doConfigure() {
172             for (Class<?> clazz : testCase.getClass().getDeclaredClasses()) {
173                 BindTo bindTo = clazz.getAnnotation(BindTo.class);
174                 if (bindTo == nullcontinue;
175                 List<Annotation> qualifiers = harvestQualifiers(clazz);
176                 Annotation classifier = qualifiers.isEmpty() null : qualifiers.get(0);
177                 boolean isSingleton = clazz.getAnnotation(Singleton.class!= null;
178 
179                 AnnotatedBindingBuilder<?> abuilder = bind(bindTo.value());
180                 if (classifier != null) {
181                     LinkedBindingBuilder<?> lbuilder = abuilder.withClassifier(classifier);
182                     if (Provider.class.isAssignableFrom(clazz)) {
183                         SingletonBindingBuilder<?> sbuilder = lbuilder.toProvider((Classclazz);
184                         if (isSingletonsbuilder.asSingleton();
185                     else {
186                         SingletonBindingBuilder<?> sbuilder = lbuilder.to((Classclazz);
187                         if (isSingletonsbuilder.asSingleton();
188                     }
189                 else {
190                     if (Provider.class.isAssignableFrom(clazz)) {
191                         SingletonBindingBuilder<?> sbuilder = abuilder.toProvider((Classclazz);
192                         if (isSingletonsbuilder.asSingleton();
193                     else {
194                         SingletonBindingBuilder<?> sbuilder = abuilder.to((Classclazz);
195                         if (isSingletonsbuilder.asSingleton();
196                     }
197                 }
198             }
199         }
200     }
201 
202     private class FieldsModule extends AbstractModule {
203         @Override
204         @SuppressWarnings("unchecked")
205         protected void doConfigure() {
206             for (Field field : testCase.getClass().getDeclaredFields()) {
207                 BindTo bindTo = field.getAnnotation(BindTo.class);
208                 if (bindTo == nullcontinue;
209                 List<Annotation> qualifiers = harvestQualifiers(field);
210                 Annotation classifier = qualifiers.isEmpty() null : qualifiers.get(0);
211                 boolean isSingleton = field.getAnnotation(Singleton.class!= null;
212 
213                 field.setAccessible(true);
214                 Object instance = null;
215                 try {
216                     instance = field.get(testCase);
217                 catch (IllegalAccessException e) {
218                     throw new IllegalArgumentException(e);
219                 }
220 
221                 if (instance != null) {
222                     AnnotatedBindingBuilder<Object> abuilder = (AnnotatedBindingBuilder<Object>bind(bindTo.value());
223                     if (classifier != null) {
224                         if (Provider.class.isAssignableFrom(instance.getClass())) {
225                             SingletonBindingBuilder<?> sbuilder = abuilder
226                                 .withClassifier(classifier)
227                                 .toProvider((Provider<Object>instance);
228                             if (isSingletonsbuilder.asSingleton();
229                         else {
230                             abuilder.withClassifier(classifier).toInstance(instance);
231                         }
232                     else if (Provider.class.isAssignableFrom(instance.getClass())) {
233                         SingletonBindingBuilder<?> sbuilder = abuilder.toProvider((Provider<Object>instance);
234                         if (isSingletonsbuilder.asSingleton();
235                     else {
236                         abuilder.toInstance(instance);
237                     }
238                 else {
239                     AnnotatedBindingBuilder<?> abuilder = bind(bindTo.value());
240                     if (classifier != null) {
241                         LinkedBindingBuilder<?> lbuilder = abuilder.withClassifier(classifier);
242                         if (Provider.class.isAssignableFrom(field.getType())) {
243                             SingletonBindingBuilder<?> sbuilder = lbuilder.toProvider((Classfield.getType());
244                             if (isSingletonsbuilder.asSingleton();
245                         else {
246                             SingletonBindingBuilder<?> sbuilder = lbuilder.to((Classfield.getType());
247                             if (isSingletonsbuilder.asSingleton();
248                         }
249                     else {
250                         if (Provider.class.isAssignableFrom(field.getType())) {
251                             SingletonBindingBuilder<?> sbuilder = abuilder.toProvider((Classfield.getType());
252                             if (isSingletonsbuilder.asSingleton();
253                         else {
254                             SingletonBindingBuilder<?> sbuilder = abuilder.to((Classfield.getType());
255                             if (isSingletonsbuilder.asSingleton();
256                         }
257                     }
258                 }
259             }
260         }
261     }
262 }