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