AbstractApplicationBootstrapper.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.ApplicationBootstrapper;
019 import griffon.core.GriffonApplication;
020 import griffon.core.env.GriffonEnvironment;
021 import griffon.core.injection.Binding;
022 import griffon.core.injection.Injector;
023 import griffon.core.injection.InjectorFactory;
024 import griffon.core.injection.Module;
025 import griffon.util.GriffonClassUtils;
026 import org.codehaus.griffon.runtime.core.injection.AbstractModule;
027 import org.slf4j.Logger;
028 import org.slf4j.LoggerFactory;
029 
030 import javax.annotation.Nonnull;
031 import java.util.*;
032 
033 import static griffon.core.GriffonExceptionHandler.sanitize;
034 import static griffon.util.AnnotationUtils.sortByDependencies;
035 import static java.util.Collections.unmodifiableCollection;
036 import static java.util.Objects.requireNonNull;
037 
038 /**
039  @author Andres Almiray
040  @since 2.0.0
041  */
042 public abstract class AbstractApplicationBootstrapper implements ApplicationBootstrapper {
043     private static final Logger LOG = LoggerFactory.getLogger(DefaultApplicationBootstrapper.class);
044     private static final String INJECTOR = "injector";
045     protected final GriffonApplication application;
046 
047     public AbstractApplicationBootstrapper(@Nonnull GriffonApplication application) {
048         this.application = requireNonNull(application, "Argument 'application' must not be null");
049     }
050 
051     @Override
052     public void bootstrap() throws Exception {
053         // 1 initialize environment settings
054         LOG.info("Griffon {}", GriffonEnvironment.getGriffonVersion());
055         LOG.info("Build: {}", GriffonEnvironment.getBuildDateTime());
056         LOG.info("JVM: {}", GriffonEnvironment.getJvmVersion());
057         LOG.info("OS: {}", GriffonEnvironment.getOsVersion());
058 
059         // 2 create bindings
060         LOG.debug("Creating module bindings");
061         Iterable<Binding<?>> bindings = createBindings();
062 
063         if (LOG.isTraceEnabled()) {
064             for (Binding<?> binding : bindings) {
065                 LOG.trace(binding.toString());
066             }
067         }
068 
069         // 3 create injector
070         LOG.debug("Creating application injector");
071         createInjector(bindings);
072     }
073 
074     @Override
075     public void run() {
076         application.initialize();
077         application.startup();
078         application.ready();
079     }
080 
081     @Nonnull
082     protected Iterable<Binding<?>> createBindings() {
083         Map<Key, Binding<?>> map = new LinkedHashMap<>();
084 
085         List<Module> modules = new ArrayList<>();
086         createApplicationModule(modules);
087         collectModuleBindings(modules);
088 
089         for (Module module : modules) {
090             for (Binding<?> binding : module.getBindings()) {
091                 map.put(Key.of(binding), binding);
092             }
093         }
094 
095         return unmodifiableCollection(map.values());
096     }
097 
098     protected void createApplicationModule(@Nonnull List<Module> modules) {
099         modules.add(new AbstractModule() {
100             @Override
101             protected void doConfigure() {
102                 bind(GriffonApplication.class)
103                     .toInstance(application);
104             }
105         });
106     }
107 
108     protected void collectModuleBindings(@Nonnull Collection<Module> modules) {
109         List<Module> moduleInstances = loadModules();
110         moduleInstances.add(0new DefaultApplicationModule());
111         Map<String, Module> sortedModules = sortModules(moduleInstances);
112         for (Map.Entry<String, Module> entry : sortedModules.entrySet()) {
113             LOG.debug("Loading module bindings from {}:{}", entry.getKey(), entry.getValue());
114             modules.add(entry.getValue());
115         }
116     }
117 
118     @Nonnull
119     protected Map<String, Module> sortModules(@Nonnull List<Module> moduleInstances) {
120         return sortByDependencies(moduleInstances, "Module""module");
121     }
122 
123     @Nonnull
124     protected abstract List<Module> loadModules();
125 
126     private void createInjector(@Nonnull Iterable<Binding<?>> bindingsthrows Exception {
127         ServiceLoader<InjectorFactory> serviceLoader = ServiceLoader.load(InjectorFactory.class);
128         try {
129             Iterator<InjectorFactory> iterator = serviceLoader.iterator();
130             InjectorFactory injectorFactory = iterator.next();
131             LOG.debug("Injector will be created by {}", injectorFactory);
132             Injector<?> injector = injectorFactory.createInjector(application, bindings);
133             GriffonClassUtils.setProperty(application, INJECTOR, injector);
134         catch (Exception e) {
135             LOG.error("An error occurred while initializing the injector", sanitize(e));
136             throw e;
137         }
138     }
139 }