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 --> text 794 * <li>Number --> number 795 * <li>Enum --> enum 796 * <li>Boolean --> boolean 797 * <li>Date --> 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 "<root>.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}