Package org.apache.wicket.protocol.http

Source Code of org.apache.wicket.protocol.http.WebApplication

/*
* 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.protocol.http;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.wicket.Application;
import org.apache.wicket.IRequestCycleFactory;
import org.apache.wicket.IRequestTarget;
import org.apache.wicket.ISessionFactory;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Response;
import org.apache.wicket.Session;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.html.pages.AccessDeniedPage;
import org.apache.wicket.markup.html.pages.InternalErrorPage;
import org.apache.wicket.markup.html.pages.PageExpiredErrorPage;
import org.apache.wicket.markup.resolver.AutoLinkResolver;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.apache.wicket.request.IRequestCycleProcessor;
import org.apache.wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy;
import org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy;
import org.apache.wicket.request.target.coding.PackageRequestTargetUrlCodingStrategy;
import org.apache.wicket.request.target.coding.SharedResourceRequestTargetUrlCodingStrategy;
import org.apache.wicket.session.ISessionStore;
import org.apache.wicket.util.collections.MostRecentlyUsedMap;
import org.apache.wicket.util.file.WebApplicationPath;
import org.apache.wicket.util.lang.PackageName;
import org.apache.wicket.util.watch.ModificationWatcher;


/**
* A web application is a subclass of Application which associates with an
* instance of WicketServlet to serve pages over the HTTP protocol. This class
* is intended to be subclassed by framework clients to define a web
* application.
* <p>
* Application settings are given defaults by the WebApplication() constructor
* and internalInit method, such as error page classes appropriate for HTML.
* WebApplication subclasses can override these values and/or modify other
* application settings by overriding the init() method and then by calling
* getXXXSettings() to retrieve an interface to a mutable Settings object. Do
* not do this in the constructor itself because the defaults will then override
* your settings.
* <p>
* If you want to use a filter specific configuration, e.g. using init
* parameters from the {@link javax.servlet.FilterConfig} object, you should
* override the init() method. For example:
*
* <pre>
*               public void init()
*               {
*                   String webXMLParameter = getInitParameter(&quot;myWebXMLParameter&quot;);
*                   URL schedulersConfig = getServletContext().getResource(&quot;/WEB-INF/schedulers.xml&quot;);
*                   ...
* </pre>
*
* @see WicketFilter
* @see org.apache.wicket.settings.IApplicationSettings
* @see org.apache.wicket.settings.IDebugSettings
* @see org.apache.wicket.settings.IExceptionSettings
* @see org.apache.wicket.settings.IMarkupSettings
* @see org.apache.wicket.settings.IPageSettings
* @see org.apache.wicket.settings.IRequestCycleSettings
* @see org.apache.wicket.settings.IResourceSettings
* @see org.apache.wicket.settings.ISecuritySettings
* @see org.apache.wicket.settings.ISessionSettings
* @see javax.servlet.Filter
* @see javax.servlet.FilterConfig
* @see javax.servlet.ServletContext
*
* @author Jonathan Locke
* @author Chris Turner
* @author Johan Compagner
* @author Eelco Hillenius
* @author Juergen Donnerstag
*/
public abstract class WebApplication extends Application implements ISessionFactory
{
  /** Log. */
  private static final Log log = LogFactory.getLog(WebApplication.class);

  /**
   * The cached application key. Will be set in
   * {@link #setWicketServlet(WicketServlet)} based on the servlet context.
   */
  private String applicationKey;

  /**
   * Map of buffered responses that are in progress per session. Buffered
   * responses are temporarily stored
   */
  private final Map bufferedResponses = new HashMap();

  /** the default request cycle processor implementation. */
  private IRequestCycleProcessor requestCycleProcessor;

  /**
   * the prefix for storing variables in the actual session (typically
   * {@link HttpSession} for this application instance.
   */
  private String sessionAttributePrefix;

  /** Session factory for this web application */
  private ISessionFactory sessionFactory = this;

  /** The WicketFilter that this application is attached to */
  private WicketFilter wicketFilter;

  /**
   * Constructor. <strong>Use {@link #init()} for any configuration of your
   * application instead of overriding the constructor.</strong>
   */
  public WebApplication()
  {
  }

