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