1 16 package org.mortbay.http; 17 18 import java.io.IOException ; 19 import java.io.Serializable ; 20 import java.util.Collections ; 21 import java.util.Enumeration ; 22 import java.util.HashMap ; 23 import java.util.Map ; 24 import java.util.ResourceBundle ; 25 26 import org.apache.commons.logging.Log; 27 import org.mortbay.log.LogFactory; 28 import org.mortbay.util.CachedResource; 29 import org.mortbay.util.LifeCycle; 30 import org.mortbay.util.LogSupport; 31 import org.mortbay.util.Resource; 32 import org.mortbay.util.StringUtil; 33 34 35 36 40 public class ResourceCache implements LifeCycle, 41 Serializable 42 { 43 private static Log log = LogFactory.getLog(ResourceCache.class); 44 45 46 47 private final static Map __dftMimeMap = new HashMap (); 48 private final static Map __encodings = new HashMap (); 49 static 50 { 51 ResourceBundle mime = ResourceBundle.getBundle("org/mortbay/http/mime"); 52 Enumeration i = mime.getKeys(); 53 while(i.hasMoreElements()) 54 { 55 String ext = (String )i.nextElement(); 56 __dftMimeMap.put(StringUtil.asciiToLowerCase(ext),mime.getString(ext)); 57 } 58 ResourceBundle encoding = ResourceBundle.getBundle("org/mortbay/http/encoding"); 59 i = encoding.getKeys(); 60 while(i.hasMoreElements()) 61 { 62 String type = (String )i.nextElement(); 63 __encodings.put(type,encoding.getString(type)); 64 } 65 } 66 67 68 69 73 74 75 76 private int _maxCachedFileSize =1*1024; 77 private int _maxCacheSize =1*1024; 78 79 80 private Resource _resourceBase; 81 private Map _mimeMap; 82 private Map _encodingMap; 83 84 85 86 private transient boolean _started; 87 88 protected transient Map _cache; 89 protected transient int _cacheSize; 90 protected transient CachedMetaData _mostRecentlyUsed; 91 protected transient CachedMetaData _leastRecentlyUsed; 92 93 94 95 97 public ResourceCache() 98 { 99 _cache=new HashMap (); 100 } 101 102 103 104 private void readObject(java.io.ObjectInputStream in) 105 throws IOException , ClassNotFoundException 106 { 107 in.defaultReadObject(); 108 _cache=new HashMap (); 109 } 110 111 112 121 public String getResourceBase() 122 { 123 if (_resourceBase==null) 124 return null; 125 return _resourceBase.toString(); 126 } 127 128 129 137 public void setResourceBase(String resourceBase) 138 { 139 try{ 140 _resourceBase=Resource.newResource(resourceBase); 141 if(log.isDebugEnabled())log.debug("resourceBase="+_resourceBase+" for "+this); 142 } 143 catch(IOException e) 144 { 145 log.debug(LogSupport.EXCEPTION,e); 146 throw new IllegalArgumentException (resourceBase+":"+e.toString()); 147 } 148 } 149 150 151 152 158 public Resource getBaseResource() 159 { 160 return _resourceBase; 161 } 162 163 164 170 public void setBaseResource(Resource base) 171 { 172 _resourceBase=base; 173 } 174 175 176 177 public int getMaxCachedFileSize() 178 { 179 return _maxCachedFileSize; 180 } 181 182 183 public void setMaxCachedFileSize(int maxCachedFileSize) 184 { 185 _maxCachedFileSize = maxCachedFileSize; 186 _cache.clear(); 187 } 188 189 190 public int getMaxCacheSize() 191 { 192 return _maxCacheSize; 193 } 194 195 196 public void setMaxCacheSize(int maxCacheSize) 197 { 198 _maxCacheSize = maxCacheSize; 199 _cache.clear(); 200 } 201 202 203 public void flushCache() 204 { 205 _cache.clear(); 206 System.gc(); 207 } 208 209 210 220 public Resource getResource(String pathInContext) 221 throws IOException 222 { 223 if(log.isTraceEnabled())log.trace("getResource "+pathInContext); 224 if (_resourceBase==null) 225 return null; 226 227 Resource resource=null; 228 229 synchronized(_cache) 231 { 232 CachedResource cached = (CachedResource)_cache.get(pathInContext); 234 if (cached!=null) 235 { 236 if(log.isTraceEnabled())log.trace("CACHE HIT: "+cached); 237 CachedMetaData cmd = (CachedMetaData)cached.getAssociate(); 238 if (cmd!=null && cmd.isValid()) 239 return cached; 240 } 241 242 resource=_resourceBase.addPath(_resourceBase.encode(pathInContext)); 244 if(log.isTraceEnabled())log.trace("CACHE MISS: "+resource); 245 if (resource==null) 246 return null; 247 248 249 if (resource.getAlias()!=null) 251 { 252 log.warn("Alias request of '"+resource.getAlias()+ 253 "' for '"+resource+"'"); 254 return null; 255 } 256 257 long len = resource.length(); 259 if (resource.exists()) 260 { 261 if (!resource.isDirectory() && pathInContext.endsWith("/")) 263 return null; 264 265 if (resource.isDirectory()) 267 { 268 if (resource.list()!=null) 269 len=resource.list().length*100; 270 else 271 len=0; 272 } 273 274 if (len>0 && len<_maxCachedFileSize && len<_maxCacheSize) 276 { 277 int needed=_maxCacheSize-(int)len; 278 while(_cacheSize>needed) 279 _leastRecentlyUsed.invalidate(); 280 281 cached=resource.cache(); 282 if(log.isTraceEnabled())log.trace("CACHED: "+resource); 283 new CachedMetaData(cached,pathInContext); 284 return cached; 285 } 286 } 287 } 288 289 new ResourceMetaData(resource); 291 return resource; 292 } 293 294 295 296 public synchronized Map getMimeMap() 297 { 298 return _mimeMap; 299 } 300 301 302 306 public void setMimeMap(Map mimeMap) 307 { 308 _mimeMap = mimeMap; 309 } 310 311 312 317 public String getMimeByExtension(String filename) 318 { 319 String type=null; 320 321 if (filename!=null) 322 { 323 int i=-1; 324 while(type==null) 325 { 326 i=filename.indexOf(".",i+1); 327 328 if (i<0 || i>=filename.length()) 329 break; 330 331 String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); 332 if (_mimeMap!=null) 333 type = (String )_mimeMap.get(ext); 334 if (type==null) 335 type=(String )__dftMimeMap.get(ext); 336 } 337 } 338 339 if (type==null) 340 { 341 if (_mimeMap!=null) 342 type=(String )_mimeMap.get("*"); 343 if (type==null) 344 type=(String )__dftMimeMap.get("*"); 345 } 346 347 return type; 348 } 349 350 351 355 public void setMimeMapping(String extension,String type) 356 { 357 if (_mimeMap==null) 358 _mimeMap=new HashMap (); 359 _mimeMap.put(StringUtil.asciiToLowerCase(extension),type); 360 } 361 362 363 364 367 public synchronized Map getEncodingMap() 368 { 369 if (_encodingMap==null) 370 _encodingMap=Collections.unmodifiableMap(__encodings); 371 return _encodingMap; 372 } 373 374 375 379 public void setEncodingMap(Map encodingMap) 380 { 381 _encodingMap = encodingMap; 382 } 383 384 385 389 public String getEncodingByMimeType(String type) 390 { 391 String encoding =null; 392 393 if (type!=null) 394 encoding=(String )_encodingMap.get(type); 395 396 return encoding; 397 } 398 399 400 404 public void setTypeEncoding(String mimeType,String encoding) 405 { 406 getEncodingMap().put(mimeType,encoding); 407 } 408 409 410 public synchronized void start() 411 throws Exception 412 { 413 if (isStarted()) 414 return; 415 getMimeMap(); 416 getEncodingMap(); 417 _started=true; 418 } 419 420 421 public boolean isStarted() 422 { 423 return _started; 424 } 425 426 427 429 public void stop() 430 throws InterruptedException 431 { 432 _started=false; 433 _cache.clear(); 434 } 435 436 437 438 442 public void destroy() 443 { 444 if (isStarted()) 445 throw new IllegalStateException ("Started"); 446 447 setMimeMap(null); 448 _encodingMap=null; 449 } 450 451 452 453 457 public ResourceMetaData getResourceMetaData(Resource resource) 458 { 459 Object o=resource.getAssociate(); 460 if (o instanceof ResourceMetaData) 461 return (ResourceMetaData)o; 462 return new ResourceMetaData(resource); 463 } 464 465 466 467 469 public class ResourceMetaData 470 { 471 protected String _name; 472 protected Resource _resource; 473 474 ResourceMetaData(Resource resource) 475 { 476 _resource=resource; 477 _name=_resource.toString(); 478 _resource.setAssociate(this); 479 } 480 481 public String getLength() 482 { 483 return Long.toString(_resource.length()); 484 } 485 486 public String getLastModified() 487 { 488 return HttpFields.formatDate(_resource.lastModified(),false); 489 } 490 491 public String getMimeType() 492 { 493 return getMimeByExtension(_name); 494 } 495 } 496 497 498 499 private class CachedMetaData extends ResourceMetaData 500 { 501 String _lastModified; 502 String _encoding; 503 String _length; 504 String _key; 505 506 CachedResource _cached; 507 CachedMetaData _prev; 508 CachedMetaData _next; 509 510 CachedMetaData(CachedResource resource, String pathInContext) 511 { 512 super(resource); 513 _cached=resource; 514 _length=super.getLength(); 515 _lastModified=super.getLastModified(); 516 _encoding=super.getMimeType(); 517 _key=pathInContext; 518 519 _next=_mostRecentlyUsed; 520 _mostRecentlyUsed=this; 521 if (_next!=null) 522 _next._prev=this; 523 _prev=null; 524 if (_leastRecentlyUsed==null) 525 _leastRecentlyUsed=this; 526 527 _cache.put(_key,resource); 528 529 _cacheSize+=_cached.length(); 530 531 } 532 533 public String getLength() 534 { 535 return _length; 536 } 537 538 public String getLastModified() 539 { 540 return _lastModified; 541 } 542 543 public String getMimeType() 544 { 545 return _encoding; 546 } 547 548 549 boolean isValid() 550 throws IOException 551 { 552 if (_cached.isUptoDate()) 553 { 554 if (_mostRecentlyUsed!=this) 555 { 556 CachedMetaData tp = _prev; 557 CachedMetaData tn = _next; 558 559 _next=_mostRecentlyUsed; 560 _mostRecentlyUsed=this; 561 if (_next!=null) 562 _next._prev=this; 563 _prev=null; 564 565 if (tp!=null) 566 tp._next=tn; 567 if (tn!=null) 568 tn._prev=tp; 569 570 if (_leastRecentlyUsed==this && tp!=null) 571 _leastRecentlyUsed=tp; 572 } 573 return true; 574 } 575 576 invalidate(); 577 return false; 578 } 579 580 public void invalidate() 581 { 582 _cache.remove(_key); 584 _cacheSize=_cacheSize-(int)_cached.length(); 585 586 587 if (_mostRecentlyUsed==this) 588 _mostRecentlyUsed=_next; 589 else 590 _prev._next=_next; 591 592 if (_leastRecentlyUsed==this) 593 _leastRecentlyUsed=_prev; 594 else 595 _next._prev=_prev; 596 597 _prev=null; 598 _next=null; 599 } 600 } 601 602 603 } 604 | Popular Tags |