  /**
   * @see org.apache.wicket.Application#getApplicationKey()
   */
  public final String getApplicationKey()
  {
    if (applicationKey == null)
    {
      throw new IllegalStateException("the application key does not seem to"
          + " be set properly or this method is called before WicketServlet is"
          + " set, which leads to the wrong behavior");
    }
    return applicationKey;
  }

  /**
   * Gets an init parameter from the filter's context.
   *
   * @param key
   *            the key to search for
   * @return the value of the filter init parameter
   */
  public final String getInitParameter(String key)
  {
    if (wicketFilter != null)
    {
      return wicketFilter.getFilterConfig().getInitParameter(key);
    }
    throw new IllegalStateException("servletContext is not set yet. Any code in your"
        + " Application object that uses the wicketServlet/Filter instance should be put"
        + " in the init() method instead of your constructor");
  }

  /**
   * Gets the default request cycle processor (with lazy initialization). This
   * is the {@link IRequestCycleProcessor} that will be used by
   * {@link RequestCycle}s when custom implementations of the request cycle
   * do not provide their own customized versions.
   *
   * @return the default request cycle processor
   */
  public final IRequestCycleProcessor getRequestCycleProcessor()
  {
    if (requestCycleProcessor == null)
    {
      requestCycleProcessor = newRequestCycleProcessor();
    }
    return requestCycleProcessor;
  }

  /**
   * Gets the servlet context for this application. Use this to get references
   * to absolute paths, global web.xml parameters (<context-param>), etc.
   *
   * @return The servlet context for this application
   */
  public final ServletContext getServletContext()
  {
    if (wicketFilter != null)
    {
      return wicketFilter.getFilterConfig().getServletContext();
    }
    throw new IllegalStateException("servletContext is not set yet. Any code in your"
        + " Application object that uses the wicket filter instance should be put"
        + " in the init() method instead of your constructor");
  }

  /**
   * Gets the prefix for storing variables in the actual session (typically
   * {@link HttpSession} for this application instance.
   *
   * @param request
   *            the request
   *
   * @return the prefix for storing variables in the actual session
   */
  public final String getSessionAttributePrefix(final WebRequest request)
  {
    if (sessionAttributePrefix == null)
    {
      String servletPath = request.getServletPath();
      if (servletPath == null)
      {
        throw new WicketRuntimeException("unable to retrieve servlet path");
      }
      sessionAttributePrefix = "wicket:" + servletPath + ":";
    }
    // Namespacing for session attributes is provided by
    // adding the servlet path
    return sessionAttributePrefix;
  }

  /**
   * @return The Wicket filter for this application
   */
  public final WicketFilter getWicketFilter()
  {
    return wicketFilter;
  }

  /**
   * @see org.apache.wicket.Application#logEventTarget(org.apache.wicket.IRequestTarget)
   */
  public void logEventTarget(IRequestTarget target)
  {
    super.logEventTarget(target);
    IRequestLogger rl = getRequestLogger();
    if (rl != null)
    {
      rl.logEventTarget(target);
    }
  }

  /**
   * @see org.apache.wicket.Application#logResponseTarget(org.apache.wicket.IRequestTarget)
   */
  public void logResponseTarget(IRequestTarget target)
  {
    super.logResponseTarget(target);
    IRequestLogger rl = getRequestLogger();
    if (rl != null)
    {
      rl.logResponseTarget(target);
    }
  }

  /**
   * Mounts an encoder at the given path.
   *
   * @param encoder
   *            the encoder that will be used for this mount
   */
  public final void mount(IRequestTargetUrlCodingStrategy encoder)
  {
    if (encoder == null)
    {
      throw new IllegalArgumentException("Encoder must be not null");
    }

    getRequestCycleProcessor().getRequestCodingStrategy().mount(encoder);
  }

