001 /* 
002  * Copyright 2008-2017 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.ApplicationBootstrapper; 
019 import griffon.core.GriffonApplication; 
020 import griffon.core.artifact.GriffonService; 
021 import griffon.core.env.GriffonEnvironment; 
022 import griffon.core.injection.Binding; 
023 import griffon.core.injection.Injector; 
024 import griffon.core.injection.InjectorFactory; 
025 import griffon.core.injection.Key; 
026 import griffon.core.injection.Module; 
027 import griffon.util.GriffonClassUtils; 
028 import griffon.util.ServiceLoaderUtils; 
029 import org.codehaus.griffon.runtime.core.injection.AbstractModule; 
030 import org.slf4j.Logger; 
031 import org.slf4j.LoggerFactory; 
032  
033 import javax.annotation.Nonnull; 
034 import java.util.ArrayList; 
035 import java.util.Collection; 
036 import java.util.Iterator; 
037 import java.util.LinkedHashMap; 
038 import java.util.List; 
039 import java.util.Map; 
040 import java.util.ServiceLoader; 
041  
042 import static griffon.core.GriffonExceptionHandler.sanitize; 
043 import static griffon.util.AnnotationUtils.sortByDependencies; 
044 import static griffon.util.ServiceLoaderUtils.load; 
045 import static java.util.Collections.unmodifiableCollection; 
046 import static java.util.Objects.requireNonNull; 
047  
048 /** 
049  * @author Andres Almiray 
050  * @since 2.0.0 
051  */ 
052 public abstract class AbstractApplicationBootstrapper implements ApplicationBootstrapper { 
053     private static final Logger LOG = LoggerFactory.getLogger(AbstractApplicationBootstrapper.class); 
054     private static final String INJECTOR = "injector"; 
055     private static final String GRIFFON_PATH = "META-INF/griffon"; 
056     private static final String PROPERTIES = ".properties"; 
057     protected final GriffonApplication application; 
058  
059     public AbstractApplicationBootstrapper(@Nonnull GriffonApplication application) { 
060         this.application = requireNonNull(application, "Argument 'application' must not be null"); 
061     } 
062  
063     @Override 
064     public void bootstrap() throws Exception { 
065         // 1 initialize environment settings 
066         LOG.info("Griffon {}", GriffonEnvironment.getGriffonVersion()); 
067         LOG.info("Build: {}", GriffonEnvironment.getBuildDateTime()); 
068         LOG.info("Revision: {}", GriffonEnvironment.getBuildRevision()); 
069         LOG.info("JVM: {}", GriffonEnvironment.getJvmVersion()); 
070         LOG.info("OS: {}", GriffonEnvironment.getOsVersion()); 
071  
072         // 2 create bindings 
073         LOG.debug("Creating module bindings"); 
074         Iterable<Binding<?>> bindings = createBindings(); 
075  
076         if (LOG.isTraceEnabled()) { 
077             for (Binding<?> binding : bindings) { 
078                 LOG.trace(binding.toString()); 
079             } 
080         } 
081  
082         // 3 create injector 
083         LOG.debug("Creating application injector"); 
084         createInjector(bindings); 
085     } 
086  
087     @Override 
088     public void run() { 
089         application.initialize(); 
090         application.startup(); 
091         application.ready(); 
092     } 
093  
094     @Nonnull 
095     protected Iterable<Binding<?>> createBindings() { 
096         Map<Key, Binding<?>> map = new LinkedHashMap<>(); 
097  
098         List<Module> modules = new ArrayList<>(); 
099         createApplicationModule(modules); 
100         createArtifactsModule(modules); 
101         collectModuleBindings(modules); 
102  
103         for (Module module : modules) { 
104             for (Binding<?> binding : module.getBindings()) { 
105                 map.put(Key.of(binding), binding); 
106             } 
107         } 
108  
109         return unmodifiableCollection(map.values()); 
110     } 
111  
112     protected void createArtifactsModule(@Nonnull List<Module> modules) { 
113         final List<Class<?>> classes = new ArrayList<>(); 
114         load(getClass().getClassLoader(), GRIFFON_PATH, new ServiceLoaderUtils.PathFilter() { 
115             @Override 
116             public boolean accept(@Nonnull String path) { 
117                 return !path.endsWith(PROPERTIES); 
118             } 
119         }, new ServiceLoaderUtils.ResourceProcessor() { 
120             @Override 
121             public void process(@Nonnull ClassLoader classLoader, @Nonnull String line) { 
122                 line = line.trim(); 
123                 try { 
124                     classes.add(classLoader.loadClass(line)); 
125                 } catch (ClassNotFoundException e) { 
126                     LOG.warn("'" + line + "' could not be resolved as a Class"); 
127                 } 
128             } 
129         }); 
130  
131         modules.add(new AbstractModule() { 
132             @Override 
133             protected void doConfigure() { 
134                 for (Class<?> clazz : classes) { 
135                     if (GriffonService.class.isAssignableFrom(clazz)) { 
136                         bind(clazz).asSingleton(); 
137                     } else { 
138                         bind(clazz); 
139                     } 
140                 } 
141             } 
142         }); 
143     } 
144  
145     protected void createApplicationModule(@Nonnull List<Module> modules) { 
146         modules.add(new AbstractModule() { 
147             @Override 
148             protected void doConfigure() { 
149                 bind(GriffonApplication.class) 
150                     .toInstance(application); 
151             } 
152         }); 
153     } 
154  
155     protected void collectModuleBindings(@Nonnull Collection<Module> modules) { 
156         List<Module> moduleInstances = loadModules(); 
157         moduleInstances.add(0, new DefaultApplicationModule()); 
158         Map<String, Module> sortedModules = sortModules(moduleInstances); 
159         for (Map.Entry<String, Module> entry : sortedModules.entrySet()) { 
160             LOG.debug("Loading module bindings from {}:{}", entry.getKey(), entry.getValue()); 
161             modules.add(entry.getValue()); 
162         } 
163     } 
164  
165     @Nonnull 
166     protected Map<String, Module> sortModules(@Nonnull List<Module> moduleInstances) { 
167         return sortByDependencies(moduleInstances, "Module", "module"); 
168     } 
169  
170     @Nonnull 
171     protected abstract List<Module> loadModules(); 
172  
173     private void createInjector(@Nonnull Iterable<Binding<?>> bindings) throws Exception { 
174         ServiceLoader<InjectorFactory> serviceLoader = ServiceLoader.load(InjectorFactory.class); 
175         try { 
176             Iterator<InjectorFactory> iterator = serviceLoader.iterator(); 
177             InjectorFactory injectorFactory = iterator.next(); 
178             LOG.debug("Injector will be created by {}", injectorFactory); 
179             Injector<?> injector = injectorFactory.createInjector(application, bindings); 
180             GriffonClassUtils.setProperty(application, INJECTOR, injector); 
181         } catch (Exception e) { 
182             LOG.error("An error occurred while initializing the injector", sanitize(e)); 
183             throw e; 
184         } 
185     } 
186 }
    
    |