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