  /**
   * Mounts all bookmarkable pages at the given path.
   *
   * @param path
   *            the path to mount the bookmarkable page class on
   * @param packageName
   *            the name of the package for which all bookmarkable pages or
   *            sharedresources should be mounted
   */
  public final void mount(final String path, final PackageName packageName)
  {
    if (packageName == null)
    {
      throw new IllegalArgumentException("PackageName cannot be null");
    }
    mount(new PackageRequestTargetUrlCodingStrategy(path, packageName));
  }

  /**
   * Mounts a bookmarkable page class to the given path.
   *
   * @param path
   *            the path to mount the bookmarkable page class on
   * @param bookmarkablePageClass
   *            the bookmarkable page class to mount
   */
  public final void mountBookmarkablePage(final String path, final Class bookmarkablePageClass)
  {
    mount(new BookmarkablePageRequestTargetUrlCodingStrategy(path, bookmarkablePageClass, null));
  }

  /**
   * Mounts a bookmarkable page class to the given pagemap and path.
   *
   * @param path
   *            the path to mount the bookmarkable page class on
   * @param pageMapName
   *            name of the pagemap this mount is for
   * @param bookmarkablePageClass
   *            the bookmarkable page class to mount
   */
  public final void mountBookmarkablePage(final String path, final String pageMapName,
      final Class bookmarkablePageClass)
  {
    mount(new BookmarkablePageRequestTargetUrlCodingStrategy(path, bookmarkablePageClass,
        pageMapName));
  }

  /**
   * Mounts a shared resource class to the given path.
   *
   * @param path
   *            the path to mount the bookmarkable page class on
   * @param resourceKey
   *            the shared key of the resource being mounted
   */
  public final void mountSharedResource(final String path, final String resourceKey)
  {
    mount(new SharedResourceRequestTargetUrlCodingStrategy(path, resourceKey));
  }

  /**
   * Create new Wicket Session object. Note, this method is not called if you
   * registered your own ISessionFactory with the Application.
   *
   * @return The created session
   * @deprecated see {@link WebApplication#newSession(Request, Response)}.
   */
  // FIXME remove this method after 1.3.0
  public final Session newSession()
  {
    throw new UnsupportedOperationException("this method is replaced by Application#newSession");
  }

  /**
   * Create new Wicket Session object. Note, this method is not called if you
   * registered your own ISessionFactory with the Application.
   *
   * @param request
   * @return The created session
   * @deprecated {@link WebApplication#newSession(Request, Response)}.
   */
  // FIXME remove this method after 1.3.0
  public final Session newSession(Request request)
  {
    throw new UnsupportedOperationException("this method is replaced by Application#newSession");
  }

  /**
   * @see org.apache.wicket.ISessionFactory#newSession(org.apache.wicket.Request,
   *      org.apache.wicket.Response)
   */
  public Session newSession(Request request, Response response)
  {
    return new WebSession(WebApplication.this, request);
  }

  /**
   * @param sessionId
   *            The session id that was destroyed
   */
  public void sessionDestroyed(String sessionId)
  {
    bufferedResponses.remove(sessionId);

    IRequestLogger logger = getRequestLogger();
    if (logger != null)
    {
      logger.sessionDestroyed(sessionId);
    }
  }

  /**
   * @param sessionFactory
   *            The session factory to use
   */
  public final void setSessionFactory(final ISessionFactory sessionFactory)
  {
    this.sessionFactory = sessionFactory;
  }

  /**
   * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
   *
   * @param wicketFilter
   *            The wicket filter instance for this application
   */
  public final void setWicketFilter(final WicketFilter wicketFilter)
  {
    this.wicketFilter = wicketFilter;
    this.applicationKey = wicketFilter.getFilterConfig().getFilterName();
  }

  /**
   * Unmounts whatever encoder is mounted at a given path.
   *
   * @param path
   *            the path of the encoder to unmount
   */
  public final void unmount(String path)
  {
    getRequestCycleProcessor().getRequestCodingStrategy().unmount(path);
  }

  /**
   * @return
   * @deprecated Replaced by {@link #getRequestCycleFactory()}
   */
  protected final IRequestCycleFactory getDefaultRequestCycleFactory()
  {
    throw new UnsupportedOperationException("obsolete method. see getRequestCycleFactory");
  }

