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