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