  /**
   * Create a request cycle factory which is used by default by WebSession.
   * You may provide your own default factory by subclassing WebApplication
   * and overriding this method or your may subclass WebSession to create a
   * session specific request cycle factory.
   *
   * @see WebSession#getRequestCycleFactory()
   * @see IRequestCycleFactory
   *
   * @return Request cycle factory
   */
  protected IRequestCycleFactory getRequestCycleFactory()
  {
    return new IRequestCycleFactory()
    {
      private static final long serialVersionUID = 1L;

      public RequestCycle newRequestCycle(final Application application,
          final Request request, final Response response)
      {
        // Respond to request
        return new WebRequestCycle((WebApplication)application, (WebRequest)request,
            (WebResponse)response);
      }
    };
  }

  /**
   * @see org.apache.wicket.Application#getSessionFactory()
   */
  protected ISessionFactory getSessionFactory()
  {
    return this.sessionFactory;
  }

  /**
   * Initialize; if you need the wicket servlet for initialization, e.g.
   * because you want to read an initParameter from web.xml or you want to
   * read a resource from the servlet's context path, you can override this
   * method and provide custom initialization. This method is called right
   * after this application class is constructed, and the wicket servlet is
   * set. <strong>Use this method for any application setup instead of the
   * constructor.</strong>
   */
  protected void init()
  {
  }

  /**
   * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
   */
  protected void internalDestroy()
  {
    // destroy the resource watcher
    ModificationWatcher resourceWatcher = getResourceSettings().getResourceWatcher(false);
    if (resourceWatcher != null)
    {
      resourceWatcher.destroy();
    }
    super.internalDestroy();
    bufferedResponses.clear();
    getSessionStore().destroy();
  }

  /**
   * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
   *
   * Internal intialization. First determine the deployment mode. First check
   * the system property -Dwicket.configuration. If it does not exist check
   * the servlet init parameter (
   * <code>&lt;init-param&gt&lt;param-name&gt;configuration&lt;/param-name&gt;</code>).
   * If not found check the servlet context init paramert
   * <code>&lt;context-param&gt&lt;param-name6gt;configuration&lt;/param-name&gt;</code>).
   * If the parameter is "development" (which is default), settings
   * appropriate for development are set. If it's "deployment" , deployment
   * settings are used. If development is specified and a "sourceFolder" init
   * parameter is also set, then resources in that folder will be polled for
   * changes.
   */
  protected void internalInit()
  {
    super.internalInit();

    // Set default error pages for HTML markup
    getApplicationSettings().setPageExpiredErrorPage(PageExpiredErrorPage.class);
    getApplicationSettings().setInternalErrorPage(InternalErrorPage.class);
    getApplicationSettings().setAccessDeniedPage(AccessDeniedPage.class);

    // Add resolver for automatically resolving HTML links
    getPageSettings().addComponentResolver(new AutoLinkResolver());

    // Set resource finder to web app path
    getResourceSettings().setResourceFinder(new WebApplicationPath(getServletContext()));

    String contextPath = getInitParameter(Application.CONTEXTPATH);
    if (contextPath != null)
    {
      getApplicationSettings().setContextPath(contextPath);
    }

    // Check if system property -Dwicket.configuration exists
    String configuration = null;
    try
    {
      configuration = System.getProperty("wicket." + Application.CONFIGURATION);
    }
    catch (SecurityException e)
    {
      // ignore; it is not allowed to read system properties
    }

    // If no system parameter check servlet specific <init-param>
    if (configuration == null)
    {
      configuration = getInitParameter(Application.CONFIGURATION);
    }
    // If no system parameter and no <init-param>, then check
    // <context-param>
    if (configuration == null)
    {
      configuration = getServletContext().getInitParameter(Application.CONFIGURATION);
    }

    // Development mode is the default if no settings have been found
    if (configuration != null)
    {
      configure(configuration, getInitParameter("sourceFolder"));
    }
    else
    {
      configure(Application.DEVELOPMENT, getInitParameter("sourceFolder"));
    }
  }

