CachingFilterpublic class CachingFilter extends Object implements Filter, com.sun.appserv.web.cache.CacheManagerListener
Fields Summary |
---|
String | filterName | String | servletName | String | urlPattern | com.sun.appserv.web.cache.CacheManager | manager | com.sun.appserv.web.cache.CacheHelper | helper | com.sun.appserv.util.cache.Cache | cache | boolean | isEnabled | private static Logger | _logger | private static boolean | _isTraceEnabled |
Methods Summary |
---|
public void | cacheManagerDisabled()cache manager listener method
if (_isTraceEnabled)
_logger.fine("CachingFilter " + filterName + " received cacheManager disabled event.");
this.isEnabled = false;
| public void | cacheManagerEnabled()cache manager listener method
if (_isTraceEnabled)
_logger.fine("CachingFilter " + filterName + " received cacheManager enabled event.");
this.isEnabled = true;
| public void | destroy()Called by the web container to indicate to a filter that it is being
taken out of service. This method is only called once all threads
within the filter's doFilter method have exited or after a timeout
period has passed.
After the web container calls this method, it will not call the doFilter
method again on this instance of the filter.
| public void | doFilter(javax.servlet.ServletRequest srequest, javax.servlet.ServletResponse sresponse, javax.servlet.FilterChain chain)The doFilter method of the Filter is called by the container
each time a request/response pair is passed through the chain due
to a client request for a resource at the end of the chain. The
FilterChain passed in to this method allows the Filter to pass on the
request and response to the next entity in the chain.
String key;
HttpServletRequest request = (HttpServletRequest)srequest;
HttpServletResponse response = (HttpServletResponse)sresponse;
request.setAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME,
filterName);
request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME,
servletName);
request.setAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN,
urlPattern);
if (isEnabled && helper.isCacheable((HttpServletRequest)request) &&
(key = helper.getCacheKey(request)) != null) {
// have the key index for reuse
int index = cache.getIndex(key);
if (_isTraceEnabled) {
_logger.fine("CachingFilter " + request.getServletPath() +
" request is cacheable; key " + key + " index = " + index);
}
HttpCacheEntry entry = null;
boolean entryReady = false, waitForRefresh = true;
// if refresh is not needed then check the cache first
if (!helper.isRefreshNeeded(request)) {
do {
// lookup cache
entry = (HttpCacheEntry) cache.get(key);
if (entry != null && entry.isValid()) {
// see if there is cached entry and is valid
entryReady = true;
break;
}
else {
/**
* a cache entry needs to be generated or refreshed.
* if there are more than one thread tries to fill/refresh
* same cache entry, then all but the first thread will block.
*/
waitForRefresh = cache.waitRefresh(index);
}
} while (waitForRefresh);
} else {
if (_isTraceEnabled) {
_logger.fine("CachingFilter " + request.getServletPath() +
" request needs a refresh; key " + key);
}
}
// do we have a valid response?
if (entryReady) {
if (_isTraceEnabled) {
_logger.fine("CachingFilter " + request.getServletPath() +
" serving response from the cache " + key);
}
sendCachedResponse(entry, response);
} else {
// call the target servlet
HttpCacheEntry oldEntry;
// setup the response wrapper (and the output stream)
CachingResponseWrapper wrapper =
new CachingResponseWrapper(response);
// call the target resource
try {
chain.doFilter(srequest, (ServletResponse)wrapper);
} catch (ServletException se) {
wrapper.clear();
throw se;
} catch (IOException ioe) {
wrapper.clear();
throw ioe;
}
// see if the there weren't any errors
if (!wrapper.isError()) {
// create/refresh the cached response entry
// compute the timeout
int timeout = helper.getTimeout(request);
// previous entry gets replaced
entry = wrapper.cacheResponse();
if (timeout == CacheHelper.TIMEOUT_VALUE_NOT_SET) {
// extracts this from the Expires: date header
Long lval = wrapper.getExpiresDateHeader();
if (lval == null) {
timeout = manager.getDefaultTimeout();
entry.computeExpireTime(timeout);
} else {
long expireTime = lval.longValue();
// set the time this entry would expires
entry.setExpireTime(expireTime);
}
} else {
entry.computeExpireTime(timeout);
}
oldEntry = (HttpCacheEntry)cache.put(key, entry,
entry.getSize());
cache.notifyRefresh(index);
// transmit the response body content
writeBody(entry, response);
} else {
/** either there was an error or response from this
* resource is not cacheable anymore; so, remove the
* old entry from the cache.
*/
oldEntry = (HttpCacheEntry)cache.remove(key);
}
// clear the wrapper (XXX: cache these??)
wrapper.clear();
}
/** clear the old entry?
* may lead to NPEs with one thread that just replaced an entry
* which might have just obtained before the new entry is put
* in cache. Must implement some sort of ref count or leave it
* to garbage collector
* if (oldEntry != null)
* oldEntry.clear();
*/
} else {
if (_isTraceEnabled) {
_logger.fine("CachingFilter " + request.getServletPath() +
" pass thru; isEnabled = " + isEnabled);
}
request.removeAttribute(DefaultCacheHelper.ATTR_CACHING_FILTER_NAME);
request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_SERVLET_NAME);
request.removeAttribute(CacheHelper.ATTR_CACHE_MAPPED_URL_PATTERN);
// pass thru
chain.doFilter(srequest, sresponse);
}
| public void | init(javax.servlet.FilterConfig filterConfig)Called by the web container to indicate to a filter that it is being
placed into service. The servlet container calls the init method exactly
once after instantiating the filter. The init method must complete
successfully before the filter is asked to do any filtering work.
filterName = filterConfig.getFilterName();
servletName = filterConfig.getInitParameter("servletName");
urlPattern = filterConfig.getInitParameter("URLPattern");
ServletContext context = filterConfig.getServletContext();
manager = (CacheManager)
context.getAttribute(CacheManager.CACHE_MANAGER_ATTR_NAME);
if (manager != null && manager.isEnabled()) {
this.cache = manager.getDefaultCache();
this.helper = manager.getCacheHelperByFilterName(filterName);
// add filter as a listener so caching can be disabled at runtime.
manager.addCacheManagerListener(this);
isEnabled = true;
}
if (_logger == null) {
_logger = LogDomains.getLogger(LogDomains.PWC_LOGGER);
_isTraceEnabled = _logger.isLoggable(Level.FINE);
}
if (_isTraceEnabled) {
_logger.fine("CachingFilter " + filterName + " ready; isEnabled = " + isEnabled + " manager = " + manager);
}
| private void | sendCachedResponse(HttpCacheEntry entry, javax.servlet.http.HttpServletResponse response)called by doFilter to send out the cached response
// status code/message
if (entry.statusCode != HttpCacheEntry.VALUE_NOT_SET) {
response.setStatus(entry.statusCode);
}
// set the outbound response headers
for (Iterator iter = entry.responseHeaders.keySet().iterator();
iter.hasNext(); ) {
String name = (String)iter.next();
ArrayList values = (ArrayList)entry.responseHeaders.get(name);
for (int i = 0; i < values.size(); i++) {
response.addHeader(name, (String)values.get(i));
}
}
// date headers
for (Iterator iter = entry.dateHeaders.keySet().iterator();
iter.hasNext(); ) {
String name = (String)iter.next();
ArrayList values = (ArrayList)entry.dateHeaders.get(name);
for (int i = 0; i < values.size(); i++) {
response.addDateHeader(name, ((Long)values.get(i)).longValue());
}
}
// cookies
for (int i = 0; i < entry.cookies.size(); i++) {
response.addCookie((Cookie)entry.cookies.get(i));
}
// content type, length and locale
if (entry.contentLength != HttpCacheEntry.VALUE_NOT_SET) {
response.setContentLength(entry.contentLength);
}
if (entry.contentType != null) {
response.setContentType(entry.contentType);
}
if (entry.locale != null) {
response.setLocale(entry.locale);
}
// the response body
writeBody(entry, response);
| private void | writeBody(HttpCacheEntry entry, javax.servlet.http.HttpServletResponse response)called by doFilter/sendCachedResponse to write the body content
ServletOutputStream out = response.getOutputStream();
out.write(entry.bytes);
|
|