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