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 }