org.apache.wicket.Application Maven / Gradle / Ivy
Show all versions of org.ops4j.pax.wicket.service Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.wicket.application.IComponentInitializationListener;
import org.apache.wicket.application.IComponentInstantiationListener;
import org.apache.wicket.application.IComponentOnAfterRenderListener;
import org.apache.wicket.application.IComponentOnBeforeRenderListener;
import org.apache.wicket.javascript.DefaultJavascriptCompressor;
import org.apache.wicket.markup.IMarkupCache;
import org.apache.wicket.markup.html.EmptySrcAttributeCheckFilter;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.IHeaderResponseDecorator;
import org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory;
import org.apache.wicket.markup.parser.filter.RelativePathPrefixHandler;
import org.apache.wicket.markup.parser.filter.WicketMessageTagHandler;
import org.apache.wicket.markup.resolver.AutoComponentResolver;
import org.apache.wicket.markup.resolver.BorderBodyResolver;
import org.apache.wicket.markup.resolver.EnclosureResolver;
import org.apache.wicket.markup.resolver.FragmentResolver;
import org.apache.wicket.markup.resolver.HtmlHeaderResolver;
import org.apache.wicket.markup.resolver.MarkupInheritanceResolver;
import org.apache.wicket.markup.resolver.ParentResolver;
import org.apache.wicket.markup.resolver.WicketContainerResolver;
import org.apache.wicket.markup.resolver.WicketLinkResolver;
import org.apache.wicket.markup.resolver.WicketMessageResolver;
import org.apache.wicket.protocol.http.IRequestLogger;
import org.apache.wicket.protocol.http.RequestLogger;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.session.ISessionStore;
import org.apache.wicket.settings.IApplicationSettings;
import org.apache.wicket.settings.IDebugSettings;
import org.apache.wicket.settings.IExceptionSettings;
import org.apache.wicket.settings.IFrameworkSettings;
import org.apache.wicket.settings.IMarkupSettings;
import org.apache.wicket.settings.IPageSettings;
import org.apache.wicket.settings.IRequestCycleSettings;
import org.apache.wicket.settings.IRequestLoggerSettings;
import org.apache.wicket.settings.IResourceSettings;
import org.apache.wicket.settings.ISecuritySettings;
import org.apache.wicket.settings.ISessionSettings;
import org.apache.wicket.settings.Settings;
import org.apache.wicket.util.convert.ConverterLocator;
import org.apache.wicket.util.lang.Classes;
import org.apache.wicket.util.lang.Objects;
import org.apache.wicket.util.lang.PropertyResolver;
import org.apache.wicket.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for all Wicket applications. To create a Wicket application, you generally should
* not directly subclass this class. Instead, you will want to subclass some subclass of
* Application, like WebApplication, which is appropriate for the protocol and markup type you are
* working with.
*
* Application has the following interesting features / attributes:
*
* - Name - The Application's name, which is the same as its class name.
*
*
- Home Page - The Application's home Page class. Subclasses must override getHomePage()
* to provide this property value.
*
*
- Settings - Application settings are partitioned into sets of related settings using
* interfaces in the org.apache.wicket.settings package. These interfaces are returned by the
* following methods, which should be used to configure framework settings for your application:
* getApplicationSettings(), getDebugSettings(), getExceptionSettings(), getMarkupSettings(),
* getPageSettings(), getRequestCycleSettings(), getSecuritySettings and getSessionSettings(). These
* settings are configured by default through the constructor or internalInit methods. Default the
* application is configured for DEVELOPMENT. You can configure this globally to DEPLOYMENT or
* override specific settings by implementing the init() method.
*
*
- Shared Resources - Resources added to an Application's SharedResources have
* application-wide scope and can be referenced using a logical scope and a name with the
* ResourceReference class. ResourceReferences can then be used by multiple components in the same
* application without additional overhead (beyond the ResourceReference instance held by each
* referee) and will yield a stable URL, permitting efficient browser caching of the resource (even
* if the resource is dynamically generated). Resources shared in this manner may also be localized.
* See {@link org.apache.wicket.ResourceReference} for more details.
*
*
- Custom Session Subclasses- In order to install your own {@link Session} subclass you
* must override Application{@link #newSession(Request, Response)}. For subclasses of
* {@link WebApplication} you will want to subclass {@link WebSession}.
*
*
*
* @see org.apache.wicket.protocol.http.WebApplication
* @author Jonathan Locke
*/
public abstract class Application
{
/** Configuration constant for the 2 types */
public static final String CONFIGURATION = "configuration";
/**
* Configuration type constant for getting the context path out of the web.xml
*/
public static final String CONTEXTPATH = "contextpath";
/** Configuration type constant for deployment */
public static final String DEPLOYMENT = "deployment";
/** Configuration type constant for development */
public static final String DEVELOPMENT = "development";
/**
* Applications keyed on the {@link #getApplicationKey()} so that they can be retrieved even
* without being in a request/ being set in the thread local (we need that e.g. for when we are
* in a destruction thread).
*/
private static final Map applicationKeyToApplication = new HashMap(
1);
/** Thread local holder of the application object. */
private static final ThreadLocal current = new ThreadLocal();
/** Log. */
private static final Logger log = LoggerFactory.getLogger(Application.class);
/** */
private List componentPreOnBeforeRenderListeners;
/** */
private List componentPostOnBeforeRenderListeners;
/** */
private List componentOnAfterRenderListeners;
/** */
private List renderHeadListeners;
/**
* The decorator this application uses to decorate any header responses created by Wicket
*/
private IHeaderResponseDecorator headerResponseDecorator;
/**
* Checks if the Application
threadlocal is set in this thread
*
* @return true if {@link Application#get()} can return the instance of application, false
* otherwise
*/
public static boolean exists()
{
return current.get() != null;
}
/**
* Get Application for current thread.
*
* @return The current thread's Application
*/
public static Application get()
{
final Application application = current.get();
if (application == null)
{
throw new WicketRuntimeException("There is no application attached to current thread " +
Thread.currentThread().getName());
}
return application;
}
/**
* Gets the Application based on the application key of that application. You typically never
* have to use this method unless you are working on an integration project.
*
* @param applicationKey
* The unique key of the application within a certain context (e.g. a web
* application)
* @return The application or null
if application has not been found
*/
public static Application get(String applicationKey)
{
Application application = applicationKeyToApplication.get(applicationKey);
return application;
}
/**
* Gets the keys of the currently registered Wicket applications for this web application. You
* typically never have to use this method unless you are working on an integration project.
*
* @return unmodifiable set with keys that correspond with {@link #getApplicationKey()}. Never
* null, but possibly empty
*/
public static Set getApplicationKeys()
{
return Collections.unmodifiableSet(applicationKeyToApplication.keySet());
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
*
* @param application
* The current application or null for this thread
*/
public static void set(final Application application)
{
if (application == null)
{
throw new IllegalArgumentException("Argument application can not be null");
}
current.set(application);
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
*/
public static void unset()
{
current.set(null);
}
/** list of {@link IComponentInstantiationListener}s. */
private IComponentInstantiationListener[] componentInstantiationListeners = new IComponentInstantiationListener[0];
/** list of {@link IComponentInitializationListener}s. */
private final CopyOnWriteArrayList componentInitializationListeners = new CopyOnWriteArrayList();
/** The converter locator instance. */
private IConverterLocator converterLocator;
/** list of initializers. */
private final List initializers = new ArrayList();
/** Application level meta data. */
private MetaDataEntry>[] metaData;
/** Name of application subclass. */
private final String name;
/** Request logger instance. */
private IRequestLogger requestLogger;
/** The session facade. */
private ISessionStore sessionStore;
/** Settings for this application. */
private Settings settings;
/** can the settings object be set/used. */
private boolean settingsAccessible;
/** Shared resources for this application */
private final SharedResources sharedResources;
/**
* Constructor. Use {@link #init()} for any configuration of your application instead of
* overriding the constructor.
*/
public Application()
{
// Create name from subclass
name = Classes.simpleName(getClass());
// Create shared resources repository
sharedResources = new SharedResources();
// Install default component instantiation listener that uses
// authorization strategy to check component instantiations.
addComponentInstantiationListener(new IComponentInstantiationListener()
{
/**
* @see org.apache.wicket.application.IComponentInstantiationListener#onInstantiation(org.apache.wicket.Component)
*/
public void onInstantiation(final Component component)
{
final Class extends Component> cl = component.getClass();
// If component instantiation is not authorized
if (!Session.get().getAuthorizationStrategy().isInstantiationAuthorized(cl))
{
// then call any unauthorized component instantiation
// listener
getSecuritySettings().getUnauthorizedComponentInstantiationListener()
.onUnauthorizedInstantiation(component);
}
}
});
}
/**
* Adds a component instantiation listener. This method should typically only be called during
* application startup; it is not thread safe.
*
* Note: wicket does not guarantee the execution order of added listeners
*
* @param listener
* the listener to add
*/
public final void addComponentInstantiationListener(
final IComponentInstantiationListener listener)
{
if (listener == null)
{
throw new IllegalArgumentException("argument listener may not be null");
}
// if an instance of this listener is already present ignore this call
for (int i = 0; i < componentInstantiationListeners.length; i++)
{
if (listener == componentInstantiationListeners[i])
{
return;
}
}
final IComponentInstantiationListener[] newListeners = new IComponentInstantiationListener[componentInstantiationListeners.length + 1];
System.arraycopy(componentInstantiationListeners, 0, newListeners, 0,
componentInstantiationListeners.length);
newListeners[componentInstantiationListeners.length] = listener;
componentInstantiationListeners = newListeners;
}
/**
* Adds a component initialization listener. This method should typically only be called during
* application startup; it is not thread safe.
*
* Each added listener will be notified after Component's {@link Component#onInitialize()}
* method has been executed.
*
*
* Note: wicket does not guarantee the execution order of added listeners
*
* @param listener
* the listener to add
*/
public final void addComponentInitializationListener(
final IComponentInitializationListener listener)
{
if (listener == null)
{
throw new IllegalArgumentException("argument listener may not be null");
}
if (componentInitializationListeners.contains(listener))
{
return;
}
componentInitializationListeners.add(listener);
}
/**
* Fires registered {@link IComponentInitializationListener}s on the component
*
* @param component
*
* @see #addComponentInitializationListener(IComponentInitializationListener)
*/
public final void fireComponentInitializationListeners(Component component)
{
for (IComponentInitializationListener listener : componentInitializationListeners)
{
listener.onInitialize(component);
}
}
/**
* Configures application settings to good defaults.
*/
public final void configure()
{
final String configurationType = getConfigurationType();
// As long as this is public api the development and deployment mode
// should counter act each other for all properties.
if (DEVELOPMENT.equalsIgnoreCase(configurationType))
{
getResourceSettings().setResourcePollFrequency(Duration.ONE_SECOND);
getDebugSettings().setComponentUseCheck(true);
getMarkupSettings().setStripWicketTags(false);
getExceptionSettings().setUnexpectedExceptionDisplay(
IExceptionSettings.SHOW_EXCEPTION_PAGE);
getDebugSettings().setAjaxDebugModeEnabled(true);
getDebugSettings().setDevelopmentUtilitiesEnabled(true);
// getDebugSettings().setOutputMarkupContainerClassName(true);
getResourceSettings().setJavascriptCompressor(null);
getRequestCycleSettings().addResponseFilter(EmptySrcAttributeCheckFilter.INSTANCE);
}
else if (DEPLOYMENT.equalsIgnoreCase(configurationType))
{
getResourceSettings().setResourcePollFrequency(null);
getDebugSettings().setComponentUseCheck(false);
getMarkupSettings().setStripWicketTags(true);
getExceptionSettings().setUnexpectedExceptionDisplay(
IExceptionSettings.SHOW_INTERNAL_ERROR_PAGE);
getDebugSettings().setAjaxDebugModeEnabled(false);
getDebugSettings().setDevelopmentUtilitiesEnabled(false);
getResourceSettings().setJavascriptCompressor(new DefaultJavascriptCompressor());
}
else
{
throw new IllegalArgumentException("Invalid configuration type: '" + configurationType +
"'. Must be \"development\" or \"deployment\".");
}
}
/**
* Gets the unique key of this application within a given context (like a web application). NOT
* INTENDED FOR FRAMEWORK CLIENTS.
*
* @return The unique key of this application
*/
public abstract String getApplicationKey();
/**
* @return Application's application-wide settings
* @see IApplicationSettings
* @since 1.2
*/
public IApplicationSettings getApplicationSettings()
{
return getSettings();
}
/**
* Gets the configuration mode to use for configuring the app, either {@link #DEVELOPMENT} or
* {@link #DEPLOYMENT}.
*
* The configuration type. Must currently be either DEVELOPMENT or DEPLOYMENT. Currently, if the
* configuration type is DEVELOPMENT, resources are polled for changes, component usage is
* checked, wicket tags are not stripped from output and a detailed exception page is used. If
* the type is DEPLOYMENT, component usage is not checked, wicket tags are stripped from output
* and a non-detailed exception page is used to display errors.
*
* Note that you should not run Wicket in DEVELOPMENT mode on production servers - the various
* debugging checks and resource polling is inefficient and may leak resources, particularly on
* webapp redeploy.
*
*
*
* To change the deployment mode, add the following to your web.xml, inside your
* mapping (or mapping if you're using 1.3.x):
*
*
* <init-param>
* <param-name>configuration</param-name>
* <param-value>deployment</param-value>
* </init-param>
*
*
*
* You can alternatively set this as a <context-param> on the whole context.
*
*
* Another option is to set the "wicket.configuration" system property to either "deployment" or
* "development". The value is not case-sensitive.
*
*
* The system property is checked first, allowing you to add a web.xml param for deployment, and
* a command-line override when you want to run in development mode during development.
*
*
* You may also override Application.getConfigurationType() to provide your own custom switch,
* in which case none of the above logic is used.
*
*
* IMPORTANT NOTE
*
* THIS METHOD IS CALLED OFTEN FROM MANY DIFFERENT POINTS IN CODE, INCLUDING DURING THE RENDER
* PROCESS, THEREFORE THE IMPLEMENTATION SHOULD BE FAST - PREFERRABLY USING A FAST-TO-RETRIEVE
* CACHED VALUE
*
*
*
* @return configuration
* @since 1.2.3 (function existed as a property getter)
* @since 1.3.0 (abstract, used to configure things)
*/
public abstract String getConfigurationType();
/**
* @return The converter locator for this application
*/
public final IConverterLocator getConverterLocator()
{
return converterLocator;
}
/**
* @return Application's debug related settings
* @see IDebugSettings
* @since 1.2
*/
public IDebugSettings getDebugSettings()
{
return getSettings();
}
/**
* @return Application's exception handling settings
* @see IExceptionSettings
* @since 1.2
*/
public IExceptionSettings getExceptionSettings()
{
return getSettings();
}
/**
* @return Wicket framework settings
* @see IFrameworkSettings
* @since 1.2
*/
public IFrameworkSettings getFrameworkSettings()
{
return getSettings();
}
/**
* Application subclasses must specify a home page class by implementing this abstract method.
*
* @return Home page class for this application
*/
public abstract Class extends Page> getHomePage();
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
*
* @return The markup cache associated with the application
* @deprecated please use {@link IMarkupSettings#getMarkupCache()} instead
*/
@Deprecated
public final IMarkupCache getMarkupCache()
{
return getMarkupSettings().getMarkupCache();
}
/**
* @return Application's markup related settings
* @see IMarkupSettings
* @since 1.2
*/
public IMarkupSettings getMarkupSettings()
{
return getSettings();
}
/**
* Gets metadata for this application using the given key.
*
* @param
* @param key
* The key for the data
* @return The metadata
* @see MetaDataKey
*/
public final T getMetaData(final MetaDataKey key)
{
return key.get(metaData);
}
/**
* Gets the name of this application.
*
* @return The application name.
*/
public final String getName()
{
return name;
}
/**
* @return Application's page related settings
* @see IPageSettings
* @since 1.2
*/
public IPageSettings getPageSettings()
{
return getSettings();
}
/**
* @return Application's request cycle related settings
* @see IDebugSettings
* @since 1.2
*/
public IRequestCycleSettings getRequestCycleSettings()
{
return getSettings();
}
/**
* Gets the {@link RequestLogger}.
*
* @return The RequestLogger
*/
public final IRequestLogger getRequestLogger()
{
if (getRequestLoggerSettings().isRequestLoggerEnabled())
{
if (requestLogger == null)
{
requestLogger = newRequestLogger();
}
}
else
{
requestLogger = null;
}
return requestLogger;
}
/**
* @return Application's resources related settings
* @see IResourceSettings
* @since 1.3
*/
public IRequestLoggerSettings getRequestLoggerSettings()
{
return getSettings();
}
/**
* @return Application's resources related settings
* @see IResourceSettings
* @since 1.2
*/
public IResourceSettings getResourceSettings()
{
return getSettings();
}
/**
* @return Application's security related settings
* @see ISecuritySettings
* @since 1.2
*/
public ISecuritySettings getSecuritySettings()
{
return getSettings();
}
/**
* @return Application's session related settings
* @see ISessionSettings
* @since 1.2
*/
public ISessionSettings getSessionSettings()
{
return getSettings();
}
/**
* Gets the facade object for working getting/ storing session instances.
*
* @return The session facade
*/
public final ISessionStore getSessionStore()
{
return sessionStore;
}
/**
* Gets the shared resources.
*
* @return The SharedResources for this application.
*/
public final SharedResources getSharedResources()
{
return sharedResources;
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
*
* Initializes wicket components.
*/
public final void initializeComponents()
{
// Load any wicket properties files we can find
try
{
// Load properties files used by all libraries
final Iterator resources = getApplicationSettings().getClassResolver()
.getResources("wicket.properties");
while (resources.hasNext())
{
InputStream in = null;
try
{
final URL url = resources.next();
final Properties properties = new Properties();
in = url.openStream();
properties.load(in);
load(properties);
}
finally
{
if (in != null)
{
in.close();
}
}
}
}
catch (IOException e)
{
throw new WicketRuntimeException("Unable to load initializers file", e);
}
// now call any initializers we read
callInitializers();
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
*
* @param target
*/
public void logEventTarget(IRequestTarget target)
{
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
*
* @param requestTarget
*/
public void logResponseTarget(IRequestTarget requestTarget)
{
}
/**
* Creates a new RequestCycle object. Override this method if you want to provide a custom
* request cycle.
*
* @param request
* The request
* @param response
* The response
* @return The request cycle
*
* @since 1.3
*/
public abstract RequestCycle newRequestCycle(final Request request, final Response response);
/**
* FOR DEPRECATION ONLY.
*
* @param application
* @param request
* @param response
* @return nothing
* @throws UnsupportedOperationException
* always
* @deprecated Applications wishing to provide custom request cycles should override method
* {@link #newRequestCycle(Request, Response)}
*/
@Deprecated
public final RequestCycle newRequestCycle(Application application, Request request,
Response response)
{
throw new UnsupportedOperationException();
}
/**
* Creates a new session. Override this method if you want to provide a custom session.
*
* @param request
* The request that will create this session.
* @param response
* The response to initialize, for example with cookies. This is important to use
* cases involving unit testing because those use cases might want to be able to sign
* a user in automatically when the session is created.
*
* @return The session
*
* @since 1.3
*/
public abstract Session newSession(Request request, Response response);
/**
* Removes a component instantiation listener. This method should typicaly only be called during
* application startup; it is not thread safe.
*
* @param listener
* the listener to remove
*/
public final void removeComponentInstantiationListener(
final IComponentInstantiationListener listener)
{
final IComponentInstantiationListener[] listeners = componentInstantiationListeners;
final int len = listeners.length;
if (listener != null && len > 0)
{
int pos = 0;
for (pos = 0; pos < len; pos++)
{
if (listener == listeners[pos])
{
break;
}
}
if (pos < len)
{
listeners[pos] = listeners[len - 1];
final IComponentInstantiationListener[] newListeners = new IComponentInstantiationListener[len - 1];
System.arraycopy(listeners, 0, newListeners, 0, newListeners.length);
componentInstantiationListeners = newListeners;
}
}
}
/**
* Sets the metadata for this application using the given key. If the metadata object is not of
* the correct type for the metadata key, an IllegalArgumentException will be thrown. For
* information on creating MetaDataKeys, see {@link MetaDataKey}.
*
* @param
* @param key
* The singleton key for the metadata
* @param object
* The metadata object
* @throws IllegalArgumentException
* @see MetaDataKey
*/
// TODO: Replace the Serializable type with Object for next wicket version
public final synchronized void setMetaData(final MetaDataKey key, final Object object)
{
metaData = key.set(metaData, object);
}
/**
* Construct and add initializer from the provided class name.
*
* @param className
*/
private final void addInitializer(String className)
{
IInitializer initializer = (IInitializer)Objects.newInstance(className);
if (initializer != null)
{
initializers.add(initializer);
}
}
/**
* Iterate initializers list, calling any {@link org.apache.wicket.IDestroyer} instances found
* in it.
*/
private final void callDestroyers()
{
for (Iterator iter = initializers.iterator(); iter.hasNext();)
{
IInitializer initializer = iter.next();
if (initializer instanceof IDestroyer)
{
log.info("[" + getName() + "] destroy: " + initializer);
((IDestroyer)initializer).destroy(this);
}
}
}
/**
* Iterate initializers list, calling any instances found in it.
*/
private final void callInitializers()
{
for (Iterator iter = initializers.iterator(); iter.hasNext();)
{
IInitializer initializer = iter.next();
log.info("[" + getName() + "] init: " + initializer);
initializer.init(this);
}
}
/**
* This method is still here for backwards compatibility with 1.1 source code. The
* getXXXSettings() methods are now preferred. This method will be removed post 1.2 version.
*
* @return Application settings
*
* @see Application#getApplicationSettings()
* @see Application#getDebugSettings()
* @see Application#getExceptionSettings()
* @see Application#getMarkupSettings()
* @see Application#getPageSettings()
* @see Application#getRequestCycleSettings()
* @see Application#getResourceSettings()
* @see Application#getSecuritySettings()
* @see Application#getSessionSettings()
*/
private Settings getSettings()
{
if (!settingsAccessible)
{
throw new WicketRuntimeException(
"Use Application.init() method for configuring your application object");
}
if (settings == null)
{
settings = new Settings(this);
}
return settings;
}
/**
* @param properties
* Properties map with names of any library initializers in it
*/
private final void load(final Properties properties)
{
addInitializer(properties.getProperty("initializer"));
addInitializer(properties.getProperty(getName() + "-initializer"));
}
/**
* Called when wicket servlet is destroyed. Overrides do not have to call super.
*
* @deprecated use {@link #onDestroy()} instead
*/
// TODO remove after deprecation release
@Deprecated
protected final void destroy()
{
}
/**
* Called when wicket servlet is destroyed. Overrides do not have to call super.
*/
protected void onDestroy()
{
}
/**
* @return Request cycle factory for this kind of session.
* @deprecated replaced by {@link #newRequestCycle(Request, Response)}
*/
// TODO remove after deprecation release
@Deprecated
protected final Object getRequestCycleFactory()
{
throw new UnsupportedOperationException();
}
/**
* Gets the factory for creating session instances.
*
* @return Factory for creating session instances
* @deprecated replaced by {@link #newSession(Request, Response)}
*/
// TODO remove after deprecation release
@Deprecated
protected final Object getSessionFactory()
{
throw new UnsupportedOperationException();
}
/**
* Allows for initialization of the application by a subclass. Use this method for any
* application setup instead of the constructor.
*/
protected void init()
{
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
*/
protected void internalDestroy()
{
// destroy detach listener
final IDetachListener detachListener = getFrameworkSettings().getDetachListener();
if (detachListener != null)
{
detachListener.onDestroyListener();
}
// Clear caches of Class keys so the classloader can be garbage
// collected (WICKET-625)
PropertyResolver.destroy(this);
getMarkupSettings().getMarkupCache().shutdown();
onDestroy();
callDestroyers();
applicationKeyToApplication.remove(getApplicationKey());
Session.unset();
RequestContext.unset();
RequestCycle.set(null);
}
/**
* THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT OVERRIDE OR CALL.
*
* Internal initialization.
*/
protected void internalInit()
{
settingsAccessible = true;
IPageSettings pageSettings = getPageSettings();
// Install default component resolvers
pageSettings.addComponentResolver(new ParentResolver());
pageSettings.addComponentResolver(new AutoComponentResolver());
pageSettings.addComponentResolver(new MarkupInheritanceResolver());
pageSettings.addComponentResolver(new HtmlHeaderResolver());
pageSettings.addComponentResolver(new WicketLinkResolver());
pageSettings.addComponentResolver(new WicketMessageResolver());
pageSettings.addComponentResolver(new WicketMessageTagHandler());
pageSettings.addComponentResolver(new FragmentResolver());
pageSettings.addComponentResolver(new RelativePathPrefixHandler());
pageSettings.addComponentResolver(new EnclosureResolver());
pageSettings.addComponentResolver(new WicketContainerResolver());
pageSettings.addComponentResolver(new BorderBodyResolver());
// Install button image resource factory
getResourceSettings().addResourceFactory("buttonFactory",
new DefaultButtonImageResourceFactory());
String applicationKey = getApplicationKey();
applicationKeyToApplication.put(applicationKey, this);
sessionStore = newSessionStore();
converterLocator = newConverterLocator();
}
/**
* Creates and returns a new instance of {@link IConverterLocator}.
*
* @return A new {@link IConverterLocator} instance
*/
protected IConverterLocator newConverterLocator()
{
return new ConverterLocator();
}
/**
* creates a new request logger when requests logging is enabled.
*
* @return The new request logger
*
*/
protected IRequestLogger newRequestLogger()
{
return new RequestLogger();
}
/**
* Creates a new session facade. Is called once per application, and is typically not something
* clients reimplement.
*
* @return The session facade
*/
protected abstract ISessionStore newSessionStore();
/**
* Notifies the registered component instantiation listeners of the construction of the provided
* component
*
* @param component
* the component that is being instantiated
*/
final void notifyComponentInstantiationListeners(final Component component)
{
final int len = componentInstantiationListeners.length;
for (int i = 0; i < len; i++)
{
componentInstantiationListeners[i].onInstantiation(component);
}
}
/**
* Adds an {@link IComponentOnBeforeRenderListener}. This method should typically only be called
* during application startup; it is not thread safe.
*
* @param listener
*/
final public void addPreComponentOnBeforeRenderListener(
final IComponentOnBeforeRenderListener listener)
{
if (componentPreOnBeforeRenderListeners == null)
{
componentPreOnBeforeRenderListeners = new ArrayList();
}
if (componentPreOnBeforeRenderListeners.contains(listener) == false)
{
componentPreOnBeforeRenderListeners.add(listener);
}
}
/**
* Removes an {@link IComponentOnBeforeRenderListener}.
*
* @param listener
*/
final public void removePreComponentOnBeforeRenderListener(
final IComponentOnBeforeRenderListener listener)
{
if (componentPreOnBeforeRenderListeners != null)
{
componentPreOnBeforeRenderListeners.remove(listener);
if (componentPreOnBeforeRenderListeners.isEmpty())
{
componentPreOnBeforeRenderListeners = null;
}
}
}
/**
* Notifies the {@link IComponentOnBeforeRenderListener}s.
*
* @param component
*/
final void notifyPreComponentOnBeforeRenderListeners(final Component component)
{
if (componentPreOnBeforeRenderListeners != null)
{
for (Iterator iter = componentPreOnBeforeRenderListeners.iterator(); iter.hasNext();)
{
IComponentOnBeforeRenderListener listener = iter.next();
listener.onBeforeRender(component);
}
}
}
/**
* Adds an {@link IComponentOnBeforeRenderListener}. This method should typically only be called
* during application startup; it is not thread safe.
*
* @param listener
*/
final public void addPostComponentOnBeforeRenderListener(
final IComponentOnBeforeRenderListener listener)
{
if (componentPostOnBeforeRenderListeners == null)
{
componentPostOnBeforeRenderListeners = new ArrayList();
}
if (componentPostOnBeforeRenderListeners.contains(listener) == false)
{
componentPostOnBeforeRenderListeners.add(listener);
}
}
/**
* Removes an {@link IComponentOnBeforeRenderListener}.
*
* @param listener
*/
final public void removePostComponentOnBeforeRenderListener(
final IComponentOnBeforeRenderListener listener)
{
if (componentPostOnBeforeRenderListeners != null)
{
componentPostOnBeforeRenderListeners.remove(listener);
if (componentPostOnBeforeRenderListeners.isEmpty())
{
componentPostOnBeforeRenderListeners = null;
}
}
}
/**
* Notifies the {@link IComponentOnBeforeRenderListener}s.
*
* @param component
*/
final void notifyPostComponentOnBeforeRenderListeners(final Component component)
{
if (componentPostOnBeforeRenderListeners != null)
{
for (Iterator iter = componentPostOnBeforeRenderListeners.iterator(); iter.hasNext();)
{
IComponentOnBeforeRenderListener listener = iter.next();
listener.onBeforeRender(component);
}
}
}
/**
* Adds an {@link IComponentOnAfterRenderListener}. This method should typically only be called
* during application startup; it is not thread safe.
*
* @param listener
*/
final public void addComponentOnAfterRenderListener(
final IComponentOnAfterRenderListener listener)
{
if (componentOnAfterRenderListeners == null)
{
componentOnAfterRenderListeners = new ArrayList();
}
if (componentOnAfterRenderListeners.contains(listener) == false)
{
componentOnAfterRenderListeners.add(listener);
}
}
/**
* Removes an {@link IComponentOnAfterRenderListener}.
*
* @param listener
*/
final public void removeComponentOnAfterRenderListener(
final IComponentOnAfterRenderListener listener)
{
if (componentOnAfterRenderListeners != null)
{
componentOnAfterRenderListeners.remove(listener);
if (componentOnAfterRenderListeners.isEmpty())
{
componentOnAfterRenderListeners = null;
}
}
}
/**
* Notifies the {@link IComponentOnAfterRenderListener}s.
*
* @param component
*/
final void notifyComponentOnAfterRenderListeners(final Component component)
{
if (componentOnAfterRenderListeners != null)
{
for (Iterator iter = componentOnAfterRenderListeners.iterator(); iter.hasNext();)
{
IComponentOnAfterRenderListener listener = iter.next();
listener.onAfterRender(component);
}
}
}
/**
* Adds a listener that will be invoked for every header response
*
* @param listener
*/
public final void addRenderHeadListener(final IHeaderContributor listener)
{
if (renderHeadListeners == null)
{
renderHeadListeners = new ArrayList();
}
renderHeadListeners.add(listener);
}
/**
*
* @param listener
*/
public void removeRenderHeadListener(final IHeaderContributor listener)
{
if (renderHeadListeners != null)
{
renderHeadListeners.remove(listener);
if (renderHeadListeners.isEmpty())
{
renderHeadListeners = null;
}
}
}
/**
* INTERNAL
*
* @param response
*/
public void notifyRenderHeadListener(final IHeaderResponse response)
{
if (renderHeadListeners != null)
{
for (Iterator iter = renderHeadListeners.iterator(); iter.hasNext();)
{
IHeaderContributor listener = iter.next();
listener.renderHead(response);
}
}
}
/**
* Sets an {@link IHeaderResponseDecorator} that you want your application to use to decorate
* header responses.
*
* @param headerResponseDecorator
* your custom decorator
*/
public void setHeaderResponseDecorator(IHeaderResponseDecorator headerResponseDecorator)
{
this.headerResponseDecorator = headerResponseDecorator;
}
/**
* INTERNAL METHOD - You shouldn't need to call this. This is called every time Wicket creates
* an IHeaderResponse. It gives you the ability to incrementally add features to an
* IHeaderResponse implementation by wrapping it in another implementation.
*
* To decorate an IHeaderResponse in your application, set the {@link IHeaderResponseDecorator}
* on the application.
*
* @see IHeaderResponseDecorator
* @param response
* the response Wicket created
* @return the response Wicket should use in IHeaderContributor traversal
*/
public final IHeaderResponse decorateHeaderResponse(IHeaderResponse response)
{
IHeaderResponse hr = headerResponseDecorator == null ? response
: headerResponseDecorator.decorate(response);
notifyRenderHeadListener(hr);
return hr;
}
}