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