001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket; 018 019import java.net.URLConnection; 020import java.time.Duration; 021import java.util.Collections; 022import java.util.List; 023import java.util.Map; 024import java.util.ServiceLoader; 025import java.util.Set; 026import java.util.function.Supplier; 027import org.apache.wicket.application.ComponentInitializationListenerCollection; 028import org.apache.wicket.application.ComponentInstantiationListenerCollection; 029import org.apache.wicket.application.ComponentOnAfterRenderListenerCollection; 030import org.apache.wicket.application.ComponentOnBeforeRenderListenerCollection; 031import org.apache.wicket.application.ComponentOnConfigureListenerCollection; 032import org.apache.wicket.application.HeaderContributorListenerCollection; 033import org.apache.wicket.application.IComponentInitializationListener; 034import org.apache.wicket.application.IComponentInstantiationListener; 035import org.apache.wicket.application.OnComponentTagListenerCollection; 036import org.apache.wicket.core.request.mapper.IMapperContext; 037import org.apache.wicket.core.util.lang.PropertyResolver; 038import org.apache.wicket.core.util.lang.WicketObjects; 039import org.apache.wicket.core.util.resource.ClassPathResourceFinder; 040import org.apache.wicket.event.IEvent; 041import org.apache.wicket.event.IEventSink; 042import org.apache.wicket.javascript.DefaultJavaScriptCompressor; 043import org.apache.wicket.markup.MarkupFactory; 044import org.apache.wicket.markup.head.HeaderItem; 045import org.apache.wicket.markup.head.IHeaderResponse; 046import org.apache.wicket.markup.head.ResourceAggregator; 047import org.apache.wicket.markup.html.HeaderResponseDecoratorCollection; 048import org.apache.wicket.markup.html.IHeaderContributor; 049import org.apache.wicket.markup.html.IHeaderResponseDecorator; 050import org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory; 051import org.apache.wicket.markup.parser.filter.EnclosureHandler; 052import org.apache.wicket.markup.parser.filter.InlineEnclosureHandler; 053import org.apache.wicket.markup.parser.filter.RelativePathPrefixHandler; 054import org.apache.wicket.markup.parser.filter.WicketLinkTagHandler; 055import org.apache.wicket.markup.parser.filter.WicketMessageTagHandler; 056import org.apache.wicket.markup.resolver.HtmlHeaderResolver; 057import org.apache.wicket.markup.resolver.WicketContainerResolver; 058import org.apache.wicket.markup.resolver.WicketMessageResolver; 059import org.apache.wicket.page.IPageManager; 060import org.apache.wicket.pageStore.IPageStore; 061import org.apache.wicket.protocol.http.IRequestLogger; 062import org.apache.wicket.protocol.http.RequestLogger; 063import org.apache.wicket.protocol.http.RequestLoggerRequestCycleListener; 064import org.apache.wicket.protocol.http.WebApplication; 065import org.apache.wicket.protocol.http.WebSession; 066import org.apache.wicket.request.IExceptionMapper; 067import org.apache.wicket.request.IRequestHandler; 068import org.apache.wicket.request.IRequestMapper; 069import org.apache.wicket.request.Request; 070import org.apache.wicket.request.Response; 071import org.apache.wicket.request.cycle.IRequestCycleListener; 072import org.apache.wicket.request.cycle.RequestCycle; 073import org.apache.wicket.request.cycle.RequestCycleContext; 074import org.apache.wicket.request.cycle.RequestCycleListenerCollection; 075import org.apache.wicket.request.mapper.ICompoundRequestMapper; 076import org.apache.wicket.request.resource.ResourceReferenceRegistry; 077import org.apache.wicket.response.filter.EmptySrcAttributeCheckFilter; 078import org.apache.wicket.session.DefaultPageFactory; 079import org.apache.wicket.session.ISessionStore; 080import org.apache.wicket.session.ISessionStore.UnboundListener; 081import org.apache.wicket.settings.ApplicationSettings; 082import org.apache.wicket.settings.DebugSettings; 083import org.apache.wicket.settings.ExceptionSettings; 084import org.apache.wicket.settings.FrameworkSettings; 085import org.apache.wicket.settings.JavaScriptLibrarySettings; 086import org.apache.wicket.settings.MarkupSettings; 087import org.apache.wicket.settings.PageSettings; 088import org.apache.wicket.settings.RequestCycleSettings; 089import org.apache.wicket.settings.RequestLoggerSettings; 090import org.apache.wicket.settings.ResourceSettings; 091import org.apache.wicket.settings.SecuritySettings; 092import org.apache.wicket.settings.StoreSettings; 093import org.apache.wicket.util.lang.Args; 094import org.apache.wicket.util.lang.Generics; 095import org.slf4j.Logger; 096import org.slf4j.LoggerFactory; 097 098/** 099 * Base class for all Wicket applications. To create a Wicket application, you generally should 100 * <i>not </i> directly subclass this class. Instead, you will want to subclass some subclass of 101 * Application, like WebApplication, which is appropriate for the protocol and markup type you are 102 * working with. 103 * <p> 104 * Application has the following interesting features / attributes: 105 * <ul> 106 * <li><b>Name </b>- The Application's name, which is the same as its class name. 107 * 108 * <li><b>Home Page </b>- The Application's home Page class. Subclasses must override getHomePage() 109 * to provide this property value. 110 * 111 * <li><b>Settings </b>- Application settings are partitioned into sets of related settings using 112 * interfaces in the org.apache.wicket.settings package. These interfaces are returned by the 113 * following methods, which should be used to configure framework settings for your application: 114 * getApplicationSettings(), getDebugSettings(), getExceptionSettings(), getMarkupSettings(), 115 * getPageSettings(), getRequestCycleSettings(), getSecuritySettings and getSessionSettings(). These 116 * settings are configured by default through the constructor or internalInit methods. Default the 117 * application is configured for DEVELOPMENT. You can configure this globally to DEPLOYMENT or 118 * override specific settings by implementing the init() method. 119 * 120 * <li><b>Shared Resources </b>- Resources added to an Application's SharedResources have 121 * application-wide scope and can be referenced using a logical scope and a name with the 122 * ResourceReference class. ResourceReferences can then be used by multiple components in the same 123 * application without additional overhead (beyond the ResourceReference instance held by each 124 * referee) and will yield a stable URL, permitting efficient browser caching of the resource (even 125 * if the resource is dynamically generated). Resources shared in this manner may also be localized. 126 * See {@link org.apache.wicket.request.resource.ResourceReference} for more details. 127 * 128 * <li><b>Custom Session Subclasses</b>- In order to install your own {@link Session} subclass you 129 * must override Application{@link #newSession(Request, Response)}. For subclasses of 130 * {@link WebApplication} you will want to subclass {@link WebSession}. 131 * 132 * </ul> 133 * 134 * @see org.apache.wicket.protocol.http.WebApplication 135 * @author Jonathan Locke 136 */ 137public abstract class Application implements UnboundListener, IEventSink, IMetadataContext<Object, Application> 138{ 139 /** Configuration constant for the 2 types */ 140 public static final String CONFIGURATION = "configuration"; 141 142 /** 143 * Applications keyed on the {@link #getApplicationKey()} so that they can be retrieved even 144 * without being in a request/ being set in the thread local (we need that e.g. for when we are 145 * in a destruction thread). 146 */ 147 private static final Map<String, Application> applicationKeyToApplication = Generics.newHashMap(1); 148 149 /** Log. */ 150 private static final Logger log = LoggerFactory.getLogger(Application.class); 151 152 /** root mapper */ 153 private IRequestMapper rootRequestMapper; 154 155 /** The converter locator instance. */ 156 private IConverterLocator converterLocator; 157 158 /** list of initializers. */ 159 private final List<IInitializer> initializers = Generics.newArrayList(); 160 161 /** Application level meta data. */ 162 private MetaDataEntry<?>[] metaData; 163 164 /** Name of application subclass. */ 165 private String name; 166 167 /** Request logger instance. */ 168 private IRequestLogger requestLogger; 169 170 /** The session facade. */ 171 private volatile ISessionStore sessionStore; 172 173 /** page renderer provider */ 174 private IPageRendererProvider pageRendererProvider; 175 176 /** request cycle provider */ 177 private IRequestCycleProvider requestCycleProvider; 178 179 /** exception mapper provider */ 180 private Supplier<IExceptionMapper> exceptionMapperProvider; 181 182 /** session store provider */ 183 private Supplier<ISessionStore> sessionStoreProvider; 184 185 /** 186 * The decorator this application uses to decorate any header responses created by Wicket 187 */ 188 private HeaderResponseDecoratorCollection headerResponseDecorators = 189 new HeaderResponseDecoratorCollection(); 190 191 /** 192 * Checks if the <code>Application</code> threadlocal is set in this thread 193 * 194 * @return true if {@link Application#get()} can return the instance of application, false 195 * otherwise 196 */ 197 public static boolean exists() 198 { 199 return ThreadContext.getApplication() != null; 200 } 201 202 /** 203 * Get Application for current thread. 204 * 205 * @return The current thread's Application 206 */ 207 public static Application get() 208 { 209 Application application = ThreadContext.getApplication(); 210 if (application == null) 211 { 212 throw new WicketRuntimeException("There is no application attached to current thread " + 213 Thread.currentThread().getName()); 214 } 215 return application; 216 } 217 218 /** 219 * Gets the Application based on the application key of that application. You typically never 220 * have to use this method unless you are working on an integration project. 221 * 222 * @param applicationKey 223 * The unique key of the application within a certain context (e.g. a web 224 * application) 225 * @return The application or <code>null</code> if application has not been found 226 */ 227 public static Application get(final String applicationKey) 228 { 229 return applicationKeyToApplication.get(applicationKey); 230 } 231 232 /** 233 * Gets the keys of the currently registered Wicket applications for this web application. You 234 * typically never have to use this method unless you are working on an integration project. 235 * 236 * @return unmodifiable set with keys that correspond with {@link #getApplicationKey()}. Never 237 * null, but possibly empty 238 */ 239 public static Set<String> getApplicationKeys() 240 { 241 return Collections.unmodifiableSet(applicationKeyToApplication.keySet()); 242 } 243 244 /** 245 * Constructor. <strong>Use {@link #init()} for any configuration of your application instead of 246 * overriding the constructor.</strong> 247 */ 248 public Application() 249 { 250 // Install default component instantiation listener that uses 251 // authorization strategy to check component instantiations. 252 getComponentInstantiationListeners().add(new IComponentInstantiationListener() 253 { 254 /** 255 * @see org.apache.wicket.application.IComponentInstantiationListener#onInstantiation(org.apache.wicket.Component) 256 */ 257 @Override 258 public void onInstantiation(final Component component) 259 { 260 final Class<? extends Component> cl = component.getClass(); 261 // If component instantiation is not authorized 262 if (!Session.get().getAuthorizationStrategy().isInstantiationAuthorized(cl)) 263 { 264 // then call any unauthorized component instantiation 265 // listener 266 getSecuritySettings().getUnauthorizedComponentInstantiationListener() 267 .onUnauthorizedInstantiation(component); 268 } 269 } 270 }); 271 } 272 273 /** 274 * Configures application settings to good defaults. 275 */ 276 public final void configure() 277 { 278 // As long as this is public api the development and deployment mode 279 // should counter act each other for all properties. 280 switch (getConfigurationType()) 281 { 282 case DEVELOPMENT : { 283 getResourceSettings().setResourcePollFrequency(Duration.ofSeconds(1)); 284 getResourceSettings().setJavaScriptCompressor(null); 285 getResourceSettings().setUseMinifiedResources(false); 286 getMarkupSettings().setStripWicketTags(false); 287 getExceptionSettings().setUnexpectedExceptionDisplay( 288 ExceptionSettings.SHOW_EXCEPTION_PAGE); 289 getDebugSettings().setComponentUseCheck(true); 290 getDebugSettings().setAjaxDebugModeEnabled(true); 291 getDebugSettings().setDevelopmentUtilitiesEnabled(true); 292 // getDebugSettings().setOutputMarkupContainerClassName(true); 293 getRequestCycleSettings().addResponseFilter(EmptySrcAttributeCheckFilter.INSTANCE); 294 break; 295 } 296 case DEPLOYMENT : { 297 getResourceSettings().setResourcePollFrequency(null); 298 getResourceSettings().setJavaScriptCompressor(new DefaultJavaScriptCompressor()); 299 getMarkupSettings().setStripWicketTags(true); 300 getExceptionSettings().setUnexpectedExceptionDisplay( 301 ExceptionSettings.SHOW_INTERNAL_ERROR_PAGE); 302 getDebugSettings().setComponentUseCheck(false); 303 getDebugSettings().setAjaxDebugModeEnabled(false); 304 getDebugSettings().setDevelopmentUtilitiesEnabled(false); 305 break; 306 } 307 } 308 } 309 310 /** 311 * Gets the unique key of this application within a given context (like a web application). NOT 312 * INTENDED FOR FRAMEWORK CLIENTS. 313 * 314 * @return The unique key of this application 315 */ 316 public abstract String getApplicationKey(); 317 318 /** 319 * Gets the configuration mode to use for configuring the app, either 320 * {@link RuntimeConfigurationType#DEVELOPMENT} or {@link RuntimeConfigurationType#DEPLOYMENT}. 321 * <p> 322 * The configuration type. Must currently be either DEVELOPMENT or DEPLOYMENT. Currently, if the 323 * configuration type is DEVELOPMENT, resources are polled for changes, component usage is 324 * checked, wicket tags are not stripped from output and a detailed exception page is used. If 325 * the type is DEPLOYMENT, component usage is not checked, wicket tags are stripped from output 326 * and a non-detailed exception page is used to display errors. 327 * <p> 328 * Note that you should not run Wicket in DEVELOPMENT mode on production servers - the various 329 * debugging checks and resource polling is inefficient and may leak resources, particularly on 330 * webapp redeploy. 331 * 332 * <div style="border-style:solid;"> 333 * <p> 334 * To change the deployment mode, add the following to your web.xml, inside your <servlet> 335 * mapping (or <filter> mapping if you're using 1.3.x): 336 * 337 * <pre> 338 * <init-param> 339 * <param-name>configuration</param-name> 340 * <param-value>deployment</param-value> 341 * </init-param> 342 * </pre> 343 * 344 * <p> 345 * You can alternatively set this as a <context-param> on the whole context. 346 * 347 * <p> 348 * Another option is to set the "wicket.configuration" system property to either "deployment" or 349 * "development". The value is not case-sensitive. 350 * 351 * <p> 352 * The system property is checked first, allowing you to add a web.xml param for deployment, and 353 * a command-line override when you want to run in development mode during development. 354 * 355 * <p> 356 * You may also override Application.getConfigurationType() to provide your own custom switch, 357 * in which case none of the above logic is used. </div> 358 * 359 * <p> 360 * IMPORTANT NOTE 361 * </p> 362 * THIS METHOD IS CALLED OFTEN FROM MANY DIFFERENT POINTS IN CODE, INCLUDING DURING THE RENDER 363 * PROCESS, THEREFORE THE IMPLEMENTATION SHOULD BE FAST - PREFERRABLY USING A FAST-TO-RETRIEVE 364 * CACHED VALUE 365 * 366 * @return configuration 367 * @since 1.2.3 (function existed as a property getter) 368 * @since 1.3.0 (abstract, used to configure things) 369 */ 370 public abstract RuntimeConfigurationType getConfigurationType(); 371 372 /** 373 * Application subclasses must specify a home page class by implementing this abstract method. 374 * 375 * @return Home page class for this application 376 */ 377 public abstract Class<? extends Page> getHomePage(); 378 379 /** 380 * @return The converter locator for this application 381 */ 382 public final IConverterLocator getConverterLocator() 383 { 384 return converterLocator; 385 } 386 387 /** 388 * Gets metadata for this application using the given key. 389 * 390 * @param <T> 391 * @param key 392 * The key for the data 393 * @return The metadata 394 * @see MetaDataKey 395 */ 396 @Override 397 public final synchronized <T> T getMetaData(final MetaDataKey<T> key) 398 { 399 return key.get(metaData); 400 } 401 402 /** 403 * Gets the name of this application. 404 * 405 * @return The application name. 406 */ 407 public final String getName() 408 { 409 return name; 410 } 411 412 /** 413 * Gets the {@link IRequestLogger}. 414 * 415 * @return The RequestLogger 416 */ 417 public final IRequestLogger getRequestLogger() 418 { 419 if (getRequestLoggerSettings().isRequestLoggerEnabled()) 420 { 421 if (requestLogger == null) 422 { 423 requestLogger = newRequestLogger(); 424 } 425 } 426 else 427 { 428 requestLogger = null; 429 } 430 return requestLogger; 431 } 432 433 /** 434 * Gets the facade object for working getting/ storing session instances. 435 * 436 * @return The session facade 437 */ 438 public final ISessionStore getSessionStore() 439 { 440 if (sessionStore == null) 441 { 442 synchronized (this) 443 { 444 if (sessionStore == null) 445 { 446 sessionStore = sessionStoreProvider.get(); 447 sessionStore.registerUnboundListener(this); 448 } 449 } 450 } 451 return sessionStore; 452 } 453 454 /** 455 * @see org.apache.wicket.session.ISessionStore.UnboundListener#sessionUnbound(java.lang.String) 456 */ 457 @Override 458 public void sessionUnbound(final String sessionId) 459 { 460 getSessionListeners().onUnbound(sessionId); 461 } 462 463 /** 464 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL. 465 * 466 * @param target 467 */ 468 public void logEventTarget(final IRequestHandler target) 469 { 470 } 471 472 /** 473 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL. 474 * 475 * @param requestTarget 476 */ 477 public void logResponseTarget(final IRequestHandler requestTarget) 478 { 479 } 480 481 /** 482 * Creates a new session. Override this method if you want to provide a custom session. 483 * 484 * @param request 485 * The request that will create this session. 486 * @param response 487 * The response to initialize, for example with cookies. This is important to use 488 * cases involving unit testing because those use cases might want to be able to sign 489 * a user in automatically when the session is created. 490 * 491 * @return The session 492 * 493 * @since 1.3 494 */ 495 public abstract Session newSession(Request request, Response response); 496 497 /** 498 * Sets the metadata for this application using the given key. If the metadata object is not of 499 * the correct type for the metadata key, an IllegalArgumentException will be thrown. For 500 * information on creating MetaDataKeys, see {@link MetaDataKey}. 501 * 502 * @param <T> 503 * @param key 504 * The singleton key for the metadata 505 * @param object 506 * The metadata object 507 * @throws IllegalArgumentException 508 * @see MetaDataKey 509 */ 510 @Override 511 public synchronized final <T> Application setMetaData(final MetaDataKey<T> key, final T object) 512 { 513 metaData = key.set(metaData, object); 514 return this; 515 } 516 517 /** 518 * Construct and add initializer from the provided class name. 519 * 520 * @param className 521 */ 522 private void addInitializer(final String className) 523 { 524 IInitializer initializer = WicketObjects.newInstance(className); 525 if (initializer != null) 526 { 527 initializers.add(initializer); 528 } 529 } 530 531 /** 532 * Iterate initializers list, calling their {@link IInitializer#destroy(Application) destroy} 533 * methods. 534 */ 535 private void destroyInitializers() 536 { 537 for (IInitializer initializer : initializers) 538 { 539 log.info("[{}] destroy: {}", getName(), initializer); 540 initializer.destroy(this); 541 } 542 } 543 544 /** 545 * Iterate initializers list, calling {@link IInitializer#init(Application)} on any instances 546 * found in it. 547 */ 548 private void initInitializers() 549 { 550 for (IInitializer initializer : initializers) 551 { 552 log.info("[{}] init: {}", getName(), initializer); 553 initializer.init(this); 554 } 555 556 final ServiceLoader<IInitializer> serviceLoaderInitializers = ServiceLoader.load(IInitializer.class); 557 for (IInitializer serviceLoaderInitializer : serviceLoaderInitializers) { 558 log.info("[{}] init: {}", getName(), serviceLoaderInitializer); 559 serviceLoaderInitializer.init(this); 560 initializers.add(serviceLoaderInitializer); 561 } 562 } 563 564 /** 565 * Called when wicket servlet is destroyed. Overrides do not have to call super. 566 */ 567 protected void onDestroy() 568 { 569 } 570 571 /** 572 * Allows for initialization of the application by a subclass. <strong>Use this method for any 573 * application setup instead of the constructor.</strong> 574 */ 575 protected void init() 576 { 577 } 578 579 /** 580 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. 581 */ 582 public void internalDestroy() 583 { 584 applicationListeners.onBeforeDestroyed(this); 585 586 // destroy detach listener 587 final IDetachListener detachListener = getFrameworkSettings().getDetachListener(); 588 if (detachListener != null) 589 { 590 detachListener.onDestroyListener(); 591 } 592 593 // Clear caches of Class keys so the classloader can be garbage 594 // collected (WICKET-625) 595 PropertyResolver.destroy(this); 596 MarkupFactory markupFactory = getMarkupSettings().getMarkupFactory(); 597 598 if (markupFactory.hasMarkupCache()) 599 { 600 markupFactory.getMarkupCache().shutdown(); 601 } 602 603 onDestroy(); 604 605 destroyInitializers(); 606 607 internalGetPageManager().destroy(); 608 getSessionStore().destroy(); 609 610 applicationKeyToApplication.remove(getApplicationKey()); 611 } 612 613 /** 614 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT OVERRIDE OR CALL. 615 * 616 * Internal initialization. 617 */ 618 protected void internalInit() 619 { 620 settingsAccessible = true; 621 PageSettings pageSettings = getPageSettings(); 622 623 // Install default component resolvers 624 pageSettings.addComponentResolver(new HtmlHeaderResolver()); 625 pageSettings.addComponentResolver(new WicketLinkTagHandler()); 626 pageSettings.addComponentResolver(new WicketMessageResolver()); 627 pageSettings.addComponentResolver(new RelativePathPrefixHandler()); 628 pageSettings.addComponentResolver(new EnclosureHandler()); 629 pageSettings.addComponentResolver(new InlineEnclosureHandler()); 630 pageSettings.addComponentResolver(new WicketMessageTagHandler()); 631 pageSettings.addComponentResolver(new WicketContainerResolver()); 632 633 getResourceSettings().getResourceFinders().add(new ClassPathResourceFinder("")); 634 635 // Install button image resource factory 636 getResourceSettings().addResourceFactory("buttonFactory", 637 new DefaultButtonImageResourceFactory()); 638 639 String applicationKey = getApplicationKey(); 640 applicationKeyToApplication.put(applicationKey, this); 641 642 converterLocator = newConverterLocator(); 643 644 setPageManagerProvider(new DefaultPageManagerProvider(this)); 645 resourceReferenceRegistry = newResourceReferenceRegistry(); 646 sharedResources = newSharedResources(resourceReferenceRegistry); 647 resourceBundles = newResourceBundles(resourceReferenceRegistry); 648 649 // set up default request mapper 650 setRootRequestMapper(new SystemMapper(this)); 651 652 pageFactory = newPageFactory(); 653 654 requestCycleProvider = RequestCycle::new; 655 exceptionMapperProvider = DefaultExceptionMapper::new; 656 657 // add a request cycle listener that logs each request for the requestlogger. 658 getRequestCycleListeners().add(new RequestLoggerRequestCycleListener()); 659 } 660 661 /** 662 * Returns a supplier of {@link IExceptionMapper} that will be used to 663 * handle exceptions which were not handled by any 664 * {@link IRequestCycleListener#onException(RequestCycle, Exception) request cycle listener}. 665 * 666 * @return the exception mapper supplier 667 * @see IRequestCycleListener#onException(RequestCycle, Exception) 668 */ 669 public Supplier<IExceptionMapper> getExceptionMapperProvider() 670 { 671 return exceptionMapperProvider; 672 } 673 674 public void setExceptionMapperProvider(Supplier<IExceptionMapper> exceptionMapperProvider) { 675 this.exceptionMapperProvider = Args.notNull(exceptionMapperProvider, "exceptionMapperProvider"); 676 } 677 678 /** 679 * 680 * @return Session state provider 681 */ 682 public final Supplier<ISessionStore> getSessionStoreProvider() 683 { 684 return sessionStoreProvider; 685 } 686 687 /** 688 * 689 * @param sessionStoreProvider 690 */ 691 public final Application setSessionStoreProvider(final Supplier<ISessionStore> sessionStoreProvider) 692 { 693 this.sessionStoreProvider = Args.notNull(sessionStoreProvider, "sessionStoreProvider"); 694 this.sessionStore = null; 695 return this; 696 } 697 698 /** 699 * Creates and returns a new instance of {@link IConverterLocator}. 700 * 701 * @return A new {@link IConverterLocator} instance 702 */ 703 protected IConverterLocator newConverterLocator() 704 { 705 return new ConverterLocator(); 706 } 707 708 /** 709 * creates a new request logger when requests logging is enabled. 710 * 711 * @return The new request logger 712 * 713 */ 714 protected IRequestLogger newRequestLogger() 715 { 716 return new RequestLogger(); 717 } 718 719 /** 720 * Converts the root mapper to a {@link ICompoundRequestMapper} if necessary and returns the 721 * converted instance. 722 * 723 * @return compound instance of the root mapper 724 */ 725 public final ICompoundRequestMapper getRootRequestMapperAsCompound() 726 { 727 IRequestMapper root = getRootRequestMapper(); 728 if (!(root instanceof ICompoundRequestMapper)) 729 { 730 root = new SystemMapper(this).add(root); 731 setRootRequestMapper(root); 732 } 733 return (ICompoundRequestMapper)root; 734 } 735 736 /** 737 * @return The root request mapper 738 */ 739 public final IRequestMapper getRootRequestMapper() 740 { 741 return rootRequestMapper; 742 } 743 744 /** 745 * Sets the root request mapper 746 * 747 * @param rootRequestMapper 748 */ 749 public final Application setRootRequestMapper(final IRequestMapper rootRequestMapper) 750 { 751 this.rootRequestMapper = rootRequestMapper; 752 return this; 753 } 754 755 /** 756 * Initialize the application 757 */ 758 public final void initApplication() 759 { 760 if (name == null) 761 { 762 throw new IllegalStateException("setName must be called before initApplication"); 763 } 764 internalInit(); 765 initInitializers(); 766 init(); 767 applicationListeners.onAfterInitialized(this); 768 769 validateInit(); 770 } 771 772 /** 773 * Gives the Application object a chance to validate if it has been properly initialized 774 */ 775 protected void validateInit() 776 { 777 if (getPageRendererProvider() == null) 778 { 779 throw new IllegalStateException( 780 "An instance of IPageRendererProvider has not yet been set on this Application. @see Application#setPageRendererProvider"); 781 } 782 if (getSessionStoreProvider() == null) 783 { 784 throw new IllegalStateException( 785 "An instance of ISessionStoreProvider has not yet been set on this Application. @see Application#setSessionStoreProvider"); 786 } 787 if (getPageManagerProvider() == null) 788 { 789 throw new IllegalStateException( 790 "An instance of IPageManagerProvider has not yet been set on this Application. @see Application#setPageManagerProvider"); 791 } 792 } 793 794 /** 795 * Sets application name. This method must be called before any other methods are invoked and 796 * can only be called once per application instance. 797 * 798 * @param name 799 * unique application name 800 */ 801 public final void setName(final String name) 802 { 803 Args.notEmpty(name, "name"); 804 805 if (this.name != null) 806 { 807 throw new IllegalStateException("Application name can only be set once."); 808 } 809 810 if (applicationKeyToApplication.get(name) != null) 811 { 812 throw new IllegalStateException("Application with name '" + name + "' already exists.'"); 813 } 814 815 this.name = name; 816 applicationKeyToApplication.put(name, this); 817 } 818 819 /** 820 * Returns the mime type for given filename. 821 * 822 * @param fileName 823 * @return mime type 824 */ 825 public String getMimeType(final String fileName) 826 { 827 return URLConnection.getFileNameMap().getContentTypeFor(fileName); 828 } 829 830 /** {@inheritDoc} */ 831 @Override 832 public void onEvent(final IEvent<?> event) 833 { 834 } 835 836 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 837 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 838 // 839 // Listeners 840 // 841 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 842 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 843 844 /** */ 845 private final ComponentOnBeforeRenderListenerCollection componentPreOnBeforeRenderListeners = new ComponentOnBeforeRenderListenerCollection(); 846 847 /** */ 848 private final ComponentOnBeforeRenderListenerCollection componentPostOnBeforeRenderListeners = new ComponentOnBeforeRenderListenerCollection(); 849 850 /** */ 851 private final ComponentOnAfterRenderListenerCollection componentOnAfterRenderListeners = new ComponentOnAfterRenderListenerCollection(); 852 853 /** */ 854 private final RequestCycleListenerCollection requestCycleListeners = new RequestCycleListenerCollection(); 855 856 private final ApplicationListenerCollection applicationListeners = new ApplicationListenerCollection(); 857 858 private final SessionListenerCollection sessionListeners = new SessionListenerCollection(); 859 860 /** list of {@link IComponentInstantiationListener}s. */ 861 private final ComponentInstantiationListenerCollection componentInstantiationListeners = new ComponentInstantiationListenerCollection(); 862 863 /** list of {@link IComponentInitializationListener}s. */ 864 private final ComponentInitializationListenerCollection componentInitializationListeners = new ComponentInitializationListenerCollection(); 865 866 /** list of {@link org.apache.wicket.application.IComponentOnConfigureListener}s. */ 867 private final ComponentOnConfigureListenerCollection componentOnConfigureListeners = new ComponentOnConfigureListenerCollection(); 868 869 /** list of {@link IHeaderContributor}s. */ 870 private final HeaderContributorListenerCollection headerContributorListeners = new HeaderContributorListenerCollection(); 871 872 private final BehaviorInstantiationListenerCollection behaviorInstantiationListeners = new BehaviorInstantiationListenerCollection(); 873 874 private final OnComponentTagListenerCollection onComponentTagListeners = new OnComponentTagListenerCollection(); 875 876 /** 877 * @return Gets the application's {@link HeaderContributorListenerCollection} 878 */ 879 public final HeaderContributorListenerCollection getHeaderContributorListeners() 880 { 881 return headerContributorListeners; 882 } 883 884 /** 885 * @return collection of initializers 886 */ 887 public final List<IInitializer> getInitializers() 888 { 889 return Collections.unmodifiableList(initializers); 890 } 891 892 /** 893 * @return collection of application listeners 894 */ 895 public final ApplicationListenerCollection getApplicationListeners() 896 { 897 return applicationListeners; 898 } 899 900 /** 901 * @return collection of session listeners 902 */ 903 public final SessionListenerCollection getSessionListeners() 904 { 905 return sessionListeners; 906 } 907 908 /** 909 * @return collection of behavior instantiation listeners 910 */ 911 public final BehaviorInstantiationListenerCollection getBehaviorInstantiationListeners() 912 { 913 return behaviorInstantiationListeners; 914 } 915 916 /** 917 * @return collection of application's on-component-tag listeners 918 */ 919 public final OnComponentTagListenerCollection getOnComponentTagListeners() { 920 return onComponentTagListeners; 921 } 922 923 /** 924 * @return Gets the application's ComponentInstantiationListenerCollection 925 */ 926 public final ComponentInstantiationListenerCollection getComponentInstantiationListeners() 927 { 928 return componentInstantiationListeners; 929 } 930 931 /** 932 * @return Gets the application's ComponentInitializationListeners 933 */ 934 public final ComponentInitializationListenerCollection getComponentInitializationListeners() 935 { 936 return componentInitializationListeners; 937 } 938 939 /** 940 * @return Gets the application's ComponentOnConfigureListeners 941 */ 942 public final ComponentOnConfigureListenerCollection getComponentOnConfigureListeners() 943 { 944 return componentOnConfigureListeners; 945 } 946 947 /** 948 * 949 * @return ComponentOnBeforeRenderListenerCollection 950 */ 951 public final ComponentOnBeforeRenderListenerCollection getComponentPreOnBeforeRenderListeners() 952 { 953 return componentPreOnBeforeRenderListeners; 954 } 955 956 /** 957 * 958 * @return ComponentOnBeforeRenderListenerCollection 959 */ 960 public final ComponentOnBeforeRenderListenerCollection getComponentPostOnBeforeRenderListeners() 961 { 962 return componentPostOnBeforeRenderListeners; 963 } 964 965 /** 966 * @return on after render listeners collection 967 */ 968 public final ComponentOnAfterRenderListenerCollection getComponentOnAfterRenderListeners() 969 { 970 return componentOnAfterRenderListeners; 971 } 972 973 /** 974 * @return the unmodifiable request list of {@link IRequestCycleListener}s in this application 975 */ 976 public RequestCycleListenerCollection getRequestCycleListeners() 977 { 978 return requestCycleListeners; 979 } 980 981 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 982 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 983 // 984 // Settings 985 // 986 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 987 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 988 989 /** Application settings */ 990 private ApplicationSettings applicationSettings; 991 992 /** JavaScriptLibrary settings */ 993 private JavaScriptLibrarySettings javaScriptLibrarySettings; 994 995 /** Debug Settings */ 996 private DebugSettings debugSettings; 997 998 /** Exception Settings */ 999 private ExceptionSettings exceptionSettings; 1000 1001 /** Framework Settings */ 1002 private FrameworkSettings frameworkSettings; 1003 1004 /** The Markup Settings */ 1005 private MarkupSettings markupSettings; 1006 1007 /** The Page Settings */ 1008 private PageSettings pageSettings; 1009 1010 /** The Request Cycle Settings */ 1011 private RequestCycleSettings requestCycleSettings; 1012 1013 /** The Request Logger Settings */ 1014 private RequestLoggerSettings requestLoggerSettings; 1015 1016 /** The Resource Settings */ 1017 private ResourceSettings resourceSettings; 1018 1019 /** The Security Settings */ 1020 private SecuritySettings securitySettings; 1021 1022 /** The settings for {@link IPageStore} and {@link IPageManager} */ 1023 private StoreSettings storeSettings; 1024 1025 /** can the settings object be set/used. */ 1026 private boolean settingsAccessible; 1027 1028 /** 1029 * @return Application's application-wide settings 1030 * @since 1.2 1031 */ 1032 public final ApplicationSettings getApplicationSettings() 1033 { 1034 checkSettingsAvailable(); 1035 if (applicationSettings == null) 1036 { 1037 applicationSettings = new ApplicationSettings(); 1038 } 1039 return applicationSettings; 1040 } 1041 1042 /** 1043 * 1044 * @param applicationSettings 1045 */ 1046 public final Application setApplicationSettings(final ApplicationSettings applicationSettings) 1047 { 1048 this.applicationSettings = applicationSettings; 1049 return this; 1050 } 1051 1052 /** 1053 * @return Application's JavaScriptLibrary settings 1054 * @since 6.0 1055 */ 1056 public final JavaScriptLibrarySettings getJavaScriptLibrarySettings() 1057 { 1058 checkSettingsAvailable(); 1059 if (javaScriptLibrarySettings == null) 1060 { 1061 javaScriptLibrarySettings = new JavaScriptLibrarySettings(); 1062 } 1063 return javaScriptLibrarySettings; 1064 } 1065 1066 /** 1067 * 1068 * @param javaScriptLibrarySettings 1069 */ 1070 public final Application setJavaScriptLibrarySettings( 1071 final JavaScriptLibrarySettings javaScriptLibrarySettings) 1072 { 1073 this.javaScriptLibrarySettings = javaScriptLibrarySettings; 1074 return this; 1075 } 1076 1077 /** 1078 * @return Application's debug related settings 1079 */ 1080 public final DebugSettings getDebugSettings() 1081 { 1082 checkSettingsAvailable(); 1083 if (debugSettings == null) 1084 { 1085 debugSettings = new DebugSettings(); 1086 } 1087 return debugSettings; 1088 } 1089 1090 /** 1091 * 1092 * @param debugSettings 1093 */ 1094 public final Application setDebugSettings(final DebugSettings debugSettings) 1095 { 1096 this.debugSettings = debugSettings; 1097 return this; 1098 } 1099 1100 /** 1101 * @return Application's exception handling settings 1102 */ 1103 public final ExceptionSettings getExceptionSettings() 1104 { 1105 checkSettingsAvailable(); 1106 if (exceptionSettings == null) 1107 { 1108 exceptionSettings = new ExceptionSettings(); 1109 } 1110 return exceptionSettings; 1111 } 1112 1113 /** 1114 * 1115 * @param exceptionSettings 1116 */ 1117 public final Application setExceptionSettings(final ExceptionSettings exceptionSettings) 1118 { 1119 this.exceptionSettings = exceptionSettings; 1120 return this; 1121 } 1122 1123 /** 1124 * @return Wicket framework settings 1125 */ 1126 public final FrameworkSettings getFrameworkSettings() 1127 { 1128 checkSettingsAvailable(); 1129 if (frameworkSettings == null) 1130 { 1131 frameworkSettings = new FrameworkSettings(this); 1132 } 1133 return frameworkSettings; 1134 } 1135 1136 /** 1137 * 1138 * @param frameworkSettings 1139 */ 1140 public final Application setFrameworkSettings(final FrameworkSettings frameworkSettings) 1141 { 1142 this.frameworkSettings = frameworkSettings; 1143 return this; 1144 } 1145 1146 /** 1147 * @return Application's page related settings 1148 */ 1149 public final PageSettings getPageSettings() 1150 { 1151 checkSettingsAvailable(); 1152 if (pageSettings == null) 1153 { 1154 pageSettings = new PageSettings(); 1155 } 1156 return pageSettings; 1157 } 1158 1159 /** 1160 * 1161 * @param pageSettings 1162 */ 1163 public final Application setPageSettings(final PageSettings pageSettings) 1164 { 1165 this.pageSettings = pageSettings; 1166 return this; 1167 } 1168 1169 /** 1170 * @return Application's request cycle related settings 1171 */ 1172 public final RequestCycleSettings getRequestCycleSettings() 1173 { 1174 checkSettingsAvailable(); 1175 if (requestCycleSettings == null) 1176 { 1177 requestCycleSettings = new RequestCycleSettings(); 1178 } 1179 return requestCycleSettings; 1180 } 1181 1182 /** 1183 * 1184 * @param requestCycleSettings 1185 */ 1186 public final Application setRequestCycleSettings(final RequestCycleSettings requestCycleSettings) 1187 { 1188 this.requestCycleSettings = requestCycleSettings; 1189 return this; 1190 } 1191 1192 /** 1193 * @return Application's markup related settings 1194 */ 1195 public MarkupSettings getMarkupSettings() 1196 { 1197 checkSettingsAvailable(); 1198 if (markupSettings == null) 1199 { 1200 markupSettings = new MarkupSettings(); 1201 } 1202 return markupSettings; 1203 } 1204 1205 /** 1206 * 1207 * @param markupSettings 1208 */ 1209 public final Application setMarkupSettings(final MarkupSettings markupSettings) 1210 { 1211 this.markupSettings = markupSettings; 1212 return this; 1213 } 1214 1215 /** 1216 * @return Application's request logger related settings 1217 */ 1218 public final RequestLoggerSettings getRequestLoggerSettings() 1219 { 1220 checkSettingsAvailable(); 1221 if (requestLoggerSettings == null) 1222 { 1223 requestLoggerSettings = new RequestLoggerSettings(); 1224 } 1225 return requestLoggerSettings; 1226 } 1227 1228 /** 1229 * 1230 * @param requestLoggerSettings 1231 */ 1232 public final Application setRequestLoggerSettings(final RequestLoggerSettings requestLoggerSettings) 1233 { 1234 this.requestLoggerSettings = requestLoggerSettings; 1235 return this; 1236 } 1237 1238 /** 1239 * @return Application's resources related settings 1240 */ 1241 public final ResourceSettings getResourceSettings() 1242 { 1243 checkSettingsAvailable(); 1244 if (resourceSettings == null) 1245 { 1246 resourceSettings = new ResourceSettings(this); 1247 } 1248 return resourceSettings; 1249 } 1250 1251 /** 1252 * 1253 * @param resourceSettings 1254 */ 1255 public final Application setResourceSettings(final ResourceSettings resourceSettings) 1256 { 1257 this.resourceSettings = resourceSettings; 1258 return this; 1259 } 1260 1261 /** 1262 * @return Application's security related settings 1263 */ 1264 public final SecuritySettings getSecuritySettings() 1265 { 1266 checkSettingsAvailable(); 1267 if (securitySettings == null) 1268 { 1269 securitySettings = new SecuritySettings(); 1270 } 1271 return securitySettings; 1272 } 1273 1274 /** 1275 * 1276 * @param securitySettings 1277 */ 1278 public final Application setSecuritySettings(final SecuritySettings securitySettings) 1279 { 1280 this.securitySettings = securitySettings; 1281 return this; 1282 } 1283 1284 /** 1285 * @return Application's stores related settings 1286 */ 1287 public final StoreSettings getStoreSettings() 1288 { 1289 checkSettingsAvailable(); 1290 if (storeSettings == null) 1291 { 1292 storeSettings = new StoreSettings(this); 1293 } 1294 return storeSettings; 1295 } 1296 1297 /** 1298 * 1299 * @param storeSettings 1300 */ 1301 public final Application setStoreSettings(final StoreSettings storeSettings) 1302 { 1303 this.storeSettings = storeSettings; 1304 return this; 1305 } 1306 1307 /** 1308 * 1309 */ 1310 protected void checkSettingsAvailable() 1311 { 1312 if (!settingsAccessible) 1313 { 1314 throw new WicketRuntimeException( 1315 "Use Application.init() method for configuring your application object"); 1316 } 1317 } 1318 1319 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1320 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1321 // 1322 // Page Manager 1323 // 1324 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1325 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1326 1327 private volatile IPageManager pageManager; 1328 private IPageManagerProvider pageManagerProvider; 1329 1330 /** 1331 * 1332 * @return PageManagerProvider 1333 */ 1334 public final IPageManagerProvider getPageManagerProvider() 1335 { 1336 return pageManagerProvider; 1337 } 1338 1339 /** 1340 * Set the provider of an {@link IPageManager}. 1341 * 1342 * @param provider 1343 * 1344 * @see DefaultPageManagerProvider 1345 */ 1346 public final Application setPageManagerProvider(final IPageManagerProvider provider) 1347 { 1348 pageManagerProvider = provider; 1349 return this; 1350 } 1351 1352 /** 1353 * Returns an unsynchronized version of page manager 1354 * 1355 * @return the page manager 1356 */ 1357 final IPageManager internalGetPageManager() 1358 { 1359 if (pageManager == null) 1360 { 1361 synchronized (this) 1362 { 1363 if (pageManager == null) 1364 { 1365 pageManager = pageManagerProvider.get(); 1366 } 1367 } 1368 } 1369 return pageManager; 1370 } 1371 1372 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1373 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1374 // 1375 // Page Rendering 1376 // 1377 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1378 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1379 1380 /** 1381 * 1382 * @return PageRendererProvider 1383 */ 1384 public final IPageRendererProvider getPageRendererProvider() 1385 { 1386 return pageRendererProvider; 1387 } 1388 1389 /** 1390 * 1391 * @param pageRendererProvider 1392 */ 1393 public final Application setPageRendererProvider(final IPageRendererProvider pageRendererProvider) 1394 { 1395 Args.notNull(pageRendererProvider, "pageRendererProvider"); 1396 this.pageRendererProvider = pageRendererProvider; 1397 return this; 1398 } 1399 1400 1401 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1402 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1403 // 1404 // Request Handler encoding 1405 // 1406 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1407 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1408 1409 private ResourceReferenceRegistry resourceReferenceRegistry; 1410 1411 private SharedResources sharedResources; 1412 1413 private ResourceBundles resourceBundles; 1414 1415 private IPageFactory pageFactory; 1416 1417 private IMapperContext encoderContext; 1418 1419 /** 1420 * Override to create custom {@link ResourceReferenceRegistry}. 1421 * 1422 * @return new {@link ResourceReferenceRegistry} instance. 1423 */ 1424 protected ResourceReferenceRegistry newResourceReferenceRegistry() 1425 { 1426 return new ResourceReferenceRegistry(); 1427 } 1428 1429 /** 1430 * Returns {@link ResourceReferenceRegistry} for this application. 1431 * 1432 * @return ResourceReferenceRegistry 1433 */ 1434 public final ResourceReferenceRegistry getResourceReferenceRegistry() 1435 { 1436 return resourceReferenceRegistry; 1437 } 1438 1439 /** 1440 * 1441 * @param registry 1442 * @return SharedResources 1443 */ 1444 protected SharedResources newSharedResources(final ResourceReferenceRegistry registry) 1445 { 1446 return new SharedResources(registry); 1447 } 1448 1449 /** 1450 * 1451 * @return SharedResources 1452 */ 1453 public SharedResources getSharedResources() 1454 { 1455 return sharedResources; 1456 } 1457 1458 protected ResourceBundles newResourceBundles(final ResourceReferenceRegistry registry) 1459 { 1460 return new ResourceBundles(registry); 1461 } 1462 1463 /** 1464 * @return The registry for resource bundles 1465 */ 1466 public ResourceBundles getResourceBundles() 1467 { 1468 return resourceBundles; 1469 } 1470 1471 /** 1472 * Override to create custom {@link IPageFactory} 1473 * 1474 * @return new {@link IPageFactory} instance. 1475 */ 1476 protected IPageFactory newPageFactory() 1477 { 1478 return new DefaultPageFactory(); 1479 } 1480 1481 /** 1482 * Returns {@link IPageFactory} for this application. 1483 * 1484 * @return page factory 1485 */ 1486 public final IPageFactory getPageFactory() 1487 { 1488 return pageFactory; 1489 } 1490 1491 /** 1492 * 1493 * @return mapper context 1494 */ 1495 public final IMapperContext getMapperContext() 1496 { 1497 if (encoderContext == null) 1498 { 1499 encoderContext = newMapperContext(); 1500 } 1501 return encoderContext; 1502 } 1503 1504 /** 1505 * Factory method for {@link IMapperContext} implementations. {@link DefaultMapperContext} may 1506 * be a good starting point for custom implementations. 1507 * 1508 * @return new instance of mapper context to be used in the application 1509 */ 1510 protected IMapperContext newMapperContext() 1511 { 1512 return new DefaultMapperContext(this); 1513 } 1514 1515 /** 1516 * 1517 * @param requestCycle 1518 * @return Session 1519 */ 1520 public Session fetchCreateAndSetSession(final RequestCycle requestCycle) 1521 { 1522 Args.notNull(requestCycle, "requestCycle"); 1523 1524 Session session = getSessionStore().lookup(requestCycle.getRequest()); 1525 if (session == null) 1526 { 1527 session = newSession(requestCycle.getRequest(), requestCycle.getResponse()); 1528 ThreadContext.setSession(session); 1529 internalGetPageManager().clear(); 1530 sessionListeners.onCreated(session); 1531 } 1532 else 1533 { 1534 ThreadContext.setSession(session); 1535 } 1536 return session; 1537 } 1538 1539 /** 1540 * 1541 * @return RequestCycleProvider 1542 */ 1543 public final IRequestCycleProvider getRequestCycleProvider() 1544 { 1545 return requestCycleProvider; 1546 } 1547 1548 /** 1549 * 1550 * @param requestCycleProvider 1551 */ 1552 public final Application setRequestCycleProvider(final IRequestCycleProvider requestCycleProvider) 1553 { 1554 this.requestCycleProvider = requestCycleProvider; 1555 return this; 1556 } 1557 1558 /** 1559 * 1560 * @param request 1561 * @param response 1562 * @return request cycle 1563 */ 1564 public final RequestCycle createRequestCycle(final Request request, final Response response) 1565 { 1566 RequestCycleContext context = new RequestCycleContext(request, response, 1567 getRootRequestMapper(), getExceptionMapperProvider().get()); 1568 1569 RequestCycle requestCycle = getRequestCycleProvider().apply(context); 1570 requestCycle.getListeners().add(requestCycleListeners); 1571 requestCycle.getListeners().add(new IRequestCycleListener() 1572 { 1573 @Override 1574 public void onEndRequest(RequestCycle cycle) 1575 { 1576 internalGetPageManager().end(); 1577 } 1578 1579 @Override 1580 public void onDetach(final RequestCycle requestCycle) 1581 { 1582 internalGetPageManager().detach(); 1583 1584 IRequestLogger requestLogger = getRequestLogger(); 1585 if (requestLogger != null) 1586 { 1587 requestLogger.requestTime((System.currentTimeMillis() - requestCycle.getStartTime())); 1588 } 1589 } 1590 }); 1591 return requestCycle; 1592 } 1593 1594 /** 1595 * Sets an {@link IHeaderResponseDecorator} that you want your application to use to decorate 1596 * header responses. 1597 * <p> 1598 * Calling this method replaces the default decorator, which utilizes a 1599 * {@link ResourceAggregator}: The given implementation should make sure, that it too wraps 1600 * responses in a {@link ResourceAggregator}, otherwise no dependencies for {@link HeaderItem}s 1601 * will be resolved. 1602 * 1603 * @param headerResponseDecorator 1604 * your custom decorator, must not be null 1605 * @deprecated use {@code add(...)} on {@link #getHeaderResponseDecorators()}. This method 1606 * removes the {@link ResourceAggregator}, which is needed to resolve resource 1607 * dependencies. 1608 */ 1609 @Deprecated 1610 public final Application 1611 setHeaderResponseDecorator(final IHeaderResponseDecorator headerResponseDecorator) 1612 { 1613 headerResponseDecorators.replaceAll(headerResponseDecorator); 1614 return this; 1615 } 1616 1617 /** 1618 * Returns the {@link HeaderResponseDecoratorCollection} used by this application. On this 1619 * collection you can add additional decorators, which will be nested in the order added. 1620 * 1621 * @return The {@link HeaderResponseDecoratorCollection} used by this application. 1622 */ 1623 public HeaderResponseDecoratorCollection getHeaderResponseDecorators() 1624 { 1625 return headerResponseDecorators; 1626 } 1627 1628 /** 1629 * INTERNAL METHOD - You shouldn't need to call this. This is called every time Wicket creates 1630 * an IHeaderResponse. It gives you the ability to incrementally add features to an 1631 * IHeaderResponse implementation by wrapping it in another implementation. 1632 * 1633 * To decorate an IHeaderResponse in your application, set the {@link IHeaderResponseDecorator} 1634 * on the application. 1635 * 1636 * @see IHeaderResponseDecorator 1637 * @param response 1638 * the response Wicket created 1639 * @return the response Wicket should use in IHeaderContributor traversal 1640 */ 1641 public final IHeaderResponse decorateHeaderResponse(final IHeaderResponse response) 1642 { 1643 return headerResponseDecorators.decorate(response); 1644 } 1645 1646 /** 1647 * 1648 * @return true, of app is in Development mode 1649 */ 1650 public final boolean usesDevelopmentConfig() 1651 { 1652 return RuntimeConfigurationType.DEVELOPMENT.equals(getConfigurationType()); 1653 } 1654 1655 /** 1656 * 1657 * @return true, of app is in Deployment mode 1658 */ 1659 public final boolean usesDeploymentConfig() 1660 { 1661 return RuntimeConfigurationType.DEPLOYMENT.equals(getConfigurationType()); 1662 } 1663}