?? servletcacheadministrator.java
字號:
/*
* Copyright (c) 2002-2003 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.oscache.web;
import com.opensymphony.oscache.base.*;
import com.opensymphony.oscache.base.events.CacheEventListener;
import com.opensymphony.oscache.base.events.ScopeEvent;
import com.opensymphony.oscache.base.events.ScopeEventListener;
import com.opensymphony.oscache.base.events.ScopeEventType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Serializable;
import java.util.*;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
/**
* A ServletCacheAdministrator creates, flushes and administers the cache.
* <p>
* This is a "servlet Singleton". This means it's not a Singleton in the traditional sense,
* that is stored in a static instance. It's a Singleton _per web app context_.
* <p>
* Once created it manages the cache path on disk through the oscache.properties
* file, and also keeps track of the flush times.
*
* @author <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
* @author <a href="mailto:tgochenour@peregrine.com">Todd Gochenour</a>
* @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
* @author <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
* @author <a href="mailto:chris@swebtec.com">Chris Miller</a>
* @version $Revision: 463 $
*/
public class ServletCacheAdministrator extends AbstractCacheAdministrator implements Serializable {
private static final transient Log log = LogFactory.getLog(ServletCacheAdministrator.class);
/**
* Constants for properties read/written from/to file
*/
private final static String CACHE_USE_HOST_DOMAIN_KEY = "cache.use.host.domain.in.key";
private final static String CACHE_KEY_KEY = "cache.key";
/**
* The default cache key that is used to store the cache in context.
*/
private final static String DEFAULT_CACHE_KEY = "__oscache_cache";
/**
* Constants for scope's name
*/
public final static String SESSION_SCOPE_NAME = "session";
public final static String APPLICATION_SCOPE_NAME = "application";
/**
* The suffix added to the cache key used to store a
* ServletCacheAdministrator will be stored in the ServletContext
*/
private final static String CACHE_ADMINISTRATOR_KEY_SUFFIX = "_admin";
/**
* The key under which an array of all ServletCacheAdministrator objects
* will be stored in the ServletContext
*/
private final static String CACHE_ADMINISTRATORS_KEY = "__oscache_admins";
/**
* Key used to store the current scope in the configuration. This is a hack
* to let the scope information get passed through to the DiskPersistenceListener,
* and will be removed in a future release.
*/
public final static String HASH_KEY_SCOPE = "scope";
/**
* Key used to store the current session ID in the configuration. This is a hack
* to let the scope information get passed through to the DiskPersistenceListener,
* and will be removed in a future release.
*/
public final static String HASH_KEY_SESSION_ID = "sessionId";
/**
* Key used to store the servlet container temporary directory in the configuration.
* This is a hack to let the scope information get passed through to the
* DiskPersistenceListener, and will be removed in a future release.
*/
public final static String HASH_KEY_CONTEXT_TMPDIR = "context.tempdir";
/**
* The string to use as a file separator.
*/
private final static String FILE_SEPARATOR = "/";
/**
* The character to use as a file separator.
*/
private final static char FILE_SEPARATOR_CHAR = FILE_SEPARATOR.charAt(0);
/**
* Constant for Key generation.
*/
private final static short AVERAGE_KEY_LENGTH = 30;
/**
* Usable caracters for key generation
*/
private static final String m_strBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* Map containing the flush times of different scopes
*/
private Map flushTimes;
/**
* Required so we can look up the app scope cache without forcing a session creation.
*/
private transient ServletContext context;
/**
* Key to use for storing and retrieving Object in contexts (Servlet, session).
*/
private String cacheKey;
/**
* Set property cache.use.host.domain.in.key=true to add domain information to key
* generation for hosting multiple sites.
*/
private boolean useHostDomainInKey = false;
/**
* Create the cache administrator.
*
* This will reset all the flush times and load the properties file.
*/
private ServletCacheAdministrator(ServletContext context, Properties p) {
super(p);
config.set(HASH_KEY_CONTEXT_TMPDIR, context.getAttribute("javax.servlet.context.tempdir"));
flushTimes = new HashMap();
initHostDomainInKey();
this.context = context;
}
/**
* Obtain an instance of the CacheAdministrator
*
* @param context The ServletContext that this CacheAdministrator is a Singleton under
* @return Returns the CacheAdministrator instance for this context
*/
public static ServletCacheAdministrator getInstance(ServletContext context) {
return getInstance(context, null);
}
/**
* Obtain an instance of the CacheAdministrator for the specified key
*
* @param context The ServletContext that this CacheAdministrator is a Singleton under
* @param key the cachekey or admincachekey for the CacheAdministrator wanted
* @return Returns the CacheAdministrator instance for this context, or null if no
* CacheAdministrator exists with the key supplied
*/
public static ServletCacheAdministrator getInstanceFromKey(ServletContext context, String key) {
// Note we do not bother to check if the key is null because it mustn't.
if (!key.endsWith(CACHE_ADMINISTRATOR_KEY_SUFFIX)) {
key = key + CACHE_ADMINISTRATOR_KEY_SUFFIX;
}
return (ServletCacheAdministrator) context.getAttribute(key);
}
/**
* Obtain an instance of the CacheAdministrator
*
* @param context The ServletContext that this CacheAdministrator is a Singleton under
* @param p the properties to use for the cache if the cache administrator has not been
* created yet. Once the administrator has been created, the properties parameter is
* ignored for all future invocations. If a null value is passed in, then the properties
* are loaded from the oscache.properties file in the classpath.
* @return Returns the CacheAdministrator instance for this context
*/
public synchronized static ServletCacheAdministrator getInstance(ServletContext context, Properties p)
{
String adminKey = null;
if (p!= null) {
adminKey = p.getProperty(CACHE_KEY_KEY);
}
if (adminKey == null) {
adminKey = DEFAULT_CACHE_KEY;
}
adminKey += CACHE_ADMINISTRATOR_KEY_SUFFIX;
ServletCacheAdministrator admin = (ServletCacheAdministrator) context.getAttribute(adminKey);
// First time we need to create the administrator and store it in the
// servlet context
if (admin == null) {
admin = new ServletCacheAdministrator(context, p);
Map admins = (Map) context.getAttribute(CACHE_ADMINISTRATORS_KEY);
if (admins == null) {
admins = new HashMap();
}
admins.put(adminKey, admin);
context.setAttribute(CACHE_ADMINISTRATORS_KEY, admins);
context.setAttribute(adminKey, admin);
if (log.isInfoEnabled()) {
log.info("Created new instance of ServletCacheAdministrator with key "+adminKey);
}
admin.getAppScopeCache(context);
}
if (admin.context == null) {
admin.context = context;
}
return admin;
}
/**
* Shuts down all servlet cache administrators. This should usually only
* be called when the controlling application shuts down.
*/
public static void destroyInstance(ServletContext context)
{
ServletCacheAdministrator admin;
Map admins = (Map) context.getAttribute(CACHE_ADMINISTRATORS_KEY);
if (admins != null)
{
Set keys = admins.keySet();
Iterator it = keys.iterator();
while (it.hasNext())
{
String adminKey = (String) it.next();
admin = (ServletCacheAdministrator) admins.get( adminKey );
if (admin != null)
{
// Finalize the application scope cache
Cache cache = (Cache) context.getAttribute(admin.getCacheKey());
if (cache != null) {
admin.finalizeListeners(cache);
context.removeAttribute(admin.getCacheKey());
context.removeAttribute(adminKey);
cache = null;
if (log.isInfoEnabled()) {
log.info("Shut down the ServletCacheAdministrator "+adminKey);
}
}
admin = null;
}
}
context.removeAttribute(CACHE_ADMINISTRATORS_KEY);
}
}
/**
* Grabs the cache for the specified scope
*
* @param request The current request
* @param scope The scope of this cache (<code>PageContext.APPLICATION_SCOPE</code>
* or <code>PageContext.SESSION_SCOPE</code>)
* @return The cache
*/
public Cache getCache(HttpServletRequest request, int scope) {
if (scope == PageContext.APPLICATION_SCOPE) {
return getAppScopeCache(context);
}
if (scope == PageContext.SESSION_SCOPE) {
return getSessionScopeCache(request.getSession(true));
}
throw new RuntimeException("The supplied scope value of " + scope + " is invalid. Acceptable values are PageContext.APPLICATION_SCOPE and PageContext.SESSION_SCOPE");
}
/**
* A convenience method to retrieve the application scope cache
* @param context the current <code>ServletContext</code>
* @return the application scope cache. If none is present, one will
* be created.
*/
public Cache getAppScopeCache(ServletContext context) {
Cache cache;
Object obj = context.getAttribute(getCacheKey());
if ((obj == null) || !(obj instanceof Cache)) {
if (log.isInfoEnabled()) {
log.info("Created new application-scoped cache at key: " + getCacheKey());
}
cache = createCache(PageContext.APPLICATION_SCOPE, null);
context.setAttribute(getCacheKey(), cache);
} else {
cache = (Cache) obj;
}
return cache;
}
/**
* A convenience method to retrieve the session scope cache
*
* @param session the current <code>HttpSession</code>
* @return the session scope cache for this session. If none is present,
* one will be created.
*/
public Cache getSessionScopeCache(HttpSession session) {
Cache cache;
Object obj = session.getAttribute(getCacheKey());
if ((obj == null) || !(obj instanceof Cache)) {
if (log.isInfoEnabled()) {
log.info("Created new session-scoped cache in session " + session.getId() + " at key: " + getCacheKey());
}
cache = createCache(PageContext.SESSION_SCOPE, session.getId());
session.setAttribute(getCacheKey(), cache);
} else {
cache = (Cache) obj;
}
return cache;
}
/**
* Get the cache key from the properties. Set it to a default value if it
* is not present in the properties
*
* @return The cache.key property or the DEFAULT_CACHE_KEY
*/
public String getCacheKey() {
if (cacheKey == null) {
cacheKey = getProperty(CACHE_KEY_KEY);
if (cacheKey == null) {
cacheKey = DEFAULT_CACHE_KEY;
}
}
return cacheKey;
}
/**
* Set the flush time for a specific scope to a specific time
*
* @param date The time to flush the scope
* @param scope The scope to be flushed
*/
public void setFlushTime(Date date, int scope) {
if (log.isInfoEnabled()) {
log.info("Flushing scope " + scope + " at " + date);
}
synchronized (flushTimes) {
if (date != null) {
// Trigger a SCOPE_FLUSHED event
dispatchScopeEvent(ScopeEventType.SCOPE_FLUSHED, scope, date, null);
flushTimes.put(new Integer(scope), date);
} else {
logError("setFlushTime called with a null date.");
throw new IllegalArgumentException("setFlushTime called with a null date.");
}
}
}
/**
* Set the flush time for a specific scope to the current time.
*
* @param scope The scope to be flushed
*/
public void setFlushTime(int scope) {
setFlushTime(new Date(), scope);
}
/**
* Get the flush time for a particular scope.
*
* @param scope The scope to get the flush time for.
* @return A date representing the time this scope was last flushed.
* Returns null if it has never been flushed.
*/
public Date getFlushTime(int scope) {
synchronized (flushTimes) {
return (Date) flushTimes.get(new Integer(scope));
}
}
/**
* Retrieve an item from the cache
*
* @param scope The cache scope
* @param request The servlet request
* @param key The key of the object to retrieve
* @param refreshPeriod The time interval specifying if an entry needs refresh
* @return The requested object
* @throws NeedsRefreshException
*/
public Object getFromCache(int scope, HttpServletRequest request, String key, int refreshPeriod) throws NeedsRefreshException {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -