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