TapestryModule.java

Index Score
org.apache.tapestry5.services
Apache Tapestry 5

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
PARAMSNumber of formal parameter declarations
SIZESize of the file in bytes
UNIQUE_OPERANDSNumber of unique operands
INTERFACE_COMPLEXITYInterface complexity
PROGRAM_VOCABHalstead program vocabulary
JAVA0108JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
LINE_COMMENTNumber of line comments
EXITSProcedure exits
OPERANDSNumber of operands
FUNCTIONSNumber of function declarations
PROGRAM_LENGTHHalstead program length
LINESNumber of lines in the source file
OPERATORSNumber of operators
DECL_COMMENTSComments in declarations
LOCLines of code
ELOCEffective lines of code
WHITESPACENumber of whitespace lines
LOGICAL_LINESNumber of statements
RETURNSNumber of return points from functions
EXEC_COMMENTSComments in executable code
COMMENTSComment lines
DOC_COMMENTNumber of javadoc comment lines
JAVA0110JAVA0110 Incorrect javadoc: no @return tag
CYCLOMATICCyclomatic complexity
JAVA0117JAVA0117 Missing javadoc: method 'method'
BLOCKSNumber of blocks
JAVA0075JAVA0075 Method parameter hides field
JAVA0144JAVA0144 Line exceeds maximum M characters
JAVA0179JAVA0179 Local variable hides visible field
JAVA0034JAVA0034 Missing braces in if statement
JAVA0138JAVA0138 N parameters defined for method (maximum: M)
PROGRAM_VOLUMEHalstead program volume
JAVA0136JAVA0136 N methods defined in class (maximum: M)
JAVA0126JAVA0126 Method declares unchecked exception in throws
COMPARISONSNumber of comparison operators
LOOPSNumber of loops
JAVA0145JAVA0145 Tab character used in source file
// Copyright 2006, 2007, 2008 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.services; import org.apache.tapestry5.*; import org.apache.tapestry5.annotations.*; import org.apache.tapestry5.beaneditor.Validate; import org.apache.tapestry5.corelib.data.BlankOption; import org.apache.tapestry5.corelib.data.GridPagerPosition; import org.apache.tapestry5.corelib.data.InsertPosition; import org.apache.tapestry5.grid.GridDataSource; import org.apache.tapestry5.internal.*; import org.apache.tapestry5.internal.beaneditor.PrimitiveFieldConstraintGenerator; import org.apache.tapestry5.internal.beaneditor.ValidateAnnotationConstraintGenerator; import org.apache.tapestry5.internal.bindings.*; import org.apache.tapestry5.internal.events.InvalidationListener; import org.apache.tapestry5.internal.grid.CollectionGridDataSource; import org.apache.tapestry5.internal.grid.NullDataSource; import org.apache.tapestry5.internal.renderers.*; import org.apache.tapestry5.internal.services.*; import org.apache.tapestry5.internal.transform.*; import org.apache.tapestry5.internal.translator.*; import org.apache.tapestry5.internal.util.IntegerRange; import org.apache.tapestry5.internal.util.RenderableAsBlock; import org.apache.tapestry5.internal.util.StringRenderable; import org.apache.tapestry5.ioc.*; import org.apache.tapestry5.ioc.annotations.*; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; import org.apache.tapestry5.ioc.internal.util.IdAllocator; import org.apache.tapestry5.ioc.services.*; import org.apache.tapestry5.ioc.util.StrategyRegistry; import org.apache.tapestry5.ioc.util.TimeInterval; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.runtime.Component; import org.apache.tapestry5.runtime.ComponentResourcesAware; import org.apache.tapestry5.runtime.RenderCommand; import org.apache.tapestry5.util.StringToEnumCoercion; import org.apache.tapestry5.validator.*; import org.slf4j.Logger; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.annotation.Annotation; import java.net.URL; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * The root module for Tapestry. */ @SuppressWarnings({"JavaDoc"}) @Marker(Core.class) @SubModule(InternalModule.class) public final class TapestryModule { private final PipelineBuilder pipelineBuilder; private final ApplicationGlobals applicationGlobals; private final PropertyShadowBuilder shadowBuilder; private final Environment environment; private final StrategyBuilder strategyBuilder; private final PropertyAccess propertyAccess; private final ComponentInstantiatorSource componentInstantiatorSource; private final ChainBuilder chainBuilder; private final Request request; private final Response response; private final ThreadLocale threadLocale; private final RequestGlobals requestGlobals; private final ActionRenderResponseGenerator actionRenderResponseGenerator; private final EnvironmentalShadowBuilder environmentalBuilder; /** * We inject all sorts of common dependencies (including builders) into the module itself (note: even though some of * these service are defined by the module itself, that's ok because services are always lazy proxies). This isn't * about efficiency (it may be slightly more efficient, but not in any noticable way), it's about eliminating the * need to keep injecting these dependencies into invividual service builder and contribution methods. */ public TapestryModule(PipelineBuilder pipelineBuilder, PropertyShadowBuilder shadowBuilder, RequestGlobals requestGlobals, ApplicationGlobals applicationGlobals, ChainBuilder chainBuilder, Environment environment, StrategyBuilder strategyBuilder, ComponentInstantiatorSource componentInstantiatorSource, PropertyAccess propertyAccess, Request request, Response response, ThreadLocale threadLocale, ActionRenderResponseGenerator actionRenderResponseGenerator, EnvironmentalShadowBuilder environmentalBuilder) { this.pipelineBuilder = pipelineBuilder; this.shadowBuilder = shadowBuilder; this.requestGlobals = requestGlobals; this.applicationGlobals = applicationGlobals; this.chainBuilder = chainBuilder; this.environment = environment; this.strategyBuilder = strategyBuilder; this.componentInstantiatorSource = componentInstantiatorSource; this.propertyAccess = propertyAccess; this.request = request; this.response = response; this.threadLocale = threadLocale; this.actionRenderResponseGenerator = actionRenderResponseGenerator; this.environmentalBuilder = environmentalBuilder; } public static void bind(ServiceBinder binder) { binder.bind(ClasspathAssetAliasManager.class, ClasspathAssetAliasManagerImpl.class); binder.bind(PersistentLocale.class, PersistentLocaleImpl.class); binder.bind(ApplicationStateManager.class, ApplicationStateManagerImpl.class); binder.bind(ApplicationStatePersistenceStrategySource.class, ApplicationStatePersistenceStrategySourceImpl.class); binder.bind(BindingSource.class, BindingSourceImpl.class); binder.bind(FieldValidatorSource.class, FieldValidatorSourceImpl.class); binder.bind(ApplicationGlobals.class, ApplicationGlobalsImpl.class); binder.bind(AssetSource.class, AssetSourceImpl.class); binder.bind(Cookies.class, CookiesImpl.class); binder.bind(Environment.class, EnvironmentImpl.class); binder.bind(FieldValidatorDefaultSource.class, FieldValidatorDefaultSourceImpl.class); binder.bind(RequestGlobals.class, RequestGlobalsImpl.class); binder.bind(ResourceDigestGenerator.class, ResourceDigestGeneratorImpl.class); binder.bind(ValidationConstraintGenerator.class, ValidationConstraintGeneratorImpl.class); binder.bind(EnvironmentalShadowBuilder.class, EnvironmentalShadowBuilderImpl.class); binder.bind(ComponentSource.class, ComponentSourceImpl.class); binder.bind(BeanModelSource.class, BeanModelSourceImpl.class); binder.bind(BeanBlockSource.class, BeanBlockSourceImpl.class); binder.bind(ComponentDefaultProvider.class, ComponentDefaultProviderImpl.class); binder.bind(MarkupWriterFactory.class, MarkupWriterFactoryImpl.class); binder.bind(FieldValidationSupport.class, FieldValidationSupportImpl.class); binder.bind(ObjectRenderer.class, LocationRenderer.class).withId("LocationRenderer"); binder.bind(ObjectProvider.class, AssetObjectProvider.class).withId("AssetObjectProvider"); binder.bind(RequestExceptionHandler.class, DefaultRequestExceptionHandler.class); binder.bind(ComponentEventResultProcessor.class, ComponentInstanceResultProcessor.class).withId( "ComponentInstanceResultProcessor"); binder.bind(NullFieldStrategySource.class, NullFieldStrategySourceImpl.class); binder.bind(HttpServletRequestFilter.class, IgnoredPathsFilter.class).withId("IgnoredPathsFilter"); binder.bind(ContextValueEncoder.class, ContextValueEncoderImpl.class); binder.bind(BaseURLSource.class, BaseURLSourceImpl.class); binder.bind(BeanBlockOverrideSource.class, BeanBlockOverrideSourceImpl.class); binder.bind(AliasManager.class, AliasManagerImpl.class).withId("AliasOverrides"); binder.bind(HiddenFieldLocationRules.class, HiddenFieldLocationRulesImpl.class); binder.bind(PageDocumentGenerator.class, PageDocumentGeneratorImpl.class); binder.bind(ResponseRenderer.class, ResponseRendererImpl.class); } // ======================================================================== // // Service Builder Methods (static) // // ======================================================================== public static Alias buildAlias(Logger logger, @Inject @Symbol(InternalConstants.TAPESTRY_ALIAS_MODE_SYMBOL) String mode, @InjectService("AliasOverrides") AliasManager overridesManager, Collection<AliasContribution> configuration) { AliasManager manager = new AliasManagerImpl(logger, configuration); return new AliasImpl(manager, mode, overridesManager); } // ======================================================================== // // Service Contribution Methods (static) // // ======================================================================== /** * Contributes the factory for serveral built-in binding prefixes ("asset", "block", "component", "literal", prop", * "nullfieldstrategy", "message", "validate", "translate", "var"). */ public static void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration, @InjectService("PropBindingFactory") BindingFactory propBindingFactory, ObjectLocator locator) { configuration.add(BindingConstants.LITERAL, new LiteralBindingFactory()); configuration.add(BindingConstants.PROP, propBindingFactory); configuration.add(BindingConstants.COMPONENT, new ComponentBindingFactory()); configuration.add(BindingConstants.MESSAGE, new MessageBindingFactory()); configuration.add(BindingConstants.VALIDATE, locator.autobuild(ValidateBindingFactory.class)); configuration.add(BindingConstants.TRANSLATE, locator.autobuild(TranslateBindingFactory.class)); configuration.add(BindingConstants.BLOCK, new BlockBindingFactory()); configuration.add(BindingConstants.ASSET, locator.autobuild(AssetBindingFactory.class)); configuration.add(BindingConstants.VAR, new RenderVariableBindingFactory()); configuration.add(BindingConstants.NULLFIELDSTRATEGY, locator.autobuild(NullFieldStrategyBindingFactory.class)); } public static void contributeClasspathAssetAliasManager(MappedConfiguration<String, String> configuration, @Symbol(SymbolConstants.TAPESTRY_VERSION) String version, // @Inject not needed, because this isn't a service builder method @Symbol("tapestry.scriptaculous.path") String scriptaculousPath, @Symbol("tapestry.datepicker.path") String datepickerPath) { // TAPESTRY-2159: All the classpath assets are inside a version numbered folder (i.e., 5.0.12). // For scriptaculous, etc., this version is not the version of the library, but the version // bundled with Tapestry. configuration.add("tapestry/" + version, "org/apache/tapestry5"); configuration.add("scriptaculous/" + version, scriptaculousPath); configuration.add("datepicker/" + version, datepickerPath); } public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration) { configuration.add(new LibraryMapping("core", "org.apache.tapestry5.corelib")); } /** * Adds a number of standard component class transform workers: <dl> <dt>Retain </dt> <dd>Allows fields to retain * their values between requests</dd> <dt>Persist </dt> <dd>Allows fields to store their their value persistently * between requests</dd> <dt>Parameter </dt> <dd>Identifies parameters based on the {@link * org.apache.tapestry5.annotations.Parameter} annotation</dd> <dt>Component </dt> <dd>Defines embedded components * based on the {@link org.apache.tapestry5.annotations.Component} annotation</dd> <dt>Mixin </dt> <dd>Adds a mixin * as part of a component's implementation</dd> <dt>Environment </dt> <dd>Allows fields to contain values extracted * from the {@link org.apache.tapestry5.services.Environment} service</dd> <dt>Inject </dt> <dd>Used with the {@link * org.apache.tapestry5.ioc.annotations.Inject} annotation, when a value is supplied</dd> <dt>InjectPage</dt> * <dd>Adds code to allow access to other pages via the {@link org.apache.tapestry5.annotations.InjectPage} field * annotation</dd> <dt>InjectBlock </dt> <dd>Allows a block from the template to be injected into a field</dd> * <dt>IncludeStylesheet </dt> <dd>Supports the {@link org.apache.tapestry5.annotations.IncludeStylesheet} * annotation</dd> <dt>IncludeJavaScriptLibrary </dt> <dd>Supports the {@link org.apache.tapestry5.annotations.IncludeJavaScriptLibrary} * annotation</dd> <dt>SupportsInformalParameters </dt> <dd>Checks for the annotation</dd> <dt>Meta </dt> <dd>Checks * for meta data and adds it to the component model</dd> <dt>ApplicationState </dt> <dd>Converts fields that * reference application state objects <dt>UnclaimedField </dt> <dd>Identifies unclaimed fields and resets them to * null/0/false at the end of the request</dd> <dt>RenderCommand </dt> <dd>Ensures all components also implement * {@link org.apache.tapestry5.runtime.RenderCommand}</dd> <dt>SetupRender, BeginRender, etc. </dt> <dd>Correspond * to component render phases and annotations</dd> <dt>InvokePostRenderCleanupOnResources </dt> <dd>Makes sure * {@link org.apache.tapestry5.internal.InternalComponentResources#postRenderCleanup()} is invoked after a component * finishes rendering</dd> <dt>Secure</dt> <dd>Checks for the {@link org.apache.tapestry5.annotations.Secure} * annotation</dd> <dt>ContentType</dt> <dd>Checks for {@link org.apache.tapestry5.annotations.ContentType} * annotation</dd> <dt>GenerateAccessors</dt> <dd>Generates accessor methods if {@link * org.apache.tapestry5.annotations.Property} annotation is present </dd> <dt>Cached</dt> <dd>Checks for the {@link * org.apache.tapestry5.annotations.Cached} annotation</dd><dt>Log</dt> <dd>Checks for the {@link * org.apache.tapestry5.annotations.Log} annotation</dd></dl> */ public static void contributeComponentClassTransformWorker( OrderedConfiguration<ComponentClassTransformWorker> configuration, ObjectLocator locator, InjectionProvider injectionProvider, ComponentClassResolver resolver) { // TODO: Proper scheduling of all of this. Since a given field or method should // only have a single annotation, the order doesn't matter so much, as long as // UnclaimedField is last. configuration.add("Cached", locator.autobuild(CachedWorker.class)); configuration.add("Meta", new MetaWorker()); configuration.add("Inject", new InjectWorker(locator, injectionProvider)); configuration.add("Secure", new SecureWorker()); configuration.add("MixinAfter", new MixinAfterWorker()); configuration.add("Component", new ComponentWorker(resolver)); configuration.add("Mixin", new MixinWorker(resolver)); configuration.add("OnEvent", new OnEventWorker()); configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker()); configuration.add("InjectPage", locator.autobuild(InjectPageWorker.class)); configuration.add("InjectContainer", new InjectContainerWorker()); configuration.add("InjectComponent", new InjectComponentWorker()); configuration.add("RenderCommand", new RenderCommandWorker()); // Default values for parameters are often some form of injection, so make sure // that Parameter fields are processed after injections. configuration.add("Parameter", locator.autobuild(ParameterWorker.class), "after:Inject*"); // Workers for the component rendering state machine methods; this is in typical // execution order. add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class, false); add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class, false); add(configuration, TransformConstants.BEFORE_RENDER_TEMPLATE_SIGNATURE, BeforeRenderTemplate.class, false); add(configuration, TransformConstants.BEFORE_RENDER_BODY_SIGNATURE, BeforeRenderBody.class, false); // These phases operate in reverse order. add(configuration, TransformConstants.AFTER_RENDER_BODY_SIGNATURE, AfterRenderBody.class, true); add(configuration, TransformConstants.AFTER_RENDER_TEMPLATE_SIGNATURE, AfterRenderTemplate.class, true); add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class, true); add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class, true); // Ideally, these should be ordered pretty late in the process to make sure there are no // side effects with other workers that do work inside the page lifecycle methods. add(configuration, PageLoaded.class, TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, "pageLoaded"); add(configuration, PageAttached.class, TransformConstants.CONTAINING_PAGE_DID_ATTACH_SIGNATURE, "pageAttached"); add(configuration, PageDetached.class, TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, "pageDetached"); configuration.add("Retain", new RetainWorker()); configuration.add("Persist", new PersistWorker()); configuration.add("IncludeStylesheet", locator.autobuild(IncludeStylesheetWorker.class), "after:SetupRender"); configuration.add("IncludeJavaScriptLibrary", locator.autobuild(IncludeJavaScriptLibraryWorker.class), "after:SetupRender"); configuration.add("InvokePostRenderCleanupOnResources", new InvokePostRenderCleanupOnResourcesWorker()); configuration.add("ContentType", new ContentTypeWorker()); configuration.add("Property", new PropertyWorker()); // These must come after Property, since they actually delete fields that may still have the annotation configuration.add("ApplicationState", locator.autobuild(ApplicationStateWorker.class), "after:Property"); configuration.add("Environment", locator.autobuild(EnvironmentalWorker.class), "after:Property"); configuration.add("Log", locator.autobuild(LogWorker.class)); // This one is always last. Any additional private fields that aren't annotated will // be converted to clear out at the end of the request. configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*"); configuration.add("PageActivationContext", new PageActivationContextWorker(), "before:OnEvent"); } /** * <dl> <dt>Annotation</dt> <dd>Checks for {@link org.apache.tapestry5.beaneditor.DataType} annotation</dd> * <dt>Default (ordered last)</dt> <dd>{@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} * service ({@link #contributeDefaultDataTypeAnalyzer(org.apache.tapestry5.ioc.MappedConfiguration)} })</dd> </dl> */ public static void contributeDataTypeAnalyzer(OrderedConfiguration<DataTypeAnalyzer> configuration, @InjectService("DefaultDataTypeAnalyzer") DataTypeAnalyzer defaultDataTypeAnalyzer) { configuration.add("Annotation", new AnnotationDataTypeAnalyzer()); configuration.add("Default", defaultDataTypeAnalyzer, "after:*"); } /** * Maps property types to data type names: <ul> <li>String --&gt; text <li>Number --&gt; number <li>Enum --&gt; enum * <li>Boolean --&gt; boolean <li>Date --&gt; date </ul> */ public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration) { // This is a special case contributed to avoid exceptions when a property type can't be // matched. DefaultDataTypeAnalyzer converts the empty string to null. configuration.add(Object.class, ""); configuration.add(String.class, "text"); configuration.add(Number.class, "number"); configuration.add(Enum.class, "enum"); configuration.add(Boolean.class, "boolean"); configuration.add(Date.class, "date"); } public static void contributeBeanBlockSource(Configuration<BeanBlockContribution> configuration) { addEditBlock(configuration, "text"); addEditBlock(configuration, "number"); addEditBlock(configuration, "enum"); addEditBlock(configuration, "boolean"); addEditBlock(configuration, "date"); addEditBlock(configuration, "password"); // longtext uses a text area, not a text field addEditBlock(configuration, "longtext"); addDisplayBlock(configuration, "enum"); addDisplayBlock(configuration, "date"); // Password and long text have special output needs. addDisplayBlock(configuration, "password"); addDisplayBlock(configuration, "longtext"); } private static void addEditBlock(Configuration<BeanBlockContribution> configuration, String dataType) { addEditBlock(configuration, dataType, dataType); } private static void addEditBlock(Configuration<BeanBlockContribution> configuration, String dataType, String blockId) { configuration.add(new BeanBlockContribution(dataType, "PropertyEditBlocks", blockId, true)); } private static void addDisplayBlock(Configuration<BeanBlockContribution> configuration, String dataType) { addDisplayBlock(configuration, dataType, dataType); } private static void addDisplayBlock(Configuration<BeanBlockContribution> configuration, String dataType, String blockId) { configuration.add(new BeanBlockContribution(dataType, "PropertyDisplayBlocks", blockId, false)); } /** * Contributes the basic set of validators: <ul> <li>required</li> <li>minlength</li> <li>maxlength</li> * <li>min</li> <li>max</li> <li>regexp</li> </ul> */ public static void contributeFieldValidatorSource(MappedConfiguration<String, Validator> configuration) { configuration.add("required", new Required()); configuration.add("minlength", new MinLength()); configuration.add("maxlength", new MaxLength()); configuration.add("min", new Min()); configuration.add("max", new Max()); configuration.add("regexp", new Regexp()); configuration.add("email", new Email()); } /** * Contributes the base set of injection providers: <dl> <dt>Default</dt> <dd>based on {@link * MasterObjectProvider}</dd> <dt>Block</dt> <dd>injects fields of type Block</dd> <dt>ComponentResources</dt> * <dd>give component access to its resources</dd> <dt>CommonResources</dt> <dd>access to properties of resources * (log, messages, etc.)</dd> <dt>Asset</dt> <dd>injection of assets (triggered via {@link Path} annotation), with * the path relative to the component class</dd> <dt>Service</dt> <dd>ordered last, for use when Inject is present * and nothing else works, matches field type against Tapestry IoC services</dd> </dl> */ public static void contributeInjectionProvider(OrderedConfiguration<InjectionProvider> configuration, MasterObjectProvider masterObjectProvider, ObjectLocator locator, SymbolSource symbolSource, AssetSource assetSource) { configuration.add("Default", new DefaultInjectionProvider(masterObjectProvider, locator)); configuration.add("ComponentResources", new ComponentResourcesInjectionProvider()); // This comes after default, to deal with conflicts between injecting a String as the // component id, and injecting a string with @Symbol or @Value. configuration.add("CommonResources", new CommonResourcesInjectionProvider(), "after:Default"); configuration.add("Asset", new AssetInjectionProvider(symbolSource, assetSource), "before:Default"); configuration.add("Block", new BlockInjectionProvider(), "before:Default"); // This needs to be the last one, since it matches against services // and might blow up if there is no match. configuration.add("Service", new ServiceInjectionProvider(locator), "after:*"); } /** * Contributes two object providers: <dl> <dt>Alias</dt> <dd> Searches by type among {@linkplain AliasContribution * contributions} to the {@link Alias} service</dd> <dt>Asset<dt> <dd> Checks for the {@link Path} annotation, and * injects an {@link Asset}</dd> <dt>Service</dt> <dd>Injects based on the {@link Service} annotation, if * present</dd> </dl> */ public static void contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> configuration, @Local final Alias alias, @InjectService("AssetObjectProvider") ObjectProvider assetObjectProvider) { // There's a nasty web of dependencies related to Alias; this wrapper class lets us // defer instantiating the Alias service implementation just long enough to defuse those // dependencies. The @Local annotation prevents a recursive call through the // MasterObjectProvider to resolve the Alias service itself; that is MasterObjectProvider // gets built using this proxy, then the proxy will trigger the construction of AliasImpl // (which itself needs MasterObjectProvider to resolve some dependencies). ObjectProvider wrapper = new ObjectProvider() { public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator) { return alias.getObjectProvider().provide(objectType, annotationProvider, locator); } }; configuration.add("Alias", wrapper, "after:Value,Symbol"); configuration.add("Asset", assetObjectProvider, "before:Alias"); configuration.add("Service", new ServiceAnnotationObjectProvider(), "before:Alias"); } public static void contributeHttpServletRequestHandler(OrderedConfiguration<HttpServletRequestFilter> configuration, @InjectService("IgnoredPathsFilter") HttpServletRequestFilter ignoredPathsFilter) { configuration.add("IgnoredPaths", ignoredPathsFilter); } /** * Continues a number of filters into the RequestHandler service: <dl> <dt>StaticFiles</dt> <dd>Checks to see if the * request is for an actual file, if so, returns true to let the servlet container process the request</dd> * <dt>CheckForUpdates</dt> <dd>Periodically fires events that checks to see if the file system sources for any * cached data has changed (see {@link org.apache.tapestry5.internal.services.CheckForUpdatesFilter}). * <dt>ErrorFilter</dt> <dd>Catches request errors and lets the {@link org.apache.tapestry5.services.RequestExceptionHandler} * handle them</dd> <dt>Localization</dt> <dd>Determines the locale for the current request from header data or * cookies in the request</dd> <dt>StoreIntoGlobals</dt> <dd>Stores the request and response into the {@link * org.apache.tapestry5.services.RequestGlobals} service (this is repeated at the end of the pipeline, in case any * filter substitutes the request or response). </dl> */ public void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration, Context context, // @Inject not needed because its a long, not a String @Symbol(SymbolConstants.FILE_CHECK_INTERVAL) @IntermediateType(TimeInterval.class) long checkInterval, @Symbol(SymbolConstants.FILE_CHECK_UPDATE_TIMEOUT) @IntermediateType(TimeInterval.class) long updateTimeout, UpdateListenerHub updateListenerHub, LocalizationSetter localizationSetter, final EndOfRequestListenerHub endOfRequestListenerHub, ObjectLocator locator) { RequestFilter staticFilesFilter = new StaticFilesFilter(context); RequestFilter storeIntoGlobals = new RequestFilter() { public boolean service(Request request, Response response, RequestHandler handler) throws IOException { requestGlobals.storeRequestResponse(request, response); return handler.service(request, response); } }; RequestFilter fireEndOfRequestEvent = new RequestFilter() { public boolean service(Request request, Response response, RequestHandler handler) throws IOException { try { return handler.service(request, response); } finally { endOfRequestListenerHub.fire(request); } } }; configuration.add("CheckForUpdates", new CheckForUpdatesFilter(updateListenerHub, checkInterval, updateTimeout), "before:*"); configuration.add("StaticFiles", staticFilesFilter); configuration.add("ErrorFilter", locator.autobuild(RequestErrorFilter.class)); configuration.add("StoreIntoGlobals", storeIntoGlobals, "after:StaticFiles", "before:ErrorFilter"); configuration.add("EndOfRequest", fireEndOfRequestEvent, "after:StoreIntoGlobals", "before:ErrorFilter"); configuration.add("Localization", new LocalizationFilter(localizationSetter), "after:ErrorFilter"); } /** * Contributes the basic set of named translators: <ul> <li>string</li> <li>byte</li> <li>integer</li> * <li>long</li> <li>float</li> <li>double</li> <li>short</li> </ul> */ public static void contributeTranslatorSource(MappedConfiguration<String, Translator> configuration) { configuration.add("string", new StringTranslator()); configuration.add("byte", new ByteTranslator()); configuration.add("integer", new IntegerTranslator()); configuration.add("long", new LongTranslator()); configuration.add("float", new FloatTranslator()); configuration.add("double", new DoubleTranslator()); configuration.add("short", new ShortTranslator()); } /** * Adds coercions: <ul> <li>String to {@link org.apache.tapestry5.SelectModel} <li>String to {@link * org.apache.tapestry5.corelib.data.InsertPosition} <li>Map to {@link org.apache.tapestry5.SelectModel} * <li>Collection to {@link GridDataSource} <li>null to {@link org.apache.tapestry5.grid.GridDataSource} <li>String * to {@link org.apache.tapestry5.corelib.data.GridPagerPosition} <li>List to {@link * org.apache.tapestry5.SelectModel} <li>{@link org.apache.tapestry5.runtime.ComponentResourcesAware} (typically, a * component) to {@link org.apache.tapestry5.ComponentResources} <li>String to {@link * org.apache.tapestry5.corelib.data.BlankOption} <li> {@link org.apache.tapestry5.ComponentResources} to {@link * org.apache.tapestry5.PropertyOverrides} <li>String to {@link org.apache.tapestry5.Renderable} <li>{@link * org.apache.tapestry5.Renderable} to {@link org.apache.tapestry5.Block}</ul> */ public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration) { add(configuration, ComponentResources.class, PropertyOverrides.class, new Coercion<ComponentResources, PropertyOverrides>() { public PropertyOverrides coerce(ComponentResources input) { return new PropertyOverridesImpl(input); } }); add(configuration, String.class, SelectModel.class, new Coercion<String, SelectModel>() { public SelectModel coerce(String input) { return TapestryInternalUtils.toSelectModel(input); } }); add(configuration, Map.class, SelectModel.class, new Coercion<Map, SelectModel>() { @SuppressWarnings("unchecked") public SelectModel coerce(Map input) { return TapestryInternalUtils.toSelectModel(input); } }); add(configuration, Collection.class, GridDataSource.class, new Coercion<Collection, GridDataSource>() { public GridDataSource coerce(Collection input) { return new CollectionGridDataSource(input); } }); add(configuration, void.class, GridDataSource.class, new Coercion<Void, GridDataSource>() { private final GridDataSource source = new NullDataSource(); public GridDataSource coerce(Void input) { return source; } }); add(configuration, String.class, GridPagerPosition.class, StringToEnumCoercion.create(GridPagerPosition.class)); add(configuration, String.class, InsertPosition.class, StringToEnumCoercion.create(InsertPosition.class)); add(configuration, String.class, BlankOption.class, StringToEnumCoercion.create(BlankOption.class)); add(configuration, List.class, SelectModel.class, new Coercion<List, SelectModel>() { @SuppressWarnings("unchecked") public SelectModel coerce(List input) { return TapestryInternalUtils.toSelectModel(input); } }); add(configuration, String.class, Pattern.class, new Coercion<String, Pattern>() { public Pattern coerce(String input) { return Pattern.compile(input); } }); add(configuration, ComponentResourcesAware.class, ComponentResources.class, new Coercion<ComponentResourcesAware, ComponentResources>() { public ComponentResources coerce(ComponentResourcesAware input) { return input.getComponentResources(); } }); add(configuration, String.class, Renderable.class, new Coercion<String, Renderable>() { public Renderable coerce(String input) { return new StringRenderable(input); } }); add(configuration, Renderable.class, Block.class, new Coercion<Renderable, Block>() { public Block coerce(Renderable input) { return new RenderableAsBlock(input); } }); } /** * Adds built-in constraint generators: <ul> <li>PrimtiveField -- primitive fields are always required * <li>ValidateAnnotation -- adds constraints from a {@link Validate} annotation </ul> */ public static void contributeValidationConstraintGenerator( OrderedConfiguration<ValidationConstraintGenerator> configuration) { configuration.add("PrimitiveField", new PrimitiveFieldConstraintGenerator()); configuration.add("ValidateAnnotation", new ValidateAnnotationConstraintGenerator()); } private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion) { CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion); configuration.add(tuple); } private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration, Class<? extends Annotation> annotationClass, TransformMethodSignature lifecycleMethodSignature, String methodAlias) { ComponentClassTransformWorker worker = new PageLifecycleAnnotationWorker(annotationClass, lifecycleMethodSignature, methodAlias); String name = TapestryInternalUtils.lastTerm(annotationClass.getName()); configuration.add(name, worker); } private static void add(OrderedConfiguration<ComponentClassTransformWorker> configuration, TransformMethodSignature signature, Class<? extends Annotation> annotationClass, boolean reverse) { // make the name match the annotation class name. String name = annotationClass.getSimpleName(); configuration.add(name, new RenderPhaseMethodWorker(signature, annotationClass, reverse)); } // ======================================================================== // // Service Builder Methods (instance) // // ======================================================================== public Context buildContext(ApplicationGlobals globals) { return shadowBuilder.build(globals, "context", Context.class); } public ComponentClassResolver buildComponentClassResolver(ServiceResources resources) { ComponentClassResolverImpl service = resources.autobuild(ComponentClassResolverImpl.class); // Allow the resolver to clean its cache when the source is invalidated componentInstantiatorSource.addInvalidationListener(service); return service; } @Marker(ClasspathProvider.class) public AssetFactory buildClasspathAssetFactory(ResourceCache resourceCache, ClasspathAssetAliasManager aliasManager) { ClasspathAssetFactory factory = new ClasspathAssetFactory(resourceCache, aliasManager); resourceCache.addInvalidationListener(factory); return factory; } @Marker(ContextProvider.class) public AssetFactory buildContextAssetFactory(ApplicationGlobals globals, RequestPathOptimizer optimizer) { return new ContextAssetFactory(request, globals.getContext(), optimizer); } /** * Builds the PropBindingFactory as a chain of command. The terminator of the chain is responsible for ordinary * property names (and property paths). Contributions to the service cover additional special cases, such as simple * literal values. * * @param configuration contributions of special factories for some constants, each contributed factory may return a * binding if applicable, or null otherwise */ public BindingFactory buildPropBindingFactory(List<BindingFactory> configuration, PropertyConduitSource propertyConduitSource) { PropBindingFactory service = new PropBindingFactory(propertyConduitSource); configuration.add(service); return chainBuilder.build(BindingFactory.class, configuration); } /** * Builds the source of {@link Messages} containing validation messages. The contributions are paths to message * bundles (resource paths within the classpath); the default contribution is "org/apache/tapestry5/internal/ValidationMessages". */ public ValidationMessagesSource buildValidationMessagesSource(Collection<String> configuration, UpdateListenerHub updateListenerHub, @ClasspathProvider AssetFactory classpathAssetFactory) { ValidationMessagesSourceImpl service = new ValidationMessagesSourceImpl(configuration, classpathAssetFactory.getRootResource()); updateListenerHub.addUpdateListener(service); return service; } public MetaDataLocator buildMetaDataLocator(ServiceResources resources) { MetaDataLocatorImpl service = resources.autobuild(MetaDataLocatorImpl.class); componentInstantiatorSource.addInvalidationListener(service); return service; } public PersistentFieldStrategy buildClientPersistentFieldStrategy(LinkFactory linkFactory, ServiceResources resources) { ClientPersistentFieldStrategy service = resources.autobuild(ClientPersistentFieldStrategy.class); linkFactory.addListener(service); return service; } /** * Builds a proxy to the current {@link org.apache.tapestry5.RenderSupport} inside this thread's {@link * Environment}. */ public RenderSupport buildRenderSupport() { return environmentalBuilder.build(RenderSupport.class); } /** * Builds a proxy to the current {@link org.apache.tapestry5.services.FormSupport} inside this thread's {@link * org.apache.tapestry5.services.Environment}. */ public FormSupport buildFormSupport() { return environmentalBuilder.build(FormSupport.class); } /** * Allows the exact steps in the component class transformation process to be defined. */ public ComponentClassTransformWorker buildComponentClassTransformWorker( List<ComponentClassTransformWorker> configuration) { return chainBuilder.build(ComponentClassTransformWorker.class, configuration); } /** * Analyzes properties to determine the data types, used to {@linkplain #contributeBeanBlockSource(org.apache.tapestry5.ioc.Configuration)} * locale display and edit blocks} for properties. The default behaviors look for a {@link * org.apache.tapestry5.beaneditor.DataType} annotation before deriving the data type from the property type. */ @Marker(Primary.class) public DataTypeAnalyzer buildDataTypeAnalyzer(List<DataTypeAnalyzer> configuration) { return chainBuilder.build(DataTypeAnalyzer.class, configuration); } /** * A chain of command for providing values for {@link Inject}-ed fields in component classes. The service's * configuration can be extended to allow for different automatic injections (based on some combination of field * type and field name). */ public InjectionProvider buildInjectionProvider(List<InjectionProvider> configuration) { return chainBuilder.build(InjectionProvider.class, configuration); } /** * Initializes the application. */ @Marker(Primary.class) public ApplicationInitializer buildApplicationInitializer(Logger logger, List<ApplicationInitializerFilter> configuration) { ApplicationInitializer terminator = new ApplicationInitializer() { public void initializeApplication(Context context) { applicationGlobals.storeContext(context); } }; return pipelineBuilder.build(logger, ApplicationInitializer.class, ApplicationInitializerFilter.class, configuration, terminator); } public HttpServletRequestHandler buildHttpServletRequestHandler(Logger logger, List<HttpServletRequestFilter> configuration, @Primary final RequestHandler handler, @Inject @Symbol(SymbolConstants.CHARSET) final String applicationCharset) { HttpServletRequestHandler terminator = new HttpServletRequestHandler() { public boolean service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException { requestGlobals.storeServletRequestResponse(servletRequest, servletResponse); Request request = new RequestImpl(servletRequest, applicationCharset); Response response = new ResponseImpl(servletResponse); // Transition from the Servlet API-based pipeline, to the Tapestry-based pipeline. return handler.service(request, response); } }; return pipelineBuilder.build(logger, HttpServletRequestHandler.class, HttpServletRequestFilter.class, configuration, terminator); } @Marker(Primary.class) public RequestHandler buildRequestHandler(Logger logger, List<RequestFilter> configuration, @Primary final Dispatcher masterDispatcher) { RequestHandler terminator = new RequestHandler() { public boolean service(Request request, Response response) throws IOException { requestGlobals.storeRequestResponse(request, response); return masterDispatcher.dispatch(request, response); } }; return pipelineBuilder.build(logger, RequestHandler.class, RequestFilter.class, configuration, terminator); } public ServletApplicationInitializer buildServletApplicationInitializer(Logger logger, List<ServletApplicationInitializerFilter> configuration, @Primary final ApplicationInitializer initializer) { ServletApplicationInitializer terminator = new ServletApplicationInitializer() { public void initializeApplication(ServletContext context) { applicationGlobals.storeServletContext(context); // And now, down the (Web) ApplicationInitializer pipeline ... initializer.initializeApplication(new ContextImpl(context)); } }; return pipelineBuilder.build(logger, ServletApplicationInitializer.class, ServletApplicationInitializerFilter.class, configuration, terminator); } /** * The component event result processor used for normal component requests. */ @Marker({Primary.class, Traditional.class}) public ComponentEventResultProcessor buildComponentEventResultProcessor( Map<Class, ComponentEventResultProcessor> configuration) { return constructComponentEventResultProcessor(configuration); } /** * The component event result processor used for Ajax-oriented component requests. */ @Marker(Ajax.class) public ComponentEventResultProcessor buildAjaxComponentEventResultProcessor( Map<Class, ComponentEventResultProcessor> configuration) { return constructComponentEventResultProcessor(configuration); } private ComponentEventResultProcessor constructComponentEventResultProcessor( Map<Class, ComponentEventResultProcessor> configuration) { Set<Class> handledTypes = CollectionFactory.newSet(configuration.keySet()); // A slight hack! configuration.put(Object.class, new ObjectComponentEventResultProcessor(handledTypes)); StrategyRegistry<ComponentEventResultProcessor> registry = StrategyRegistry.newInstance( ComponentEventResultProcessor.class, configuration); return strategyBuilder.build(registry); } /** * The default data type analyzer is the final analyzer consulted and identifies the type entirely pased on the * property type, working against its own configuration (mapping property type class to data type). */ public DataTypeAnalyzer buildDefaultDataTypeAnalyzer(ServiceResources resources) { DefaultDataTypeAnalyzer service = resources.autobuild(DefaultDataTypeAnalyzer.class); componentInstantiatorSource.addInvalidationListener(service); return service; } public TranslatorSource buildTranslatorSource(ServiceResources resources) { TranslatorSourceImpl service = resources.autobuild(TranslatorSourceImpl.class); componentInstantiatorSource.addInvalidationListener(service); return service; } @Marker(Primary.class) public ObjectRenderer buildObjectRenderer(Map<Class, ObjectRenderer> configuration) { StrategyRegistry<ObjectRenderer> registry = StrategyRegistry.newInstance(ObjectRenderer.class, configuration); return strategyBuilder.build(registry); } /** * Returns a {@link org.apache.tapestry5.ioc.services.ClassFactory} that can be used to create extra classes around * component classes. This ClassFactory will be cleared whenever an underlying component class is discovered to have * changed. Use of this class factory implies that your code will become aware of this (if necessary) to discard any * cached object (alas, this currently involves dipping into the internals side to register for the correct * notifications). Failure to properly clean up can result in really nasty PermGen space memory leaks. */ @Marker(ComponentLayer.class) public ClassFactory buildComponentClassFactory() { return shadowBuilder.build(componentInstantiatorSource, "classFactory", ClassFactory.class); } /** * Ordered contributions to the MasterDispatcher service allow different URL matching strategies to occur. */ @Marker(Primary.class) public Dispatcher buildMasterDispatcher(List<Dispatcher> configuration) { return chainBuilder.build(Dispatcher.class, configuration); } public PropertyConduitSource buildPropertyConduitSource(@ComponentLayer ClassFactory componentClassFactory) { PropertyConduitSourceImpl service = new PropertyConduitSourceImpl(propertyAccess, componentClassFactory); componentInstantiatorSource.addInvalidationListener(service); return service; } /** * Builds a shadow of the RequestGlobals.request property. Note again that the shadow can be an ordinary singleton, * even though RequestGlobals is perthread. */ public Request buildRequest() { return shadowBuilder.build(requestGlobals, "request", Request.class); } /** * Builds a shadow of the RequestGlobals.HTTPServletRequest property. Generally, you should inject the {@link * Request} service instead, as future version of Tapestry may operate beyond just the servlet API. */ public HttpServletRequest buildHttpServletRequest() { return shadowBuilder.build(requestGlobals, "HTTPServletRequest", HttpServletRequest.class); } /** * Builds a shadow of the RequestGlobals.response property. Note again that the shadow can be an ordinary singleton, * even though RequestGlobals is perthread. */ public Response buildResponse() { return shadowBuilder.build(requestGlobals, "response", Response.class); } /** * The MarkupRenderer service is used to render a full page as markup. Supports an ordered configuration of {@link * org.apache.tapestry5.services.MarkupRendererFilter}s. * * @param pageRenderQueue handles the bulk of the work * @param logger used to log errors building the pipeline * @param configuration filters on this service * @return the service * @see #contributeMarkupRenderer(org.apache.tapestry5.ioc.OrderedConfiguration, org.apache.tapestry5.Asset, * org.apache.tapestry5.Asset, ValidationMessagesSource, org.apache.tapestry5.ioc.services.SymbolSource, * AssetSource) */ public MarkupRenderer buildMarkupRenderer(final PageRenderQueue pageRenderQueue, Logger logger, List<MarkupRendererFilter> configuration) { MarkupRenderer terminator = new MarkupRenderer() { public void renderMarkup(MarkupWriter writer) { pageRenderQueue.render(writer); } }; return pipelineBuilder.build(logger, MarkupRenderer.class, MarkupRendererFilter.class, configuration, terminator); } /** * A wrapper around {@link org.apache.tapestry5.internal.services.PageRenderQueue} used for partial page renders. * Supports an ordered configuration of {@link org.apache.tapestry5.services.PartialMarkupRendererFilter}s. * * @param logger used to log warnings creating the pipeline * @param configuration filters for the service * @param renderQueue does most of the work * @return the service * @see #contributePartialMarkupRenderer(org.apache.tapestry5.ioc.OrderedConfiguration, org.apache.tapestry5.Asset, * org.apache.tapestry5.ioc.services.SymbolSource, AssetSource, ValidationMessagesSource) */ public PartialMarkupRenderer buildPartialMarkupRenderer(Logger logger, List<PartialMarkupRendererFilter> configuration, final PageRenderQueue renderQueue) { PartialMarkupRenderer terminator = new PartialMarkupRenderer() { public void renderMarkup(MarkupWriter writer, JSONObject reply) { renderQueue.renderPartial(writer, reply); } }; return pipelineBuilder.build(logger, PartialMarkupRenderer.class, PartialMarkupRendererFilter.class, configuration, terminator); } public PageRenderRequestHandler buildPageRenderRequestHandler(List<PageRenderRequestFilter> configuration, Logger logger, ServiceResources resources) { return pipelineBuilder.build(logger, PageRenderRequestHandler.class, PageRenderRequestFilter.class, configuration, resources.autobuild(PageRenderRequestHandlerImpl.class)); } /** * Builds the component action request handler for traditional (non-Ajax) requests. These typically result in a * redirect to a Tapestry render URL. * * @see org.apache.tapestry5.internal.services.ComponentEventRequestHandlerImpl */ @Marker(Traditional.class) public ComponentEventRequestHandler buildComponentEventRequestHandler( List<ComponentEventRequestFilter> configuration, Logger logger, ServiceResources resources) { return pipelineBuilder.build(logger, ComponentEventRequestHandler.class, ComponentEventRequestFilter.class, configuration, resources.autobuild(ComponentEventRequestHandlerImpl.class)); } /** * Builds the action request handler for Ajax requests, based on {@link org.apache.tapestry5.internal.services.AjaxComponentEventRequestHandler}. * Filters on the request handler are supported here as well. */ @Marker(Ajax.class) public ComponentEventRequestHandler buildAjaxComponentEventRequestHandler( List<ComponentEventRequestFilter> configuration, Logger logger, ServiceResources resources) { return pipelineBuilder.build(logger, ComponentEventRequestHandler.class, ComponentEventRequestFilter.class, configuration, resources.autobuild(AjaxComponentEventRequestHandler.class)); } // ======================================================================== // // Service Contribution Methods (instance) // // ======================================================================== /** * Contributes the default "session" strategy. */ public void contributeApplicationStatePersistenceStrategySource( MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration, @Local ApplicationStatePersistenceStrategy sessionStategy) { configuration.add("session", sessionStategy); } public ApplicationStatePersistenceStrategy buildSessionApplicationStatePersistenceStrategy(ObjectLocator locator) { return locator.autobuild(SessionApplicationStatePersistenceStrategy.class); } public void contributeAssetSource(MappedConfiguration<String, AssetFactory> configuration, @ContextProvider AssetFactory contextAssetFactory, @ClasspathProvider AssetFactory classpathAssetFactory) { configuration.add("context", contextAssetFactory); configuration.add("classpath", classpathAssetFactory); } /** * Contributes handlers for the following types: <dl> <dt>Object</dt> <dd>Failure case, added to provide a more * useful exception message</dd> <dt>{@link Link}</dt> <dd>Sends a redirect to the link (which is typically a page * render link)</dd> <dt>String</dt> <dd>Sends a page render redirect</dd> <dt>Class</dt> <dd>Interpreted as the * class name of a page, sends a page render render redirect (this is more refactoring safe than the page name)</dd> * <dt>{@link Component}</dt> <dd>A page's root component (though a non-root component will work, but will generate * a warning). A direct to the containing page is sent.</dd> <dt>{@link org.apache.tapestry5.StreamResponse}</dt> * <dd>The stream response is sent as the actual reply.</dd> <dt>URL</dt> <dd>Sends a redirect to a (presumably) * external URL</dd> </dl> */ public void contributeComponentEventResultProcessor( @InjectService("ComponentInstanceResultProcessor") ComponentEventResultProcessor componentInstanceProcessor, ComponentClassResolver componentClassResolver, final RequestPageCache requestPageCache, MappedConfiguration<Class, ComponentEventResultProcessor> configuration) { configuration.add(Link.class, new ComponentEventResultProcessor<Link>() { public void processResultValue(Link value) throws IOException { response.sendRedirect(value); } }); configuration.add(URL.class, new ComponentEventResultProcessor<URL>() { public void processResultValue(URL value) throws IOException { response.sendRedirect(value.toExternalForm()); } }); configuration.add(String.class, new StringResultProcessor(requestPageCache, actionRenderResponseGenerator)); configuration.add(Class.class, new ClassResultProcessor(componentClassResolver, requestPageCache, actionRenderResponseGenerator)); configuration.add(Component.class, componentInstanceProcessor); configuration.add(StreamResponse.class, new StreamResponseResultProcessor(response)); } /** * Contributes handlers for the following types: <dl> <dt>Object</dt> <dd>Failure case, added to provide more useful * exception message</dd> <dt>{@link RenderCommand}</dt> <dd>Typically, a {@link org.apache.tapestry5.Block}</dd> * <dt>{@link Component}</dt> <dd>Renders the component and its body</dd> <dt>{@link * org.apache.tapestry5.json.JSONObject}</dt> <dd>The JSONObject is returned as a text/javascript response</dd> * <dt>{@link org.apache.tapestry5.StreamResponse}</dt> <dd>The stream response is sent as the actual response</dd> * </dl> */ public void contributeAjaxComponentEventResultProcessor( MappedConfiguration<Class, ComponentEventResultProcessor> configuration, ObjectLocator locator) { configuration.add(RenderCommand.class, locator.autobuild(RenderCommandComponentEventResultProcessor.class)); configuration.add(Component.class, locator.autobuild(AjaxComponentInstanceEventResultProcessor.class)); configuration.add(JSONObject.class, locator.autobuild(JSONObjectEventResultProcessor.class)); configuration.add(StreamResponse.class, new StreamResponseResultProcessor(response)); } /** * The MasterDispatcher is a chain-of-command of individual Dispatchers, each handling (like a servlet) a particular * kind of incoming request. <dl> <dt>RootPath</dt> <dd>Renders the start page for the "/" request</dd> * <dt>Asset</dt> <dd>Provides access to classpath assets</dd> <dt>PageRender</dt> <dd>Identifies the {@link * org.apache.tapestry5.services.PageRenderRequestParameters} and forwards onto {@link * PageRenderRequestHandler}</dd> <dt>ComponentEvent</dt> <dd>Identifies the {@link ComponentEventRequestParameters} * and forwards onto the {@link ComponentEventRequestHandler}</dd> </dl> */ public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration, ObjectLocator locator) { // Looks for the root path and renders the start page. This is maintained for compatibility // with earlier versions of Tapestry 5, it is recommended that an Index page be used instead. configuration.add("RootPath", locator.autobuild(RootPathDispatcher.class), "before:Asset"); // This goes first because an asset to be streamed may have an file extension, such as // ".html", that will confuse the later dispatchers. configuration.add("Asset", locator.autobuild(AssetDispatcher.class), "before:ComponentEvent"); configuration.add("ComponentEvent", locator.autobuild(ComponentEventDispatcher.class), "before:PageRender"); configuration.add("PageRender", locator.autobuild(PageRenderDispatcher.class)); } /** * Contributes a default object renderer for type Object, plus specialized renderers for {@link * org.apache.tapestry5.services.Request}, {@link org.apache.tapestry5.ioc.Location}, {@link * org.apache.tapestry5.ComponentResources}, {@link org.apache.tapestry5.EventContext}, List, and Object[]. */ public void contributeObjectRenderer(MappedConfiguration<Class, ObjectRenderer> configuration, @InjectService("LocationRenderer") ObjectRenderer locationRenderer, final TypeCoercer typeCoercer, ObjectLocator locator) { configuration.add(Object.class, new ObjectRenderer() { public void render(Object object, MarkupWriter writer) { writer.write(String.valueOf(object)); } }); configuration.add(Request.class, locator.autobuild(RequestRenderer.class)); configuration.add(Location.class, locationRenderer); ObjectRenderer preformatted = new ObjectRenderer<Object>() { public void render(Object object, MarkupWriter writer) { writer.element("pre"); writer.write(typeCoercer.coerce(object, String.class)); writer.end(); } }; configuration.add(ClassTransformation.class, preformatted); configuration.add(List.class, locator.autobuild(ListRenderer.class)); configuration.add(Object[].class, locator.autobuild(ObjectArrayRenderer.class)); configuration.add(ComponentResources.class, locator.autobuild(ComponentResourcesRenderer.class)); configuration.add(EventContext.class, locator.autobuild(EventContextRenderer.class)); } /** * Adds page render filters, each of which provides an {@link org.apache.tapestry5.annotations.Environmental} * service. Filters often provide {@link Environmental} services needed by components as they render. <dl> * <dt>PageRenderSupport</dt> <dd>Provides {@link org.apache.tapestry5.RenderSupport}</dd> * <dt>ClientBehaviorSupport</dt> <dd>Provides {@link org.apache.tapestry5.internal.services.ClientBehaviorSupport}</dd> * <dt>Heartbeat</dt> <dd>Provides {@link org.apache.tapestry5.services.Heartbeat}</dd> * <dt>DefaultValidationDecorator</dt> <dd>Provides {@link org.apache.tapestry5.ValidationDecorator} (as an instance * of {@link org.apache.tapestry5.internal.DefaultValidationDecorator})</dd> </dl> */ public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration, @Symbol(SymbolConstants.PRODUCTION_MODE) final boolean productionMode, @Path("${tapestry.default-stylesheet}") final Asset stylesheetAsset, @Path("${tapestry.field-error-marker}") final Asset fieldErrorIcon, final ValidationMessagesSource validationMessagesSource, final SymbolSource symbolSource, final AssetSource assetSource) { MarkupRendererFilter pageRenderSupport = new MarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) { DocumentLinkerImpl linker = new DocumentLinkerImpl(productionMode); RenderSupportImpl support = new RenderSupportImpl(linker, symbolSource, assetSource, // Core scripts added to any page that uses scripting "${tapestry.scriptaculous}/prototype.js", "${tapestry.scriptaculous}/scriptaculous.js", "${tapestry.scriptaculous}/effects.js", // Uses functions defined by the prior three "org/apache/tapestry5/tapestry.js"); support.addStylesheetLink(stylesheetAsset, null); environment.push(RenderSupport.class, support); renderer.renderMarkup(writer); support.commit(); linker.updateDocument(writer.getDocument()); environment.pop(RenderSupport.class); } }; MarkupRendererFilter clientBehaviorSupport = new MarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) { RenderSupport renderSupport = environment.peekRequired(RenderSupport.class); ClientBehaviorSupportImpl clientBehaviorSupport = new ClientBehaviorSupportImpl(renderSupport); environment.push(ClientBehaviorSupport.class, clientBehaviorSupport); renderer.renderMarkup(writer); environment.pop(ClientBehaviorSupport.class); clientBehaviorSupport.commit(); } }; MarkupRendererFilter heartbeat = new MarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) { Heartbeat heartbeat = new HeartbeatImpl(); heartbeat.begin(); environment.push(Heartbeat.class, heartbeat); renderer.renderMarkup(writer); environment.pop(Heartbeat.class); heartbeat.end(); } }; MarkupRendererFilter defaultValidationDecorator = new MarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) { Messages messages = validationMessagesSource.getValidationMessages(threadLocale.getLocale()); ValidationDecorator decorator = new DefaultValidationDecorator(environment, messages, fieldErrorIcon, writer); environment.push(ValidationDecorator.class, decorator); renderer.renderMarkup(writer); environment.pop(ValidationDecorator.class); } }; configuration.add("RenderSupport", pageRenderSupport); configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:RenderSupport"); configuration.add("Heartbeat", heartbeat, "after:RenderSupport"); configuration.add("DefaultValidationDecorator", defaultValidationDecorator, "after:Heartbeat"); } /** * Contributes {@link PartialMarkupRendererFilter}s used when rendering a partial Ajax response. This is an analog * to {@link #contributeMarkupRenderer(org.apache.tapestry5.ioc.OrderedConfiguration, org.apache.tapestry5.Asset, * org.apache.tapestry5.Asset, ValidationMessagesSource, org.apache.tapestry5.ioc.services.SymbolSource, * AssetSource)} } and overlaps it to some degree. <dl> <dt> PageRenderSupport </dt> <dd>Provides {@link * org.apache.tapestry5.RenderSupport}</dd> <dt>ClientBehaviorSupport</dt> <dd>Provides {@link * org.apache.tapestry5.internal.services.ClientBehaviorSupport}</dd> <dt>Heartbeat</dt> <dd>Provides {@link * org.apache.tapestry5.services.Heartbeat}</dd> <dt>DefaultValidationDecorator</dt> <dd>Provides {@link * org.apache.tapestry5.ValidationDecorator} (as an instance of {@link org.apache.tapestry5.internal.DefaultValidationDecorator})</dd> * </dl> */ public void contributePartialMarkupRenderer(OrderedConfiguration<PartialMarkupRendererFilter> configuration, @Path("${tapestry.field-error-marker}") final Asset fieldErrorIcon, final SymbolSource symbolSource, final AssetSource assetSource, final ValidationMessagesSource validationMessagesSource) { PartialMarkupRendererFilter pageRenderSupport = new PartialMarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer) { String uid = Long.toHexString(System.currentTimeMillis()); String namespace = ":" + uid; IdAllocator idAllocator = new IdAllocator(namespace); PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker(); RenderSupportImpl support = new RenderSupportImpl(linker, symbolSource, assetSource, idAllocator); environment.push(RenderSupport.class, support); renderer.renderMarkup(writer, reply); support.commit(); environment.pop(RenderSupport.class); linker.commit(reply); } }; PartialMarkupRendererFilter clientBehaviorSupport = new PartialMarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer) { RenderSupport renderSupport = environment.peekRequired(RenderSupport.class); ClientBehaviorSupportImpl support = new ClientBehaviorSupportImpl(renderSupport); environment.push(ClientBehaviorSupport.class, support); renderer.renderMarkup(writer, reply); environment.pop(ClientBehaviorSupport.class); support.commit(); } }; PartialMarkupRendererFilter heartbeat = new PartialMarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer) { Heartbeat heartbeat = new HeartbeatImpl(); heartbeat.begin(); environment.push(Heartbeat.class, heartbeat); renderer.renderMarkup(writer, reply); environment.pop(Heartbeat.class); heartbeat.end(); } }; PartialMarkupRendererFilter defaultValidationDecorator = new PartialMarkupRendererFilter() { public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer) { Messages messages = validationMessagesSource.getValidationMessages(threadLocale.getLocale()); ValidationDecorator decorator = new DefaultValidationDecorator(environment, messages, fieldErrorIcon, writer); environment.push(ValidationDecorator.class, decorator); renderer.renderMarkup(writer, reply); environment.pop(ValidationDecorator.class); } }; configuration.add("RenderSupport", pageRenderSupport); configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:RenderSupport"); configuration.add("Heartbeat", heartbeat, "after:RenderSupport"); configuration.add("DefaultValidationDecorator", defaultValidationDecorator, "after:Heartbeat"); } /** * Contributes several strategies: <dl> <dt>session <dd>Values are stored in the {@link Session} <dt>flash * <dd>Values are stored in the {@link Session}, until the next request (for the page) <dt>client <dd>Values are * encoded into URLs (or hidden form fields) </dl> */ public void contributePersistentFieldManager(MappedConfiguration<String, PersistentFieldStrategy> configuration, Request request, @InjectService("ClientPersistentFieldStrategy") PersistentFieldStrategy clientStrategy) { configuration.add("session", new SessionPersistentFieldStrategy(request)); configuration.add(PersistenceConstants.FLASH, new FlashPersistentFieldStrategy(request)); configuration.add("client", clientStrategy); } public void contributeValidationMessagesSource(Configuration<String> configuration) { configuration.add("org/apache/tapestry5/internal/ValidationMessages"); } public ValueEncoderSource buildValueEncoderSource(Map<Class, ValueEncoderFactory> configuration) { ValueEncoderSourceImpl service = new ValueEncoderSourceImpl(configuration); componentInstantiatorSource.addInvalidationListener(service); return service; } /** * Contributes {@link ValueEncoderFactory}s for types: <ul> <li>Object <li>String <li>Enum </ul> */ @SuppressWarnings("unchecked") public static void contributeValueEncoderSource(MappedConfiguration<Class, ValueEncoderFactory> configuration, ObjectLocator locator) { configuration.add(Object.class, locator.autobuild(TypeCoercedValueEncoderFactory.class)); configuration.add(String.class, GenericValueEncoderFactory.create(new StringValueEncoder())); configuration.add(Enum.class, new EnumValueEncoderFactory()); } /** * Contributes a single filter, "Secure", which checks for non-secure requests that access secure pages. */ public void contributePageRenderRequestHandler(OrderedConfiguration<PageRenderRequestFilter> configuration, final RequestSecurityManager securityManager) { PageRenderRequestFilter secureFilter = new PageRenderRequestFilter() { public void handle(PageRenderRequestParameters parameters, PageRenderRequestHandler handler) throws IOException { if (securityManager.checkForInsecureRequest(parameters.getLogicalPageName())) return; handler.handle(parameters); } }; configuration.add("Secure", secureFilter); } /** * Configures the extensions that will require a digest to be downloaded via the asset dispatcher. Most resources * are "safe", they don't require a digest. For unsafe resources, the digest is incorporated into the URL to ensure * that the client side isn't just "fishing". * <p/> * The extensions must be all lower case. * <p/> * This contributes "class" and "tml" (the template extension). * * @param configuration collection of extensions */ public static void contributeResourceDigestGenerator(Configuration<String> configuration) { // Java class files always require a digest. configuration.add("class"); // Likewise, we don't want people fishing for templates. configuration.add(InternalConstants.TEMPLATE_EXTENSION); } public static void contributeTemplateParser(MappedConfiguration<String, URL> config) { // Any class inside the internal module would do. Or we could move all these // files to o.a.t.services. Class c = UpdateListenerHub.class; config.add("-//W3C//DTD XHTML 1.0 Strict//EN", c.getResource("xhtml1-strict.dtd")); config.add("-//W3C//DTD XHTML 1.0 Transitional//EN", c .getResource("xhtml1-transitional.dtd")); config.add("-//W3C//DTD XHTML 1.0 Frameset//EN", c.getResource("xhtml1-frameset.dtd")); config.add("-//W3C//DTD HTML 4.01//EN", c.getResource("xhtml1-strict.dtd")); config.add("-//W3C//DTD HTML 4.01 Transitional//EN", c .getResource("xhtml1-transitional.dtd")); config.add("-//W3C//DTD HTML 4.01 Frameset//EN", c.getResource("xhtml1-frameset.dtd")); config.add("-//W3C//ENTITIES Latin 1 for XHTML//EN", c.getResource("xhtml-lat1.ent")); config.add("-//W3C//ENTITIES Symbols for XHTML//EN", c.getResource("xhtml-symbol.ent")); config.add("-//W3C//ENTITIES Special for XHTML//EN", c.getResource("xhtml-special.ent")); } /** * Contributes factory defaults that map be overridden. * * @see TapestryModule#contributeClasspathAssetAliasManager(org.apache.tapestry5.ioc.MappedConfiguration, String, * String, String) */ public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration) { // Remember this is request-to-request time, presumably it'll take the developer more than // one second to make a change, save it, and switch back to the browser. configuration.add(SymbolConstants.FILE_CHECK_INTERVAL, "1 s"); configuration.add(SymbolConstants.FILE_CHECK_UPDATE_TIMEOUT, "50 ms"); // This should be overridden for particular applications. configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en,it,zh_CN,pt_PT,de_DE,ru"); configuration.add(SymbolConstants.TAPESTRY_VERSION, VersionUtils.readVersionNumber( "META-INF/maven/org.apache.tapestry/tapestry-core/pom.properties")); configuration.add("tapestry.default-cookie-max-age", "7 d"); configuration.add("tapestry.start-page-name", "start"); configuration.add("tapestry.default-stylesheet", "org/apache/tapestry5/default.css"); configuration.add("tapestry.field-error-marker", "org/apache/tapestry5/field-error-marker.gif"); configuration.add("tapestry.page-pool.soft-limit", "5"); configuration.add("tapestry.page-pool.soft-wait", "10 ms"); configuration.add("tapestry.page-pool.hard-limit", "20"); configuration.add("tapestry.page-pool.active-window", "10 m"); configuration.add(SymbolConstants.SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS, "false"); configuration.add(SymbolConstants.FORCE_ABSOLUTE_URIS, "false"); configuration.add(SymbolConstants.PRODUCTION_MODE, "true"); configuration.add(SymbolConstants.COMPRESS_WHITESPACE, "true"); configuration.add(MetaDataConstants.SECURE_PAGE, "false"); // This is designed to make it easy to keep synchronized with script.aculo.ous. As we // support a new version, we create a new folder, and update the path entry. We can then // delete the old version folder (or keep it around). This should be more manageable than // overwriting the local copy with updates (it's too easy for files deleted between scriptaculous // releases to be accidentally left lying around). There's also a ClasspathAliasManager // contribution based on the path. configuration.add("tapestry.scriptaculous", "classpath:${tapestry.scriptaculous.path}"); configuration.add("tapestry.scriptaculous.path", "org/apache/tapestry5/scriptaculous_1_8_1"); // Likewise for WebFX DatePicker, currently version 1.0.6 configuration.add("tapestry.datepicker.path", "org/apache/tapestry5/datepicker_106"); configuration.add("tapestry.datepicker", "classpath:${tapestry.datepicker.path}"); configuration.add(PersistentFieldManagerImpl.META_KEY, PersistentFieldManagerImpl.DEFAULT_STRATEGY); configuration.add(MetaDataConstants.RESPONSE_CONTENT_TYPE, "text/html"); configuration.add(SymbolConstants.CHARSET, "UTF-8"); configuration.add(SymbolConstants.APPLICATION_CATALOG, "WEB-INF/${tapestry.app-name}.properties"); configuration.add(SymbolConstants.EXCEPTION_REPORT_PAGE, "ExceptionReport"); } /** * Adds content types for "css" and "js" file extensions. <dl> <dt>css</dt> <dd>test/css</dd> <dt>js</dt> * <dd>text/javascript</dd> </dl> */ @SuppressWarnings({"JavaDoc"}) public void contributeResourceStreamer(MappedConfiguration<String, String> configuration) { configuration.add("css", "text/css"); configuration.add("js", "text/javascript"); } /** * Adds a listener to the {@link org.apache.tapestry5.internal.services.ComponentInstantiatorSource} that clears the * {@link PropertyAccess} and {@link TypeCoercer} caches on a class loader invalidation. In addition, forces the * realization of {@link ComponentClassResolver} at startup. */ public void contributeApplicationInitializer(OrderedConfiguration<ApplicationInitializerFilter> configuration, final TypeCoercer typeCoercer, final ComponentClassResolver componentClassResolver) { final InvalidationListener listener = new InvalidationListener() { public void objectWasInvalidated() { propertyAccess.clearCache(); typeCoercer.clearCache(); } }; ApplicationInitializerFilter clearCaches = new ApplicationInitializerFilter() { public void initializeApplication(Context context, ApplicationInitializer initializer) { // Snuck in here is the logic to clear the PropertyAccess service's cache whenever // the component class loader is invalidated. componentInstantiatorSource.addInvalidationListener(listener); initializer.initializeApplication(context); // We don't care about the result, but this forces a load of the service // at application startup, rather than on first request. componentClassResolver.isPageName("ForceLoadAtStartup"); } }; configuration.add("ClearCachesOnInvalidation", clearCaches); } public void contributePropBindingFactory(OrderedConfiguration<BindingFactory> configuration) { BindingFactory keywordFactory = new BindingFactory() { private final Map<String, Object> keywords = CollectionFactory.newCaseInsensitiveMap(); { keywords.put("true", Boolean.TRUE); keywords.put("false", Boolean.FALSE); keywords.put("null", null); } public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { String key = expression.trim(); if (keywords.containsKey(key)) return new LiteralBinding(description, keywords.get(key), location); return null; } }; BindingFactory thisFactory = new BindingFactory() { public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { if ("this".equalsIgnoreCase(expression.trim())) return new LiteralBinding(description, container.getComponent(), location); return null; } }; BindingFactory longFactory = new BindingFactory() { private final Pattern pattern = Pattern.compile("^\\s*(-?\\d+)\\s*$"); public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { Matcher matcher = pattern.matcher(expression); if (matcher.matches()) { String value = matcher.group(1); return new LiteralBinding(description, new Long(value), location); } return null; } }; BindingFactory intRangeFactory = new BindingFactory() { private final Pattern pattern = Pattern .compile("^\\s*(-?\\d+)\\s*\\.\\.\\s*(-?\\d+)\\s*$"); public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { Matcher matcher = pattern.matcher(expression); if (matcher.matches()) { int start = Integer.parseInt(matcher.group(1)); int finish = Integer.parseInt(matcher.group(2)); IntegerRange range = new IntegerRange(start, finish); return new LiteralBinding(description, range, location); } return null; } }; BindingFactory doubleFactory = new BindingFactory() { // So, either 1234. or 1234.56 or .78 private final Pattern pattern = Pattern .compile("^\\s*(\\-?((\\d+\\.)|(\\d*\\.\\d+)))\\s*$"); public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { Matcher matcher = pattern.matcher(expression); if (matcher.matches()) { String value = matcher.group(1); return new LiteralBinding(description, new Double(value), location); } return null; } }; BindingFactory stringFactory = new BindingFactory() { // This will match embedded single quotes as-is, no escaping necessary. private final Pattern pattern = Pattern.compile("^\\s*'(.*)'\\s*$"); public Binding newBinding(String description, ComponentResources container, ComponentResources component, String expression, Location location) { Matcher matcher = pattern.matcher(expression); if (matcher.matches()) { String value = matcher.group(1); return new LiteralBinding(description, value, location); } return null; } }; // To be honest, order probably doesn't matter. configuration.add("Keyword", keywordFactory); configuration.add("This", thisFactory); configuration.add("Long", longFactory); configuration.add("IntRange", intRangeFactory); configuration.add("Double", doubleFactory); configuration.add("StringLiteral", stringFactory); } /** * Contributes filters: <dl> <dt>Ajax</dt> <dd>Determines if the request is Ajax oriented, and redirects to an * alternative handler if so</dd> <dt>ImmediateRender</dt> <dd>When {@linkplain * org.apache.tapestry5.SymbolConstants#SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS immediate action response rendering} * is enabled, generates the markup response (instead of a page redirect response, which is the normal behavior) * </dd> <dt>Secure</dt> <dd>Sends a redirect if an non-secure request accesses a secure page</dd></dl> */ public void contributeComponentEventRequestHandler(OrderedConfiguration<ComponentEventRequestFilter> configuration, final RequestSecurityManager requestSecurityManager, @Ajax ComponentEventRequestHandler ajaxHandler, ObjectLocator locator) { ComponentEventRequestFilter secureFilter = new ComponentEventRequestFilter() { public void handle(ComponentEventRequestParameters parameters, ComponentEventRequestHandler handler) throws IOException { if (requestSecurityManager.checkForInsecureRequest(parameters.getActivePageName())) return; handler.handle(parameters); } }; configuration.add("Ajax", new AjaxFilter(request, ajaxHandler)); configuration.add("ImmediateRender", locator.autobuild(ImmediateActionRenderResponseFilter.class)); configuration.add("Secure", secureFilter, "before:Ajax"); } /** * Contributes strategies accessible via the {@link NullFieldStrategySource} service. * <p/> * <dl> <dt>default</dt> <dd>Does nothing, nulls stay null.</dd> <dt>zero</dt> <dd>Null values are converted to * zero.</dd> </dl> */ public static void contributeNullFieldStrategySource(MappedConfiguration<String, NullFieldStrategy> configuration) { configuration.add("default", new DefaultNullFieldStrategy()); configuration.add("zero", new ZeroNullFieldStrategy()); } /** * Determines positioning of hidden fields relative to other elements (this is needed by {@link * org.apache.tapestry5.corelib.components.FormFragment} and others. * <p/> * For elements input, select, textarea and label the hidden field is positioned after. * <p/> * For elements p, div, li and td, the hidden field is positioned inside. */ public static void contributeHiddenFieldLocationRules( MappedConfiguration<String, RelativeElementPosition> configuration) { configuration.add("input", RelativeElementPosition.AFTER); configuration.add("select", RelativeElementPosition.AFTER); configuration.add("textarea", RelativeElementPosition.AFTER); configuration.add("label", RelativeElementPosition.AFTER); configuration.add("p", RelativeElementPosition.INSIDE); configuration.add("div", RelativeElementPosition.INSIDE); configuration.add("td", RelativeElementPosition.INSIDE); configuration.add("li", RelativeElementPosition.INSIDE); } }

