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