1 4 package org.roller.presentation.pagecache.rollercache; 5 import java.io.IOException ; 6 import java.util.Iterator ; 7 import java.util.Locale ; 8 import java.util.Map ; 9 import java.util.Set ; 10 import java.util.TreeMap ; 11 12 import javax.servlet.FilterChain ; 13 import javax.servlet.FilterConfig ; 14 import javax.servlet.ServletException ; 15 import javax.servlet.ServletRequest ; 16 import javax.servlet.ServletResponse ; 17 import javax.servlet.http.HttpServletRequest ; 18 import javax.servlet.http.HttpServletResponse ; 19 20 import org.apache.commons.logging.Log; 21 import org.apache.commons.logging.LogFactory; 22 import org.roller.config.RollerConfig; 23 import org.roller.pojos.UserData; 24 import org.roller.presentation.LanguageUtil; 25 import org.roller.presentation.pagecache.FilterHandler; 26 import org.roller.util.LRUCache2; 27 28 38 public class LRUCacheHandler2 implements FilterHandler 39 { 40 private static Log mLogger = 41 LogFactory.getFactory().getInstance(LRUCacheHandler2.class); 42 43 private LRUCache2 mPageCache = null; 44 private String mName = null; 45 46 private int misses = 0; 48 private int hits = 0; 49 50 private final static String FILE_SEPARATOR = "/"; 51 private final static char FILE_SEPARATOR_CHAR = FILE_SEPARATOR.charAt(0); 52 private final static short AVERAGE_KEY_LENGTH = 30; 53 private static final String m_strBase64Chars = 54 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 55 56 public LRUCacheHandler2(FilterConfig config) 57 { 58 mName = config.getFilterName(); 59 mLogger.info("Initializing for: " + mName); 60 61 String cacheSize = RollerConfig.getProperty("cache.filter.page.size"); 62 String cacheTimeout = RollerConfig.getProperty("cache.filter.page.timeout"); 63 64 int size = 200; 65 try 66 { 67 size = Integer.parseInt(cacheSize); 68 } 69 catch (Exception e) 70 { 71 mLogger.warn(config.getFilterName() 72 + "Can't read cache size parameter, using default..."); 73 } 74 mLogger.info(mName + " size=" + size); 75 76 long timeout = 30000; 77 try 78 { 79 timeout = Long.parseLong(cacheTimeout); 80 } 81 catch (Exception e) 82 { 83 mLogger.warn(config.getFilterName() 84 + "Can't read timeout parameter, using default."); 85 } 86 mLogger.info(mName + " timeout=" + timeout + "seconds"); 87 mPageCache = new LRUCache2(size, timeout*1000); 88 } 89 90 93 public void destroy() 94 { 95 } 96 97 102 public void doFilter(ServletRequest req, ServletResponse res, 103 FilterChain chain) throws ServletException , IOException 104 { 105 HttpServletRequest request = (HttpServletRequest ) req; 106 HttpServletResponse response = (HttpServletResponse ) res; 107 108 Locale locale = null; 112 try 113 { 114 locale = LanguageUtil.getViewLocale(request); 115 } 116 catch (Exception e) 117 { 118 mLogger.debug("Unable determine view local from request"); 120 response.sendError(HttpServletResponse.SC_NOT_FOUND); 121 return; 122 } 123 124 String generatedKey = null; 126 if (locale != null) 127 { 128 generatedKey = generateEntryKey(null, 129 request, 1, locale.getLanguage()); 130 } 131 else 132 { 133 generatedKey = generateEntryKey(null, 134 request, 1, null); 135 } 136 137 java.security.Principal prince = request.getUserPrincipal(); 139 StringBuffer keyb = new StringBuffer (); 140 keyb.append(generatedKey); 141 if (prince != null) 142 { 143 keyb.append("_"); 144 keyb.append(prince); 145 } 146 String key = keyb.toString(); 147 148 ResponseContent respContent = (ResponseContent)getFromCache(key); 149 if (respContent == null) 150 { 151 try 152 { 153 CacheHttpServletResponseWrapper cacheResponse = 154 new CacheHttpServletResponseWrapper(response); 155 156 chain.doFilter(request, cacheResponse); 157 cacheResponse.flushBuffer(); 158 159 if (request.getAttribute("DisplayException") == null) 162 { 163 ResponseContent rc = cacheResponse.getContent(); 164 putToCache(key, rc); 165 } 166 else 167 { 168 StringBuffer sb = new StringBuffer (); 169 sb.append("Display exception, cache, key="); 170 sb.append(key); 171 mLogger.error(sb.toString()); 172 } 173 } 174 catch (java.net.SocketException se) 175 { 176 } 178 catch (Exception e) 179 { 180 StringBuffer sb = new StringBuffer (); 182 sb.append("Error rendering page, key="); 183 sb.append(key); 184 mLogger.error(sb.toString()); 185 mLogger.debug(e); 186 } 187 } 188 else 189 { 190 try 191 { 192 respContent.writeTo(response); 193 } 194 catch (java.net.SocketException se) 195 { 196 } 198 catch (Exception e) 199 { 200 if (mLogger.isDebugEnabled()) 201 { 202 StringBuffer sb = new StringBuffer (); 203 sb.append("Probably a client abort exception, key="); 204 sb.append(key); 205 mLogger.error(sb.toString()); 206 } 207 } 208 209 } 210 } 211 212 215 public synchronized void flushCache(HttpServletRequest req) 216 { 217 mPageCache.purge(); 218 } 219 220 223 public synchronized void removeFromCache(HttpServletRequest req, UserData user) 224 { 225 String rssString = "/rss/" + user.getUserName(); String pageString = "/page/" + user.getUserName(); String mainRssString = "/rss_"; String mainPageString = "/main.do"; String planetPageString = "/planet.do"; 232 int beforeSize = mPageCache.size(); 233 mPageCache.purge(new String [] 234 { 235 rssString, 236 pageString, 237 mainRssString, 238 mainPageString, 239 planetPageString 240 }); 241 int afterSize = mPageCache.size(); 242 243 if (mLogger.isDebugEnabled()) 244 { 245 StringBuffer sb = new StringBuffer (); 246 sb.append("Purged, count="); 247 sb.append(beforeSize - afterSize); 248 sb.append(", user="); 249 sb.append(user.getUserName()); 250 mLogger.debug(sb.toString()); 251 } 252 } 253 254 258 public synchronized Object getFromCache(String key) 259 { 260 Object entry = mPageCache.get(key); 261 262 if (entry != null && mLogger.isDebugEnabled()) 263 { 264 hits++; 265 } 266 return entry; 267 } 268 269 public synchronized void putToCache(String key, Object entry) 270 { 271 mPageCache.put(key, entry); 272 if (mLogger.isDebugEnabled()) 273 { 274 misses++; 275 276 StringBuffer sb = new StringBuffer (); 277 sb.append("Missed, cache size="); 278 sb.append(mPageCache.size()); 279 sb.append(", hits="); 280 sb.append(hits); 281 sb.append(", misses="); 282 sb.append(misses); 283 sb.append(", key="); 284 sb.append(key); 285 mLogger.debug(sb.toString()); 286 } 287 } 288 289 public String generateEntryKey(String key, 290 HttpServletRequest request, int scope, String language) 291 { 292 StringBuffer cBuffer = new StringBuffer (AVERAGE_KEY_LENGTH); 293 if (language != null) 295 { 296 cBuffer.append(FILE_SEPARATOR).append(language); 297 } 298 299 301 if (key != null) 302 { 303 cBuffer.append(FILE_SEPARATOR).append(key); 304 } 305 else 306 { 307 String generatedKey = request.getRequestURI(); 308 if (generatedKey.charAt(0) != FILE_SEPARATOR_CHAR) 309 { 310 cBuffer.append(FILE_SEPARATOR_CHAR); 311 } 312 cBuffer.append(generatedKey); 313 cBuffer.append("_").append(request.getMethod()).append("_"); 314 generatedKey = getSortedQueryString(request); 315 if (generatedKey != null) 316 { 317 try 318 { 319 java.security.MessageDigest digest = 320 java.security.MessageDigest.getInstance("MD5"); 321 byte[] b = digest.digest(generatedKey.getBytes()); 322 cBuffer.append("_"); 323 cBuffer.append(toBase64(b).replace('/', '_')); 325 } 326 catch (Exception e) 327 { 328 } 330 } 331 } 332 return cBuffer.toString(); 333 } 334 335 protected String getSortedQueryString(HttpServletRequest request) 336 { 337 Map paramMap = request.getParameterMap(); 338 if (paramMap.isEmpty()) 339 { 340 return null; 341 } 342 Set paramSet = new TreeMap (paramMap).entrySet(); 343 StringBuffer buf = new StringBuffer (); 344 boolean first = true; 345 for (Iterator it = paramSet.iterator(); it.hasNext();) 346 { 347 Map.Entry entry = (Map.Entry ) it.next(); 348 String [] values = (String []) entry.getValue(); 349 for (int i = 0; i < values.length; i++) 350 { 351 String key = (String ) entry.getKey(); 352 if ((key.length() != 10) || !"jsessionid".equals(key)) 353 { 354 if (first) 355 { 356 first = false; 357 } 358 else 359 { 360 buf.append('&'); 361 } 362 buf.append(key).append('=').append(values[i]); 363 } 364 } 365 } 366 if (buf.length() == 0) 368 { 369 return null; 370 } 371 else 372 { 373 return buf.toString(); 374 } 375 } 376 377 380 private static String toBase64(byte[] aValue) 381 { 382 int byte1; 383 int byte2; 384 int byte3; 385 int iByteLen = aValue.length; 386 StringBuffer tt = new StringBuffer (); 387 for (int i = 0; i < iByteLen; i += 3) 388 { 389 boolean bByte2 = (i + 1) < iByteLen; 390 boolean bByte3 = (i + 2) < iByteLen; 391 byte1 = aValue[i] & 0xFF; 392 byte2 = (bByte2) ? (aValue[i + 1] & 0xFF) : 0; 393 byte3 = (bByte3) ? (aValue[i + 2] & 0xFF) : 0; 394 tt.append(m_strBase64Chars.charAt(byte1 / 4)); 395 tt.append(m_strBase64Chars.charAt((byte2 / 16) 396 + ((byte1 & 0x3) * 16))); 397 tt.append(((bByte2) ? m_strBase64Chars.charAt((byte3 / 64) 398 + ((byte2 & 0xF) * 4)) : '=')); 399 tt.append(((bByte3) ? m_strBase64Chars.charAt(byte3 & 0x3F) : '=')); 400 } 401 return tt.toString(); 402 } 403 } 404 | Popular Tags |