The table below shows all metrics for TapestryModule.java.

MetricValueDescription
BLOCKS130.00Number of blocks
BLOCK_COMMENT 0.00Number of block comment lines
COMMENTS407.00Comment lines
COMMENT_DENSITY 0.44Comment density
COMPARISONS 8.00Number of comparison operators
CYCLOMATIC131.00Cyclomatic complexity
DECL_COMMENTS71.00Comments in declarations
DOC_COMMENT310.00Number of javadoc comment lines
ELOC916.00Effective lines of code
EXEC_COMMENTS33.00Comments in executable code
EXITS232.00Procedure exits
FUNCTIONS123.00Number of function declarations
HALSTEAD_DIFFICULTY43.31Halstead difficulty
HALSTEAD_EFFORT 0.00Halstead effort
INTERFACE_COMPLEXITY417.00Interface complexity
JAVA0001 1.00JAVA0001 Package name does not contain only lower case letters
JAVA0002 0.00JAVA0002 Package name does not begin with a top level domain name or country code
JAVA0003 0.00JAVA0003 Minimize use of on-demand (.*) imports
JAVA0004 0.00JAVA0004 Unnecessary import from java.lang
JAVA0005 1.00JAVA0005 Imports not in specified order
JAVA0006 0.00JAVA0006 Empty finally block
JAVA0007 0.00JAVA0007 Should not declare public field
JAVA0008 0.00JAVA0008 Empty catch block
JAVA0009 0.00JAVA0009 Protected member in final class
JAVA0010 0.00JAVA0010 Non-instantiable class does not contain a non-private static member
JAVA0011 0.00JAVA0011 Abstract class does not contain an abstract method
JAVA0012 0.00JAVA0012 Non-constructor method with same name as declaring class
JAVA0013 0.00JAVA0013 Non-blank final field is not static
JAVA0014 0.00JAVA0014 Class with only static members has non-private constructor
JAVA0015 0.00JAVA0015 Package class contains public nested type
JAVA0016 0.00JAVA0016 Abstract class contains public constructor
JAVA0017 0.00JAVA0017 Class name does not have required form
JAVA0018 0.00JAVA0018 Method name does not have required form
JAVA0019 0.00JAVA0019 Interface name does not have required form
JAVA0020 0.00JAVA0020 Field name does not have required form
JAVA0021 0.00JAVA0021 Interface method name does not have required form
JAVA0022 0.00JAVA0022 Static final field name does not have required form
JAVA0023 0.00JAVA0023 Empty finalize method
JAVA0024 0.00JAVA0024 Empty class
JAVA0025 0.00JAVA0025 Method override is empty
JAVA0026 0.00JAVA0026 Finalize method with parameters
JAVA0029 0.00JAVA0029 Private method not used
JAVA0030 0.00JAVA0030 Private field not used
JAVA0031 0.00JAVA0031 Case statement not properly closed
JAVA0032 0.00JAVA0032 Switch statement missing default
JAVA0033 0.00JAVA0033 default: not last case in switch statement
JAVA0034 4.00JAVA0034 Missing braces in if statement
JAVA0035 0.00JAVA0035 Missing braces in for statement
JAVA0036 0.00JAVA0036 Missing braces in while statement
JAVA0038 0.00JAVA0038 Non-case label in switch statement
JAVA0039 0.00JAVA0039 Break statement with label
JAVA0040 0.00JAVA0040 Switch statement contains N cases (maximum: M)
JAVA0041 0.00JAVA0041 Nested synchronized block
JAVA0042 0.00JAVA0042 Empty synchronized statement
JAVA0043 0.00JAVA0043 Inner class does not use outer class
JAVA0044 0.00JAVA0044 Serializable class with no instance variables
JAVA0045 0.00JAVA0045 Serializable class with only transient fields
JAVA0046 0.00JAVA0046 Name of class not derived from Exception ends with 'Exception'
JAVA0047 0.00JAVA0047 Serializable class derives from invalid base class
JAVA0048 0.00JAVA0048 Name of class derived from Exception does not end with 'Exception'
JAVA0049 0.00JAVA0049 Nested block at depth N (maximum: M)
JAVA0050 0.00JAVA0050 Class derives from java.lang.Error
JAVA0051 0.00JAVA0051 Class derives from java.lang.RuntimeException
JAVA0052 0.00JAVA0052 Class derives from java.lang.Throwable
JAVA0053 0.00JAVA0053 Unused label
JAVA0054 0.00JAVA0054 Inheritance depth N exceeds maximum M
JAVA0055 0.00JAVA0055 Class should be interface
JAVA0056 0.00JAVA0056 Unnecessary abstract modifier for interface or annotation
JAVA0057 0.00JAVA0057 Unnecessary default constructor
JAVA0058 0.00JAVA0058 Constructor calls super()
JAVA0059 0.00JAVA0059 Method override only calls super()
JAVA0061 0.00JAVA0061 Inaccessible member in anonymous class
JAVA0062 0.00JAVA0062 Public class missing public member or protected constructor
JAVA0063 0.00JAVA0063 Identifier name should not contain '$'
JAVA0064 0.00JAVA0064 N variations of identifier name (maximum: M)
JAVA0065 0.00JAVA0065 Unnecessary final modifier for method in final class
JAVA0066 0.00JAVA0066 Unnecessary modifier for interface nested type
JAVA0067 0.00JAVA0067 Array descriptor on identifier name
JAVA0068 0.00JAVA0068 Modifiers not declared in recommended order
JAVA0071 0.00JAVA0071 Strings compared with ==
JAVA0073 0.00JAVA0073 Integer division in floating-point context
JAVA0074 0.00JAVA0074 Use of Object.notify()
JAVA0075 7.00JAVA0075 Method parameter hides field
JAVA0076 0.00JAVA0076 Use of magic number
JAVA0077 0.00JAVA0077 Private field not used in declaring class
JAVA0078 0.00JAVA0078 Floating point values compared with ==
JAVA0079 0.00JAVA0079 Use of instance to reference static member
JAVA0080 0.00JAVA0080 Import declaration not used
JAVA0081 0.00JAVA0081 Boolean literal in comparison
JAVA0082 0.00JAVA0082 Unnecessary widening cast
JAVA0083 0.00JAVA0083 Unnecessary instanceof test
JAVA0084 0.00JAVA0084 Should use compound assignment operator
JAVA0085 0.00JAVA0085 Use of sun.* class
JAVA0087 0.00JAVA0087 Use of Thread.sleep()
JAVA0089 0.00JAVA0089 Use of restricted package
JAVA0092 0.00JAVA0092 Use of restricted type
JAVA0093 0.00JAVA0093 Redundant assignment
JAVA0094 0.00JAVA0094 Field hides a superclass field
JAVA0095 0.00JAVA0095 Uninitialized private field
JAVA0096 0.00JAVA0096 Field in nested class hides outer field
JAVA0098 0.00JAVA0098 Minimize use of implicit field initializers
JAVA0100 0.00JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0101 0.00JAVA0101 Unnecessary modifier for field in interface
JAVA0102 0.00JAVA0102 Last statement in finalize() not super.finalize()
JAVA0103 0.00JAVA0103 Explicit call to finalize()
JAVA0104 0.00JAVA0104 finalize() only calls super.finalize()
JAVA0105 0.00JAVA0105 Duplicate import declaration
JAVA0106 0.00JAVA0106 Unnecessary import from current package
JAVA0108107.00JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
JAVA0109 0.00JAVA0109 Incorrect javadoc: no parameter 'parameter'
JAVA011018.00JAVA0110 Incorrect javadoc: no @return tag
JAVA0111 0.00JAVA0111 Incorrect javadoc: @return tag for void method
JAVA0112 0.00JAVA0112 Incorrect javadoc: no exception 'exception' in throws
JAVA0113 1.00JAVA0113 Incorrect javadoc: no @author tag
JAVA0114 1.00JAVA0114 Incorrect javadoc: no @version tag
JAVA0115 0.00JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0116 0.00JAVA0116 Missing javadoc: field 'field'
JAVA011725.00JAVA0117 Missing javadoc: method 'method'
JAVA0118 0.00JAVA0118 Missing javadoc: type 'type'
JAVA0119 0.00JAVA0119 Control variable changed within body of for loop
JAVA0123 0.00JAVA0123 Use all three components of for loop
JAVA0125 0.00JAVA0125 Continue statement with label
JAVA0126 0.00JAVA0126 Method declares unchecked exception in throws
JAVA0128 0.00JAVA0128 Public constructor in non-public class
JAVA0130 0.00JAVA0130 Non-static method does not use instance fields
JAVA0131 0.00JAVA0131 Compatible method does not override base
JAVA0132 0.00JAVA0132 Method overload with compatible signature
JAVA0133 0.00JAVA0133 Non-synchronized method overrides synchronized method
JAVA0135 0.00JAVA0135 Only one of Object.equals and Object.hashCode defined: missing 'method'
JAVA0136 1.00JAVA0136 N methods defined in class (maximum: M)
JAVA0137 0.00JAVA0137 Non-abstract class missing constructor
JAVA0138 3.00JAVA0138 N parameters defined for method (maximum: M)
JAVA0139 0.00JAVA0139 Definition of main other than public static void main(java.lang.String[])
JAVA0141 0.00JAVA0141 Unnecessary modifier for method in interface
JAVA0143 0.00JAVA0143 Synchronized method
JAVA0144 5.00JAVA0144 Line exceeds maximum M characters
JAVA0145 0.00JAVA0145 Tab character used in source file
JAVA0150 0.00JAVA0150 java.lang.Error (or subclass) thrown
JAVA0153 0.00JAVA0153 Inefficient conversion of integer to string
JAVA0159 0.00JAVA0159 Inefficient conversion of string to integer
JAVA0160 0.00JAVA0160 Method does not throw specified exception
JAVA0161 0.00JAVA0161 Conditional wait() not in loop
JAVA0163 0.00JAVA0163 Empty statement
JAVA0165 0.00JAVA0165 Conflicting return statement in finally block
JAVA0166 0.00JAVA0166 Generic exception caught
JAVA0167 0.00JAVA0167 ThreadDeath not rethrown
JAVA0169 0.00JAVA0169 Unnecessary catch block: exception 'exception'
JAVA0170 0.00JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0171 0.00JAVA0171 Unused local variable
JAVA0173 0.00JAVA0173 Unused method parameter
JAVA0174 0.00JAVA0174 Assigned local variable never used
JAVA0175 0.00JAVA0175 Successive assignment to variable
JAVA0176 0.00JAVA0176 Local variable name does not have required form
JAVA0177 0.00JAVA0177 Variable declaration missing initializer
JAVA0179 2.00JAVA0179 Local variable hides visible field
JAVA0233 0.00JAVA0233 Definition of serialVersionUID other than 'private static final long serialVersionUID'
JAVA0234 0.00JAVA0234 Class is Serializable but does not define serialVersionUID
JAVA0235 0.00JAVA0235 Class defines serialVersionUID but does not implement Serializable
JAVA0236 0.00JAVA0236 Attempt to clone an object which does not implement Cloneable
JAVA0237 0.00JAVA0237 Class implements Cloneable but does not have public clone method
JAVA0238 0.00JAVA0238 Clone method does not call super.clone()
JAVA0239 0.00JAVA0239 Class declares 'readObject' or 'writeObject' but does not implement Serializable
JAVA0240 0.00JAVA0240 Serializable class which declares readObject or writeObject but not both
JAVA0241 0.00JAVA0241 'readObject' or 'writeObject' should be declared private in Serializable class
JAVA0242 0.00JAVA0242 Transient field in non-Serializable class
JAVA0243 0.00JAVA0243 'readResolve' or 'writeReplace' should be declared private or protected
JAVA0244 0.00JAVA0244 Field or method name in subclass differs only by case from inherited field or method
JAVA0245 0.00JAVA0245 JUnit TestCase with non-trivial constructor
JAVA0246 0.00JAVA0246 JUnit assertXXX statement missing message parameter
JAVA0247 0.00JAVA0247 JUnit 'setUp()' and 'tearDown()' should call super method
JAVA0248 0.00JAVA0248 JUnit method 'setUp' or 'tearDown' with incorrect signature
JAVA0249 0.00JAVA0249 JUnit TestCase 'suite()' should be declared static
JAVA0250 0.00JAVA0250 JUnit TestCase declares testXXX method with incorrect signature
JAVA0251 0.00JAVA0251 Use '%n' for line breaks in printf/format for platform independence
JAVA0252 0.00JAVA0252 'enum' is a Java 1.5 reserved word
JAVA0253 0.00JAVA0253 Not all enum constants consumed in switch statement
JAVA0254 0.00JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0255 0.00JAVA0255 Result of method invocation not used
JAVA0256 0.00JAVA0256 Assignment of external collection/array to field
JAVA0257 0.00JAVA0257 Use of 'Constant Interface' anti-pattern
JAVA0258 0.00JAVA0258 Implement Iterable for foreach compatibility
JAVA0259 0.00JAVA0259 Return of collection/array field
JAVA0260 0.00JAVA0260 Use 'enum' instead of Enumerated Type pattern
JAVA0261 0.00JAVA0261 Use specialized Enum collection types
JAVA0262 0.00JAVA0262 Use of char in integer context
JAVA0263 0.00JAVA0263 Long literal ends with 'l' instead of 'L'
JAVA0264 0.00JAVA0264 Integer math in long context - check for overflow
JAVA0265 0.00JAVA0265 Use of Throwable.printStackTrace()
JAVA0266 0.00JAVA0266 Use of System.out
JAVA0267 0.00JAVA0267 Use of System.err
JAVA0269 0.00JAVA0269 Contents of StringBuffer never used
JAVA0270 0.00JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0271 0.00JAVA0271 Minimize use of on-demand (.*) static imports
JAVA0272 0.00JAVA0272 Thread.run() called
JAVA0273 0.00JAVA0273 Non-final derivative of Thread calls start() in constructor
JAVA0274 0.00JAVA0274 Serializable class has a synchronized readObject()
JAVA0275 0.00JAVA0275 Serializable class has a synchronized writeObject() and no other synchronized methods
JAVA0276 0.00JAVA0276 Unnecessary use of String constructor
JAVA0277 0.00JAVA0277 Iterator.next() implementation does not throw NoSuchElementException
JAVA0278 0.00JAVA0278 Unnecessary use of Boolean constructor
JAVA0279 0.00JAVA0279 Serialization method readObject or readObjectNoData calls an overridable method
JAVA0280 0.00JAVA0280 IllegalMonitorStateException caught
JAVA0281 0.00JAVA0281 Iterator.next() not called in loop
JAVA0282 0.00JAVA0282 Call to Iterator.next() in loop which does not test Iterator.hasNext()
JAVA0283 0.00JAVA0283 Control variable not updated in loop body
JAVA0284 0.00JAVA0284 Explicit garbage collection
JAVA0285 0.00JAVA0285 Dereference of potentially null variable
JAVA0286 0.00JAVA0286 Dereference of null variable
JAVA0287 0.00JAVA0287 Unnecessary null check
JAVA0288 0.00JAVA0288 Inconsistent null check
LINES2068.00Number of lines in the source file
LINE_COMMENT97.00Number of line comments
LOC1219.00Lines of code
LOGICAL_LINES550.00Number of statements
LOOPS 0.00Number of loops
NEST_DEPTH 3.00Maximum nesting depth
OPERANDS3305.00Number of operands
OPERATORS5259.00Number of operators
PARAMS274.00Number of formal parameter declarations
PROGRAM_LENGTH8564.00Halstead program length
PROGRAM_VOCAB1488.00Halstead program vocabulary
PROGRAM_VOLUME 0.00Halstead program volume
RETURNS143.00Number of return points from functions
SIZE94942.00Size of the file in bytes
UNIQUE_OPERANDS1450.00Number of unique operands
UNIQUE_OPERATORS38.00Number of unique operators
WHITESPACE442.00Number of whitespace lines