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