  /**
   * Gets a new request cycle processor for web requests. May be replaced by
   * subclasses which whishes to uses there own implementation of
   * IRequestCycleProcessor.
   *
   * NOTE this can't be moved to application as portlets use two different
   * request cycle processors, and hence have two different methods for them,
   * depending on the kind of request.
   *
   * @return IRequestCycleProcessor
   */
  protected IRequestCycleProcessor newRequestCycleProcessor()
  {
    return new WebRequestCycleProcessor();
  }

  /**
   * @see org.apache.wicket.Application#newSessionStore()
   */
  protected ISessionStore newSessionStore()
  {
    return new SecondLevelCacheSessionStore(this, new FilePageStore());
  }

  /**
   * Create a new WebRequest. Subclasses of WebRequest could e.g. decode and
   * obfuscated URL which has been encoded by an appropriate WebResponse.
   *
   * @param servletRequest
   * @return a WebRequest object
   */
  protected WebRequest newWebRequest(final HttpServletRequest servletRequest)
  {
    return new ServletWebRequest(servletRequest);
  }

  /**
   * Create a WebResponse. Subclasses of WebRequest could e.g. encode wicket's
   * default URL and hide the details from the user. A appropriate WebRequest
   * must be implemented and configured to decode the encoded URL.
   *
   * @param servletResponse
   * @return a WebResponse object
   */
  protected WebResponse newWebResponse(final HttpServletResponse servletResponse)
  {
    return (getRequestCycleSettings().getBufferResponse() ? new BufferedWebResponse(
        servletResponse) : new WebResponse(servletResponse));
  }

  /*
   * Set the application key value
   */
  protected final void setApplicationKey(String applicationKey)
  {
    this.applicationKey = applicationKey;
  }

  /**
   * Add a buffered response to the redirect buffer.
   *
   * @param sessionId
   *            the session id
   * @param bufferId
   *            the id that should be used for storing the buffer
   * @param renderedResponse
   *            the response to buffer
   */
  final void addBufferedResponse(String sessionId, String bufferId,
      BufferedHttpServletResponse renderedResponse)
  {
    Map responsesPerSession = (Map)bufferedResponses.get(sessionId);
    if (responsesPerSession == null)
    {
      responsesPerSession = new MostRecentlyUsedMap(4);
      bufferedResponses.put(sessionId, responsesPerSession);
    }
    responsesPerSession.put(bufferId, renderedResponse);
  }

  /**
   * Log that this application is started.
   */
  final void logStarted()
  {
    String version = getFrameworkSettings().getVersion();
    StringBuffer b = new StringBuffer();
    b.append("[").append(getName()).append("] Started Wicket ");
    if (!"n/a".equals(version))
    {
      b.append("version ").append(version).append(" ");
    }
    b.append("in ").append(getConfigurationType()).append(" mode");
    log.info(b.toString());
  }

  /**
   * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
   *
   * Creates a new RequestCycle for the given request and response using the
   * application's request cycle factory.
   *
   * @param request
   *            The request
   * @param response
   *            The response
   * @return The new request cycle.
   */
  final RequestCycle newRequestCycle(final Request request, final Response response)
  {
    return getRequestCycleFactory().newRequestCycle(this, request, response);
  }

  // TODO remove after deprecation release

  /**
   * Returns the redirect map where the buffered render pages are stored in
   * and removes it immediately.
   *
   * @param sessionId
   *            the session id
   *
   * @param bufferId
   *            the id of the buffer as passed in as a request parameter
   * @return the buffered response or null if not found (when this request is
   *         on a different box than the original request came in
   */
  final BufferedHttpServletResponse popBufferedResponse(String sessionId, String bufferId)
  {
    Map responsesPerSession = (Map)bufferedResponses.get(sessionId);
    if (responsesPerSession != null)
    {
      BufferedHttpServletResponse buffered = (BufferedHttpServletResponse)responsesPerSession
          .remove(bufferId);
      if (responsesPerSession.size() == 0)
      {
        bufferedResponses.remove(sessionId);
      }
      return buffered;
    }
    return null;
  }
}
TOP

Related Classes of org.apache.wicket.protocol.http.WebApplication

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.