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