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(0, new DefaultApplicationModule());
111 Map<String, Module> sortedModules = sortByDependencies(moduleInstances, "Module", "module");
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 abstract List<Module> loadModules();
120
121 private void createInjector(@Nonnull Iterable<Binding<?>> bindings) throws Exception {
122 ServiceLoader<InjectorFactory> serviceLoader = ServiceLoader.load(InjectorFactory.class);
123 try {
124 Iterator<InjectorFactory> iterator = serviceLoader.iterator();
125 InjectorFactory injectorFactory = iterator.next();
126 LOG.debug("Injector will be created by {}", injectorFactory);
127 Injector<?> injector = injectorFactory.createInjector(application, bindings);
128 GriffonClassUtils.setProperty(application, INJECTOR, injector);
129 } catch (Exception e) {
130 LOG.error("An error occurred while initializing the injector", sanitize(e));
131 throw e;
132 }
133 }
134 }
|