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