    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.modules;
    014
    015import java.io.IOException;
    016import java.io.InputStream;
    017import java.lang.annotation.Annotation;
    018import java.math.BigDecimal;
    019import java.math.BigInteger;
    020import java.net.URL;
    021import java.text.DateFormat;
    022import java.text.SimpleDateFormat;
    023import java.util.Calendar;
    024import java.util.Collection;
    025import java.util.Date;
    026import java.util.List;
    027import java.util.Locale;
    028import java.util.Map;
    029import java.util.Properties;
    030import java.util.Set;
    031import java.util.regex.Pattern;
    032
    033import org.apache.tapestry5.Asset;
    034import org.apache.tapestry5.BindingConstants;
    035import org.apache.tapestry5.Block;
    036import org.apache.tapestry5.ComponentParameterConstants;
    037import org.apache.tapestry5.ComponentResources;
    038import org.apache.tapestry5.EventContext;
    039import org.apache.tapestry5.Field;
    040import org.apache.tapestry5.FieldValidationSupport;
    041import org.apache.tapestry5.FieldValidator;
    042import org.apache.tapestry5.MarkupWriter;
    043import org.apache.tapestry5.MetaDataConstants;
    044import org.apache.tapestry5.NullFieldStrategy;
    045import org.apache.tapestry5.PersistenceConstants;
    046import org.apache.tapestry5.PropertyOverrides;
    047import org.apache.tapestry5.Renderable;
    048import org.apache.tapestry5.SelectModel;
    049import org.apache.tapestry5.StreamResponse;
    050import org.apache.tapestry5.SymbolConstants;
    051import org.apache.tapestry5.Translator;
    052import org.apache.tapestry5.ValidationDecorator;
    053import org.apache.tapestry5.Validator;
    054import org.apache.tapestry5.ValueEncoder;
    055import org.apache.tapestry5.ajax.MultiZoneUpdate;
    056import org.apache.tapestry5.alerts.AlertManager;
    057import org.apache.tapestry5.annotations.ActivationRequestParameter;
    058import org.apache.tapestry5.annotations.BindParameter;
    059import org.apache.tapestry5.annotations.ContentType;
    060import org.apache.tapestry5.annotations.DiscardAfter;
    061import org.apache.tapestry5.annotations.HeartbeatDeferred;
    062import org.apache.tapestry5.annotations.Import;
    063import org.apache.tapestry5.annotations.Meta;
    064import org.apache.tapestry5.annotations.MixinAfter;
    065import org.apache.tapestry5.annotations.PageActivationContext;
    066import org.apache.tapestry5.annotations.PageAttached;
    067import org.apache.tapestry5.annotations.PageDetached;
    068import org.apache.tapestry5.annotations.PageLoaded;
    069import org.apache.tapestry5.annotations.PageReset;
    070import org.apache.tapestry5.annotations.Path;
    071import org.apache.tapestry5.annotations.Persist;
    072import org.apache.tapestry5.annotations.Secure;
    073import org.apache.tapestry5.annotations.Service;
    074import org.apache.tapestry5.annotations.SessionAttribute;
    075import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
    076import org.apache.tapestry5.annotations.WhitelistAccessOnly;
    077import org.apache.tapestry5.beaneditor.DataTypeConstants;
    078import org.apache.tapestry5.beaneditor.Validate;
    079import org.apache.tapestry5.beanmodel.internal.services.BeanModelSourceImpl;
    080import org.apache.tapestry5.beanmodel.internal.services.PropertyConduitSourceImpl;
    081import org.apache.tapestry5.beanmodel.services.BeanModelSource;
    082import org.apache.tapestry5.beanmodel.services.PropertyConduitSource;
    083import org.apache.tapestry5.commons.AnnotationProvider;
    084import org.apache.tapestry5.commons.Configuration;
    085import org.apache.tapestry5.commons.Location;
    086import org.apache.tapestry5.commons.MappedConfiguration;
    087import org.apache.tapestry5.commons.Messages;
    088import org.apache.tapestry5.commons.ObjectLocator;
    089import org.apache.tapestry5.commons.ObjectProvider;
    090import org.apache.tapestry5.commons.OrderedConfiguration;
    091import org.apache.tapestry5.commons.Resource;
    092import org.apache.tapestry5.commons.internal.BasicDataTypeAnalyzers;
    093import org.apache.tapestry5.commons.internal.services.AnnotationDataTypeAnalyzer;
    094import org.apache.tapestry5.commons.internal.services.DefaultDataTypeAnalyzer;
    095import org.apache.tapestry5.commons.internal.services.StringInterner;
    096import org.apache.tapestry5.commons.internal.services.StringInternerImpl;
    097import org.apache.tapestry5.commons.services.Coercion;
    098import org.apache.tapestry5.commons.services.CoercionTuple;
    099import org.apache.tapestry5.commons.services.DataTypeAnalyzer;
    100import org.apache.tapestry5.commons.services.InvalidationEventHub;
    101import org.apache.tapestry5.commons.services.PlasticProxyFactory;
    102import org.apache.tapestry5.commons.services.PropertyAccess;
    103import org.apache.tapestry5.commons.services.TypeCoercer;
    104import org.apache.tapestry5.commons.util.AvailableValues;
    105import org.apache.tapestry5.commons.util.CollectionFactory;
    106import org.apache.tapestry5.commons.util.StrategyRegistry;
    107import org.apache.tapestry5.corelib.data.SecureOption;
    108import org.apache.tapestry5.grid.GridConstants;
    109import org.apache.tapestry5.grid.GridDataSource;
    110import org.apache.tapestry5.http.Link;
    111import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
    112import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants;
    113import org.apache.tapestry5.http.internal.TapestryHttpInternalSymbols;
    114import org.apache.tapestry5.http.modules.TapestryHttpModule;
    115import org.apache.tapestry5.http.services.ApplicationGlobals;
    116import org.apache.tapestry5.http.services.ApplicationInitializer;
    117import org.apache.tapestry5.http.services.ApplicationInitializerFilter;
    118import org.apache.tapestry5.http.services.Context;
    119import org.apache.tapestry5.http.services.Dispatcher;
    120import org.apache.tapestry5.http.services.HttpServletRequestFilter;
    121import org.apache.tapestry5.http.services.Request;
    122import org.apache.tapestry5.http.services.RequestFilter;
    123import org.apache.tapestry5.http.services.RequestGlobals;
    124import org.apache.tapestry5.http.services.RequestHandler;
    125import org.apache.tapestry5.http.services.Response;
    126import org.apache.tapestry5.http.services.Session;
    127import org.apache.tapestry5.internal.ComponentOverrideImpl;
    128import org.apache.tapestry5.internal.DefaultNullFieldStrategy;
    129import org.apache.tapestry5.internal.DefaultValueLabelProvider;
    130import org.apache.tapestry5.internal.InternalConstants;
    131import org.apache.tapestry5.internal.InternalSymbols;
    132import org.apache.tapestry5.internal.PropertyOverridesImpl;
    133import org.apache.tapestry5.internal.TapestryInternalUtils;
    134import org.apache.tapestry5.internal.ZeroNullFieldStrategy;
    135import org.apache.tapestry5.internal.alerts.AlertManagerImpl;
    136import org.apache.tapestry5.internal.beaneditor.EnvironmentMessages;
    137import org.apache.tapestry5.internal.beaneditor.MessagesConstraintGenerator;
    138import org.apache.tapestry5.internal.beaneditor.PrimitiveFieldConstraintGenerator;
    139import org.apache.tapestry5.internal.beaneditor.ValidateAnnotationConstraintGenerator;
    140import org.apache.tapestry5.internal.bindings.AssetBindingFactory;
    141import org.apache.tapestry5.internal.bindings.BlockBindingFactory;
    142import org.apache.tapestry5.internal.bindings.ComponentBindingFactory;
    143import org.apache.tapestry5.internal.bindings.ContextBindingFactory;
    144import org.apache.tapestry5.internal.bindings.LiteralBindingFactory;
    145import org.apache.tapestry5.internal.bindings.MessageBindingFactory;
    146import org.apache.tapestry5.internal.bindings.NullFieldStrategyBindingFactory;
    147import org.apache.tapestry5.internal.bindings.PropBindingFactory;
    148import org.apache.tapestry5.internal.bindings.RenderVariableBindingFactory;
    149import org.apache.tapestry5.internal.bindings.SymbolBindingFactory;
    150import org.apache.tapestry5.internal.bindings.TranslateBindingFactory;
    151import org.apache.tapestry5.internal.bindings.ValidateBindingFactory;
    152import org.apache.tapestry5.internal.dynamic.DynamicTemplateParserImpl;
    153import org.apache.tapestry5.internal.grid.CollectionGridDataSource;
    154import org.apache.tapestry5.internal.grid.NullDataSource;
    155import org.apache.tapestry5.internal.renderers.AvailableValuesRenderer;
    156import org.apache.tapestry5.internal.renderers.ComponentResourcesRenderer;
    157import org.apache.tapestry5.internal.renderers.EventContextRenderer;
    158import org.apache.tapestry5.internal.renderers.ListRenderer;
    159import org.apache.tapestry5.internal.renderers.LocationRenderer;
    160import org.apache.tapestry5.internal.renderers.ObjectArrayRenderer;
    161import org.apache.tapestry5.internal.renderers.RequestRenderer;
    162import org.apache.tapestry5.internal.services.*;
    163import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateFilter;
    164import org.apache.tapestry5.internal.services.ajax.AjaxResponseRendererImpl;
    165import org.apache.tapestry5.internal.services.ajax.MultiZoneUpdateEventResultProcessor;
    166import org.apache.tapestry5.internal.services.exceptions.ExceptionReportWriterImpl;
    167import org.apache.tapestry5.internal.services.exceptions.ExceptionReporterImpl;
    168import org.apache.tapestry5.internal.services.linktransform.LinkTransformerImpl;
    169import org.apache.tapestry5.internal.services.linktransform.LinkTransformerInterceptor;
    170import org.apache.tapestry5.internal.services.messages.PropertiesFileParserImpl;
    171import org.apache.tapestry5.internal.services.meta.ContentTypeExtractor;
    172import org.apache.tapestry5.internal.services.meta.MetaAnnotationExtractor;
    173import org.apache.tapestry5.internal.services.meta.MetaWorkerImpl;
    174import org.apache.tapestry5.internal.services.meta.UnknownActivationContextExtractor;
    175import org.apache.tapestry5.internal.services.rest.DefaultOpenApiDescriptionGenerator;
    176import org.apache.tapestry5.internal.services.rest.DefaultOpenApiTypeDescriber;
    177import org.apache.tapestry5.internal.services.rest.MappedEntityManagerImpl;
    178import org.apache.tapestry5.internal.services.security.ClientWhitelistImpl;
    179import org.apache.tapestry5.internal.services.security.LocalhostOnly;
    180import org.apache.tapestry5.internal.services.templates.DefaultTemplateLocator;
    181import org.apache.tapestry5.internal.services.templates.PageTemplateLocator;
    182import org.apache.tapestry5.internal.transform.ActivationRequestParameterWorker;
    183import org.apache.tapestry5.internal.transform.ApplicationStateWorker;
    184import org.apache.tapestry5.internal.transform.BindParameterWorker;
    185import org.apache.tapestry5.internal.transform.CachedWorker;
    186import org.apache.tapestry5.internal.transform.ComponentWorker;
    187import org.apache.tapestry5.internal.transform.DiscardAfterWorker;
    188import org.apache.tapestry5.internal.transform.EnvironmentalWorker;
    189import org.apache.tapestry5.internal.transform.HeartbeatDeferredWorker;
    190import org.apache.tapestry5.internal.transform.ImportWorker;
    191import org.apache.tapestry5.internal.transform.InjectComponentWorker;
    192import org.apache.tapestry5.internal.transform.InjectContainerWorker;
    193import org.apache.tapestry5.internal.transform.InjectNamedProvider;
    194import org.apache.tapestry5.internal.transform.InjectPageWorker;
    195import org.apache.tapestry5.internal.transform.InjectServiceWorker;
    196import org.apache.tapestry5.internal.transform.InjectWorker;
    197import org.apache.tapestry5.internal.transform.LogWorker;
    198import org.apache.tapestry5.internal.transform.MixinAfterWorker;
    199import org.apache.tapestry5.internal.transform.MixinWorker;
    200import org.apache.tapestry5.internal.transform.OnEventWorker;
    201import org.apache.tapestry5.internal.transform.OperationWorker;
    202import org.apache.tapestry5.internal.transform.PageActivationContextWorker;
    203import org.apache.tapestry5.internal.transform.PageLifecycleAnnotationWorker;
    204import org.apache.tapestry5.internal.transform.PageResetAnnotationWorker;
    205import org.apache.tapestry5.internal.transform.ParameterWorker;
    206import org.apache.tapestry5.internal.transform.PersistWorker;
    207import org.apache.tapestry5.internal.transform.PropertyWorker;
    208import org.apache.tapestry5.internal.transform.RenderCommandWorker;
    209import org.apache.tapestry5.internal.transform.RenderPhaseMethodWorker;
    210import org.apache.tapestry5.internal.transform.RetainWorker;
    211import org.apache.tapestry5.internal.transform.SessionAttributeWorker;
    212import org.apache.tapestry5.internal.transform.SupportsInformalParametersWorker;
    213import org.apache.tapestry5.internal.transform.UnclaimedFieldWorker;
    214import org.apache.tapestry5.internal.translator.NumericTranslator;
    215import org.apache.tapestry5.internal.translator.NumericTranslatorSupport;
    216import org.apache.tapestry5.internal.translator.StringTranslator;
    217import org.apache.tapestry5.internal.util.RenderableAsBlock;
    218import org.apache.tapestry5.internal.util.StringRenderable;
    219import org.apache.tapestry5.internal.validator.ValidatorMacroImpl;
    220import org.apache.tapestry5.ioc.MethodAdviceReceiver;
    221import org.apache.tapestry5.ioc.OperationTracker;
    222import org.apache.tapestry5.ioc.ScopeConstants;
    223import org.apache.tapestry5.ioc.ServiceBinder;
    224import org.apache.tapestry5.ioc.annotations.Advise;
    225import org.apache.tapestry5.ioc.annotations.Autobuild;
    226import org.apache.tapestry5.ioc.annotations.ComponentClasses;
    227import org.apache.tapestry5.ioc.annotations.ComponentLayer;
    228import org.apache.tapestry5.ioc.annotations.Contribute;
    229import org.apache.tapestry5.ioc.annotations.ImportModule;
    230import org.apache.tapestry5.ioc.annotations.Inject;
    231import org.apache.tapestry5.ioc.annotations.InjectService;
    232import org.apache.tapestry5.ioc.annotations.Local;
    233import org.apache.tapestry5.ioc.annotations.Marker;
    234import org.apache.tapestry5.ioc.annotations.Match;
    235import org.apache.tapestry5.ioc.annotations.Operation;
    236import org.apache.tapestry5.ioc.annotations.Primary;
    237import org.apache.tapestry5.ioc.annotations.Scope;
    238import org.apache.tapestry5.ioc.annotations.Startup;
    239import org.apache.tapestry5.ioc.annotations.Symbol;
    240import org.apache.tapestry5.ioc.services.Builtin;
    241import org.apache.tapestry5.ioc.services.ChainBuilder;
    242import org.apache.tapestry5.ioc.services.LazyAdvisor;
    243import org.apache.tapestry5.ioc.services.MasterObjectProvider;
    244import org.apache.tapestry5.ioc.services.PerThreadValue;
    245import org.apache.tapestry5.ioc.services.PerthreadManager;
    246import org.apache.tapestry5.ioc.services.PipelineBuilder;
    247import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
    248import org.apache.tapestry5.ioc.services.ServiceOverride;
    249import org.apache.tapestry5.ioc.services.StrategyBuilder;
    250import org.apache.tapestry5.ioc.services.SymbolSource;
    251import org.apache.tapestry5.ioc.services.ThreadLocale;
    252import org.apache.tapestry5.ioc.services.UpdateListener;
    253import org.apache.tapestry5.ioc.services.UpdateListenerHub;
    254import org.apache.tapestry5.json.JSONArray;
    255import org.apache.tapestry5.json.JSONObject;
    256import org.apache.tapestry5.json.modules.JSONModule;
    257import org.apache.tapestry5.plastic.MethodAdvice;
    258import org.apache.tapestry5.plastic.MethodDescription;
    259import org.apache.tapestry5.plastic.MethodInvocation;
    260import org.apache.tapestry5.runtime.Component;
    261import org.apache.tapestry5.runtime.ComponentResourcesAware;
    262import org.apache.tapestry5.runtime.RenderCommand;
    263import org.apache.tapestry5.runtime.RenderQueue;
    264import org.apache.tapestry5.services.Ajax;
    265import org.apache.tapestry5.services.ApplicationStateManager;
    266import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy;
    267import org.apache.tapestry5.services.ApplicationStatePersistenceStrategySource;
    268import org.apache.tapestry5.services.AssetFactory;
    269import org.apache.tapestry5.services.AssetSource;
    270import org.apache.tapestry5.services.BeanBlockContribution;
    271import org.apache.tapestry5.services.BeanBlockOverrideSource;
    272import org.apache.tapestry5.services.BeanBlockSource;
    273import org.apache.tapestry5.services.BindingFactory;
    274import org.apache.tapestry5.services.BindingSource;
    275import org.apache.tapestry5.services.ClientBehaviorSupport;
    276import org.apache.tapestry5.services.ClientDataEncoder;
    277import org.apache.tapestry5.services.ComponentClassResolver;
    278import org.apache.tapestry5.services.ComponentDefaultProvider;
    279import org.apache.tapestry5.services.ComponentEventLinkEncoder;
    280import org.apache.tapestry5.services.ComponentEventRequestFilter;
    281import org.apache.tapestry5.services.ComponentEventRequestHandler;
    282import org.apache.tapestry5.services.ComponentEventRequestParameters;
    283import org.apache.tapestry5.services.ComponentEventResultProcessor;
    284import org.apache.tapestry5.services.ComponentLibraryInfo;
    285import org.apache.tapestry5.services.ComponentLibraryInfoSource;
    286import org.apache.tapestry5.services.ComponentMessages;
    287import org.apache.tapestry5.services.ComponentOverride;
    288import org.apache.tapestry5.services.ComponentRequestFilter;
    289import org.apache.tapestry5.services.ComponentRequestHandler;
    290import org.apache.tapestry5.services.ComponentSource;
    291import org.apache.tapestry5.services.ComponentTemplates;
    292import org.apache.tapestry5.services.ContextPathEncoder;
    293import org.apache.tapestry5.services.ContextProvider;
    294import org.apache.tapestry5.services.ContextValueEncoder;
    295import org.apache.tapestry5.services.Cookies;
    296import org.apache.tapestry5.services.Core;
    297import org.apache.tapestry5.services.DateUtilities;
    298import org.apache.tapestry5.services.DefaultObjectRenderer;
    299import org.apache.tapestry5.services.DisplayBlockContribution;
    300import org.apache.tapestry5.services.EditBlockContribution;
    301import org.apache.tapestry5.services.Environment;
    302import org.apache.tapestry5.services.EnvironmentalShadowBuilder;
    303import org.apache.tapestry5.services.ExceptionReportWriter;
    304import org.apache.tapestry5.services.ExceptionReporter;
    305import org.apache.tapestry5.services.FieldTranslatorSource;
    306import org.apache.tapestry5.services.FieldValidatorDefaultSource;
    307import org.apache.tapestry5.services.FieldValidatorSource;
    308import org.apache.tapestry5.services.FormSupport;
    309import org.apache.tapestry5.services.Heartbeat;
    310import org.apache.tapestry5.services.HiddenFieldLocationRules;
    311import org.apache.tapestry5.services.Html5Support;
    312import org.apache.tapestry5.services.HttpError;
    313import org.apache.tapestry5.services.HttpStatus;
    314import org.apache.tapestry5.services.InitializeActivePageName;
    315import org.apache.tapestry5.services.LibraryMapping;
    316import org.apache.tapestry5.services.LinkCreationHub;
    317import org.apache.tapestry5.services.MarkupRenderer;
    318import org.apache.tapestry5.services.MarkupRendererFilter;
    319import org.apache.tapestry5.services.MarkupWriterFactory;
    320import org.apache.tapestry5.services.MetaDataLocator;
    321import org.apache.tapestry5.services.NullFieldStrategySource;
    322import org.apache.tapestry5.services.ObjectRenderer;
    323import org.apache.tapestry5.services.PageDocumentGenerator;
    324import org.apache.tapestry5.services.PageRenderLinkSource;
    325import org.apache.tapestry5.services.PageRenderRequestFilter;
    326import org.apache.tapestry5.services.PageRenderRequestHandler;
    327import org.apache.tapestry5.services.PageRenderRequestParameters;
    328import org.apache.tapestry5.services.PartialMarkupRenderer;
    329import org.apache.tapestry5.services.PartialMarkupRendererFilter;
    330import org.apache.tapestry5.services.PartialTemplateRenderer;
    331import org.apache.tapestry5.services.PathConstructor;
    332import org.apache.tapestry5.services.PersistentFieldStrategy;
    333import org.apache.tapestry5.services.PersistentLocale;
    334import org.apache.tapestry5.services.RelativeElementPosition;
    335import org.apache.tapestry5.services.RequestExceptionHandler;
    336import org.apache.tapestry5.services.ResourceDigestGenerator;
    337import org.apache.tapestry5.services.ResponseRenderer;
    338import org.apache.tapestry5.services.SelectModelFactory;
    339import org.apache.tapestry5.services.StackTraceElementAnalyzer;
    340import org.apache.tapestry5.services.StackTraceElementClassConstants;
    341import org.apache.tapestry5.services.StreamPageContent;
    342import org.apache.tapestry5.services.Traditional;
    343import org.apache.tapestry5.services.TransformConstants;
    344import org.apache.tapestry5.services.TranslatorAlternatesSource;
    345import org.apache.tapestry5.services.TranslatorSource;
    346import org.apache.tapestry5.services.URLEncoder;
    347import org.apache.tapestry5.services.ValidationConstraintGenerator;
    348import org.apache.tapestry5.services.ValidationDecoratorFactory;
    349import org.apache.tapestry5.services.ValueEncoderFactory;
    350import org.apache.tapestry5.services.ValueEncoderSource;
    351import org.apache.tapestry5.services.ValueLabelProvider;
    352import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
    353import org.apache.tapestry5.services.dynamic.DynamicTemplate;
    354import org.apache.tapestry5.services.dynamic.DynamicTemplateParser;
    355import org.apache.tapestry5.services.javascript.JavaScriptSupport;
    356import org.apache.tapestry5.services.javascript.ModuleManager;
    357import org.apache.tapestry5.services.linktransform.ComponentEventLinkTransformer;
    358import org.apache.tapestry5.services.linktransform.LinkTransformer;
    359import org.apache.tapestry5.services.linktransform.PageRenderLinkTransformer;
    360import org.apache.tapestry5.services.messages.ComponentMessagesSource;
    361import org.apache.tapestry5.services.messages.PropertiesFileParser;
    362import org.apache.tapestry5.services.meta.FixedExtractor;
    363import org.apache.tapestry5.services.meta.MetaDataExtractor;
    364import org.apache.tapestry5.services.meta.MetaWorker;
    365import org.apache.tapestry5.services.pageload.PreloaderMode;
    366import org.apache.tapestry5.services.rest.OpenApiDescriptionGenerator;
    367import org.apache.tapestry5.services.rest.OpenApiTypeDescriber;
    368import org.apache.tapestry5.services.rest.MappedEntityManager;
    369import org.apache.tapestry5.services.security.ClientWhitelist;
    370import org.apache.tapestry5.services.security.WhitelistAnalyzer;
    371import org.apache.tapestry5.services.templates.ComponentTemplateLocator;
    372import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
    373import org.apache.tapestry5.services.transform.InjectionProvider2;
    374import org.apache.tapestry5.validator.Checked;
    375import org.apache.tapestry5.validator.Email;
    376import org.apache.tapestry5.validator.Max;
    377import org.apache.tapestry5.validator.MaxLength;
    378import org.apache.tapestry5.validator.Min;
    379import org.apache.tapestry5.validator.MinLength;
    380import org.apache.tapestry5.validator.None;
    381import org.apache.tapestry5.validator.Regexp;
    382import org.apache.tapestry5.validator.Required;
    383import org.apache.tapestry5.validator.Unchecked;
    384import org.apache.tapestry5.validator.ValidatorMacro;
    385import org.slf4j.Logger;
    386
    387/**
    388 * The root module for Tapestry.
    389 */
    390@Marker(Core.class)
    391@ImportModule(
    392        {InternalModule.class, AssetsModule.class, PageLoadModule.class, JavaScriptModule.class, CompatibilityModule.class, DashboardModule.class, TapestryHttpModule.class, JSONModule.class})
    393public final class TapestryModule
    394{
    395    private final PipelineBuilder pipelineBuilder;
    396
    397    private final PropertyShadowBuilder shadowBuilder;
    398
    399    private final Environment environment;
    400
    401    private final StrategyBuilder strategyBuilder;
    402
    403    private final PropertyAccess propertyAccess;
    404
    405    private final ChainBuilder chainBuilder;
    406
    407    private final Request request;
    408
    409    private final Response response;
    410
    411    private final RequestGlobals requestGlobals;
    412
    413    private final EnvironmentalShadowBuilder environmentalBuilder;
    414
    415    private final EndOfRequestEventHub endOfRequestEventHub;
    416
    417    /**
    418     * We inject all sorts of common dependencies (including builders) into the
    419     * module itself (note: even though some of
    420     * these service are defined by the module itself, that's ok because
    421     * services are always lazy proxies). This isn't
    422     * about efficiency (it may be slightly more efficient, but not in any
    423     * noticeable way), it's about eliminating the
    424     * need to keep injecting these dependencies into individual service builder
    425     * and contribution methods.
    426     */
    427    public TapestryModule(PipelineBuilder pipelineBuilder,
    428
    429                          PropertyShadowBuilder shadowBuilder,
    430
    431                          RequestGlobals requestGlobals,
    432
    433                          ChainBuilder chainBuilder,
    434
    435                          Environment environment,
    436
    437                          StrategyBuilder strategyBuilder,
    438
    439                          PropertyAccess propertyAccess,
    440
    441                          Request request,
    442
    443                          Response response,
    444
    445                          EnvironmentalShadowBuilder environmentalBuilder,
    446
    447                          EndOfRequestEventHub endOfRequestEventHub)
    448    {
    449        this.pipelineBuilder = pipelineBuilder;
    450        this.shadowBuilder = shadowBuilder;
    451        this.requestGlobals = requestGlobals;
    452        this.chainBuilder = chainBuilder;
    453        this.environment = environment;
    454        this.strategyBuilder = strategyBuilder;
    455        this.propertyAccess = propertyAccess;
    456        this.request = request;
    457        this.response = response;
    458        this.environmentalBuilder = environmentalBuilder;
    459        this.endOfRequestEventHub = endOfRequestEventHub;
    460    }
    461
    462    public static void bind(ServiceBinder binder)
    463    {
    464        binder.bind(PersistentLocale.class, PersistentLocaleImpl.class);
    465        binder.bind(ApplicationStateManager.class, ApplicationStateManagerImpl.class);
    466        binder.bind(ApplicationStatePersistenceStrategySource.class,
    467                ApplicationStatePersistenceStrategySourceImpl.class);
    468        binder.bind(BindingSource.class, BindingSourceImpl.class);
    469        binder.bind(FieldValidatorSource.class, FieldValidatorSourceImpl.class);
    470        binder.bind(Cookies.class, CookiesImpl.class);
    471        binder.bind(FieldValidatorDefaultSource.class, FieldValidatorDefaultSourceImpl.class);
    472        binder.bind(ResourceDigestGenerator.class, ResourceDigestGeneratorImpl.class);  // Remove in 5.5
    473        binder.bind(ValidationConstraintGenerator.class, ValidationConstraintGeneratorImpl.class);
    474        binder.bind(EnvironmentalShadowBuilder.class, EnvironmentalShadowBuilderImpl.class);
    475        binder.bind(ComponentSource.class, ComponentSourceImpl.class);
    476        binder.bind(BeanModelSource.class, BeanModelSourceImpl.class);
    477        binder.bind(BeanBlockSource.class, BeanBlockSourceImpl.class);
    478        binder.bind(ComponentDefaultProvider.class, ComponentDefaultProviderImpl.class);
    479        binder.bind(MarkupWriterFactory.class, MarkupWriterFactoryImpl.class);
    480        binder.bind(FieldValidationSupport.class, FieldValidationSupportImpl.class);
    481        binder.bind(ObjectRenderer.class, LocationRenderer.class).withSimpleId();
    482        binder.bind(ObjectProvider.class, AssetObjectProvider.class).withSimpleId();
    483        binder.bind(RequestExceptionHandler.class, DefaultRequestExceptionHandler.class);
    484        binder.bind(ComponentEventResultProcessor.class, ComponentInstanceResultProcessor.class).withSimpleId();
    485        binder.bind(NullFieldStrategySource.class, NullFieldStrategySourceImpl.class);
    486        binder.bind(HttpServletRequestFilter.class, IgnoredPathsFilter.class).withSimpleId();
    487        binder.bind(ContextValueEncoder.class, ContextValueEncoderImpl.class);
    488        binder.bind(BeanBlockOverrideSource.class, BeanBlockOverrideSourceImpl.class);
    489        binder.bind(HiddenFieldLocationRules.class, HiddenFieldLocationRulesImpl.class);
    490        binder.bind(PageDocumentGenerator.class, PageDocumentGeneratorImpl.class);
    491        binder.bind(ResponseRenderer.class, ResponseRendererImpl.class);
    492        binder.bind(FieldTranslatorSource.class, FieldTranslatorSourceImpl.class);
    493        binder.bind(BindingFactory.class, MessageBindingFactory.class).withSimpleId();
    494        binder.bind(BindingFactory.class, ValidateBindingFactory.class).withSimpleId();
    495        binder.bind(BindingFactory.class, TranslateBindingFactory.class).withSimpleId();
    496        binder.bind(BindingFactory.class, AssetBindingFactory.class).withSimpleId();
    497        binder.bind(BindingFactory.class, ContextBindingFactory.class).withSimpleId();
    498        binder.bind(BindingFactory.class, NullFieldStrategyBindingFactory.class).withSimpleId();
    499        binder.bind(BindingFactory.class, SymbolBindingFactory.class).withSimpleId();
    500        binder.bind(URLEncoder.class, URLEncoderImpl.class);
    501        binder.bind(ContextPathEncoder.class, ContextPathEncoderImpl.class);
    502        binder.bind(ApplicationStatePersistenceStrategy.class, SessionApplicationStatePersistenceStrategy.class).withSimpleId();
    503        binder.bind(NumericTranslatorSupport.class);
    504        binder.bind(ClientDataEncoder.class, ClientDataEncoderImpl.class);
    505        binder.bind(ComponentEventLinkEncoder.class, ComponentEventLinkEncoderImpl.class);
    506        binder.bind(PageRenderLinkSource.class, PageRenderLinkSourceImpl.class);
    507        binder.bind(ValidatorMacro.class, ValidatorMacroImpl.class);
    508        binder.bind(PropertiesFileParser.class, PropertiesFileParserImpl.class);
    509        binder.bind(PageActivator.class, PageActivatorImpl.class);
    510        binder.bind(Dispatcher.class, AssetDispatcher.class).withSimpleId();
    511        binder.bind(TranslatorAlternatesSource.class, TranslatorAlternatesSourceImpl.class);
    512        binder.bind(MetaWorker.class, MetaWorkerImpl.class);
    513        binder.bind(LinkTransformer.class, LinkTransformerImpl.class);
    514        binder.bind(SelectModelFactory.class, SelectModelFactoryImpl.class);
    515        binder.bind(DynamicTemplateParser.class, DynamicTemplateParserImpl.class);
    516        binder.bind(AjaxResponseRenderer.class, AjaxResponseRendererImpl.class);
    517        binder.bind(AlertManager.class, AlertManagerImpl.class);
    518        binder.bind(ValidationDecoratorFactory.class, ValidationDecoratorFactoryImpl.class);
    519        binder.bind(PropertyConduitSource.class, PropertyConduitSourceImpl.class);
    520        binder.bind(ClientWhitelist.class, ClientWhitelistImpl.class);
    521        binder.bind(MetaDataLocator.class, MetaDataLocatorImpl.class);
    522        binder.bind(ComponentClassCache.class, ComponentClassCacheImpl.class);
    523        binder.bind(PageActivationContextCollector.class, PageActivationContextCollectorImpl.class);
    524        binder.bind(StringInterner.class, StringInternerImpl.class);
    525        binder.bind(ValueEncoderSource.class, ValueEncoderSourceImpl.class);
    526        binder.bind(PathConstructor.class, PathConstructorImpl.class);
    527        binder.bind(DateUtilities.class, DateUtilitiesImpl.class);
    528        binder.bind(PartialTemplateRenderer.class, PartialTemplateRendererImpl.class);
    529        binder.bind(ExceptionReporter.class, ExceptionReporterImpl.class);
    530        binder.bind(ExceptionReportWriter.class, ExceptionReportWriterImpl.class);
    531        binder.bind(ComponentOverride.class, ComponentOverrideImpl.class).eagerLoad();
    532        binder.bind(Html5Support.class, Html5SupportImpl.class);
    533        binder.bind(MappedEntityManager.class, MappedEntityManagerImpl.class);
    534    }
    535
    536    // ========================================================================
    537    //
    538    // Service Builder Methods (static)
    539    //
    540    // ========================================================================
    541
    542    // ========================================================================
    543    //
    544    // Service Contribution Methods (static)
    545    //
    546    // ========================================================================
    547
    548    /**
    549     * Contributes the factory for several built-in binding prefixes ("asset",
    550     * "block", "component", "literal", prop",
    551     * "nullfieldstrategy", "message", "validate", "translate", "var").
    552     */
    553    public static void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration,
    554
    555                                               @InjectService("PropBindingFactory")
    556                                               BindingFactory propBindingFactory,
    557
    558                                               @InjectService("MessageBindingFactory")
    559                                               BindingFactory messageBindingFactory,
    560
    561                                               @InjectService("ValidateBindingFactory")
    562                                               BindingFactory validateBindingFactory,
    563
    564                                               @InjectService("TranslateBindingFactory")
    565                                               BindingFactory translateBindingFactory,
    566
    567                                               @InjectService("AssetBindingFactory")
    568                                               BindingFactory assetBindingFactory,
    569
    570                                               @InjectService("NullFieldStrategyBindingFactory")
    571                                               BindingFactory nullFieldStrategyBindingFactory,
    572
    573                                               @InjectService("ContextBindingFactory")
    574                                               BindingFactory contextBindingFactory,
    575
    576                                               @InjectService("SymbolBindingFactory")
    577                                               BindingFactory symbolBindingFactory)
    578    {
    579        configuration.add(BindingConstants.LITERAL, new LiteralBindingFactory());
    580        configuration.add(BindingConstants.COMPONENT, new ComponentBindingFactory());
    581        configuration.add(BindingConstants.VAR, new RenderVariableBindingFactory());
    582        configuration.add(BindingConstants.BLOCK, new BlockBindingFactory());
    583
    584        configuration.add(BindingConstants.PROP, propBindingFactory);
    585        configuration.add(BindingConstants.MESSAGE, messageBindingFactory);
    586        configuration.add(BindingConstants.VALIDATE, validateBindingFactory);
    587        configuration.add(BindingConstants.TRANSLATE, translateBindingFactory);
    588        configuration.add(BindingConstants.ASSET, assetBindingFactory);
    589        configuration.add(BindingConstants.NULLFIELDSTRATEGY, nullFieldStrategyBindingFactory);
    590        configuration.add(BindingConstants.CONTEXT, contextBindingFactory);
    591        configuration.add(BindingConstants.SYMBOL, symbolBindingFactory);
    592    }
    593
    594
    595    @Contribute(ComponentClassResolver.class)
    596    public static void provideCoreAndAppLibraries(Configuration<LibraryMapping> configuration,
    597                                                  @Symbol(TapestryHttpInternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
    598                                                  String appRootPackage)
    599    {
    600        configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.corelib"));
    601        configuration.add(new LibraryMapping("", appRootPackage));
    602    }
    603
    604    /**
    605     * Adds a number of standard component class transform workers:
    606     * <dl>
    607     * <dt>Parameter</dt>
    608     * <dd>Identifies parameters based on the {@link org.apache.tapestry5.annotations.Parameter} annotation</dd>
    609     * <dt>BindParameter</dt>
    610     * <dd>Support for the {@link BindParameter} annotation</dd>
    611     * <dt>Property</dt>
    612     * <dd>Generates accessor methods if {@link org.apache.tapestry5.annotations.Property} annotation is present</dd>
    613     * <dt>Import</dt>
    614     * <dd>Supports the {@link Import} annotation</dd>
    615     * <dt>UnclaimedField</dt>
    616     * <dd>Manages unclaimed fields, storing their value in a {@link PerThreadValue}</dd>
    617     * <dt>OnEvent</dt>
    618     * <dd>Handle the @OnEvent annotation, and related naming convention</dd>
    619     * <dt>RenderCommand</dt>
    620     * <dd>Ensures all components also implement {@link org.apache.tapestry5.runtime.RenderCommand}</dd>
    621     * <dt>SupportsInformalParameters</dt>
    622     * <dd>Checks for the annotation</dd>
    623     * <dt>RenderPhase</dt>
    624     * <dd>Link in render phase methods</dd>
    625     * <dt>Retain</dt>
    626     * <dd>Allows fields to retain their values between requests</dd>
    627     * <dt>Meta</dt>
    628     * <dd>Checks for meta data annotations and adds it to the component model</dd>
    629     * <dt>PageActivationContext</dt> <dd>Support for {@link PageActivationContext} annotation</dd>
    630     * <dt>DiscardAfter</dt> <dd>Support for {@link DiscardAfter} method annotation </dd>
    631     * <dt>MixinAfter</dt> <dd>Support for the {@link MixinAfter} mixin class annotation</dd>
    632     * <dt>PageReset</dt>
    633     * <dd>Checks for the {@link PageReset} annotation</dd>
    634     * <dt>Mixin</dt>
    635     * <dd>Adds a mixin as part of a component's implementation</dd>
    636     * <dt>Cached</dt>
    637     * <dd>Checks for the {@link org.apache.tapestry5.annotations.Cached} annotation</dd>
    638     * <dt>ActivationRequestParameter</dt>
    639     * <dd>Support for the {@link ActivationRequestParameter} annotation</dd>
    640     * <dt>PageLoaded, PageAttached, PageDetached</dt>
    641     * <dd>Support for annotations {@link PageLoaded}, {@link PageAttached}, {@link PageDetached}</dd>
    642     * <dt>InjectService</dt>
    643     * <dd>Handles the {@link org.apache.tapestry5.ioc.annotations.InjectService} annotation</dd>
    644     * <dt>Component</dt>
    645     * <dd>Defines embedded components based on the {@link org.apache.tapestry5.annotations.Component} annotation</dd>
    646     * <dt>Environment</dt>
    647     * <dd>Allows fields to contain values extracted from the {@link org.apache.tapestry5.services.Environment} service</dd>
    648     * <dt>ApplicationState</dt>
    649     * <dd>Converts fields that reference application state objects</dd>
    650     * <dt>Persist</dt>
    651     * <dd>Allows fields to store their their value persistently between requests via {@link Persist}</dd>
    652     * <dt>SessionAttribute</dt>
    653     * <dd>Support for the {@link SessionAttribute}</dd>
    654     * <dt>Log</dt>
    655     * <dd>Checks for the {@link org.apache.tapestry5.annotations.Log} annotation</dd>
    656     * <dt>HeartbeatDeferred
    657     * <dd>Support for the {@link HeartbeatDeferred} annotation, which defers method invocation to the end of the {@link Heartbeat}
    658     * <dt>Inject</dt>
    659     * <dd>Used with the {@link org.apache.tapestry5.ioc.annotations.Inject} annotation, when a value is supplied</dd>
    660     * <dt>Operation</dt> <dd>Support for the {@link Operation} method annotation</dd>
    661     * </dl>
    662     */
    663    @Contribute(ComponentClassTransformWorker2.class)
    664    @Primary
    665    public static void provideTransformWorkers(
    666            OrderedConfiguration<ComponentClassTransformWorker2> configuration,
    667            MetaWorker metaWorker,
    668            ComponentClassResolver resolver)
    669    {
    670        configuration.add("Property", new PropertyWorker());
    671
    672        // Order this one pretty early:
    673
    674        configuration.addInstance("Operation", OperationWorker.class);
    675
    676        configuration.add("RenderCommand", new RenderCommandWorker());
    677
    678        configuration.addInstance("OnEvent", OnEventWorker.class);
    679
    680        configuration.add("MixinAfter", new MixinAfterWorker());
    681
    682        // These must come after Property, since they actually delete fields
    683        // that may still have the annotation
    684        configuration.addInstance("ApplicationState", ApplicationStateWorker.class);
    685        configuration.addInstance("Environment", EnvironmentalWorker.class);
    686
    687        configuration.add("Component", new ComponentWorker(resolver));
    688        configuration.add("Mixin", new MixinWorker(resolver));
    689        configuration.addInstance("InjectPage", InjectPageWorker.class);
    690        configuration.addInstance("InjectComponent", InjectComponentWorker.class);
    691        configuration.addInstance("InjectContainer", InjectContainerWorker.class);
    692
    693        // Default values for parameters are often some form of injection, so
    694        // make sure that Parameter fields are processed after injections.
    695
    696        configuration.addInstance("Parameter", ParameterWorker.class);
    697
    698        // bind parameter should always go after parameter to make sure all
    699        // parameters have been properly setup.
    700        configuration.addInstance("BindParameter", BindParameterWorker.class);
    701
    702        configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
    703
    704        configuration.addInstance("RenderPhase", RenderPhaseMethodWorker.class);
    705
    706        // Import advises methods, usually render phase methods, so it must come after RenderPhase.
    707
    708        configuration.addInstance("Import", ImportWorker.class);
    709
    710        configuration.add("Meta", metaWorker.getWorker());
    711
    712        configuration.add("Retain", new RetainWorker());
    713
    714        configuration.add("PageActivationContext", new PageActivationContextWorker());
    715        configuration
    716                .addInstance("ActivationRequestParameter", ActivationRequestParameterWorker.class);
    717
    718        configuration.addInstance("Cached", CachedWorker.class);
    719
    720        configuration.addInstance("DiscardAfter", DiscardAfterWorker.class);
    721
    722        add(configuration, PageLoaded.class, TransformConstants.CONTAINING_PAGE_DID_LOAD_DESCRIPTION);
    723        add(configuration, PageAttached.class, TransformConstants.CONTAINING_PAGE_DID_ATTACH_DESCRIPTION);
    724        add(configuration, PageDetached.class, TransformConstants.CONTAINING_PAGE_DID_DETACH_DESCRIPTION);
    725
    726        configuration.addInstance("PageReset", PageResetAnnotationWorker.class);
    727        configuration.addInstance("InjectService", InjectServiceWorker.class);
    728
    729        configuration.addInstance("Inject", InjectWorker.class);
    730
    731        configuration.addInstance("Persist", PersistWorker.class);
    732
    733        configuration.addInstance("SessionAttribute", SessionAttributeWorker.class);
    734
    735        configuration.addInstance("Log", LogWorker.class);
    736
    737        configuration.addInstance("HeartbeatDeferred", HeartbeatDeferredWorker.class);
    738
    739        // This one is always last. Any additional private fields that aren't
    740        // annotated will
    741        // be converted to clear out at the end of the request.
    742
    743        configuration.addInstance("UnclaimedField", UnclaimedFieldWorker.class, "after:*");
    744    }
    745
    746    /**
    747     * <dl>
    748     * <dt>Annotation</dt>
    749     * <dd>Checks for {@link org.apache.tapestry5.beaneditor.DataType} annotation</dd>
    750     * <dt>Default (ordered last)</dt>
    751     * <dd>
    752     * {@link org.apache.tapestry5.commons.internal.services.DefaultDataTypeAnalyzer} service (
    753     * {@link #contributeDefaultDataTypeAnalyzer(org.apache.tapestry5.commons.MappedConfiguration)} )</dd>
    754     * </dl>
    755     */
    756    public static void contributeDataTypeAnalyzer(OrderedConfiguration<DataTypeAnalyzer> configuration,
    757                                                  @InjectService("DefaultDataTypeAnalyzer")
    758                                                  DataTypeAnalyzer defaultDataTypeAnalyzer)
    759    {
    760        configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
    761        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
    762    }
    763
    764    /**
    765     * Maps property types to data type names:
    766     * <ul>
    767     * <li>String --&gt; text
    768     * <li>Number --&gt; number
    769     * <li>Enum --&gt; enum
    770     * <li>Boolean --&gt; boolean
    771     * <li>Date --&gt; date
    772     * </ul>
    773     */
    774    public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
    775    {
    776        BasicDataTypeAnalyzers.provideDefaultDataTypeAnalyzers(configuration);
    777    }
    778
    779    @Contribute(BeanBlockSource.class)
    780    public static void provideDefaultBeanBlocks(Configuration<BeanBlockContribution> configuration)
    781    {
    782        addEditBlock(configuration, DataTypeConstants.TEXT);
    783        addEditBlock(configuration, DataTypeConstants.NUMBER);
    784        addEditBlock(configuration, DataTypeConstants.ENUM);
    785        addEditBlock(configuration, DataTypeConstants.BOOLEAN);
    786        addEditBlock(configuration, DataTypeConstants.DATE);
    787        addEditBlock(configuration, DataTypeConstants.PASSWORD);
    788        addEditBlock(configuration, DataTypeConstants.CALENDAR);
    789
    790        // longtext uses a text area, not a text field
    791
    792        addEditBlock(configuration, DataTypeConstants.LONG_TEXT);
    793
    794        addDisplayBlock(configuration, DataTypeConstants.ENUM);
    795        addDisplayBlock(configuration, DataTypeConstants.DATE);
    796        addDisplayBlock(configuration, DataTypeConstants.CALENDAR);
    797
    798        // Password and long text have special output needs.
    799        addDisplayBlock(configuration, DataTypeConstants.PASSWORD);
    800        addDisplayBlock(configuration, DataTypeConstants.LONG_TEXT);
    801    }
    802
    803    private static void addEditBlock(Configuration<BeanBlockContribution> configuration, String dataType)
    804    {
    805        addEditBlock(configuration, dataType, dataType);
    806    }
    807
    808    private static void addEditBlock(Configuration<BeanBlockContribution> configuration, String dataType, String blockId)
    809    {
    810        configuration.add(new EditBlockContribution(dataType, "PropertyEditBlocks", blockId));
    811    }
    812
    813    private static void addDisplayBlock(Configuration<BeanBlockContribution> configuration, String dataType)
    814    {
    815        addDisplayBlock(configuration, dataType, dataType);
    816    }
    817
    818    private static void addDisplayBlock(Configuration<BeanBlockContribution> configuration, String dataType,
    819                                        String blockId)
    820    {
    821        configuration.add(new DisplayBlockContribution(dataType, "PropertyDisplayBlocks", blockId));
    822    }
    823
    824    /**
    825     * Contributes the basic set of validators:
    826     * <ul>
    827     * <li>required</li>
    828     * <li>minlength</li>
    829     * <li>maxlength</li>
    830     * <li>min</li>
    831     * <li>max</li>
    832     * <li>regexp</li>
    833     * <li>email</li>
    834     * <li>none</li>
    835     * </ul>
    836     */
    837    @Contribute(FieldValidatorSource.class)
    838    public static void setupCoreFrameworkValidators(MappedConfiguration<String, Validator> configuration)
    839    {
    840        configuration.addInstance("required", Required.class);
    841        configuration.addInstance("minlength", MinLength.class);
    842        configuration.addInstance("maxlength", MaxLength.class);
    843        configuration.addInstance("min", Min.class);
    844        configuration.addInstance("max", Max.class);
    845        configuration.addInstance("regexp", Regexp.class);
    846        configuration.addInstance("email", Email.class);
    847        configuration.addInstance("checked", Checked.class);
    848        configuration.addInstance("unchecked", Unchecked.class);
    849        configuration.add("none", new None());
    850    }
    851
    852    /**
    853     * <dl>
    854     * <dt>Default</dt>
    855     * <dd>based on {@link MasterObjectProvider}</dd>
    856     * <dt>Named</dt> <dd>Handles fields with the {@link javax.inject.Named} annotation</dd>
    857     * <dt>Block</dt>
    858     * <dd>injects fields of type {@link Block}</dd>
    859     * <dt>CommonResources</dt>
    860     * <dd>Access to properties of resources (log, messages, etc.)</dd>
    861     * <dt>Asset</dt>
    862     * <dd>injection of assets (triggered via {@link Path} annotation), with the path relative to the component class</dd>
    863     * <dt>Service</dt>
    864     * <dd>Ordered last, for use when Inject is present and nothing else works, matches field type against Tapestry IoC
    865     * services</dd>
    866     * </dl>
    867     */
    868    @Contribute(InjectionProvider2.class)
    869    public static void provideStandardInjectionProviders(OrderedConfiguration<InjectionProvider2> configuration, SymbolSource symbolSource,
    870
    871                                                         AssetSource assetSource)
    872    {
    873        configuration.addInstance("Named", InjectNamedProvider.class);
    874        configuration.add("Block", new BlockInjectionProvider());
    875        configuration.add("Asset", new AssetInjectionProvider(assetSource));
    876
    877        configuration.add("CommonResources", new CommonResourcesInjectionProvider());
    878
    879        configuration.addInstance("Default", DefaultInjectionProvider.class);
    880
    881        // This needs to be the last one, since it matches against services
    882        // and might blow up if there is no match.
    883        configuration.addInstance("Service", ServiceInjectionProvider.class, "after:*");
    884    }
    885
    886    /**
    887     * Contributes two object providers:
    888     * <dl>
    889     * <dt>Asset
    890     * <dt>
    891     * <dd>Checks for the {@link Path} annotation, and injects an {@link Asset}</dd>
    892     * <dt>Service</dt>
    893     * <dd>Injects based on the {@link Service} annotation, if present</dd>
    894     * <dt>ApplicationMessages</dt>
    895     * <dd>Injects the global application messages</dd>
    896     * </dl>
    897     */
    898    public static void contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> configuration,
    899
    900                                                      @InjectService("AssetObjectProvider")
    901                                                      ObjectProvider assetObjectProvider,
    902
    903                                                      ObjectLocator locator)
    904    {
    905        configuration.add("Asset", assetObjectProvider, "before:AnnotationBasedContributions");
    906
    907        configuration.add("Service", new ServiceAnnotationObjectProvider(), "before:AnnotationBasedContributions");
    908
    909        configuration.add("ApplicationMessages", new ApplicationMessageCatalogObjectProvider(locator),
    910                "before:AnnotationBasedContributions");
    911
    912    }
    913
    914    /**
    915     * <dl>
    916     * <dt>StoreIntoGlobals</dt>
    917     * <dd>Stores the request and response into {@link org.apache.tapestry5.http.services.RequestGlobals} at the start of the
    918     * pipeline</dd>
    919     * <dt>IgnoredPaths</dt>
    920     * <dd>Identifies requests that are known (via the IgnoredPathsFilter service's configuration) to be mapped to other
    921     * applications</dd>
    922     * <dt>GZip</dt>
    923     * <dd>Handles GZIP compression of response streams (if supported by client)</dd>
    924     * </dl>
    925     */
    926    public void contributeHttpServletRequestHandler(OrderedConfiguration<HttpServletRequestFilter> configuration,
    927
    928                                                    @InjectService("IgnoredPathsFilter")
    929                                                    HttpServletRequestFilter ignoredPathsFilter)
    930    {
    931        configuration.add("IgnoredPaths", ignoredPathsFilter);
    932    }
    933
    934    /**
    935     * Continues a number of filters into the RequestHandler service:
    936     * <dl>
    937     * <dt>StaticFiles</dt>
    938     * <dd>Checks to see if the request is for an actual file, if so, returns true to let the servlet container process
    939     * the request</dd>
    940     * <dt>CheckForUpdates</dt>
    941     * <dd>Periodically fires events that checks to see if the file system sources for any cached data has changed (see
    942     * {@link org.apache.tapestry5.internal.services.CheckForUpdatesFilter}). Starting in 5.3, this filter will be null
    943     * in production mode (it will only be active in development mode).
    944     * <dt>ErrorFilter</dt>
    945     * <dd>Catches request errors and lets the {@link org.apache.tapestry5.services.RequestExceptionHandler} handle them
    946     * </dd>
    947     * <dt>StoreIntoGlobals</dt>
    948     * <dd>Stores the request and response into the {@link org.apache.tapestry5.http.services.RequestGlobals} service (this
    949     * is repeated at the end of the pipeline, in case any filter substitutes the request or response).
    950     * <dt>EndOfRequest</dt>
    951     * <dd>Notifies internal services that the request has ended</dd>
    952     * </dl>
    953     */
    954    public void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration, Context context,
    955
    956                                         @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
    957                                         boolean productionMode)
    958    {
    959        RequestFilter staticFilesFilter = new StaticFilesFilter(context);
    960
    961        RequestFilter storeIntoGlobals = new RequestFilter()
    962        {
    963            public boolean service(Request request, Response response, RequestHandler handler) throws IOException
    964            {
    965                requestGlobals.storeRequestResponse(request, response);
    966
    967                return handler.service(request, response);
    968            }
    969        };
    970
    971        RequestFilter fireEndOfRequestEvent = new RequestFilter()
    972        {
    973            public boolean service(Request request, Response response, RequestHandler handler) throws IOException
    974            {
    975                try
    976                {
    977                    return handler.service(request, response);
    978                } finally
    979                {
    980                    endOfRequestEventHub.fire();
    981                }
    982            }
    983        };
    984
    985        if (productionMode)
    986        {
    987            configuration.add("CheckForUpdates", null, "before:*");
    988        } else
    989        {
    990            configuration.addInstance("CheckForUpdates", CheckForUpdatesFilter.class, "before:*");
    991        }
    992
    993        configuration.add("StaticFiles", staticFilesFilter);
    994
    995        configuration.add("StoreIntoGlobals", storeIntoGlobals);
    996
    997        configuration.add("EndOfRequest", fireEndOfRequestEvent);
    998
    999        configuration.addInstance("ErrorFilter", RequestErrorFilter.class);
    1000    }
    1001
    1002    /**
    1003     * Contributes the basic set of translators:
    1004     * <ul>
    1005     * <li>string</li>
    1006     * <li>byte</li>
    1007     * <li>short</li>
    1008     * <li>integer</li>
    1009     * <li>long</li>
    1010     * <li>float</li>
    1011     * <li>double</li>
    1012     * <li>BigInteger</li>
    1013     * <li>BigDecimal</li>
    1014     * </ul>
    1015     */
    1016    public static void contributeTranslatorSource(MappedConfiguration<Class, Translator> configuration,
    1017                                                  NumericTranslatorSupport support, Html5Support html5Support)
    1018    {
    1019
    1020        configuration.add(String.class, new StringTranslator());
    1021
    1022        Class[] types = new Class[]
    1023                {Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigInteger.class,
    1024                        BigDecimal.class};
    1025
    1026        for (Class type : types)
    1027        {
    1028            String name = type.getSimpleName().toLowerCase();
    1029
    1030            configuration.add(type, new NumericTranslator(name, type, support, html5Support));
    1031        }
    1032    }
    1033
    1034    /**
    1035     * Adds coercions:
    1036     * <ul>
    1037     * <li>String to {@link SelectModel}
    1038     * <li>Map to {@link SelectModel}
    1039     * <li>Collection to {@link GridDataSource}
    1040     * <li>null to {@link GridDataSource}
    1041     * <li>List to {@link SelectModel}
    1042     * <li>{@link ComponentResourcesAware} (typically, a component) to {@link ComponentResources}
    1043     * <li>{@link ComponentResources} to {@link PropertyOverrides}
    1044     * <li>String to {@link Renderable}
    1045     * <li>{@link Renderable} to {@link Block}
    1046     * <li>String to {@link DateFormat}
    1047     * <li>String to {@link Resource} (via {@link AssetSource#resourceForPath(String)})
    1048     * <li>{@link Renderable} to {@link RenderCommand}</li>
    1049     * <li>String to {@link Pattern}</li>
    1050     * <li>String to {@link DateFormat}</li>
    1051     * <li>{@link Resource} to {@link DynamicTemplate}</li>
    1052     * <li>{@link Asset} to {@link Resource}</li>
    1053     * <li>{@link ValueEncoder} to {@link ValueEncoderFactory}</li>
    1054     * </ul>
    1055     */
    1056    public static void contributeTypeCoercer(MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration,
    1057
    1058                                             final ObjectLocator objectLocator,
    1059
    1060                                             @Builtin
    1061                                             final ThreadLocale threadLocale,
    1062
    1063                                             @Core
    1064                                             final AssetSource assetSource,
    1065
    1066                                             @Core
    1067                                             final DynamicTemplateParser dynamicTemplateParser)
    1068    {
    1069        CoercionTuple<ComponentResources, PropertyOverrides> componentResourcesToPropertyOverrides = CoercionTuple.create(ComponentResources.class, PropertyOverrides.class,
    1070                new Coercion<ComponentResources, PropertyOverrides>()
    1071                {
    1072                    public PropertyOverrides coerce(ComponentResources input)
    1073                    {
    1074                        return new PropertyOverridesImpl(input);
    1075                    }
    1076                });
    1077        configuration.add(componentResourcesToPropertyOverrides.getKey(), componentResourcesToPropertyOverrides);
    1078
    1079
    1080        // See TAP5-2184 for why this causes some trouble!
    1081        CoercionTuple<String, SelectModel> stringToSelectModel = CoercionTuple.create(String.class, SelectModel.class, new Coercion<String, SelectModel>()
    1082        {
    1083            public SelectModel coerce(String input)
    1084            {
    1085                return TapestryInternalUtils.toSelectModel(input);
    1086            }
    1087        });
    1088        configuration.add(stringToSelectModel.getKey(), stringToSelectModel);
    1089
    1090        CoercionTuple<Map, SelectModel> mapToSelectModel = CoercionTuple.create(Map.class, SelectModel.class, new Coercion<Map, SelectModel>()
    1091        {
    1092            @SuppressWarnings("unchecked")
    1093            public SelectModel coerce(Map input)
    1094            {
    1095                return TapestryInternalUtils.toSelectModel(input);
    1096            }
    1097        });
    1098        configuration.add(mapToSelectModel.getKey(), mapToSelectModel);
    1099
    1100        CoercionTuple<Collection, GridDataSource> collectionToGridDataSource = CoercionTuple.create(Collection.class, GridDataSource.class,
    1101                new Coercion<Collection, GridDataSource>()
    1102                {
    1103                    public GridDataSource coerce(Collection input)
    1104                    {
    1105                        return new CollectionGridDataSource(input);
    1106                    }
    1107                });
    1108        configuration.add(collectionToGridDataSource.getKey(), collectionToGridDataSource);
    1109
    1110        CoercionTuple<Void, GridDataSource> voidToGridDataSource = CoercionTuple.create(void.class, GridDataSource.class, new Coercion<Void, GridDataSource>()
    1111        {
    1112            private final GridDataSource source = new NullDataSource();
    1113
    1114            public GridDataSource coerce(Void input)
    1115            {
    1116                return source;
    1117            }
    1118        });
    1119        configuration.add(voidToGridDataSource.getKey(), voidToGridDataSource);
    1120
    1121        CoercionTuple<List, SelectModel> listToSelectModel = CoercionTuple.create(List.class, SelectModel.class, new Coercion<List, SelectModel>()
    1122        {
    1123            private SelectModelFactory selectModelFactory;
    1124
    1125            @SuppressWarnings("unchecked")
    1126            public SelectModel coerce(List input)
    1127            {
    1128                // This doesn't look thread safe, but it is because its a one-time transition from null
    1129                // to another value, and a race condition is harmless.
    1130                if (selectModelFactory == null)
    1131                {
    1132                    selectModelFactory = objectLocator.getService(SelectModelFactory.class);
    1133                }
    1134
    1135                return selectModelFactory.create(input);
    1136            }
    1137        });
    1138        configuration.add(listToSelectModel.getKey(), listToSelectModel);
    1139
    1140        CoercionTuple<String, Pattern> stringToPattern = CoercionTuple.create(String.class, Pattern.class, new Coercion<String, Pattern>()
    1141        {
    1142            public Pattern coerce(String input)
    1143            {
    1144                return Pattern.compile(input);
    1145            }
    1146        });
    1147        configuration.add(stringToPattern.getKey(), stringToPattern);
    1148
    1149        CoercionTuple<ComponentResourcesAware, ComponentResources> componentResourcesAwareToComponentResources = CoercionTuple.create(ComponentResourcesAware.class, ComponentResources.class,
    1150                new Coercion<ComponentResourcesAware, ComponentResources>()
    1151                {
    1152
    1153                    public ComponentResources coerce(ComponentResourcesAware input)
    1154                    {
    1155                        return input.getComponentResources();
    1156                    }
    1157                });
    1158        configuration.add(componentResourcesAwareToComponentResources.getKey(), componentResourcesAwareToComponentResources);
    1159
    1160        CoercionTuple<String, Renderable> stringToRenderable = CoercionTuple.create(String.class, Renderable.class, new Coercion<String, Renderable>()
    1161        {
    1162            public Renderable coerce(String input)
    1163            {
    1164                return new StringRenderable(input);
    1165            }
    1166        });
    1167        configuration.add(stringToRenderable.getKey(), stringToRenderable);
    1168
    1169        CoercionTuple<Renderable, Block> renderableToBlock = CoercionTuple.create(Renderable.class, Block.class, new Coercion<Renderable, Block>()
    1170        {
    1171            public Block coerce(Renderable input)
    1172            {
    1173                return new RenderableAsBlock(input);
    1174            }
    1175        });
    1176        configuration.add(renderableToBlock.getKey(), renderableToBlock);
    1177
    1178        CoercionTuple<String, DateFormat> stringToDateFormat = CoercionTuple.create(String.class, DateFormat.class, new Coercion<String, DateFormat>()
    1179        {
    1180            public DateFormat coerce(String input)
    1181            {
    1182                final SimpleDateFormat dateFormat = new SimpleDateFormat(input, threadLocale.getLocale());
    1183                final String lenient = objectLocator.getService(SymbolSource.class).valueForSymbol(SymbolConstants.LENIENT_DATE_FORMAT);
    1184                dateFormat.setLenient(Boolean.parseBoolean(lenient));
    1185                return dateFormat;
    1186            }
    1187        });
    1188        configuration.add(stringToDateFormat.getKey(), stringToDateFormat);
    1189
    1190        CoercionTuple<String, Resource> stringToResource = CoercionTuple.create(String.class, Resource.class, new Coercion<String, Resource>()
    1191        {
    1192            public Resource coerce(String input)
    1193            {
    1194                return assetSource.resourceForPath(input);
    1195            }
    1196        });
    1197        configuration.add(stringToResource.getKey(), stringToResource);
    1198
    1199        CoercionTuple<Renderable, RenderCommand> renderableToRenderCommand = CoercionTuple.create(Renderable.class, RenderCommand.class,
    1200                new Coercion<Renderable, RenderCommand>()
    1201                {
    1202                    public RenderCommand coerce(final Renderable input)
    1203                    {
    1204                        return new RenderCommand()
    1205                        {
    1206                            public void render(MarkupWriter writer, RenderQueue queue)
    1207                            {
    1208                                input.render(writer);
    1209                            }
    1210                        };
    1211                    }
    1212                });
    1213        configuration.add(renderableToRenderCommand.getKey(), renderableToRenderCommand);
    1214
    1215        CoercionTuple<Date, Calendar> dateToCalendar = CoercionTuple.create(Date.class, Calendar.class, new Coercion<Date, Calendar>()
    1216        {
    1217            public Calendar coerce(Date input)
    1218            {
    1219                Calendar calendar = Calendar.getInstance(threadLocale.getLocale());
    1220                calendar.setTime(input);
    1221                return calendar;
    1222            }
    1223        });
    1224        configuration.add(dateToCalendar.getKey(), dateToCalendar);
    1225
    1226        CoercionTuple<Resource, DynamicTemplate> resourceToDynamicTemplate = CoercionTuple.create(Resource.class, DynamicTemplate.class,
    1227                new Coercion<Resource, DynamicTemplate>()
    1228                {
    1229                    public DynamicTemplate coerce(Resource input)
    1230                    {
    1231                        return dynamicTemplateParser.parseTemplate(input);
    1232                    }
    1233                });
    1234        configuration.add(resourceToDynamicTemplate.getKey(), resourceToDynamicTemplate);
    1235
    1236        CoercionTuple<Asset, Resource> assetToResource = CoercionTuple.create(Asset.class, Resource.class, new Coercion<Asset, Resource>()
    1237        {
    1238            public Resource coerce(Asset input)
    1239            {
    1240                return input.getResource();
    1241            }
    1242        });
    1243        configuration.add(assetToResource.getKey(), assetToResource);
    1244
    1245        CoercionTuple<ValueEncoder, ValueEncoderFactory> valueEncoderToValueEncoderFactory = CoercionTuple.create(ValueEncoder.class, ValueEncoderFactory.class, new Coercion<ValueEncoder, ValueEncoderFactory>()
    1246        {
    1247            public ValueEncoderFactory coerce(ValueEncoder input)
    1248            {
    1249                return new GenericValueEncoderFactory(input);
    1250            }
    1251        });
    1252        configuration.add(valueEncoderToValueEncoderFactory.getKey(), valueEncoderToValueEncoderFactory);
    1253    }
    1254
    1255    /**
    1256     * Adds built-in constraint generators:
    1257     * <ul>
    1258     * <li>PrimtiveField -- primitive fields are always required
    1259     * <li>ValidateAnnotation -- adds constraints from a {@link Validate} annotation
    1260     * </ul>
    1261     */
    1262    public static void contributeValidationConstraintGenerator(
    1263            OrderedConfiguration<ValidationConstraintGenerator> configuration)
    1264    {
    1265        configuration.add("PrimitiveField", new PrimitiveFieldConstraintGenerator());
    1266        configuration.add("ValidateAnnotation", new ValidateAnnotationConstraintGenerator());
    1267        configuration.addInstance("Messages", MessagesConstraintGenerator.class);
    1268    }
    1269
    1270    private static void add(OrderedConfiguration<ComponentClassTransformWorker2> configuration,
    1271                            Class<? extends Annotation> annotationClass, MethodDescription description)
    1272    {
    1273        String name = TapestryInternalUtils.lastTerm(annotationClass.getName());
    1274
    1275        ComponentClassTransformWorker2 worker = new PageLifecycleAnnotationWorker(annotationClass,
    1276                description, name);
    1277
    1278        configuration.add(name, worker);
    1279    }
    1280
    1281    // ========================================================================
    1282    //
    1283    // Service Builder Methods (instance)
    1284    //
    1285    // ========================================================================
    1286
    1287    public Context buildContext(ApplicationGlobals globals)
    1288    {
    1289        return shadowBuilder.build(globals, "context", Context.class);
    1290    }
    1291
    1292    public static ComponentClassResolver buildComponentClassResolver(@Autobuild
    1293                                                                     ComponentClassResolverImpl service, @ComponentClasses
    1294                                                                     InvalidationEventHub hub)
    1295    {
    1296        // Allow the resolver to clean its cache when the component classes
    1297        // change
    1298
    1299        hub.addInvalidationListener(service);
    1300
    1301        return service;
    1302    }
    1303
    1304
    1305    /**
    1306     * Builds the PropBindingFactory as a chain of command. The terminator of
    1307     * the chain is responsible for ordinary
    1308     * property names (and property paths).
    1309     *
    1310     * This mechanism has been replaced in 5.1 with a more sophisticated parser based on ANTLR. See <a
    1311     * href="https://issues.apache.org/jira/browse/TAP5-79">TAP5-79</a> for details. There are no longer any built-in
    1312     * contributions to the configuration.
    1313     *
    1314     * @param configuration
    1315     *         contributions of special factories for some constants, each
    1316     *         contributed factory may return a
    1317     *         binding if applicable, or null otherwise
    1318     */
    1319    public BindingFactory buildPropBindingFactory(List<BindingFactory> configuration, @Autobuild
    1320    PropBindingFactory service)
    1321    {
    1322        configuration.add(service);
    1323
    1324        return chainBuilder.build(BindingFactory.class, configuration);
    1325    }
    1326
    1327    public PersistentFieldStrategy buildClientPersistentFieldStrategy(LinkCreationHub linkCreationHub, @Autobuild
    1328    ClientPersistentFieldStrategy service)
    1329    {
    1330        linkCreationHub.addListener(service);
    1331
    1332        return service;
    1333    }
    1334
    1335    /**
    1336     * Builds a proxy to the current {@link org.apache.tapestry5.services.ClientBehaviorSupport} inside this
    1337     * thread's {@link org.apache.tapestry5.services.Environment}.
    1338     *
    1339     * @since 5.1.0.1
    1340     */
    1341
    1342    public ClientBehaviorSupport buildClientBehaviorSupport()
    1343    {
    1344        return environmentalBuilder.build(ClientBehaviorSupport.class);
    1345    }
    1346
    1347    /**
    1348     * Builds a proxy to the current {@link org.apache.tapestry5.services.FormSupport} inside this
    1349     * thread's {@link org.apache.tapestry5.services.Environment}.
    1350     */
    1351    public FormSupport buildFormSupport()
    1352    {
    1353        return environmentalBuilder.build(FormSupport.class);
    1354    }
    1355
    1356    /**
    1357     * Allows the exact steps in the component class transformation process to
    1358     * be defined.
    1359     */
    1360    @Marker(Primary.class)
    1361    public ComponentClassTransformWorker2 buildComponentClassTransformWorker(
    1362            List<ComponentClassTransformWorker2> configuration)
    1363
    1364    {
    1365        return chainBuilder.build(ComponentClassTransformWorker2.class, configuration);
    1366    }
    1367
    1368    /**
    1369     * Analyzes properties to determine the data types, used to
    1370     * {@linkplain #provideDefaultBeanBlocks(org.apache.tapestry5.commons.Configuration)} locale
    1371     * display and edit blocks for properties. The default behaviors
    1372     * look for a {@link org.apache.tapestry5.beaneditor.DataType} annotation
    1373     * before deriving the data type from the property type.
    1374     */
    1375    @Marker(Primary.class)
    1376    public DataTypeAnalyzer buildDataTypeAnalyzer(List<DataTypeAnalyzer> configuration)
    1377    {
    1378        return chainBuilder.build(DataTypeAnalyzer.class, configuration);
    1379    }
    1380
    1381    /**
    1382     * A chain of command for providing values for {@link Inject}-ed fields in
    1383     * component classes. The service's
    1384     * configuration can be extended to allow for different automatic injections
    1385     * (based on some combination of field
    1386     * type and field name).
    1387     */
    1388    public InjectionProvider2 buildInjectionProvider(List<InjectionProvider2> configuration)
    1389    {
    1390        return chainBuilder.build(InjectionProvider2.class, configuration);
    1391    }
    1392
    1393    /**
    1394     * The component event result processor used for normal component requests.
    1395     */
    1396    @Marker(
    1397            {Primary.class, Traditional.class})
    1398    public ComponentEventResultProcessor buildComponentEventResultProcessor(
    1399            Map<Class, ComponentEventResultProcessor> configuration, @ComponentClasses
    1400    InvalidationEventHub hub)
    1401    {
    1402        return constructComponentEventResultProcessor(configuration, hub);
    1403    }
    1404
    1405    /**
    1406     * The component event result processor used for Ajax-oriented component
    1407     * requests.
    1408     */
    1409    @Marker(Ajax.class)
    1410    public ComponentEventResultProcessor buildAjaxComponentEventResultProcessor(
    1411            Map<Class, ComponentEventResultProcessor> configuration, @ComponentClasses
    1412    InvalidationEventHub hub)
    1413    {
    1414        return constructComponentEventResultProcessor(configuration, hub);
    1415    }
    1416
    1417    private ComponentEventResultProcessor constructComponentEventResultProcessor(
    1418            Map<Class, ComponentEventResultProcessor> configuration, InvalidationEventHub hub)
    1419    {
    1420        Set<Class> handledTypes = CollectionFactory.newSet(configuration.keySet());
    1421
    1422        // A slight hack!
    1423
    1424        configuration.put(Object.class, new ObjectComponentEventResultProcessor(handledTypes));
    1425
    1426        final StrategyRegistry<ComponentEventResultProcessor> registry = StrategyRegistry.newInstance(
    1427                ComponentEventResultProcessor.class, configuration);
    1428
    1429        //As the registry will cache component classes, we need to clear the cache when we reload components to avoid memory leaks in permgen
    1430        hub.addInvalidationCallback(new Runnable()
    1431        {
    1432            public void run()
    1433            {
    1434                registry.clearCache();
    1435            }
    1436        });
    1437
    1438        return strategyBuilder.build(registry);
    1439    }
    1440
    1441    /**
    1442     * The default data type analyzer is the final analyzer consulted and
    1443     * identifies the type entirely pased on the
    1444     * property type, working against its own configuration (mapping property
    1445     * type class to data type).
    1446     */
    1447    public static DataTypeAnalyzer buildDefaultDataTypeAnalyzer(@Autobuild
    1448                                                                DefaultDataTypeAnalyzer service, @ComponentClasses
    1449                                                                InvalidationEventHub hub)
    1450    {
    1451        hub.addInvalidationCallback(service);
    1452
    1453        return service;
    1454    }
    1455
    1456    public static TranslatorSource buildTranslatorSource(Map<Class, Translator> configuration,
    1457                                                         TranslatorAlternatesSource alternatesSource,
    1458                                                         @ComponentClasses
    1459                                                         InvalidationEventHub hub)
    1460    {
    1461        TranslatorSourceImpl service = new TranslatorSourceImpl(configuration,
    1462                alternatesSource.getTranslatorAlternates());
    1463
    1464        hub.addInvalidationCallback(service);
    1465
    1466        return service;
    1467    }
    1468
    1469    @Marker(Primary.class)
    1470    public ObjectRenderer buildObjectRenderer(Map<Class, ObjectRenderer> configuration)
    1471    {
    1472        return strategyBuilder.build(ObjectRenderer.class, configuration);
    1473    }
    1474
    1475    /**
    1476     * Returns a {@link PlasticProxyFactory} that can be used to create extra classes around component classes. This
    1477     * factory will be cleared whenever an underlying component class is discovered to have changed. Use of this
    1478     * factory implies that your code will become aware of this (if necessary) to discard any cached object (alas,
    1479     * this currently involves dipping into the internals side to register for the correct notifications). Failure to
    1480     * properly clean up can result in really nasty PermGen space memory leaks.
    1481     */
    1482    @Marker(ComponentLayer.class)
    1483    public PlasticProxyFactory buildComponentProxyFactory(ComponentInstantiatorSource source)
    1484    {
    1485        return shadowBuilder.build(source, "proxyFactory", PlasticProxyFactory.class);
    1486    }
    1487
    1488    /**
    1489     * The MarkupRenderer service is used to render a full page as markup.
    1490     * Supports an ordered configuration of {@link org.apache.tapestry5.services.MarkupRendererFilter}s.
    1491     */
    1492    public MarkupRenderer buildMarkupRenderer(Logger logger, @Autobuild
    1493    MarkupRendererTerminator terminator, List<MarkupRendererFilter> configuration)
    1494    {
    1495        return pipelineBuilder.build(logger, MarkupRenderer.class, MarkupRendererFilter.class, configuration,
    1496                terminator);
    1497    }
    1498
    1499    /**
    1500     * A wrapper around {@link org.apache.tapestry5.internal.services.PageRenderQueue} used for
    1501     * partial page renders.
    1502     * Supports an ordered configuration of {@link org.apache.tapestry5.services.PartialMarkupRendererFilter}s.
    1503     */
    1504    public PartialMarkupRenderer buildPartialMarkupRenderer(Logger logger,
    1505                                                            List<PartialMarkupRendererFilter> configuration, @Autobuild
    1506    PartialMarkupRendererTerminator terminator)
    1507    {
    1508        return pipelineBuilder.build(logger, PartialMarkupRenderer.class, PartialMarkupRendererFilter.class,
    1509                configuration, terminator);
    1510    }
    1511
    1512    public PageRenderRequestHandler buildPageRenderRequestHandler(List<PageRenderRequestFilter> configuration,
    1513                                                                  Logger logger, @Autobuild
    1514    PageRenderRequestHandlerImpl terminator)
    1515    {
    1516        return pipelineBuilder.build(logger, PageRenderRequestHandler.class, PageRenderRequestFilter.class,
    1517                configuration, terminator);
    1518    }
    1519
    1520    /**
    1521     * Builds the component action request handler for traditional (non-Ajax)
    1522     * requests. These typically result in a
    1523     * redirect to a Tapestry render URL.
    1524     */
    1525    @Marker(
    1526            {Traditional.class, Primary.class})
    1527    public ComponentEventRequestHandler buildComponentEventRequestHandler(
    1528            List<ComponentEventRequestFilter> configuration, Logger logger, @Autobuild
    1529    ComponentEventRequestHandlerImpl terminator)
    1530    {
    1531        return pipelineBuilder.build(logger, ComponentEventRequestHandler.class, ComponentEventRequestFilter.class,
    1532                configuration, terminator);
    1533    }
    1534
    1535    /**
    1536     * Builds the action request handler for Ajax requests, based on a
    1537     * {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder
    1538     * pipeline} around {@link org.apache.tapestry5.internal.services.AjaxComponentEventRequestHandler} . Filters on
    1539     * the
    1540     * request handler are supported here as well.
    1541     */
    1542    @Marker(
    1543            {Ajax.class, Primary.class})
    1544    public ComponentEventRequestHandler buildAjaxComponentEventRequestHandler(
    1545            List<ComponentEventRequestFilter> configuration, Logger logger, @Autobuild
    1546    AjaxComponentEventRequestHandler terminator)
    1547    {
    1548        return pipelineBuilder.build(logger, ComponentEventRequestHandler.class, ComponentEventRequestFilter.class,
    1549                configuration, terminator);
    1550    }
    1551
    1552    // ========================================================================
    1553    //
    1554    // Service Contribution Methods (instance)
    1555    //
    1556    // ========================================================================
    1557
    1558    /**
    1559     * Contributes the default "session" strategy.
    1560     */
    1561    public void contributeApplicationStatePersistenceStrategySource(
    1562            MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration,
    1563
    1564            @Local
    1565            ApplicationStatePersistenceStrategy sessionStategy)
    1566    {
    1567        configuration.add("session", sessionStategy);
    1568    }
    1569
    1570    /**
    1571     * Contributes handlers for the following types:
    1572     * <dl>
    1573     * <dt>Object</dt>
    1574     * <dd>Failure case, added to provide a more useful exception message</dd>
    1575     * <dt>{@link Link}</dt>
    1576     * <dd>Sends a redirect to the link (which is typically a page render link)</dd>
    1577     * <dt>String</dt>
    1578     * <dd>Sends a page render redirect</dd>
    1579     * <dt>Class</dt>
    1580     * <dd>Interpreted as the class name of a page, sends a page render render redirect (this is more refactoring safe
    1581     * than the page name)</dd>
    1582     * <dt>{@link Component}</dt>
    1583     * <dd>A page's root component (though a non-root component will work, but will generate a warning). A direct to the
    1584     * containing page is sent.</dd>
    1585     * <dt>{@link org.apache.tapestry5.StreamResponse}</dt>
    1586     * <dd>The stream response is sent as the actual reply.</dd>
    1587     * <dt>URL</dt>
    1588     * <dd>Sends a redirect to a (presumably) external URL</dd>
    1589     * </dl>
    1590     */
    1591    public void contributeComponentEventResultProcessor(@Traditional
    1592                                                        @ComponentInstanceProcessor
    1593                                                        ComponentEventResultProcessor componentInstanceProcessor,
    1594
    1595                                                        MappedConfiguration<Class, ComponentEventResultProcessor> configuration)
    1596    {
    1597        configuration.add(Link.class, new ComponentEventResultProcessor<Link>()
    1598        {
    1599            public void processResultValue(Link value) throws IOException
    1600            {
    1601                response.sendRedirect(value);
    1602            }
    1603        });
    1604
    1605        configuration.add(URL.class, new ComponentEventResultProcessor<URL>()
    1606        {
    1607            public void processResultValue(URL value) throws IOException
    1608            {
    1609                response.sendRedirect(value.toExternalForm());
    1610            }
    1611        });
    1612
    1613        configuration.addInstance(HttpError.class, HttpErrorComponentEventResultProcessor.class);
    1614        configuration.addInstance(HttpStatus.class, HttpStatusComponentEventResultProcessor.class);
    1615
    1616        configuration.addInstance(String.class, PageNameComponentEventResultProcessor.class);
    1617
    1618        configuration.addInstance(Class.class, ClassResultProcessor.class);
    1619
    1620        configuration.add(Component.class, componentInstanceProcessor);
    1621
    1622        configuration.addInstance(StreamResponse.class, StreamResponseResultProcessor.class);
    1623
    1624        configuration.addInstance(StreamPageContent.class, StreamPageContentResultProcessor.class);
    1625
    1626        configuration.addInstance(JSONArray.class, JSONCollectionEventResultProcessor.class);
    1627        configuration.addInstance(JSONObject.class, JSONCollectionEventResultProcessor.class);
    1628    }
    1629
    1630    /**
    1631     * Contributes handlers for the following types:
    1632     * <dl>
    1633     * <dt>Object</dt>
    1634     * <dd>Failure case, added to provide more useful exception message</dd>
    1635     * <dt>{@link RenderCommand}</dt>
    1636     * <dd>Typically, a {@link org.apache.tapestry5.Block}</dd>
    1637     * <dt>{@link org.apache.tapestry5.annotations.Component}</dt>
    1638     * <dd>Renders the component and its body (unless its a page, in which case a redirect JSON response is sent)</dd>
    1639     * <dt>{@link org.apache.tapestry5.json.JSONObject} or {@link org.apache.tapestry5.json.JSONArray}</dt>
    1640     * <dd>The JSONObject is returned as a text/javascript response</dd>
    1641     * <dt>{@link org.apache.tapestry5.StreamResponse}</dt>
    1642     * <dd>The stream response is sent as the actual response</dd>
    1643     * <dt>String</dt>
    1644     * <dd>Interprets the value as a logical page name and sends a client response to redirect to that page</dd>
    1645     * <dt>{@link org.apache.tapestry5.http.Link}</dt>
    1646     * <dd>Sends a JSON response to redirect to the link</dd>
    1647     * <dt>{@link Class}</dt>
    1648     * <dd>Treats the class as a page class and sends a redirect for a page render for that page</dd>
    1649     * <dt>{@link org.apache.tapestry5.ajax.MultiZoneUpdate}</dt>
    1650     * <dd>Sends a single JSON response to update the content of multiple zones
    1651     * </dl>
    1652     *
    1653     * In most cases, when you want to support a new type, you should convert it to one of the built-in supported types
    1654     * (such as {@link RenderCommand}. You can then inject the master AjaxComponentEventResultProcessor (use the
    1655     * {@link Ajax} marker annotation) and delegate to it.
    1656     */
    1657    @Contribute(ComponentEventResultProcessor.class)
    1658    @Ajax
    1659    public static void provideBaseAjaxComponentEventResultProcessors(
    1660            MappedConfiguration<Class, ComponentEventResultProcessor> configuration)
    1661    {
    1662        configuration.addInstance(RenderCommand.class, RenderCommandComponentEventResultProcessor.class);
    1663        configuration.addInstance(Component.class, AjaxComponentInstanceEventResultProcessor.class);
    1664        configuration.addInstance(JSONObject.class, JSONObjectEventResultProcessor.class);
    1665        configuration.addInstance(JSONArray.class, JSONCollectionEventResultProcessor.class);
    1666        configuration.addInstance(StreamResponse.class, StreamResponseResultProcessor.class);
    1667        configuration.addInstance(String.class, AjaxPageNameComponentEventResultProcessor.class);
    1668        configuration.addInstance(Link.class, AjaxLinkComponentEventResultProcessor.class);
    1669        configuration.addInstance(URL.class, AjaxURLComponentEventResultProcessor.class);
    1670        configuration.addInstance(Class.class, AjaxPageClassComponentEventResultProcessor.class);
    1671        configuration.addInstance(MultiZoneUpdate.class, MultiZoneUpdateEventResultProcessor.class);
    1672        configuration.addInstance(HttpError.class, HttpErrorComponentEventResultProcessor.class);
    1673    }
    1674
    1675    /**
    1676     * The MasterDispatcher is a chain-of-command of individual Dispatchers,
    1677     * each handling (like a servlet) a particular
    1678     * kind of incoming request.
    1679     * <dl>
    1680     * <dt>RootPath</dt>
    1681     * <dd>Renders the start page for the "/" request (outdated)</dd>
    1682     * <dt>PageRender</dt>
    1683     * <dd>Identifies the {@link org.apache.tapestry5.services.PageRenderRequestParameters} and forwards onto
    1684     * {@link PageRenderRequestHandler}</dd>
    1685     * <dt>ComponentEvent</dt>
    1686     * <dd>Identifies the {@link ComponentEventRequestParameters} and forwards onto the
    1687     * {@link ComponentEventRequestHandler}</dd>
    1688     * </dl>
    1689     */
    1690    public static void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
    1691            @Symbol(SymbolConstants.PUBLISH_OPENAPI_DEFINITON) final boolean publishOpenApiDefinition)
    1692    {
    1693
    1694        if (publishOpenApiDefinition)
    1695        {
    1696            configuration.addInstance("OpenAPI", OpenApiDescriptionDispatcher.class, "before:PageRender", "before:ComponentEvent");
    1697        }
    1698
    1699        // Looks for the root path and renders the start page. This is
    1700        // maintained for compatibility
    1701        // with earlier versions of Tapestry 5, it is recommended that an Index
    1702        // page be used instead.
    1703
    1704        configuration.addInstance("RootPath", RootPathDispatcher.class, "before:Asset");
    1705
    1706        configuration.addInstance("ComponentEvent", ComponentEventDispatcher.class, "before:PageRender");
    1707
    1708        configuration.addInstance("PageRender", PageRenderDispatcher.class);
    1709    }
    1710
    1711    /**
    1712     * Contributes a default object renderer for type Object, plus specialized
    1713     * renderers for {@link org.apache.tapestry5.http.services.Request}, {@link org.apache.tapestry5.commons.Location},
    1714     * {@link org.apache.tapestry5.ComponentResources}, {@link org.apache.tapestry5.EventContext},
    1715     * {@link AvailableValues},
    1716     * List, and Object[].
    1717     */
    1718    @SuppressWarnings("unchecked")
    1719    public void contributeObjectRenderer(MappedConfiguration<Class, ObjectRenderer> configuration,
    1720
    1721                                         @InjectService("LocationRenderer")
    1722                                         ObjectRenderer locationRenderer,
    1723
    1724                                         final TypeCoercer typeCoercer)
    1725    {
    1726        configuration.add(Object.class, new DefaultObjectRenderer());
    1727
    1728        configuration.addInstance(Request.class, RequestRenderer.class);
    1729
    1730        configuration.add(Location.class, locationRenderer);
    1731
    1732        ObjectRenderer preformatted = new ObjectRenderer<Object>()
    1733        {
    1734            public void render(Object object, MarkupWriter writer)
    1735            {
    1736                writer.element("pre");
    1737                writer.write(typeCoercer.coerce(object, String.class));
    1738                writer.end();
    1739            }
    1740        };
    1741
    1742        configuration.addInstance(List.class, ListRenderer.class);
    1743        configuration.addInstance(Object[].class, ObjectArrayRenderer.class);
    1744        configuration.addInstance(ComponentResources.class, ComponentResourcesRenderer.class);
    1745        configuration.addInstance(EventContext.class, EventContextRenderer.class);
    1746        configuration.add(AvailableValues.class, new AvailableValuesRenderer());
    1747    }
    1748
    1749    /**
    1750     * Adds page render filters, each of which provides an {@link org.apache.tapestry5.annotations.Environmental}
    1751     * service. Filters
    1752     * often provide {@link org.apache.tapestry5.annotations.Environmental} services needed by
    1753     * components as they render.
    1754     * <dl>
    1755     * <dt>DocumentLinker</dt>
    1756     * <dd>Provides {@link org.apache.tapestry5.internal.services.DocumentLinker}</dd>
    1757     * <dt>ClientBehaviorSupport (deprecated in 5.4)</dt>
    1758     * <dd>Provides {@link ClientBehaviorSupport}</dd>
    1759     * <dt>Heartbeat</dt>
    1760     * <dd>Provides {@link org.apache.tapestry5.services.Heartbeat}</dd>
    1761     * <dt>ValidationDecorator (deprecated in 5.4)</dt>
    1762     * <dd>Provides {@link org.apache.tapestry5.ValidationDecorator} (via {@link ValidationDecoratorFactory#newInstance(org.apache.tapestry5.MarkupWriter)})</dd>
    1763     * <dt>PageNameMeta (since 5.4)</dt>
    1764     * <dd>Renders a {@code <meta/>} tag describing the active page name (development mode only)</dd>
    1765     * <dt>ImportCoreStack (since 5.4) </dt>
    1766     * <dd>Imports the "core" stack (necessary to get the Bootstrap CSS, if nothing else).</dd>
    1767     * </dl>
    1768     *
    1769     * @see org.apache.tapestry5.SymbolConstants#OMIT_GENERATOR_META
    1770     * @see org.apache.tapestry5.http.TapestryHttpSymbolConstants#PRODUCTION_MODE
    1771     * @see org.apache.tapestry5.SymbolConstants#INCLUDE_CORE_STACK
    1772     * @see org.apache.tapestry5.SymbolConstants#ENABLE_PAGELOADING_MASK
    1773     */
    1774    public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration,
    1775
    1776                                         final ModuleManager moduleManager,
    1777
    1778                                         @Symbol(SymbolConstants.OMIT_GENERATOR_META)
    1779                                         final boolean omitGeneratorMeta,
    1780
    1781                                         @Symbol(TapestryHttpSymbolConstants.TAPESTRY_VERSION)
    1782                                         final String tapestryVersion,
    1783
    1784                                         @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
    1785                                         boolean productionMode,
    1786
    1787                                         @Symbol(SymbolConstants.INCLUDE_CORE_STACK)
    1788                                         final boolean includeCoreStack,
    1789
    1790                                         @Symbol(SymbolConstants.ENABLE_PAGELOADING_MASK)
    1791                                         final boolean enablePageloadingMask,
    1792
    1793                                         final ValidationDecoratorFactory validationDecoratorFactory)
    1794    {
    1795        MarkupRendererFilter documentLinker = new MarkupRendererFilter()
    1796        {
    1797            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
    1798            {
    1799                DocumentLinkerImpl linker = new DocumentLinkerImpl(moduleManager, omitGeneratorMeta, enablePageloadingMask, tapestryVersion);
    1800
    1801                environment.push(DocumentLinker.class, linker);
    1802
    1803                renderer.renderMarkup(writer);
    1804
    1805                environment.pop(DocumentLinker.class);
    1806
    1807                linker.updateDocument(writer.getDocument());
    1808            }
    1809        };
    1810
    1811
    1812        MarkupRendererFilter clientBehaviorSupport = new MarkupRendererFilter()
    1813        {
    1814            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
    1815            {
    1816                ClientBehaviorSupportImpl clientBehaviorSupport = new ClientBehaviorSupportImpl();
    1817
    1818                environment.push(ClientBehaviorSupport.class, clientBehaviorSupport);
    1819
    1820                renderer.renderMarkup(writer);
    1821
    1822                environment.pop(ClientBehaviorSupport.class);
    1823            }
    1824        };
    1825
    1826        MarkupRendererFilter heartbeat = new MarkupRendererFilter()
    1827        {
    1828            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
    1829            {
    1830                Heartbeat heartbeat = new HeartbeatImpl();
    1831
    1832                heartbeat.begin();
    1833
    1834                environment.push(Heartbeat.class, heartbeat);
    1835
    1836                renderer.renderMarkup(writer);
    1837
    1838                environment.pop(Heartbeat.class);
    1839
    1840                heartbeat.end();
    1841            }
    1842        };
    1843
    1844        MarkupRendererFilter defaultValidationDecorator = new MarkupRendererFilter()
    1845        {
    1846            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
    1847            {
    1848                ValidationDecorator decorator = validationDecoratorFactory.newInstance(writer);
    1849
    1850                environment.push(ValidationDecorator.class, decorator);
    1851
    1852                renderer.renderMarkup(writer);
    1853
    1854                environment.pop(ValidationDecorator.class);
    1855            }
    1856        };
    1857
    1858        MarkupRendererFilter importCoreStack = new MarkupRendererFilter()
    1859        {
    1860            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
    1861            {
    1862                renderer.renderMarkup(writer);
    1863
    1864                environment.peekRequired(JavaScriptSupport.class).importStack(InternalConstants.CORE_STACK_NAME);
    1865            }
    1866        };
    1867
    1868        configuration.add("DocumentLinker", documentLinker);
    1869        configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:JavaScriptSupport");
    1870        configuration.add("Heartbeat", heartbeat);
    1871        configuration.add("ValidationDecorator", defaultValidationDecorator);
    1872
    1873        if (includeCoreStack)
    1874        {
    1875            configuration.add("ImportCoreStack", importCoreStack);
    1876        }
    1877
    1878        if (productionMode)
    1879        {
    1880            configuration.add("PageNameMeta", null);
    1881        } else
    1882        {
    1883            configuration.addInstance("PageNameMeta", PageNameMetaInjector.class);
    1884        }
    1885    }
    1886
    1887    /**
    1888     * Contributes {@link PartialMarkupRendererFilter}s used when rendering a
    1889     * partial Ajax response.
    1890     * <dl>
    1891     * <dt>DocumentLinker
    1892     * <dd>Provides {@link org.apache.tapestry5.internal.services.DocumentLinker}
    1893     * <dt>ClientBehaviorSupport</dt>
    1894     * <dd>Provides {@link ClientBehaviorSupport}</dd>
    1895     * <dt>Heartbeat</dt>
    1896     * <dd>Provides {@link org.apache.tapestry5.services.Heartbeat}</dd>
    1897     * <dt>DefaultValidationDecorator</dt>
    1898     * <dt>ValidationDecorator</dt>
    1899     * <dd>Provides {@link org.apache.tapestry5.ValidationDecorator} (via {@link ValidationDecoratorFactory#newInstance(org.apache.tapestry5.MarkupWriter)})</dd>
    1900     * </dl>
    1901     */
    1902    public void contributePartialMarkupRenderer(OrderedConfiguration<PartialMarkupRendererFilter> configuration,
    1903
    1904                                                final ValidationDecoratorFactory validationDecoratorFactory)
    1905    {
    1906        PartialMarkupRendererFilter documentLinker = new PartialMarkupRendererFilter()
    1907        {
    1908            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    1909            {
    1910                PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
    1911
    1912                environment.push(DocumentLinker.class, linker);
    1913
    1914                renderer.renderMarkup(writer, reply);
    1915
    1916                environment.pop(DocumentLinker.class);
    1917
    1918                linker.commit(reply);
    1919            }
    1920        };
    1921
    1922
    1923        PartialMarkupRendererFilter clientBehaviorSupport = new PartialMarkupRendererFilter()
    1924        {
    1925            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    1926            {
    1927                ClientBehaviorSupportImpl support = new ClientBehaviorSupportImpl();
    1928
    1929                environment.push(ClientBehaviorSupport.class, support);
    1930
    1931                renderer.renderMarkup(writer, reply);
    1932
    1933                environment.pop(ClientBehaviorSupport.class);
    1934            }
    1935        };
    1936
    1937        PartialMarkupRendererFilter heartbeat = new PartialMarkupRendererFilter()
    1938        {
    1939            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    1940            {
    1941                Heartbeat heartbeat = new HeartbeatImpl();
    1942
    1943                heartbeat.begin();
    1944
    1945                environment.push(Heartbeat.class, heartbeat);
    1946
    1947                renderer.renderMarkup(writer, reply);
    1948
    1949                environment.pop(Heartbeat.class);
    1950
    1951                heartbeat.end();
    1952            }
    1953        };
    1954
    1955        PartialMarkupRendererFilter defaultValidationDecorator = new PartialMarkupRendererFilter()
    1956        {
    1957            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    1958            {
    1959                ValidationDecorator decorator = validationDecoratorFactory.newInstance(writer);
    1960
    1961                environment.push(ValidationDecorator.class, decorator);
    1962
    1963                renderer.renderMarkup(writer, reply);
    1964
    1965                environment.pop(ValidationDecorator.class);
    1966            }
    1967        };
    1968
    1969        configuration.add("DocumentLinker", documentLinker);
    1970        configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:JavaScriptSupport");
    1971        configuration.add("Heartbeat", heartbeat);
    1972        configuration.add("ValidationDecorator", defaultValidationDecorator);
    1973    }
    1974
    1975    /**
    1976     * Contributes several strategies:
    1977     * <dl>
    1978     * <dt>session
    1979     * <dd>Values are stored in the {@link Session}
    1980     * <dt>flash
    1981     * <dd>Values are stored in the {@link Session}, until the next request (for the page)
    1982     * <dt>client
    1983     * <dd>Values are encoded into URLs (or hidden form fields)
    1984     * </dl>
    1985     */
    1986    public void contributePersistentFieldManager(MappedConfiguration<String, PersistentFieldStrategy> configuration,
    1987
    1988                                                 Request request,
    1989
    1990                                                 @InjectService("ClientPersistentFieldStrategy")
    1991                                                 PersistentFieldStrategy clientStrategy)
    1992    {
    1993        configuration.add(PersistenceConstants.SESSION, new SessionPersistentFieldStrategy(request));
    1994        configuration.add(PersistenceConstants.FLASH, new FlashPersistentFieldStrategy(request));
    1995        configuration.add(PersistenceConstants.CLIENT, clientStrategy);
    1996    }
    1997
    1998    /**
    1999     * Contributes {@link ValueEncoder}s or {@link ValueEncoderFactory}s for types:
    2000     * <ul>
    2001     * <li>Object
    2002     * <li>String
    2003     * <li>Enum
    2004     * </ul>
    2005     */
    2006    @SuppressWarnings("all")
    2007    public static void contributeValueEncoderSource(MappedConfiguration<Class, Object> configuration)
    2008    {
    2009        configuration.addInstance(Object.class, TypeCoercedValueEncoderFactory.class);
    2010        configuration.add(String.class, new StringValueEncoder());
    2011    }
    2012
    2013    /**
    2014     * Contributes a single filter, "Secure", which checks for non-secure
    2015     * requests that access secure pages.
    2016     */
    2017    public void contributePageRenderRequestHandler(OrderedConfiguration<PageRenderRequestFilter> configuration,
    2018                                                   final RequestSecurityManager securityManager)
    2019    {
    2020        PageRenderRequestFilter secureFilter = new PageRenderRequestFilter()
    2021        {
    2022            public void handle(PageRenderRequestParameters parameters, PageRenderRequestHandler handler)
    2023                    throws IOException
    2024            {
    2025
    2026                if (securityManager.checkForInsecurePageRenderRequest(parameters))
    2027                    return;
    2028
    2029                handler.handle(parameters);
    2030            }
    2031        };
    2032
    2033        configuration.add("Secure", secureFilter);
    2034    }
    2035
    2036    public static void contributeTemplateParser(MappedConfiguration<String, URL> config)
    2037    {
    2038        // Any class inside the internal module would do. Or we could move all
    2039        // these
    2040        // files to o.a.t.services.
    2041
    2042        Class c = TemplateParserImpl.class;
    2043
    2044        config.add("-//W3C//DTD XHTML 1.0 Strict//EN", c.getResource("xhtml1-strict.dtd"));
    2045        config.add("-//W3C//DTD XHTML 1.0 Transitional//EN", c.getResource("xhtml1-transitional.dtd"));
    2046        config.add("-//W3C//DTD XHTML 1.0 Frameset//EN", c.getResource("xhtml1-frameset.dtd"));
    2047        config.add("-//W3C//DTD HTML 4.01//EN", c.getResource("xhtml1-strict.dtd"));
    2048        config.add("-//W3C//DTD HTML 4.01 Transitional//EN", c.getResource("xhtml1-transitional.dtd"));
    2049        config.add("-//W3C//DTD HTML 4.01 Frameset//EN", c.getResource("xhtml1-frameset.dtd"));
    2050        config.add("-//W3C//ENTITIES Latin 1 for XHTML//EN", c.getResource("xhtml-lat1.ent"));
    2051        config.add("-//W3C//ENTITIES Symbols for XHTML//EN", c.getResource("xhtml-symbol.ent"));
    2052        config.add("-//W3C//ENTITIES Special for XHTML//EN", c.getResource("xhtml-special.ent"));
    2053    }
    2054
    2055    /**
    2056     * Contributes factory defaults that may be overridden.
    2057     */
    2058    public static void contributeFactoryDefaults(MappedConfiguration<String, Object> configuration)
    2059    {
    2060        // Remember this is request-to-request time, presumably it'll take the
    2061        // developer more than
    2062        // one second to make a change, save it, and switch back to the browser.
    2063
    2064        configuration.add(SymbolConstants.FILE_CHECK_INTERVAL, "1 s");
    2065        configuration.add(SymbolConstants.FILE_CHECK_UPDATE_TIMEOUT, "50 ms");
    2066
    2067        // This should be overridden for particular applications. These are the
    2068        // locales for which we have (at least some) localized messages.
    2069        configuration.add(SymbolConstants.SUPPORTED_LOCALES,
    2070                "en,it,es,zh_CN,pt_PT,de,ru,hr,fi_FI,sv_SE,fr,da,pt_BR,ja,el,bg,nn,nb,sr_RS,mk_MK");
    2071
    2072        configuration.add(SymbolConstants.COOKIE_MAX_AGE, "7 d");
    2073
    2074        configuration.add(SymbolConstants.START_PAGE_NAME, "start");
    2075
    2076        configuration.add(TapestryHttpSymbolConstants.PRODUCTION_MODE, true);
    2077
    2078        configuration.add(SymbolConstants.COMPRESS_WHITESPACE, true);
    2079
    2080        configuration.add(MetaDataConstants.SECURE_PAGE, false);
    2081
    2082        configuration.add(SymbolConstants.FORM_CLIENT_LOGIC_ENABLED, true);
    2083
    2084        // This is designed to make it easy to keep synchronized with
    2085        // script.aculo.ous. As we support a new version, we create a new folder, and update the
    2086        // path entry. We can then delete the old version folder (or keep it around). This should
    2087        // be more manageable than overwriting the local copy with updates (it's too easy for
    2088        // files deleted between scriptaculous releases to be accidentally left lying around).
    2089        // There's also a ClasspathAliasManager contribution based on the path.
    2090
    2091        configuration.add(SymbolConstants.SCRIPTACULOUS, "${tapestry.asset.root}/scriptaculous_1_9_0");
    2092
    2093        // Likewise for WebFX DatePicker, currently version 1.0.6
    2094
    2095        configuration.add(SymbolConstants.DATEPICKER, "${tapestry.asset.root}/datepicker_106");
    2096
    2097        configuration.add(SymbolConstants.PERSISTENCE_STRATEGY, PersistenceConstants.SESSION);
    2098
    2099        configuration.add(MetaDataConstants.RESPONSE_CONTENT_TYPE, "text/html");
    2100
    2101        configuration.add(SymbolConstants.APPLICATION_CATALOG,
    2102                String.format("context:WEB-INF/${%s}.properties", TapestryHttpInternalSymbols.APP_NAME));
    2103
    2104        configuration.add(SymbolConstants.EXCEPTION_REPORT_PAGE, "ExceptionReport");
    2105
    2106        configuration.add(SymbolConstants.OMIT_GENERATOR_META, false);
    2107
    2108        configuration.add(SymbolConstants.SECURE_ENABLED, SymbolConstants.PRODUCTION_MODE_VALUE);
    2109        configuration.add(SymbolConstants.COMPACT_JSON, SymbolConstants.PRODUCTION_MODE_VALUE);
    2110
    2111        configuration.add(SymbolConstants.ENCODE_LOCALE_INTO_PATH, true);
    2112
    2113        configuration.add(InternalSymbols.RESERVED_FORM_CONTROL_NAMES, "reset,submit,select,id,method,action,onsubmit," + InternalConstants.CANCEL_NAME);
    2114
    2115        configuration.add(SymbolConstants.COMPONENT_RENDER_TRACING_ENABLED, false);
    2116
    2117        configuration.add(SymbolConstants.APPLICATION_FOLDER, "");
    2118
    2119        // Grid component parameter defaults
    2120        configuration.add(ComponentParameterConstants.GRID_ROWS_PER_PAGE, GridConstants.ROWS_PER_PAGE);
    2121        configuration.add(ComponentParameterConstants.GRID_PAGER_POSITION, GridConstants.PAGER_POSITION);
    2122        configuration.add(ComponentParameterConstants.GRID_EMPTY_BLOCK, GridConstants.EMPTY_BLOCK);
    2123        configuration.add(ComponentParameterConstants.GRID_TABLE_CSS_CLASS, GridConstants.TABLE_CLASS);
    2124        configuration.add(ComponentParameterConstants.GRIDPAGER_PAGE_RANGE, GridConstants.PAGER_PAGE_RANGE);
    2125        configuration.add(ComponentParameterConstants.GRIDCOLUMNS_SORTABLE_ASSET, GridConstants.COLUMNS_SORTABLE);
    2126        configuration.add(ComponentParameterConstants.GRIDCOLUMNS_ASCENDING_ASSET, GridConstants.COLUMNS_ASCENDING);
    2127        configuration.add(ComponentParameterConstants.GRIDCOLUMNS_DESCENDING_ASSET, GridConstants.COLUMNS_DESCENDING);
    2128
    2129        // FormInjector component parameter defaults
    2130        configuration.add(ComponentParameterConstants.FORMINJECTOR_INSERT_POSITION, "above");
    2131        configuration.add(ComponentParameterConstants.FORMINJECTOR_SHOW_FUNCTION, "highlight");
    2132
    2133        // Palette component parameter defaults
    2134        configuration.add(ComponentParameterConstants.PALETTE_ROWS_SIZE, 10);
    2135
    2136        // Defaults for components that use a SelectModel
    2137        configuration.add(ComponentParameterConstants.VALIDATE_WITH_MODEL, SecureOption.AUTO);
    2138
    2139        // Zone component parameters defaults
    2140        configuration.add(ComponentParameterConstants.ZONE_SHOW_METHOD, "show");
    2141        configuration.add(ComponentParameterConstants.ZONE_UPDATE_METHOD, "highlight");
    2142
    2143        // By default, no page is on the whitelist unless it has the @WhitelistAccessOnly annotation
    2144        configuration.add(MetaDataConstants.WHITELIST_ONLY_PAGE, false);
    2145
    2146        configuration.add(TapestryHttpSymbolConstants.CONTEXT_PATH, "");
    2147
    2148        // Leaving this as the default results in a runtime error logged to the console (and a default password is used);
    2149        // you are expected to override this symbol.
    2150        configuration.add(SymbolConstants.HMAC_PASSPHRASE, "");
    2151
    2152        // TAP5-2070 keep the old behavior, defaults to false
    2153        configuration.add(MetaDataConstants.UNKNOWN_ACTIVATION_CONTEXT_CHECK, false);
    2154
    2155        // TAP5-2197
    2156        configuration.add(SymbolConstants.INCLUDE_CORE_STACK, true);
    2157
    2158        // TAP5-2182
    2159        configuration.add(SymbolConstants.FORM_GROUP_WRAPPER_CSS_CLASS, "form-group");
    2160        configuration.add(SymbolConstants.FORM_GROUP_LABEL_CSS_CLASS, "control-label");
    2161        configuration.add(SymbolConstants.FORM_GROUP_FORM_FIELD_WRAPPER_ELEMENT_NAME, "");
    2162        configuration.add(SymbolConstants.FORM_GROUP_FORM_FIELD_WRAPPER_ELEMENT_CSS_CLASS, "");
    2163        configuration.add(SymbolConstants.FORM_FIELD_CSS_CLASS, "form-control");
    2164
    2165        // Grid's default table CSS class comes from the ComponentParameterConstants.GRID_TABLE_CSS_CLASS symbol
    2166        configuration.add(SymbolConstants.BEAN_DISPLAY_CSS_CLASS, "well dl-horizontal");
    2167        configuration.add(SymbolConstants.BEAN_EDITOR_BOOLEAN_PROPERTY_DIV_CSS_CLASS, "input-group");
    2168        configuration.add(SymbolConstants.ERROR_CSS_CLASS, "help-block");
    2169        configuration.add(SymbolConstants.AJAX_FORM_LOOP_ADD_ROW_LINK_CSS_CLASS, "btn btn-default btn-sm");
    2170        configuration.add(SymbolConstants.ERRORS_BASE_CSS_CLASS, "alert-dismissable");
    2171        configuration.add(SymbolConstants.ERRORS_DEFAULT_CLASS_PARAMETER_VALUE, "alert alert-danger");
    2172        configuration.add(SymbolConstants.ERRORS_CLOSE_BUTTON_CSS_CLASS, "close");
    2173
    2174        // TAP5-1998
    2175        configuration.add(SymbolConstants.LENIENT_DATE_FORMAT, false);
    2176
    2177        // TAP5-2187
    2178        configuration.add(SymbolConstants.STRICT_CSS_URL_REWRITING, false);
    2179
    2180        configuration.add(SymbolConstants.EXCEPTION_REPORTS_DIR, "build/exceptions");
    2181
    2182        // TAP5-1815
    2183        configuration.add(SymbolConstants.ENABLE_HTML5_SUPPORT, false);
    2184
    2185        configuration.add(SymbolConstants.RESTRICTIVE_ENVIRONMENT, false);
    2186
    2187        configuration.add(SymbolConstants.ENABLE_PAGELOADING_MASK, true);
    2188        configuration.add(SymbolConstants.PRELOADER_MODE, PreloaderMode.PRODUCTION);
    2189
    2190        configuration.add(SymbolConstants.OPENAPI_VERSION, "3.0.0");
    2191        configuration.add(SymbolConstants.PUBLISH_OPENAPI_DEFINITON, "false");
    2192        configuration.add(SymbolConstants.OPENAPI_DESCRIPTION_PATH, "/openapi.json");
    2193        configuration.add(SymbolConstants.OPENAPI_BASE_PATH, "/");
    2194    }
    2195
    2196    /**
    2197     * Adds a listener to the {@link org.apache.tapestry5.internal.services.ComponentInstantiatorSource} that clears the
    2198     * {@link PropertyAccess} and {@link TypeCoercer} caches on
    2199     * a class loader invalidation. In addition, forces the
    2200     * realization of {@link ComponentClassResolver} at startup.
    2201     */
    2202    public void contributeApplicationInitializer(OrderedConfiguration<ApplicationInitializerFilter> configuration,
    2203                                                 final TypeCoercer typeCoercer, final ComponentClassResolver componentClassResolver, @ComponentClasses
    2204    final InvalidationEventHub invalidationEventHub, final @Autobuild
    2205                                                 RestoreDirtySessionObjects restoreDirtySessionObjects)
    2206    {
    2207        final Runnable callback = new Runnable()
    2208        {
    2209            public void run()
    2210            {
    2211                propertyAccess.clearCache();
    2212
    2213                typeCoercer.clearCache();
    2214            }
    2215        };
    2216
    2217        ApplicationInitializerFilter clearCaches = new ApplicationInitializerFilter()
    2218        {
    2219            public void initializeApplication(Context context, ApplicationInitializer initializer)
    2220            {
    2221                // Snuck in here is the logic to clear the PropertyAccess
    2222                // service's cache whenever
    2223                // the component class loader is invalidated.
    2224
    2225                invalidationEventHub.addInvalidationCallback(callback);
    2226
    2227                endOfRequestEventHub.addEndOfRequestListener(restoreDirtySessionObjects);
    2228
    2229                // Perform other pending initialization
    2230
    2231                initializer.initializeApplication(context);
    2232
    2233                // We don't care about the result, but this forces a load of the
    2234                // service
    2235                // at application startup, rather than on first request.
    2236
    2237                componentClassResolver.isPageName("ForceLoadAtStartup");
    2238            }
    2239        };
    2240
    2241        configuration.add("ClearCachesOnInvalidation", clearCaches);
    2242    }
    2243
    2244    /**
    2245     * Contributes filters:
    2246     * <dl>
    2247     * <dt>Ajax</dt>
    2248     * <dd>Determines if the request is Ajax oriented, and redirects to an alternative handler if so</dd>
    2249     * <dt>Secure</dt>
    2250     * <dd>Sends a redirect if an non-secure request accesses a secure page</dd>
    2251     * </dl>
    2252     */
    2253    public void contributeComponentEventRequestHandler(OrderedConfiguration<ComponentEventRequestFilter> configuration,
    2254                                                       final RequestSecurityManager requestSecurityManager, @Ajax
    2255    ComponentEventRequestHandler ajaxHandler)
    2256    {
    2257        ComponentEventRequestFilter secureFilter = new ComponentEventRequestFilter()
    2258        {
    2259            public void handle(ComponentEventRequestParameters parameters, ComponentEventRequestHandler handler)
    2260                    throws IOException
    2261            {
    2262                if (requestSecurityManager.checkForInsecureComponentEventRequest(parameters))
    2263                    return;
    2264
    2265                handler.handle(parameters);
    2266            }
    2267        };
    2268        configuration.add("Secure", secureFilter);
    2269
    2270        configuration.add("Ajax", new AjaxFilter(request, ajaxHandler));
    2271    }
    2272
    2273    /**
    2274     * Contributes:
    2275     * <dl>
    2276     * <dt>AjaxFormUpdate</dt>
    2277     * <dd>{@link AjaxFormUpdateFilter}</dd>
    2278     * </dl>
    2279     *
    2280     * @since 5.2.0
    2281     */
    2282    public static void contributeAjaxComponentEventRequestHandler(
    2283            OrderedConfiguration<ComponentEventRequestFilter> configuration)
    2284    {
    2285        configuration.addInstance("AjaxFormUpdate", AjaxFormUpdateFilter.class);
    2286    }
    2287
    2288    /**
    2289     * Contributes strategies accessible via the {@link NullFieldStrategySource} service.
    2290     *
    2291     * <dl>
    2292     * <dt>default</dt>
    2293     * <dd>Does nothing, nulls stay null.</dd>
    2294     * <dt>zero</dt>
    2295     * <dd>Null values are converted to zero.</dd>
    2296     * </dl>
    2297     */
    2298    public static void contributeNullFieldStrategySource(MappedConfiguration<String, NullFieldStrategy> configuration)
    2299    {
    2300        configuration.add("default", new DefaultNullFieldStrategy());
    2301        configuration.add("zero", new ZeroNullFieldStrategy());
    2302    }
    2303
    2304    /**
    2305     * Determines positioning of hidden fields relative to other elements (this
    2306     * is needed by {@link org.apache.tapestry5.corelib.components.FormFragment} and others.
    2307     *
    2308     * For elements input, select, textarea and label the hidden field is positioned after.
    2309     *
    2310     * For elements p, div, li and td, the hidden field is positioned inside.
    2311     */
    2312    public static void contributeHiddenFieldLocationRules(
    2313            MappedConfiguration<String, RelativeElementPosition> configuration)
    2314    {
    2315        configuration.add("input", RelativeElementPosition.AFTER);
    2316        configuration.add("select", RelativeElementPosition.AFTER);
    2317        configuration.add("textarea", RelativeElementPosition.AFTER);
    2318        configuration.add("label", RelativeElementPosition.AFTER);
    2319
    2320        configuration.add("p", RelativeElementPosition.INSIDE);
    2321        configuration.add("div", RelativeElementPosition.INSIDE);
    2322        configuration.add("td", RelativeElementPosition.INSIDE);
    2323        configuration.add("li", RelativeElementPosition.INSIDE);
    2324    }
    2325
    2326    /**
    2327     * @since 5.1.0.0
    2328     */
    2329    public static LinkCreationHub buildLinkCreationHub(LinkSource source)
    2330    {
    2331        return source.getLinkCreationHub();
    2332    }
    2333
    2334    /**
    2335     * Exposes the public portion of the internal {@link InternalComponentInvalidationEventHub} service.
    2336     *
    2337     * @since 5.1.0.0
    2338     */
    2339    @Marker(ComponentClasses.class)
    2340    public static InvalidationEventHub buildComponentClassesInvalidationEventHub(
    2341            InternalComponentInvalidationEventHub trueHub)
    2342    {
    2343        return trueHub;
    2344    }
    2345
    2346    /**
    2347     * @since 5.1.0.0
    2348     */
    2349    @Marker(ComponentTemplates.class)
    2350    public static InvalidationEventHub buildComponentTemplatesInvalidationEventHub(
    2351            ComponentTemplateSource templateSource)
    2352    {
    2353        return templateSource.getInvalidationEventHub();
    2354    }
    2355
    2356    /**
    2357     * @since 5.1.0.0
    2358     */
    2359    @Marker(ComponentMessages.class)
    2360    public static InvalidationEventHub buildComponentMessagesInvalidationEventHub(ComponentMessagesSource messagesSource)
    2361    {
    2362        return messagesSource.getInvalidationEventHub();
    2363    }
    2364
    2365    @Scope(ScopeConstants.PERTHREAD)
    2366    public Environment buildEnvironment(PerthreadManager perthreadManager)
    2367    {
    2368        final EnvironmentImpl service = new EnvironmentImpl();
    2369
    2370        perthreadManager.addThreadCleanupCallback(new Runnable()
    2371        {
    2372            public void run()
    2373            {
    2374                service.threadDidCleanup();
    2375            }
    2376        });
    2377
    2378        return service;
    2379    }
    2380
    2381    /**
    2382     * @since 5.1.1.0
    2383     */
    2384    @Marker(Primary.class)
    2385    public StackTraceElementAnalyzer buildMasterStackTraceElementAnalyzer(List<StackTraceElementAnalyzer> configuration)
    2386    {
    2387        return chainBuilder.build(StackTraceElementAnalyzer.class, configuration);
    2388    }
    2389
    2390    /**
    2391     * Contributes:
    2392     * <dl>
    2393     * <dt>Application</dt>
    2394     * <dd>Checks for classes in the application package</dd>
    2395     * <dt>Proxies</dt>
    2396     * <dd>Checks for classes that appear to be generated proxies.</dd>
    2397     * <dt>SunReflect</dt>
    2398     * <dd>Checks for <code>sun.reflect</code> (which are omitted)
    2399     * <dt>TapestryAOP</dt>
    2400     * <dd>Omits stack frames for classes related to Tapestry AOP (such as advice, etc.)</dd>
    2401     * <dt>OperationTracker</dt>
    2402     * <dd>Omits stack frames related to {@link OperationTracker}</dd>
    2403     * <dt>Access</dt>
    2404     * <dd>Omits stack frames used to provide access to container class private members</dd>
    2405     * </dl>
    2406     *
    2407     * @since 5.1.0.0
    2408     */
    2409    public static void contributeMasterStackTraceElementAnalyzer(
    2410            OrderedConfiguration<StackTraceElementAnalyzer> configuration)
    2411    {
    2412        configuration.addInstance("TapestryAOP", TapestryAOPStackFrameAnalyzer.class);
    2413        configuration.add("Proxies", new ProxiesStackTraceElementAnalyzer());
    2414        configuration.add("Synthetic", new SyntheticStackTraceElementAnalyzer());
    2415        configuration.add("SunReflect", new PrefixCheckStackTraceElementAnalyzer(
    2416                StackTraceElementClassConstants.OMITTED, "sun.reflect."));
    2417        configuration.add("OperationTracker", new RegexpStackTraceElementAnalyzer(Pattern.compile("internal\\.(RegistryImpl|PerThreadOperationTracker|OperationTrackerImpl).*(run|invoke|perform)\\("), StackTraceElementClassConstants.OMITTED));
    2418        configuration.add("Access", new RegexpStackTraceElementAnalyzer(Pattern.compile("\\.access\\$\\d+\\("), StackTraceElementClassConstants.OMITTED));
    2419
    2420        configuration.addInstance("Application", ApplicationStackTraceElementAnalyzer.class);
    2421
    2422    }
    2423
    2424
    2425    /**
    2426     * Advises the {@link org.apache.tapestry5.services.messages.ComponentMessagesSource} service so
    2427     * that the creation
    2428     * of {@link org.apache.tapestry5.commons.Messages} instances can be deferred.
    2429     *
    2430     * @since 5.1.0.0
    2431     */
    2432    @Match("ComponentMessagesSource")
    2433    public static void adviseLazy(LazyAdvisor advisor, MethodAdviceReceiver receiver)
    2434    {
    2435        advisor.addLazyMethodInvocationAdvice(receiver);
    2436    }
    2437
    2438    /**
    2439     * @since 5.1.0.0
    2440     */
    2441    public ComponentRequestHandler buildComponentRequestHandler(List<ComponentRequestFilter> configuration,
    2442
    2443                                                                @Autobuild
    2444                                                                ComponentRequestHandlerTerminator terminator,
    2445
    2446                                                                Logger logger)
    2447    {
    2448        return pipelineBuilder.build(logger, ComponentRequestHandler.class, ComponentRequestFilter.class,
    2449                configuration, terminator);
    2450    }
    2451
    2452    /**
    2453     * Contributes:
    2454     * <dl>
    2455     * <dt>OperationTracker</dt>
    2456     * <dd>Tracks general information about the request using {@link OperationTracker}</dd>
    2457     * <dt>UnknownComponentFilter (production mode only)</dt>
    2458     * <dd>{@link org.apache.tapestry5.internal.services.ProductionModeUnknownComponentFilter} - Detects request with unknown component and aborts handling to ultimately deliver a 404 response</dd>
    2459     * <dt>InitializeActivePageName
    2460     * <dd>{@link InitializeActivePageName}
    2461     * <dt>DeferredResponseRenderer</dt>
    2462     * <dd>{@link DeferredResponseRenderer}</dd>
    2463     * </dl>
    2464     *
    2465     * @since 5.2.0
    2466     */
    2467    public void contributeComponentRequestHandler(OrderedConfiguration<ComponentRequestFilter> configuration, @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE) boolean productionMode)
    2468    {
    2469        configuration.addInstance("OperationTracker", RequestOperationTracker.class);
    2470
    2471        if (productionMode)
    2472        {
    2473            configuration.addInstance("UnknownComponentFilter", ProductionModeUnknownComponentFilter.class);
    2474        }
    2475
    2476        configuration.addInstance("InitializeActivePageName", InitializeActivePageName.class);
    2477        configuration.addInstance("DeferredResponseRenderer", DeferredResponseRenderer.class);
    2478    }
    2479
    2480    /**
    2481     * Decorate FieldValidatorDefaultSource to setup the EnvironmentMessages
    2482     * object and place it in the environment.
    2483     * Although this could have been implemented directly in the default
    2484     * implementation of the service, doing it
    2485     * as service decoration ensures that the environment will be properly setup
    2486     * even if a user overrides the default
    2487     * service implementation.
    2488     *
    2489     * @param defaultSource
    2490     *         The service to decorate
    2491     * @param environment
    2492     */
    2493    public static FieldValidatorDefaultSource decorateFieldValidatorDefaultSource(
    2494            final FieldValidatorDefaultSource defaultSource, final Environment environment)
    2495    {
    2496        return new FieldValidatorDefaultSource()
    2497        {
    2498
    2499            public FieldValidator createDefaultValidator(Field field, String overrideId, Messages overrideMessages,
    2500                                                         Locale locale, Class propertyType, AnnotationProvider propertyAnnotations)
    2501            {
    2502                environment.push(EnvironmentMessages.class, new EnvironmentMessages(overrideMessages, overrideId));
    2503                FieldValidator fieldValidator = defaultSource.createDefaultValidator(field, overrideId,
    2504                        overrideMessages, locale, propertyType, propertyAnnotations);
    2505                environment.pop(EnvironmentMessages.class);
    2506                return fieldValidator;
    2507            }
    2508
    2509            public FieldValidator createDefaultValidator(ComponentResources resources, String parameterName)
    2510            {
    2511
    2512                EnvironmentMessages em = new EnvironmentMessages(resources.getContainerMessages(), resources.getId());
    2513                environment.push(EnvironmentMessages.class, em);
    2514                FieldValidator fieldValidator = defaultSource.createDefaultValidator(resources, parameterName);
    2515                environment.pop(EnvironmentMessages.class);
    2516                return fieldValidator;
    2517            }
    2518        };
    2519    }
    2520
    2521    /**
    2522     * Exposes the Environmental {@link Heartbeat} as an injectable service.
    2523     *
    2524     * @since 5.2.0
    2525     */
    2526    public Heartbeat buildHeartbeat()
    2527    {
    2528        return environmentalBuilder.build(Heartbeat.class);
    2529    }
    2530
    2531    public static ComponentMessagesSource buildComponentMessagesSource(UpdateListenerHub updateListenerHub, @Autobuild
    2532    ComponentMessagesSourceImpl service)
    2533    {
    2534        updateListenerHub.addUpdateListener(service);
    2535
    2536        return service;
    2537    }
    2538
    2539    /**
    2540     * Contributes extractors for {@link Meta}, {@link Secure}, {@link ContentType} and {@link WhitelistAccessOnly} annotations.
    2541     *
    2542     * @since 5.2.0
    2543     */
    2544    @SuppressWarnings("unchecked")
    2545    public static void contributeMetaWorker(MappedConfiguration<Class, MetaDataExtractor> configuration)
    2546    {
    2547        configuration.addInstance(Meta.class, MetaAnnotationExtractor.class);
    2548        configuration.add(Secure.class, new FixedExtractor(MetaDataConstants.SECURE_PAGE));
    2549        configuration.addInstance(ContentType.class, ContentTypeExtractor.class);
    2550        configuration.add(WhitelistAccessOnly.class, new FixedExtractor(MetaDataConstants.WHITELIST_ONLY_PAGE));
    2551        configuration.addInstance(UnknownActivationContextCheck.class, UnknownActivationContextExtractor.class);
    2552    }
    2553
    2554    /**
    2555     * Builds the {@link ComponentTemplateLocator} as a chain of command.
    2556     *
    2557     * @since 5.2.0
    2558     */
    2559    @Marker(Primary.class)
    2560    public ComponentTemplateLocator buildComponentTemplateLocator(List<ComponentTemplateLocator> configuration)
    2561    {
    2562        return chainBuilder.build(ComponentTemplateLocator.class, configuration);
    2563    }
    2564
    2565    /**
    2566     * Contributes two template locators:
    2567     * <dl>
    2568     * <dt>Default</dt>
    2569     * <dd>Searches for the template on the classpath ({@link DefaultTemplateLocator}</dd>
    2570     * <dt>Page</dt>
    2571     * <dd>Searches for <em>page</em> templates in the context ({@link PageTemplateLocator})</dd>
    2572     * </dl>
    2573     *
    2574     * @since 5.2.0
    2575     */
    2576    public static void contributeComponentTemplateLocator(OrderedConfiguration<ComponentTemplateLocator> configuration,
    2577                                                          @ContextProvider
    2578                                                          AssetFactory contextAssetFactory,
    2579                                                          @Symbol(SymbolConstants.APPLICATION_FOLDER) String applicationFolder,
    2580                                                          ComponentClassResolver componentClassResolver)
    2581    {
    2582        configuration.add("Default", new DefaultTemplateLocator());
    2583        configuration
    2584                .add("Page", new PageTemplateLocator(contextAssetFactory.getRootResource(), componentClassResolver, applicationFolder));
    2585
    2586    }
    2587
    2588    /**
    2589     * Builds {@link ComponentEventLinkTransformer} service as a chain of command.
    2590     *
    2591     * @since 5.2.0
    2592     */
    2593    @Marker(Primary.class)
    2594    public ComponentEventLinkTransformer buildComponentEventLinkTransformer(
    2595            List<ComponentEventLinkTransformer> configuration)
    2596    {
    2597        return chainBuilder.build(ComponentEventLinkTransformer.class, configuration);
    2598    }
    2599
    2600    /**
    2601     * Builds {@link PageRenderLinkTransformer} service as a chain of command.
    2602     *
    2603     * @since 5.2.0
    2604     */
    2605    @Marker(Primary.class)
    2606    public PageRenderLinkTransformer buildPageRenderLinkTransformer(List<PageRenderLinkTransformer> configuration)
    2607    {
    2608        return chainBuilder.build(PageRenderLinkTransformer.class, configuration);
    2609    }
    2610
    2611    /**
    2612     * Provides the "LinkTransformer" interceptor for the {@link ComponentEventLinkEncoder} service.
    2613     * Other decorations
    2614     * should come after LinkTransformer.
    2615     *
    2616     * @since 5.2.0
    2617     */
    2618    @Match("ComponentEventLinkEncoder")
    2619    public ComponentEventLinkEncoder decorateLinkTransformer(LinkTransformer linkTransformer,
    2620                                                             ComponentEventLinkEncoder delegate)
    2621    {
    2622        return new LinkTransformerInterceptor(linkTransformer, delegate);
    2623    }
    2624
    2625    /**
    2626     * In production mode, override {@link UpdateListenerHub} to be an empty placeholder.
    2627     */
    2628    @Contribute(ServiceOverride.class)
    2629    public static void productionModeOverrides(MappedConfiguration<Class, Object> configuration,
    2630                                               @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
    2631                                               boolean productionMode)
    2632    {
    2633        if (productionMode)
    2634        {
    2635            configuration.add(UpdateListenerHub.class, new UpdateListenerHub()
    2636            {
    2637                public void fireCheckForUpdates()
    2638                {
    2639                }
    2640
    2641                public void addUpdateListener(UpdateListener listener)
    2642                {
    2643
    2644                }
    2645            });
    2646        }
    2647    }
    2648
    2649    /**
    2650     * Contributes a single default analyzer:
    2651     * <dl>
    2652     * <dt>LocalhostOnly</dt>
    2653     * <dd>Identifies requests from localhost as on client whitelist</dd>
    2654     * </dl>
    2655     *
    2656     * @since 5.3
    2657     */
    2658    @Contribute(ClientWhitelist.class)
    2659    public static void defaultWhitelist(OrderedConfiguration<WhitelistAnalyzer> configuration)
    2660    {
    2661        configuration.add("LocalhostOnly", new LocalhostOnly());
    2662    }
    2663
    2664    @Startup
    2665    public static void registerToClearPlasticProxyFactoryOnInvalidation(@ComponentClasses InvalidationEventHub hub, @Builtin final PlasticProxyFactory proxyFactory)
    2666    {
    2667        hub.addInvalidationCallback(new Runnable()
    2668        {
    2669            public void run()
    2670            {
    2671                proxyFactory.clearCache();
    2672            }
    2673        });
    2674    }
    2675
    2676    /**
    2677     * @since 5.4
    2678     */
    2679    @Contribute(ValueLabelProvider.class)
    2680    public void defaultValueLabelProviders(MappedConfiguration<Class, ValueLabelProvider> configuration)
    2681    {
    2682        configuration.addInstance(Object.class, DefaultValueLabelProvider.class);
    2683        configuration.addInstance(Enum.class, EnumValueLabelProvider.class);
    2684    }
    2685
    2686    /**
    2687     * @since 5.4
    2688     */
    2689    public ValueLabelProvider<?> buildValueLabelProvider(Map<Class, ValueLabelProvider> configuration)
    2690    {
    2691        return strategyBuilder.build(ValueLabelProvider.class, configuration);
    2692    }
    2693
    2694    @Advise(serviceInterface = ComponentInstantiatorSource.class)
    2695    public static void componentReplacer(MethodAdviceReceiver methodAdviceReceiver,
    2696                                         final ComponentOverride componentReplacer) throws NoSuchMethodException, SecurityException
    2697    {
    2698
    2699        if (componentReplacer.hasReplacements())
    2700        {
    2701
    2702            MethodAdvice advice = new MethodAdvice()
    2703            {
    2704                @Override
    2705                public void advise(MethodInvocation invocation)
    2706                {
    2707                    String className = (String) invocation.getParameter(0);
    2708                    final Class<?> replacement = componentReplacer.getReplacement(className);
    2709                    if (replacement != null)
    2710                    {
    2711                        invocation.setParameter(0, replacement.getName());
    2712                    }
    2713                    invocation.proceed();
    2714                }
    2715            };
    2716
    2717            methodAdviceReceiver.adviseMethod(
    2718                    ComponentInstantiatorSource.class.getMethod("getInstantiator", String.class), advice);
    2719
    2720        }
    2721    }
    2722
    2723    public static ComponentLibraryInfoSource buildComponentLibraryInfoSource(List<ComponentLibraryInfoSource> configuration,
    2724                                                                             ChainBuilder chainBuilder)
    2725    {
    2726        return chainBuilder.build(ComponentLibraryInfoSource.class, configuration);
    2727    }
    2728
    2729    @Contribute(ComponentLibraryInfoSource.class)
    2730    public static void addBuiltInComponentLibraryInfoSources(OrderedConfiguration<ComponentLibraryInfoSource> configuration)
    2731    {
    2732        configuration.addInstance("Maven", MavenComponentLibraryInfoSource.class);
    2733        configuration.add("TapestryCore", new TapestryCoreComponentLibraryInfoSource());
    2734    }
    2735
    2736    public static OpenApiDescriptionGenerator buildOpenApiDocumentationGenerator(List<OpenApiDescriptionGenerator> configuration,
    2737            ChainBuilder chainBuilder)
    2738    {
    2739        return chainBuilder.build(OpenApiDescriptionGenerator.class, configuration);
    2740    }
    2741
    2742    public static OpenApiTypeDescriber buildOpenApiTypeDescriber(List<OpenApiTypeDescriber> configuration,
    2743            ChainBuilder chainBuilder)
    2744    {
    2745        return chainBuilder.build(OpenApiTypeDescriber.class, configuration);
    2746    }
    2747
    2748    @Contribute(OpenApiDescriptionGenerator.class)
    2749    public static void addBuiltInOpenApiDocumentationGenerator(
    2750            OrderedConfiguration<OpenApiDescriptionGenerator> configuration) {
    2751        configuration.addInstance("Default", DefaultOpenApiDescriptionGenerator.class, "before:*");
    2752    }
    2753
    2754    @Contribute(OpenApiTypeDescriber.class)
    2755    public static void addBuiltInOpenApiTypeDescriber(
    2756            OrderedConfiguration<OpenApiTypeDescriber> configuration) {
    2757        configuration.addInstance("Default", DefaultOpenApiTypeDescriber.class, "before:*");
    2758    }
    2759
    2760    /**
    2761     * Contributes the package "&lt;root&gt;.rest.entities" to the configuration,
    2762     * so that it will be scanned for mapped entity classes.
    2763     */
    2764    public static void contributeMappedEntityManager(Configuration<String> configuration,
    2765            @Symbol(TapestryHttpInternalConstants.TAPESTRY_APP_PACKAGE_PARAM) String appRootPackage)
    2766    {
    2767        configuration.add(appRootPackage + ".rest.entities");
    2768    }
    2769
    2770    private static final class TapestryCoreComponentLibraryInfoSource implements
    2771            ComponentLibraryInfoSource
    2772    {
    2773        @Override
    2774        public ComponentLibraryInfo find(LibraryMapping libraryMapping)
    2775        {
    2776            ComponentLibraryInfo info = null;
    2777            if (libraryMapping.libraryName.equals("core"))
    2778            {
    2779
    2780                info = new ComponentLibraryInfo();
    2781
    2782                // the information above will probably not change in the future, or change very
    2783                // infrequently, so I see no problem in hardwiring them here.
    2784                info.setArtifactId("tapestry-core");
    2785                info.setGroupId("org.apache.tapestry");
    2786                info.setName("Tapestry 5 core component library");
    2787                info.setDescription("Components provided out-of-the-box by Tapestry");
    2788                info.setDocumentationUrl("http://tapestry.apache.org/component-reference.html");
    2789                info.setJavadocUrl("http://tapestry.apache.org/current/apidocs/");
    2790                info.setSourceBrowseUrl("https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary");
    2791                info.setSourceRootUrl("https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=blob;f=tapestry-core/src/main/java/");
    2792                info.setIssueTrackerUrl("https://issues.apache.org/jira/browse/TAP5");
    2793                info.setHomepageUrl("http://tapestry.apache.org");
    2794                info.setLibraryMapping(libraryMapping);
    2795
    2796                final InputStream inputStream = TapestryModule.class.getResourceAsStream(
    2797                        "/META-INF/gradle/org.apache.tapestry/tapestry-core/project.properties");
    2798
    2799                if (inputStream != null)
    2800                {
    2801                    Properties properties = new Properties();
    2802                    try
    2803                    {
    2804                        properties.load(inputStream);
    2805                    } catch (IOException e)
    2806                    {
    2807                        throw new RuntimeException(e);
    2808                    }
    2809                    info.setVersion(properties.getProperty("version"));
    2810                }
    2811            }
    2812            return info;
    2813        }
    2814    }
    2815
    2816}