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