Package org.springframework.web.servlet.view

Source Code of org.springframework.web.servlet.view.AbstractCachingViewResolver

/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed 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.springframework.web.servlet.view;

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

import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

/**
* Convenient base class for {@link org.springframework.web.servlet.ViewResolver}
* implementations. Caches {@link org.springframework.web.servlet.View} objects
* once resolved: This means that view resolution won't be a performance problem,
* no matter how costly initial view retrieval is.
*
* <p>Subclasses need to implement the {@link #loadView} template method,
* building the View object for a specific view name and locale.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see #loadView
*/
public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {

  /** Whether we should cache views, once resolved */
  private boolean cache = true;

  /** Whether we should refrain from resolving views again if unresolved once */
  private boolean cacheUnresolved = true;

  /** Map from view key to View instance */
  private final Map<Object, View> viewCache = new HashMap<Object, View>();


  /**
   * Enable or disable caching.
   * <p>Default is "true": caching is enabled.
   * Disable this only for debugging and development.
   * <p><b>Warning: Disabling caching can severely impact performance.</b>
   */
  public void setCache(boolean cache) {
    this.cache = cache;
  }

  /**
   * Return if caching is enabled.
   */
  public boolean isCache() {
    return this.cache;
  }

  /**
   * Whether a view name once resolved to {@code null} should be cached and
   * automatically resolved to {@code null} subsequently.
   * <p>Default is "true": unresolved view names are being cached, as of Spring 3.1.
   * Note that this flag only applies if the general {@link #setCache "cache"}
   * flag is kept at its default of "true" as well.
   * <p>Of specific interest is the ability for some AbstractUrlBasedView
   * implementations (FreeMarker, Velocity, Tiles) to check if an underlying
   * resource exists via {@link AbstractUrlBasedView#checkResource(Locale)}.
   * With this flag set to "false", an underlying resource that re-appears
   * is noticed and used. With the flag set to "true", one check is made only.
   */
  public void setCacheUnresolved(boolean cacheUnresolved) {
    this.cacheUnresolved = cacheUnresolved;
  }

  /**
   * Return if caching of unresolved views is enabled.
   */
  public boolean isCacheUnresolved() {
    return this.cacheUnresolved;
  }


  public View resolveViewName(String viewName, Locale locale) throws Exception {
    if (!isCache()) {
      return createView(viewName, locale);
    }
    else {
      Object cacheKey = getCacheKey(viewName, locale);
      synchronized (this.viewCache) {
        View view = this.viewCache.get(cacheKey);
        if (view == null && (!this.cacheUnresolved || !this.viewCache.containsKey(cacheKey))) {
          // Ask the subclass to create the View object.
          view = createView(viewName, locale);
          if (view != null || this.cacheUnresolved) {
            this.viewCache.put(cacheKey, view);
            if (logger.isTraceEnabled()) {
              logger.trace("Cached view [" + cacheKey + "]");
            }
          }
        }
        return view;
      }
    }
  }

  /**
   * Return the cache key for the given view name and the given locale.
   * <p>Default is a String consisting of view name and locale suffix.
   * Can be overridden in subclasses.
   * <p>Needs to respect the locale in general, as a different locale can
   * lead to a different view resource.
   */
  protected Object getCacheKey(String viewName, Locale locale) {
    return viewName + "_" + locale;
  }

  /**
   * Provides functionality to clear the cache for a certain view.
   * <p>This can be handy in case developer are able to modify views
   * (e.g. Velocity templates) at runtime after which you'd need to
   * clear the cache for the specified view.
   * @param viewName the view name for which the cached view object
   * (if any) needs to be removed
   * @param locale the locale for which the view object should be removed
   */
  public void removeFromCache(String viewName, Locale locale) {
    if (!this.cache) {
      logger.warn("View caching is SWITCHED OFF -- removal not necessary");     
    }
    else {
      Object cacheKey = getCacheKey(viewName, locale);
      Object cachedView;
      synchronized (this.viewCache) {
        cachedView = this.viewCache.remove(cacheKey);
      }
      if (cachedView == null) {
        // Some debug output might be useful...
        if (logger.isDebugEnabled()) {
          logger.debug("No cached instance for view '" + cacheKey + "' was found");
        }
      }
      else {
        if (logger.isDebugEnabled()) {
          logger.debug("Cache for view " + cacheKey + " has been cleared");
        }
      }
    }
  }

  /**
   * Clear the entire view cache, removing all cached view objects.
   * Subsequent resolve calls will lead to recreation of demanded view objects.
   */
  public void clearCache() {
    logger.debug("Clearing entire view cache");
    synchronized (this.viewCache) {
      this.viewCache.clear();
    }
  }


  /**
   * Create the actual View object.
   * <p>The default implementation delegates to {@link #loadView}.
   * This can be overridden to resolve certain view names in a special fashion,
   * before delegating to the actual <code>loadView</code> implementation
   * provided by the subclass.
   * @param viewName the name of the view to retrieve
   * @param locale the Locale to retrieve the view for
   * @return the View instance, or <code>null</code> if not found
   * (optional, to allow for ViewResolver chaining)
   * @throws Exception if the view couldn't be resolved
   * @see #loadView
   */
  protected View createView(String viewName, Locale locale) throws Exception {
    return loadView(viewName, locale);
  }

  /**
   * Subclasses must implement this method, building a View object
   * for the specified view. The returned View objects will be
   * cached by this ViewResolver base class.
   * <p>Subclasses are not forced to support internationalization:
   * A subclass that does not may simply ignore the locale parameter.
   * @param viewName the name of the view to retrieve
   * @param locale the Locale to retrieve the view for
   * @return the View instance, or <code>null</code> if not found
   * (optional, to allow for ViewResolver chaining)
   * @throws Exception if the view couldn't be resolved
   * @see #resolveViewName
   */
  protected abstract View loadView(String viewName, Locale locale) throws Exception;

}
TOP

Related Classes of org.springframework.web.servlet.view.AbstractCachingViewResolver

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.