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