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