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