blob: 151c3d41129819a33c3def6ba7f394bf8bc3fc91 [file] [log] [blame]
// Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry5.internal;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.ioc.IOCUtilities;
import org.apache.tapestry5.ioc.Registry;
import org.apache.tapestry5.ioc.RegistryBuilder;
import org.apache.tapestry5.ioc.def.ContributionDef;
import org.apache.tapestry5.ioc.def.ModuleDef;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.services.TapestryModule;
import org.slf4j.Logger;
import java.util.Formatter;
import java.util.List;
/**
* This class is used to build the {@link Registry}. The Registry contains
* {@link org.apache.tapestry5.ioc.services.TapestryIOCModule} and {@link TapestryModule}, any
* modules identified by {@link #addModules(Class[])} )}, plus the application module.
* <p/>
* The application module is optional.
* <p/>
* The application module is identified as <em>package</em>.services.<em>appName</em>Module, where
* <em>package</em> and the <em>appName</em> are specified by the caller.
*/
public class TapestryAppInitializer
{
private final Logger logger;
private final SymbolProvider appProvider;
private final String appName;
private final String aliasMode;
private final long startTime;
private final RegistryBuilder builder = new RegistryBuilder();
private long registryCreatedTime;
private Registry registry;
/**
* @param logger
* logger for output confirmation
* @param appProvider
* provides symbols for the application (normally, from the ServletContext init
* parameters)
* @param appName
* the name of the application (i.e., the name of the application servlet)
* @param aliasMode
* the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
* normally "servlet"
*/
public TapestryAppInitializer(Logger logger, String appPackage, String appName, String aliasMode)
{
this(logger, new SingleKeySymbolProvider(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM,
appPackage), appName, aliasMode, null);
}
/**
* @param logger
* logger for output confirmation
* @param appProvider
* provides symbols for the application (normally, from the ServletContext init
* parameters)
* @param appName
* the name of the application (i.e., the name of the application servlet)
* @param aliasMode
* the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
* normally "servlet"
* @deprecated Use
* {@link #TapestryAppInitializer(Logger, SymbolProvider, String, String, String)}
* instead
*/
public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName,
String aliasMode)
{
this(logger, appProvider, appName, aliasMode, null);
}
/**
* @param logger
* logger for output confirmation
* @param appProvider
* provides symbols for the application (normally, from the ServletContext init
* parameters)
* @param appName
* the name of the application (i.e., the name of the application servlet)
* @param aliasMode
* the mode, used by the {@link org.apache.tapestry5.services.Alias} service,
* normally "servlet"
* @param executionModes
* an optional, comma-seperated list of execution modes, each of which is used
* to find a list of additional module classes to load (key
* <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
* context)
*/
public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName,
String aliasMode, String executionModes)
{
this.logger = logger;
this.appProvider = appProvider;
String appPackage = appProvider
.valueForSymbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
this.appName = appName;
this.aliasMode = aliasMode;
startTime = System.currentTimeMillis();
if (!Boolean.parseBoolean(appProvider
.valueForSymbol(InternalConstants.DISABLE_DEFAULT_MODULES_PARAM)))
{
IOCUtilities.addDefaultModules(builder);
}
// This gets added automatically.
addModules(TapestryModule.class);
String className = appPackage + ".services." + InternalUtils.capitalize(this.appName)
+ "Module";
try
{
// This class is possibly loaded by a parent class loader of the application class
// loader. The context class loader should have the appropriate view to the module class,
// if any.
Class moduleClass = Thread.currentThread().getContextClassLoader().loadClass(className);
builder.add(moduleClass);
}
catch (ClassNotFoundException ex)
{
// That's OK, not all applications will have a module class, even though any
// non-trivial application will.
}
// Add a synthetic module that contributes symbol sources.
addSyntheticSymbolSourceModule(appPackage);
for (String mode : TapestryInternalUtils.splitAtCommas(executionModes))
{
String key = String.format("tapestry.%s-modules", mode);
String moduleList = appProvider.valueForSymbol(key);
for (String moduleClassName : TapestryInternalUtils.splitAtCommas(moduleList))
{
builder.add(moduleClassName);
}
}
}
/**
* Adds additional modules.
*
* @param moduleDefs
*/
public void addModules(ModuleDef... moduleDefs)
{
for (ModuleDef def : moduleDefs)
builder.add(def);
}
public void addModules(Class... moduleClasses)
{
builder.add(moduleClasses);
}
private void addSyntheticSymbolSourceModule(String appPackage)
{
ContributionDef appPathContribution = new SyntheticSymbolSourceContributionDef("AppPath",
new SingleKeySymbolProvider(InternalSymbols.APP_PACKAGE_PATH, appPackage.replace(
'.', '/')));
ContributionDef symbolSourceContribution = new SyntheticSymbolSourceContributionDef(
"ServletContext", appProvider, "before:ApplicationDefaults");
ContributionDef aliasModeContribution = new SyntheticSymbolSourceContributionDef(
"AliasMode", new SingleKeySymbolProvider(InternalSymbols.ALIAS_MODE, aliasMode),
"before:ServletContext");
ContributionDef appNameContribution = new SyntheticSymbolSourceContributionDef("AppName",
new SingleKeySymbolProvider(InternalSymbols.APP_NAME, appName),
"before:ServletContext");
builder.add(new SyntheticModuleDef(symbolSourceContribution, aliasModeContribution,
appNameContribution, appPathContribution));
}
public Registry createRegistry()
{
registryCreatedTime = System.currentTimeMillis();
registry = builder.build();
return registry;
}
public void announceStartup()
{
long toFinish = System.currentTimeMillis();
SymbolSource source = registry.getService("SymbolSource", SymbolSource.class);
StringBuilder buffer = new StringBuilder("Startup status:\n\n");
Formatter f = new Formatter(buffer);
f.format("Application '%s' (Tapestry version %s).\n\n"
+ "Startup time: %,d ms to build IoC Registry, %,d ms overall.\n\n"
+ "Startup services status:\n", appName, source
.valueForSymbol(SymbolConstants.TAPESTRY_VERSION), registryCreatedTime - startTime,
toFinish - startTime);
int unrealized = 0;
ServiceActivityScoreboard scoreboard = registry.getService(ServiceActivityScoreboard.class);
List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();
int longest = 0;
// One pass to find the longest name, and to count the unrealized services.
for (ServiceActivity activity : serviceActivity)
{
Status status = activity.getStatus();
longest = Math.max(longest, activity.getServiceId().length());
if (status == Status.DEFINED || status == Status.VIRTUAL)
unrealized++;
}
String formatString = "%" + longest + "s: %s\n";
// A second pass to output all the services
for (ServiceActivity activity : serviceActivity)
{
f.format(formatString, activity.getServiceId(), activity.getStatus().name());
}
f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized
/ serviceActivity.size(), unrealized, serviceActivity.size());
logger.info(buffer.toString());
}
}