103928aee4356845252ac6b662d5c72c29903813eJake Slack// 203928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 303928aee4356845252ac6b662d5c72c29903813eJake Slack// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 403928aee4356845252ac6b662d5c72c29903813eJake Slack// ------------------------------------------------------------------------ 503928aee4356845252ac6b662d5c72c29903813eJake Slack// All rights reserved. This program and the accompanying materials 603928aee4356845252ac6b662d5c72c29903813eJake Slack// are made available under the terms of the Eclipse Public License v1.0 703928aee4356845252ac6b662d5c72c29903813eJake Slack// and Apache License v2.0 which accompanies this distribution. 803928aee4356845252ac6b662d5c72c29903813eJake Slack// 903928aee4356845252ac6b662d5c72c29903813eJake Slack// The Eclipse Public License is available at 1003928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.eclipse.org/legal/epl-v10.html 1103928aee4356845252ac6b662d5c72c29903813eJake Slack// 1203928aee4356845252ac6b662d5c72c29903813eJake Slack// The Apache License v2.0 is available at 1303928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.opensource.org/licenses/apache2.0.php 1403928aee4356845252ac6b662d5c72c29903813eJake Slack// 1503928aee4356845252ac6b662d5c72c29903813eJake Slack// You may elect to redistribute this code under either of these licenses. 1603928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 1703928aee4356845252ac6b662d5c72c29903813eJake Slack// 1803928aee4356845252ac6b662d5c72c29903813eJake Slack 1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.server; 2003928aee4356845252ac6b662d5c72c29903813eJake Slack 2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.ByteArrayInputStream; 2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException; 2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.InputStream; 2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Comparator; 2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.SortedSet; 2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.TreeSet; 2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.ConcurrentHashMap; 2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.ConcurrentMap; 2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.atomic.AtomicInteger; 3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.atomic.AtomicReference; 3103928aee4356845252ac6b662d5c72c29903813eJake Slack 3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpContent; 3303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpContent.ResourceAsHttpContent; 3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpFields; 3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.MimeTypes; 3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffer; 3703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ByteArrayBuffer; 3803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.View; 3903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.DirectNIOBuffer; 4003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.IndirectNIOBuffer; 4103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log; 4203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger; 4303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.resource.Resource; 4403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.resource.ResourceFactory; 4503928aee4356845252ac6b662d5c72c29903813eJake Slack 4603928aee4356845252ac6b662d5c72c29903813eJake Slack 4703928aee4356845252ac6b662d5c72c29903813eJake Slack/* ------------------------------------------------------------ */ 4803928aee4356845252ac6b662d5c72c29903813eJake Slack/** 4903928aee4356845252ac6b662d5c72c29903813eJake Slack * 5003928aee4356845252ac6b662d5c72c29903813eJake Slack */ 5103928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class ResourceCache 5203928aee4356845252ac6b662d5c72c29903813eJake Slack{ 5303928aee4356845252ac6b662d5c72c29903813eJake Slack private static final Logger LOG = Log.getLogger(ResourceCache.class); 5403928aee4356845252ac6b662d5c72c29903813eJake Slack 5503928aee4356845252ac6b662d5c72c29903813eJake Slack private final ConcurrentMap<String,Content> _cache; 5603928aee4356845252ac6b662d5c72c29903813eJake Slack private final AtomicInteger _cachedSize; 5703928aee4356845252ac6b662d5c72c29903813eJake Slack private final AtomicInteger _cachedFiles; 5803928aee4356845252ac6b662d5c72c29903813eJake Slack private final ResourceFactory _factory; 5903928aee4356845252ac6b662d5c72c29903813eJake Slack private final ResourceCache _parent; 6003928aee4356845252ac6b662d5c72c29903813eJake Slack private final MimeTypes _mimeTypes; 6103928aee4356845252ac6b662d5c72c29903813eJake Slack private final boolean _etags; 6203928aee4356845252ac6b662d5c72c29903813eJake Slack 6303928aee4356845252ac6b662d5c72c29903813eJake Slack private boolean _useFileMappedBuffer=true; 6403928aee4356845252ac6b662d5c72c29903813eJake Slack private int _maxCachedFileSize =4*1024*1024; 6503928aee4356845252ac6b662d5c72c29903813eJake Slack private int _maxCachedFiles=2048; 6603928aee4356845252ac6b662d5c72c29903813eJake Slack private int _maxCacheSize =32*1024*1024; 6703928aee4356845252ac6b662d5c72c29903813eJake Slack 6803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 6903928aee4356845252ac6b662d5c72c29903813eJake Slack /** Constructor. 7003928aee4356845252ac6b662d5c72c29903813eJake Slack * @param mimeTypes Mimetype to use for meta data 7103928aee4356845252ac6b662d5c72c29903813eJake Slack */ 7203928aee4356845252ac6b662d5c72c29903813eJake Slack public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags) 7303928aee4356845252ac6b662d5c72c29903813eJake Slack { 7403928aee4356845252ac6b662d5c72c29903813eJake Slack _factory = factory; 7503928aee4356845252ac6b662d5c72c29903813eJake Slack _cache=new ConcurrentHashMap<String,Content>(); 7603928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedSize=new AtomicInteger(); 7703928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedFiles=new AtomicInteger(); 7803928aee4356845252ac6b662d5c72c29903813eJake Slack _mimeTypes=mimeTypes; 7903928aee4356845252ac6b662d5c72c29903813eJake Slack _parent=parent; 8003928aee4356845252ac6b662d5c72c29903813eJake Slack _etags=etags; 8103928aee4356845252ac6b662d5c72c29903813eJake Slack _useFileMappedBuffer=useFileMappedBuffer; 8203928aee4356845252ac6b662d5c72c29903813eJake Slack } 8303928aee4356845252ac6b662d5c72c29903813eJake Slack 8403928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 8503928aee4356845252ac6b662d5c72c29903813eJake Slack public int getCachedSize() 8603928aee4356845252ac6b662d5c72c29903813eJake Slack { 8703928aee4356845252ac6b662d5c72c29903813eJake Slack return _cachedSize.get(); 8803928aee4356845252ac6b662d5c72c29903813eJake Slack } 8903928aee4356845252ac6b662d5c72c29903813eJake Slack 9003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 9103928aee4356845252ac6b662d5c72c29903813eJake Slack public int getCachedFiles() 9203928aee4356845252ac6b662d5c72c29903813eJake Slack { 9303928aee4356845252ac6b662d5c72c29903813eJake Slack return _cachedFiles.get(); 9403928aee4356845252ac6b662d5c72c29903813eJake Slack } 9503928aee4356845252ac6b662d5c72c29903813eJake Slack 9603928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 9703928aee4356845252ac6b662d5c72c29903813eJake Slack public int getMaxCachedFileSize() 9803928aee4356845252ac6b662d5c72c29903813eJake Slack { 9903928aee4356845252ac6b662d5c72c29903813eJake Slack return _maxCachedFileSize; 10003928aee4356845252ac6b662d5c72c29903813eJake Slack } 10103928aee4356845252ac6b662d5c72c29903813eJake Slack 10203928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 10303928aee4356845252ac6b662d5c72c29903813eJake Slack public void setMaxCachedFileSize(int maxCachedFileSize) 10403928aee4356845252ac6b662d5c72c29903813eJake Slack { 10503928aee4356845252ac6b662d5c72c29903813eJake Slack _maxCachedFileSize = maxCachedFileSize; 10603928aee4356845252ac6b662d5c72c29903813eJake Slack shrinkCache(); 10703928aee4356845252ac6b662d5c72c29903813eJake Slack } 10803928aee4356845252ac6b662d5c72c29903813eJake Slack 10903928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 11003928aee4356845252ac6b662d5c72c29903813eJake Slack public int getMaxCacheSize() 11103928aee4356845252ac6b662d5c72c29903813eJake Slack { 11203928aee4356845252ac6b662d5c72c29903813eJake Slack return _maxCacheSize; 11303928aee4356845252ac6b662d5c72c29903813eJake Slack } 11403928aee4356845252ac6b662d5c72c29903813eJake Slack 11503928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 11603928aee4356845252ac6b662d5c72c29903813eJake Slack public void setMaxCacheSize(int maxCacheSize) 11703928aee4356845252ac6b662d5c72c29903813eJake Slack { 11803928aee4356845252ac6b662d5c72c29903813eJake Slack _maxCacheSize = maxCacheSize; 11903928aee4356845252ac6b662d5c72c29903813eJake Slack shrinkCache(); 12003928aee4356845252ac6b662d5c72c29903813eJake Slack } 12103928aee4356845252ac6b662d5c72c29903813eJake Slack 12203928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 12303928aee4356845252ac6b662d5c72c29903813eJake Slack /** 12403928aee4356845252ac6b662d5c72c29903813eJake Slack * @return Returns the maxCachedFiles. 12503928aee4356845252ac6b662d5c72c29903813eJake Slack */ 12603928aee4356845252ac6b662d5c72c29903813eJake Slack public int getMaxCachedFiles() 12703928aee4356845252ac6b662d5c72c29903813eJake Slack { 12803928aee4356845252ac6b662d5c72c29903813eJake Slack return _maxCachedFiles; 12903928aee4356845252ac6b662d5c72c29903813eJake Slack } 13003928aee4356845252ac6b662d5c72c29903813eJake Slack 13103928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 13203928aee4356845252ac6b662d5c72c29903813eJake Slack /** 13303928aee4356845252ac6b662d5c72c29903813eJake Slack * @param maxCachedFiles The maxCachedFiles to set. 13403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 13503928aee4356845252ac6b662d5c72c29903813eJake Slack public void setMaxCachedFiles(int maxCachedFiles) 13603928aee4356845252ac6b662d5c72c29903813eJake Slack { 13703928aee4356845252ac6b662d5c72c29903813eJake Slack _maxCachedFiles = maxCachedFiles; 13803928aee4356845252ac6b662d5c72c29903813eJake Slack shrinkCache(); 13903928aee4356845252ac6b662d5c72c29903813eJake Slack } 14003928aee4356845252ac6b662d5c72c29903813eJake Slack 14103928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 14203928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean isUseFileMappedBuffer() 14303928aee4356845252ac6b662d5c72c29903813eJake Slack { 14403928aee4356845252ac6b662d5c72c29903813eJake Slack return _useFileMappedBuffer; 14503928aee4356845252ac6b662d5c72c29903813eJake Slack } 14603928aee4356845252ac6b662d5c72c29903813eJake Slack 14703928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 14803928aee4356845252ac6b662d5c72c29903813eJake Slack public void setUseFileMappedBuffer(boolean useFileMappedBuffer) 14903928aee4356845252ac6b662d5c72c29903813eJake Slack { 15003928aee4356845252ac6b662d5c72c29903813eJake Slack _useFileMappedBuffer = useFileMappedBuffer; 15103928aee4356845252ac6b662d5c72c29903813eJake Slack } 15203928aee4356845252ac6b662d5c72c29903813eJake Slack 15303928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 15403928aee4356845252ac6b662d5c72c29903813eJake Slack public void flushCache() 15503928aee4356845252ac6b662d5c72c29903813eJake Slack { 15603928aee4356845252ac6b662d5c72c29903813eJake Slack if (_cache!=null) 15703928aee4356845252ac6b662d5c72c29903813eJake Slack { 15803928aee4356845252ac6b662d5c72c29903813eJake Slack while (_cache.size()>0) 15903928aee4356845252ac6b662d5c72c29903813eJake Slack { 16003928aee4356845252ac6b662d5c72c29903813eJake Slack for (String path : _cache.keySet()) 16103928aee4356845252ac6b662d5c72c29903813eJake Slack { 16203928aee4356845252ac6b662d5c72c29903813eJake Slack Content content = _cache.remove(path); 16303928aee4356845252ac6b662d5c72c29903813eJake Slack if (content!=null) 16403928aee4356845252ac6b662d5c72c29903813eJake Slack content.invalidate(); 16503928aee4356845252ac6b662d5c72c29903813eJake Slack } 16603928aee4356845252ac6b662d5c72c29903813eJake Slack } 16703928aee4356845252ac6b662d5c72c29903813eJake Slack } 16803928aee4356845252ac6b662d5c72c29903813eJake Slack } 16903928aee4356845252ac6b662d5c72c29903813eJake Slack 17003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 17103928aee4356845252ac6b662d5c72c29903813eJake Slack /** Get a Entry from the cache. 17203928aee4356845252ac6b662d5c72c29903813eJake Slack * Get either a valid entry object or create a new one if possible. 17303928aee4356845252ac6b662d5c72c29903813eJake Slack * 17403928aee4356845252ac6b662d5c72c29903813eJake Slack * @param pathInContext The key into the cache 17503928aee4356845252ac6b662d5c72c29903813eJake Slack * @return The entry matching <code>pathInContext</code>, or a new entry 17603928aee4356845252ac6b662d5c72c29903813eJake Slack * if no matching entry was found. If the content exists but is not cachable, 17703928aee4356845252ac6b662d5c72c29903813eJake Slack * then a {@link ResourceAsHttpContent} instance is return. If 17803928aee4356845252ac6b662d5c72c29903813eJake Slack * the resource does not exist, then null is returned. 17903928aee4356845252ac6b662d5c72c29903813eJake Slack * @throws IOException Problem loading the resource 18003928aee4356845252ac6b662d5c72c29903813eJake Slack */ 18103928aee4356845252ac6b662d5c72c29903813eJake Slack public HttpContent lookup(String pathInContext) 18203928aee4356845252ac6b662d5c72c29903813eJake Slack throws IOException 18303928aee4356845252ac6b662d5c72c29903813eJake Slack { 18403928aee4356845252ac6b662d5c72c29903813eJake Slack // Is the content in this cache? 18503928aee4356845252ac6b662d5c72c29903813eJake Slack Content content =_cache.get(pathInContext); 18603928aee4356845252ac6b662d5c72c29903813eJake Slack if (content!=null && (content).isValid()) 18703928aee4356845252ac6b662d5c72c29903813eJake Slack return content; 18803928aee4356845252ac6b662d5c72c29903813eJake Slack 18903928aee4356845252ac6b662d5c72c29903813eJake Slack // try loading the content from our factory. 19003928aee4356845252ac6b662d5c72c29903813eJake Slack Resource resource=_factory.getResource(pathInContext); 19103928aee4356845252ac6b662d5c72c29903813eJake Slack HttpContent loaded = load(pathInContext,resource); 19203928aee4356845252ac6b662d5c72c29903813eJake Slack if (loaded!=null) 19303928aee4356845252ac6b662d5c72c29903813eJake Slack return loaded; 19403928aee4356845252ac6b662d5c72c29903813eJake Slack 19503928aee4356845252ac6b662d5c72c29903813eJake Slack // Is the content in the parent cache? 19603928aee4356845252ac6b662d5c72c29903813eJake Slack if (_parent!=null) 19703928aee4356845252ac6b662d5c72c29903813eJake Slack { 19803928aee4356845252ac6b662d5c72c29903813eJake Slack HttpContent httpContent=_parent.lookup(pathInContext); 19903928aee4356845252ac6b662d5c72c29903813eJake Slack if (httpContent!=null) 20003928aee4356845252ac6b662d5c72c29903813eJake Slack return httpContent; 20103928aee4356845252ac6b662d5c72c29903813eJake Slack } 20203928aee4356845252ac6b662d5c72c29903813eJake Slack 20303928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 20403928aee4356845252ac6b662d5c72c29903813eJake Slack } 20503928aee4356845252ac6b662d5c72c29903813eJake Slack 20603928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 20703928aee4356845252ac6b662d5c72c29903813eJake Slack /** 20803928aee4356845252ac6b662d5c72c29903813eJake Slack * @param resource 20903928aee4356845252ac6b662d5c72c29903813eJake Slack * @return True if the resource is cacheable. The default implementation tests the cache sizes. 21003928aee4356845252ac6b662d5c72c29903813eJake Slack */ 21103928aee4356845252ac6b662d5c72c29903813eJake Slack protected boolean isCacheable(Resource resource) 21203928aee4356845252ac6b662d5c72c29903813eJake Slack { 21303928aee4356845252ac6b662d5c72c29903813eJake Slack long len = resource.length(); 21403928aee4356845252ac6b662d5c72c29903813eJake Slack 21503928aee4356845252ac6b662d5c72c29903813eJake Slack // Will it fit in the cache? 21603928aee4356845252ac6b662d5c72c29903813eJake Slack return (len>0 && len<_maxCachedFileSize && len<_maxCacheSize); 21703928aee4356845252ac6b662d5c72c29903813eJake Slack } 21803928aee4356845252ac6b662d5c72c29903813eJake Slack 21903928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 22003928aee4356845252ac6b662d5c72c29903813eJake Slack private HttpContent load(String pathInContext, Resource resource) 22103928aee4356845252ac6b662d5c72c29903813eJake Slack throws IOException 22203928aee4356845252ac6b662d5c72c29903813eJake Slack { 22303928aee4356845252ac6b662d5c72c29903813eJake Slack Content content=null; 22403928aee4356845252ac6b662d5c72c29903813eJake Slack 22503928aee4356845252ac6b662d5c72c29903813eJake Slack if (resource==null || !resource.exists()) 22603928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 22703928aee4356845252ac6b662d5c72c29903813eJake Slack 22803928aee4356845252ac6b662d5c72c29903813eJake Slack // Will it fit in the cache? 22903928aee4356845252ac6b662d5c72c29903813eJake Slack if (!resource.isDirectory() && isCacheable(resource)) 23003928aee4356845252ac6b662d5c72c29903813eJake Slack { 23103928aee4356845252ac6b662d5c72c29903813eJake Slack // Create the Content (to increment the cache sizes before adding the content 23203928aee4356845252ac6b662d5c72c29903813eJake Slack content = new Content(pathInContext,resource); 23303928aee4356845252ac6b662d5c72c29903813eJake Slack 23403928aee4356845252ac6b662d5c72c29903813eJake Slack // reduce the cache to an acceptable size. 23503928aee4356845252ac6b662d5c72c29903813eJake Slack shrinkCache(); 23603928aee4356845252ac6b662d5c72c29903813eJake Slack 23703928aee4356845252ac6b662d5c72c29903813eJake Slack // Add it to the cache. 23803928aee4356845252ac6b662d5c72c29903813eJake Slack Content added = _cache.putIfAbsent(pathInContext,content); 23903928aee4356845252ac6b662d5c72c29903813eJake Slack if (added!=null) 24003928aee4356845252ac6b662d5c72c29903813eJake Slack { 24103928aee4356845252ac6b662d5c72c29903813eJake Slack content.invalidate(); 24203928aee4356845252ac6b662d5c72c29903813eJake Slack content=added; 24303928aee4356845252ac6b662d5c72c29903813eJake Slack } 24403928aee4356845252ac6b662d5c72c29903813eJake Slack 24503928aee4356845252ac6b662d5c72c29903813eJake Slack return content; 24603928aee4356845252ac6b662d5c72c29903813eJake Slack } 24703928aee4356845252ac6b662d5c72c29903813eJake Slack 24803928aee4356845252ac6b662d5c72c29903813eJake Slack return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etags); 24903928aee4356845252ac6b662d5c72c29903813eJake Slack 25003928aee4356845252ac6b662d5c72c29903813eJake Slack } 25103928aee4356845252ac6b662d5c72c29903813eJake Slack 25203928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 25303928aee4356845252ac6b662d5c72c29903813eJake Slack private void shrinkCache() 25403928aee4356845252ac6b662d5c72c29903813eJake Slack { 25503928aee4356845252ac6b662d5c72c29903813eJake Slack // While we need to shrink 25603928aee4356845252ac6b662d5c72c29903813eJake Slack while (_cache.size()>0 && (_cachedFiles.get()>_maxCachedFiles || _cachedSize.get()>_maxCacheSize)) 25703928aee4356845252ac6b662d5c72c29903813eJake Slack { 25803928aee4356845252ac6b662d5c72c29903813eJake Slack // Scan the entire cache and generate an ordered list by last accessed time. 25903928aee4356845252ac6b662d5c72c29903813eJake Slack SortedSet<Content> sorted= new TreeSet<Content>( 26003928aee4356845252ac6b662d5c72c29903813eJake Slack new Comparator<Content>() 26103928aee4356845252ac6b662d5c72c29903813eJake Slack { 26203928aee4356845252ac6b662d5c72c29903813eJake Slack public int compare(Content c1, Content c2) 26303928aee4356845252ac6b662d5c72c29903813eJake Slack { 26403928aee4356845252ac6b662d5c72c29903813eJake Slack if (c1._lastAccessed<c2._lastAccessed) 26503928aee4356845252ac6b662d5c72c29903813eJake Slack return -1; 26603928aee4356845252ac6b662d5c72c29903813eJake Slack 26703928aee4356845252ac6b662d5c72c29903813eJake Slack if (c1._lastAccessed>c2._lastAccessed) 26803928aee4356845252ac6b662d5c72c29903813eJake Slack return 1; 26903928aee4356845252ac6b662d5c72c29903813eJake Slack 27003928aee4356845252ac6b662d5c72c29903813eJake Slack if (c1._length<c2._length) 27103928aee4356845252ac6b662d5c72c29903813eJake Slack return -1; 27203928aee4356845252ac6b662d5c72c29903813eJake Slack 27303928aee4356845252ac6b662d5c72c29903813eJake Slack return c1._key.compareTo(c2._key); 27403928aee4356845252ac6b662d5c72c29903813eJake Slack } 27503928aee4356845252ac6b662d5c72c29903813eJake Slack }); 27603928aee4356845252ac6b662d5c72c29903813eJake Slack for (Content content : _cache.values()) 27703928aee4356845252ac6b662d5c72c29903813eJake Slack sorted.add(content); 27803928aee4356845252ac6b662d5c72c29903813eJake Slack 27903928aee4356845252ac6b662d5c72c29903813eJake Slack // Invalidate least recently used first 28003928aee4356845252ac6b662d5c72c29903813eJake Slack for (Content content : sorted) 28103928aee4356845252ac6b662d5c72c29903813eJake Slack { 28203928aee4356845252ac6b662d5c72c29903813eJake Slack if (_cachedFiles.get()<=_maxCachedFiles && _cachedSize.get()<=_maxCacheSize) 28303928aee4356845252ac6b662d5c72c29903813eJake Slack break; 28403928aee4356845252ac6b662d5c72c29903813eJake Slack if (content==_cache.remove(content.getKey())) 28503928aee4356845252ac6b662d5c72c29903813eJake Slack content.invalidate(); 28603928aee4356845252ac6b662d5c72c29903813eJake Slack } 28703928aee4356845252ac6b662d5c72c29903813eJake Slack } 28803928aee4356845252ac6b662d5c72c29903813eJake Slack } 28903928aee4356845252ac6b662d5c72c29903813eJake Slack 29003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 29103928aee4356845252ac6b662d5c72c29903813eJake Slack protected Buffer getIndirectBuffer(Resource resource) 29203928aee4356845252ac6b662d5c72c29903813eJake Slack { 29303928aee4356845252ac6b662d5c72c29903813eJake Slack try 29403928aee4356845252ac6b662d5c72c29903813eJake Slack { 29503928aee4356845252ac6b662d5c72c29903813eJake Slack int len=(int)resource.length(); 29603928aee4356845252ac6b662d5c72c29903813eJake Slack if (len<0) 29703928aee4356845252ac6b662d5c72c29903813eJake Slack { 29803928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn("invalid resource: "+String.valueOf(resource)+" "+len); 29903928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 30003928aee4356845252ac6b662d5c72c29903813eJake Slack } 30103928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer = new IndirectNIOBuffer(len); 30203928aee4356845252ac6b662d5c72c29903813eJake Slack InputStream is = resource.getInputStream(); 30303928aee4356845252ac6b662d5c72c29903813eJake Slack buffer.readFrom(is,len); 30403928aee4356845252ac6b662d5c72c29903813eJake Slack is.close(); 30503928aee4356845252ac6b662d5c72c29903813eJake Slack return buffer; 30603928aee4356845252ac6b662d5c72c29903813eJake Slack } 30703928aee4356845252ac6b662d5c72c29903813eJake Slack catch(IOException e) 30803928aee4356845252ac6b662d5c72c29903813eJake Slack { 30903928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn(e); 31003928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 31103928aee4356845252ac6b662d5c72c29903813eJake Slack } 31203928aee4356845252ac6b662d5c72c29903813eJake Slack } 31303928aee4356845252ac6b662d5c72c29903813eJake Slack 31403928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 31503928aee4356845252ac6b662d5c72c29903813eJake Slack protected Buffer getDirectBuffer(Resource resource) 31603928aee4356845252ac6b662d5c72c29903813eJake Slack { 31703928aee4356845252ac6b662d5c72c29903813eJake Slack try 31803928aee4356845252ac6b662d5c72c29903813eJake Slack { 31903928aee4356845252ac6b662d5c72c29903813eJake Slack if (_useFileMappedBuffer && resource.getFile()!=null) 32003928aee4356845252ac6b662d5c72c29903813eJake Slack return new DirectNIOBuffer(resource.getFile()); 32103928aee4356845252ac6b662d5c72c29903813eJake Slack 32203928aee4356845252ac6b662d5c72c29903813eJake Slack int len=(int)resource.length(); 32303928aee4356845252ac6b662d5c72c29903813eJake Slack if (len<0) 32403928aee4356845252ac6b662d5c72c29903813eJake Slack { 32503928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn("invalid resource: "+String.valueOf(resource)+" "+len); 32603928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 32703928aee4356845252ac6b662d5c72c29903813eJake Slack } 32803928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer = new DirectNIOBuffer(len); 32903928aee4356845252ac6b662d5c72c29903813eJake Slack InputStream is = resource.getInputStream(); 33003928aee4356845252ac6b662d5c72c29903813eJake Slack buffer.readFrom(is,len); 33103928aee4356845252ac6b662d5c72c29903813eJake Slack is.close(); 33203928aee4356845252ac6b662d5c72c29903813eJake Slack return buffer; 33303928aee4356845252ac6b662d5c72c29903813eJake Slack } 33403928aee4356845252ac6b662d5c72c29903813eJake Slack catch(IOException e) 33503928aee4356845252ac6b662d5c72c29903813eJake Slack { 33603928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn(e); 33703928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 33803928aee4356845252ac6b662d5c72c29903813eJake Slack } 33903928aee4356845252ac6b662d5c72c29903813eJake Slack } 34003928aee4356845252ac6b662d5c72c29903813eJake Slack 34103928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 34203928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 34303928aee4356845252ac6b662d5c72c29903813eJake Slack public String toString() 34403928aee4356845252ac6b662d5c72c29903813eJake Slack { 34503928aee4356845252ac6b662d5c72c29903813eJake Slack return "ResourceCache["+_parent+","+_factory+"]@"+hashCode(); 34603928aee4356845252ac6b662d5c72c29903813eJake Slack } 34703928aee4356845252ac6b662d5c72c29903813eJake Slack 34803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 34903928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 35003928aee4356845252ac6b662d5c72c29903813eJake Slack /** MetaData associated with a context Resource. 35103928aee4356845252ac6b662d5c72c29903813eJake Slack */ 35203928aee4356845252ac6b662d5c72c29903813eJake Slack public class Content implements HttpContent 35303928aee4356845252ac6b662d5c72c29903813eJake Slack { 35403928aee4356845252ac6b662d5c72c29903813eJake Slack final Resource _resource; 35503928aee4356845252ac6b662d5c72c29903813eJake Slack final int _length; 35603928aee4356845252ac6b662d5c72c29903813eJake Slack final String _key; 35703928aee4356845252ac6b662d5c72c29903813eJake Slack final long _lastModified; 35803928aee4356845252ac6b662d5c72c29903813eJake Slack final Buffer _lastModifiedBytes; 35903928aee4356845252ac6b662d5c72c29903813eJake Slack final Buffer _contentType; 36003928aee4356845252ac6b662d5c72c29903813eJake Slack final Buffer _etagBuffer; 36103928aee4356845252ac6b662d5c72c29903813eJake Slack 36203928aee4356845252ac6b662d5c72c29903813eJake Slack volatile long _lastAccessed; 36303928aee4356845252ac6b662d5c72c29903813eJake Slack AtomicReference<Buffer> _indirectBuffer=new AtomicReference<Buffer>(); 36403928aee4356845252ac6b662d5c72c29903813eJake Slack AtomicReference<Buffer> _directBuffer=new AtomicReference<Buffer>(); 36503928aee4356845252ac6b662d5c72c29903813eJake Slack 36603928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 36703928aee4356845252ac6b662d5c72c29903813eJake Slack Content(String pathInContext,Resource resource) 36803928aee4356845252ac6b662d5c72c29903813eJake Slack { 36903928aee4356845252ac6b662d5c72c29903813eJake Slack _key=pathInContext; 37003928aee4356845252ac6b662d5c72c29903813eJake Slack _resource=resource; 37103928aee4356845252ac6b662d5c72c29903813eJake Slack 37203928aee4356845252ac6b662d5c72c29903813eJake Slack _contentType=_mimeTypes.getMimeByExtension(_resource.toString()); 37303928aee4356845252ac6b662d5c72c29903813eJake Slack boolean exists=resource.exists(); 37403928aee4356845252ac6b662d5c72c29903813eJake Slack _lastModified=exists?resource.lastModified():-1; 37503928aee4356845252ac6b662d5c72c29903813eJake Slack _lastModifiedBytes=_lastModified<0?null:new ByteArrayBuffer(HttpFields.formatDate(_lastModified)); 37603928aee4356845252ac6b662d5c72c29903813eJake Slack 37703928aee4356845252ac6b662d5c72c29903813eJake Slack _length=exists?(int)resource.length():0; 37803928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedSize.addAndGet(_length); 37903928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedFiles.incrementAndGet(); 38003928aee4356845252ac6b662d5c72c29903813eJake Slack _lastAccessed=System.currentTimeMillis(); 38103928aee4356845252ac6b662d5c72c29903813eJake Slack 38203928aee4356845252ac6b662d5c72c29903813eJake Slack _etagBuffer=_etags?new ByteArrayBuffer(resource.getWeakETag()):null; 38303928aee4356845252ac6b662d5c72c29903813eJake Slack } 38403928aee4356845252ac6b662d5c72c29903813eJake Slack 38503928aee4356845252ac6b662d5c72c29903813eJake Slack 38603928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 38703928aee4356845252ac6b662d5c72c29903813eJake Slack public String getKey() 38803928aee4356845252ac6b662d5c72c29903813eJake Slack { 38903928aee4356845252ac6b662d5c72c29903813eJake Slack return _key; 39003928aee4356845252ac6b662d5c72c29903813eJake Slack } 39103928aee4356845252ac6b662d5c72c29903813eJake Slack 39203928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 39303928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean isCached() 39403928aee4356845252ac6b662d5c72c29903813eJake Slack { 39503928aee4356845252ac6b662d5c72c29903813eJake Slack return _key!=null; 39603928aee4356845252ac6b662d5c72c29903813eJake Slack } 39703928aee4356845252ac6b662d5c72c29903813eJake Slack 39803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 39903928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean isMiss() 40003928aee4356845252ac6b662d5c72c29903813eJake Slack { 40103928aee4356845252ac6b662d5c72c29903813eJake Slack return false; 40203928aee4356845252ac6b662d5c72c29903813eJake Slack } 40303928aee4356845252ac6b662d5c72c29903813eJake Slack 40403928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 40503928aee4356845252ac6b662d5c72c29903813eJake Slack public Resource getResource() 40603928aee4356845252ac6b662d5c72c29903813eJake Slack { 40703928aee4356845252ac6b662d5c72c29903813eJake Slack return _resource; 40803928aee4356845252ac6b662d5c72c29903813eJake Slack } 40903928aee4356845252ac6b662d5c72c29903813eJake Slack 41003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 41103928aee4356845252ac6b662d5c72c29903813eJake Slack public Buffer getETag() 41203928aee4356845252ac6b662d5c72c29903813eJake Slack { 41303928aee4356845252ac6b662d5c72c29903813eJake Slack return _etagBuffer; 41403928aee4356845252ac6b662d5c72c29903813eJake Slack } 41503928aee4356845252ac6b662d5c72c29903813eJake Slack 41603928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 41703928aee4356845252ac6b662d5c72c29903813eJake Slack boolean isValid() 41803928aee4356845252ac6b662d5c72c29903813eJake Slack { 41903928aee4356845252ac6b662d5c72c29903813eJake Slack if (_lastModified==_resource.lastModified() && _length==_resource.length()) 42003928aee4356845252ac6b662d5c72c29903813eJake Slack { 42103928aee4356845252ac6b662d5c72c29903813eJake Slack _lastAccessed=System.currentTimeMillis(); 42203928aee4356845252ac6b662d5c72c29903813eJake Slack return true; 42303928aee4356845252ac6b662d5c72c29903813eJake Slack } 42403928aee4356845252ac6b662d5c72c29903813eJake Slack 42503928aee4356845252ac6b662d5c72c29903813eJake Slack if (this==_cache.remove(_key)) 42603928aee4356845252ac6b662d5c72c29903813eJake Slack invalidate(); 42703928aee4356845252ac6b662d5c72c29903813eJake Slack return false; 42803928aee4356845252ac6b662d5c72c29903813eJake Slack } 42903928aee4356845252ac6b662d5c72c29903813eJake Slack 43003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 43103928aee4356845252ac6b662d5c72c29903813eJake Slack protected void invalidate() 43203928aee4356845252ac6b662d5c72c29903813eJake Slack { 43303928aee4356845252ac6b662d5c72c29903813eJake Slack // Invalidate it 43403928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedSize.addAndGet(-_length); 43503928aee4356845252ac6b662d5c72c29903813eJake Slack _cachedFiles.decrementAndGet(); 43603928aee4356845252ac6b662d5c72c29903813eJake Slack _resource.release(); 43703928aee4356845252ac6b662d5c72c29903813eJake Slack } 43803928aee4356845252ac6b662d5c72c29903813eJake Slack 43903928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 44003928aee4356845252ac6b662d5c72c29903813eJake Slack public Buffer getLastModified() 44103928aee4356845252ac6b662d5c72c29903813eJake Slack { 44203928aee4356845252ac6b662d5c72c29903813eJake Slack return _lastModifiedBytes; 44303928aee4356845252ac6b662d5c72c29903813eJake Slack } 44403928aee4356845252ac6b662d5c72c29903813eJake Slack 44503928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 44603928aee4356845252ac6b662d5c72c29903813eJake Slack public Buffer getContentType() 44703928aee4356845252ac6b662d5c72c29903813eJake Slack { 44803928aee4356845252ac6b662d5c72c29903813eJake Slack return _contentType; 44903928aee4356845252ac6b662d5c72c29903813eJake Slack } 45003928aee4356845252ac6b662d5c72c29903813eJake Slack 45103928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 45203928aee4356845252ac6b662d5c72c29903813eJake Slack public void release() 45303928aee4356845252ac6b662d5c72c29903813eJake Slack { 45403928aee4356845252ac6b662d5c72c29903813eJake Slack // don't release while cached. Release when invalidated. 45503928aee4356845252ac6b662d5c72c29903813eJake Slack } 45603928aee4356845252ac6b662d5c72c29903813eJake Slack 45703928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 45803928aee4356845252ac6b662d5c72c29903813eJake Slack public Buffer getIndirectBuffer() 45903928aee4356845252ac6b662d5c72c29903813eJake Slack { 46003928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer = _indirectBuffer.get(); 46103928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer==null) 46203928aee4356845252ac6b662d5c72c29903813eJake Slack { 46303928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer2=ResourceCache.this.getIndirectBuffer(_resource); 46403928aee4356845252ac6b662d5c72c29903813eJake Slack 46503928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer2==null) 46603928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn("Could not load "+this); 46703928aee4356845252ac6b662d5c72c29903813eJake Slack else if (_indirectBuffer.compareAndSet(null,buffer2)) 46803928aee4356845252ac6b662d5c72c29903813eJake Slack buffer=buffer2; 46903928aee4356845252ac6b662d5c72c29903813eJake Slack else 47003928aee4356845252ac6b662d5c72c29903813eJake Slack buffer=_indirectBuffer.get(); 47103928aee4356845252ac6b662d5c72c29903813eJake Slack } 47203928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer==null) 47303928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 47403928aee4356845252ac6b662d5c72c29903813eJake Slack return new View(buffer); 47503928aee4356845252ac6b662d5c72c29903813eJake Slack } 47603928aee4356845252ac6b662d5c72c29903813eJake Slack 47703928aee4356845252ac6b662d5c72c29903813eJake Slack 47803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 47903928aee4356845252ac6b662d5c72c29903813eJake Slack public Buffer getDirectBuffer() 48003928aee4356845252ac6b662d5c72c29903813eJake Slack { 48103928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer = _directBuffer.get(); 48203928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer==null) 48303928aee4356845252ac6b662d5c72c29903813eJake Slack { 48403928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer buffer2=ResourceCache.this.getDirectBuffer(_resource); 48503928aee4356845252ac6b662d5c72c29903813eJake Slack 48603928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer2==null) 48703928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn("Could not load "+this); 48803928aee4356845252ac6b662d5c72c29903813eJake Slack else if (_directBuffer.compareAndSet(null,buffer2)) 48903928aee4356845252ac6b662d5c72c29903813eJake Slack buffer=buffer2; 49003928aee4356845252ac6b662d5c72c29903813eJake Slack else 49103928aee4356845252ac6b662d5c72c29903813eJake Slack buffer=_directBuffer.get(); 49203928aee4356845252ac6b662d5c72c29903813eJake Slack } 49303928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer==null) 49403928aee4356845252ac6b662d5c72c29903813eJake Slack return null; 49503928aee4356845252ac6b662d5c72c29903813eJake Slack 49603928aee4356845252ac6b662d5c72c29903813eJake Slack return new View(buffer); 49703928aee4356845252ac6b662d5c72c29903813eJake Slack } 49803928aee4356845252ac6b662d5c72c29903813eJake Slack 49903928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 50003928aee4356845252ac6b662d5c72c29903813eJake Slack public long getContentLength() 50103928aee4356845252ac6b662d5c72c29903813eJake Slack { 50203928aee4356845252ac6b662d5c72c29903813eJake Slack return _length; 50303928aee4356845252ac6b662d5c72c29903813eJake Slack } 50403928aee4356845252ac6b662d5c72c29903813eJake Slack 50503928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 50603928aee4356845252ac6b662d5c72c29903813eJake Slack public InputStream getInputStream() throws IOException 50703928aee4356845252ac6b662d5c72c29903813eJake Slack { 50803928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer indirect = getIndirectBuffer(); 50903928aee4356845252ac6b662d5c72c29903813eJake Slack if (indirect!=null && indirect.array()!=null) 51003928aee4356845252ac6b662d5c72c29903813eJake Slack return new ByteArrayInputStream(indirect.array(),indirect.getIndex(),indirect.length()); 51103928aee4356845252ac6b662d5c72c29903813eJake Slack 51203928aee4356845252ac6b662d5c72c29903813eJake Slack return _resource.getInputStream(); 51303928aee4356845252ac6b662d5c72c29903813eJake Slack } 51403928aee4356845252ac6b662d5c72c29903813eJake Slack 51503928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 51603928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 51703928aee4356845252ac6b662d5c72c29903813eJake Slack public String toString() 51803928aee4356845252ac6b662d5c72c29903813eJake Slack { 51903928aee4356845252ac6b662d5c72c29903813eJake Slack return String.format("%s %s %d %s %s",_resource,_resource.exists(),_resource.lastModified(),_contentType,_lastModifiedBytes); 52003928aee4356845252ac6b662d5c72c29903813eJake Slack } 52103928aee4356845252ac6b662d5c72c29903813eJake Slack } 52203928aee4356845252ac6b662d5c72c29903813eJake Slack} 523