001 // Copyright 2006, 2007, 2008, 2009, 2010, 2011 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
015 package org.apache.tapestry5.internal;
016
017 import org.apache.tapestry5.SymbolConstants;
018 import org.apache.tapestry5.ioc.IOCUtilities;
019 import org.apache.tapestry5.ioc.Registry;
020 import org.apache.tapestry5.ioc.RegistryBuilder;
021 import org.apache.tapestry5.ioc.def.ContributionDef;
022 import org.apache.tapestry5.ioc.def.ModuleDef;
023 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
024 import org.apache.tapestry5.ioc.services.*;
025 import org.apache.tapestry5.services.TapestryModule;
026 import org.slf4j.Logger;
027
028 import java.util.Formatter;
029 import java.util.List;
030
031 /**
032 * This class is used to build the {@link Registry}. The Registry contains
033 * {@link org.apache.tapestry5.ioc.services.TapestryIOCModule} and {@link TapestryModule}, any
034 * modules identified by {@link #addModules(Class[])} )}, plus the application module.
035 * <p/>
036 * The application module is optional.
037 * <p/>
038 * The application module is identified as <em>package</em>.services.<em>appName</em>Module, where
039 * <em>package</em> and the <em>appName</em> are specified by the caller.
040 */
041 @SuppressWarnings("rawtypes")
042 public class TapestryAppInitializer
043 {
044 private final Logger logger;
045
046 private final SymbolProvider appProvider;
047
048 private final String appName;
049
050 private final long startTime;
051
052 private final RegistryBuilder builder = new RegistryBuilder();
053
054 private long registryCreatedTime;
055
056 private Registry registry;
057
058 /**
059 * @param logger logger for output confirmation
060 * @param appPackage root package name to search for pages and components
061 * @param appName the name of the application (i.e., the name of the application servlet)
062 * @param aliasMode ignored (was used in 5.2)
063 * @deprecated Use {@link #TapestryAppInitializer(Logger, String, String)} instead. To be removed
064 * in 5.4.
065 */
066 public TapestryAppInitializer(Logger logger, String appPackage, String appName, String aliasMode)
067 {
068 this(logger, appPackage, appName);
069 }
070
071 /**
072 * @param logger logger for output confirmation
073 * @param appPackage root package name to search for pages and components
074 * @param appName the name of the application (i.e., the name of the application servlet)
075 */
076 public TapestryAppInitializer(Logger logger, String appPackage, String appName)
077 {
078 this(logger, new SingleKeySymbolProvider(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM, appPackage), appName,
079 null);
080 }
081
082 /**
083 * @param logger logger for output confirmation
084 * @param appProvider provides symbols for the application (normally, from the ServletContext init
085 * parameters)
086 * @param appName the name of the application (i.e., the name of the application servlet)
087 * @param aliasMode ignored (was used in 5.2 and earlier)
088 * @param executionModes an optional, comma-separated list of execution modes, each of which is used
089 * to find a list of additional module classes to load (key
090 * <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
091 * context)
092 * @deprecated Use {@link #TapestryAppInitializer(Logger, SymbolProvider, String, String)} instead.
093 * To be removed in 5.4.
094 */
095 public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName, String aliasMode,
096 String executionModes)
097 {
098 this(logger, appProvider, appName, executionModes);
099 }
100
101 /**
102 * @param logger logger for output confirmation
103 * @param appProvider provides symbols for the application (normally, from the ServletContext init
104 * parameters)
105 * @param appName the name of the application (i.e., the name of the application servlet)
106 * @param executionModes an optional, comma-separated list of execution modes, each of which is used
107 * to find a list of additional module classes to load (key
108 * <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
109 * context)
110 */
111 public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName, String executionModes)
112 {
113 this.logger = logger;
114 this.appProvider = appProvider;
115
116 String appPackage = appProvider.valueForSymbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
117
118 this.appName = appName;
119
120 startTime = System.currentTimeMillis();
121
122 if (!Boolean.parseBoolean(appProvider.valueForSymbol(InternalConstants.DISABLE_DEFAULT_MODULES_PARAM)))
123 {
124 IOCUtilities.addDefaultModules(builder);
125 }
126
127 // This gets added automatically.
128
129 addModules(TapestryModule.class);
130
131 String className = appPackage + ".services." + InternalUtils.capitalize(this.appName) + "Module";
132
133 try
134 {
135 // This class is possibly loaded by a parent class loader of the application class
136 // loader. The context class loader should have the appropriate view to the module
137 // class,
138 // if any.
139
140 Class moduleClass = Thread.currentThread().getContextClassLoader().loadClass(className);
141
142 builder.add(moduleClass);
143 } catch (ClassNotFoundException ex)
144 {
145 // That's OK, not all applications will have a module class, even though any
146 // non-trivial application will.
147 logger.warn("Application Module class {} not found", className);
148 }
149
150 // Add a synthetic module that contributes symbol sources.
151
152 addSyntheticSymbolSourceModule(appPackage);
153
154 for (String mode : TapestryInternalUtils.splitAtCommas(executionModes))
155 {
156 String key = String.format("tapestry.%s-modules", mode);
157 String moduleList = appProvider.valueForSymbol(key);
158
159 for (String moduleClassName : TapestryInternalUtils.splitAtCommas(moduleList))
160 {
161 builder.add(moduleClassName);
162 }
163 }
164 }
165
166 /**
167 * Adds additional modules.
168 *
169 * @param moduleDefs
170 */
171 public void addModules(ModuleDef... moduleDefs)
172 {
173 for (ModuleDef def : moduleDefs)
174 builder.add(def);
175 }
176
177 public void addModules(Class... moduleClasses)
178 {
179 builder.add(moduleClasses);
180 }
181
182 private void addSyntheticSymbolSourceModule(String appPackage)
183 {
184 ContributionDef appPathContribution = new SyntheticSymbolSourceContributionDef("AppPath",
185 new SingleKeySymbolProvider(InternalSymbols.APP_PACKAGE_PATH, appPackage.replace('.', '/')));
186
187 ContributionDef symbolSourceContribution = new SyntheticSymbolSourceContributionDef("ServletContext",
188 appProvider, "before:ApplicationDefaults", "after:EnvironmentVariables");
189
190 ContributionDef appNameContribution = new SyntheticSymbolSourceContributionDef("AppName",
191 new SingleKeySymbolProvider(InternalSymbols.APP_NAME, appName), "before:ServletContext");
192
193 builder.add(new SyntheticModuleDef(symbolSourceContribution, appNameContribution, appPathContribution));
194 }
195
196 public Registry createRegistry()
197 {
198 registryCreatedTime = System.currentTimeMillis();
199
200 registry = builder.build();
201
202 return registry;
203 }
204
205 public void announceStartup()
206 {
207 long toFinish = System.currentTimeMillis();
208
209 SymbolSource source = registry.getService("SymbolSource", SymbolSource.class);
210
211 StringBuilder buffer = new StringBuilder("Startup status:\n\nServices:\n\n");
212 Formatter f = new Formatter(buffer);
213
214
215 int unrealized = 0;
216
217 ServiceActivityScoreboard scoreboard = registry.getService(ServiceActivityScoreboard.class);
218
219 List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();
220
221 int longest = 0;
222
223 // One pass to find the longest name, and to count the unrealized services.
224
225 for (ServiceActivity activity : serviceActivity)
226 {
227 Status status = activity.getStatus();
228
229 longest = Math.max(longest, activity.getServiceId().length());
230
231 if (status == Status.DEFINED || status == Status.VIRTUAL)
232 unrealized++;
233 }
234
235 String formatString = "%" + longest + "s: %s\n";
236
237 // A second pass to output all the services
238
239 for (ServiceActivity activity : serviceActivity)
240 {
241 f.format(formatString, activity.getServiceId(), activity.getStatus().name());
242 }
243
244 f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized / serviceActivity.size(), unrealized,
245 serviceActivity.size());
246
247
248 f.format("\nApplication '%s' (version %s) startup time: %,d ms to build IoC Registry, %,d ms overall.", appName,
249 source.valueForSymbol(SymbolConstants.APPLICATION_VERSION),
250 registryCreatedTime - startTime,
251 toFinish - startTime);
252
253 String version = source.valueForSymbol(SymbolConstants.TAPESTRY_VERSION);
254 boolean productionMode = Boolean.parseBoolean(source.valueForSymbol(SymbolConstants.PRODUCTION_MODE));
255
256
257 buffer.append("\n\n");
258 buffer.append(" ______ __ ____\n");
259 buffer.append("/_ __/__ ____ ___ ___ / /_______ __ / __/\n");
260 buffer.append(" / / / _ `/ _ \\/ -_|_-</ __/ __/ // / /__ \\ \n");
261 buffer.append("/_/ \\_,_/ .__/\\__/___/\\__/_/ \\_, / /____/\n");
262 f.format(" /_/ /___/ %s%s\n\n",
263 version, productionMode ? "" : " (development mode)");
264
265 logger.info(buffer.toString());
266 }
267 }