Code cleanups.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2018-04-11 15:05:58 +02:00
parent c14f7efc95
commit b09760ca9a
1 changed files with 201 additions and 273 deletions

View File

@ -24,7 +24,6 @@ import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
@ -50,15 +49,12 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory; import org.eclipse.jetty.util.resource.ResourceFactory;
/**
* Caching HttpContent.Factory
*/
public class CachedContentFactory implements HttpContent.ContentFactory public class CachedContentFactory implements HttpContent.ContentFactory
{ {
private static final Logger LOG = Log.getLogger(CachedContentFactory.class); private static final Logger LOG = Log.getLogger(CachedContentFactory.class);
private final static Map<CompressedContentFormat, CachedPrecompressedHttpContent> NO_PRECOMPRESSED = Collections.unmodifiableMap(Collections.emptyMap()); private final static Map<CompressedContentFormat, CachedPrecompressedHttpContent> NO_PRECOMPRESSED = Collections.unmodifiableMap(Collections.emptyMap());
private final ConcurrentMap<String,CachedHttpContent> _cache; private final ConcurrentMap<String, CachedHttpContent> _cache;
private final AtomicInteger _cachedSize; private final AtomicInteger _cachedSize;
private final AtomicInteger _cachedFiles; private final AtomicInteger _cachedFiles;
private final ResourceFactory _factory; private final ResourceFactory _factory;
@ -66,84 +62,77 @@ public class CachedContentFactory implements HttpContent.ContentFactory
private final MimeTypes _mimeTypes; private final MimeTypes _mimeTypes;
private final boolean _etags; private final boolean _etags;
private final CompressedContentFormat[] _precompressedFormats; private final CompressedContentFormat[] _precompressedFormats;
private final boolean _useFileMappedBuffer; private final boolean _useFileMappedBuffer;
private int _maxCachedFileSize = 128*1024*1024; private int _maxCachedFileSize = 128 * 1024 * 1024;
private int _maxCachedFiles= 2048; private int _maxCachedFiles = 2048;
private int _maxCacheSize = 256*1024*1024; private int _maxCacheSize = 256 * 1024 * 1024;
/* ------------------------------------------------------------ */ /**
/** Constructor. * Constructor.
* @param parent the parent resource cache *
* @param factory the resource factory * @param parent the parent resource cache
* @param mimeTypes Mimetype to use for meta data * @param factory the resource factory
* @param useFileMappedBuffer true to file memory mapped buffers * @param mimeTypes Mimetype to use for meta data
* @param etags true to support etags * @param useFileMappedBuffer true to file memory mapped buffers
* @param etags true to support etags
* @param precompressedFormats array of precompression formats to support * @param precompressedFormats array of precompression formats to support
*/ */
public CachedContentFactory(CachedContentFactory parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags,CompressedContentFormat[] precompressedFormats) public CachedContentFactory(CachedContentFactory parent, ResourceFactory factory, MimeTypes mimeTypes, boolean useFileMappedBuffer, boolean etags, CompressedContentFormat[] precompressedFormats)
{ {
_factory = factory; _factory = factory;
_cache=new ConcurrentHashMap<String,CachedHttpContent>(); _cache = new ConcurrentHashMap<>();
_cachedSize=new AtomicInteger(); _cachedSize = new AtomicInteger();
_cachedFiles=new AtomicInteger(); _cachedFiles = new AtomicInteger();
_mimeTypes=mimeTypes; _mimeTypes = mimeTypes;
_parent=parent; _parent = parent;
_useFileMappedBuffer=useFileMappedBuffer; _useFileMappedBuffer = useFileMappedBuffer;
_etags=etags; _etags = etags;
_precompressedFormats=precompressedFormats; _precompressedFormats = precompressedFormats;
} }
/* ------------------------------------------------------------ */
public int getCachedSize() public int getCachedSize()
{ {
return _cachedSize.get(); return _cachedSize.get();
} }
/* ------------------------------------------------------------ */
public int getCachedFiles() public int getCachedFiles()
{ {
return _cachedFiles.get(); return _cachedFiles.get();
} }
/* ------------------------------------------------------------ */
public int getMaxCachedFileSize() public int getMaxCachedFileSize()
{ {
return _maxCachedFileSize; return _maxCachedFileSize;
} }
/* ------------------------------------------------------------ */
public void setMaxCachedFileSize(int maxCachedFileSize) public void setMaxCachedFileSize(int maxCachedFileSize)
{ {
_maxCachedFileSize = maxCachedFileSize; _maxCachedFileSize = maxCachedFileSize;
shrinkCache(); shrinkCache();
} }
/* ------------------------------------------------------------ */
public int getMaxCacheSize() public int getMaxCacheSize()
{ {
return _maxCacheSize; return _maxCacheSize;
} }
/* ------------------------------------------------------------ */
public void setMaxCacheSize(int maxCacheSize) public void setMaxCacheSize(int maxCacheSize)
{ {
_maxCacheSize = maxCacheSize; _maxCacheSize = maxCacheSize;
shrinkCache(); shrinkCache();
} }
/* ------------------------------------------------------------ */
/** /**
* @return Returns the maxCachedFiles. * @return the max number of cached files.
*/ */
public int getMaxCachedFiles() public int getMaxCachedFiles()
{ {
return _maxCachedFiles; return _maxCachedFiles;
} }
/* ------------------------------------------------------------ */
/** /**
* @param maxCachedFiles The maxCachedFiles to set. * @param maxCachedFiles the max number of cached files.
*/ */
public void setMaxCachedFiles(int maxCachedFiles) public void setMaxCachedFiles(int maxCachedFiles)
{ {
@ -151,106 +140,94 @@ public class CachedContentFactory implements HttpContent.ContentFactory
shrinkCache(); shrinkCache();
} }
/* ------------------------------------------------------------ */
public boolean isUseFileMappedBuffer() public boolean isUseFileMappedBuffer()
{ {
return _useFileMappedBuffer; return _useFileMappedBuffer;
} }
/* ------------------------------------------------------------ */
public void flushCache() public void flushCache()
{ {
if (_cache!=null) while (_cache.size() > 0)
{ {
while (_cache.size()>0) for (String path : _cache.keySet())
{ {
for (String path : _cache.keySet()) CachedHttpContent content = _cache.remove(path);
{ if (content != null)
CachedHttpContent content = _cache.remove(path); content.invalidate();
if (content!=null)
content.invalidate();
}
} }
} }
} }
/* ------------------------------------------------------------ */
@Deprecated @Deprecated
public HttpContent lookup(String pathInContext) public HttpContent lookup(String pathInContext) throws IOException
throws IOException
{ {
return getContent(pathInContext,_maxCachedFileSize); return getContent(pathInContext, _maxCachedFileSize);
} }
/* ------------------------------------------------------------ */ /**
/** Get a Entry from the cache. * <p>Returns an entry from the cache, or creates a new one.</p>
* Get either a valid entry object or create a new one if possible.
* *
* @param pathInContext The key into the cache * @param pathInContext The key into the cache
* @param maxBufferSize The maximum buffer to allocated for this request. For cached content, a larger buffer may have * @param maxBufferSize The maximum buffer size allocated for this request. For cached content, a larger buffer may have
* previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls. * previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls.
* @return The entry matching <code>pathInContext</code>, or a new entry * @return The entry matching {@code pathInContext}, or a new entry
* if no matching entry was found. If the content exists but is not cachable, * if no matching entry was found. If the content exists but is not cacheable,
* then a {@link ResourceHttpContent} instance is return. If * then a {@link ResourceHttpContent} instance is returned. If
* the resource does not exist, then null is returned. * the resource does not exist, then null is returned.
* @throws IOException Problem loading the resource * @throws IOException if the resource cannot be retrieved
*/ */
@Override @Override
public HttpContent getContent(String pathInContext,int maxBufferSize) public HttpContent getContent(String pathInContext, int maxBufferSize) throws IOException
throws IOException
{ {
// Is the content in this cache? // Is the content in this cache?
CachedHttpContent content =_cache.get(pathInContext); CachedHttpContent content = _cache.get(pathInContext);
if (content!=null && (content).isValid()) if (content != null && (content).isValid())
return content; return content;
// try loading the content from our factory. // try loading the content from our factory.
Resource resource=_factory.getResource(pathInContext); Resource resource = _factory.getResource(pathInContext);
HttpContent loaded = load(pathInContext,resource,maxBufferSize); HttpContent loaded = load(pathInContext, resource, maxBufferSize);
if (loaded!=null) if (loaded != null)
return loaded; return loaded;
// Is the content in the parent cache? // Is the content in the parent cache?
if (_parent!=null) if (_parent != null)
{ {
HttpContent httpContent=_parent.getContent(pathInContext,maxBufferSize); HttpContent httpContent = _parent.getContent(pathInContext, maxBufferSize);
if (httpContent!=null) if (httpContent != null)
return httpContent; return httpContent;
} }
return null; return null;
} }
/* ------------------------------------------------------------ */
/** /**
* @param resource the resource to test * @param resource the resource to test
* @return True if the resource is cacheable. The default implementation tests the cache sizes. * @return whether the resource is cacheable. The default implementation tests the cache sizes.
*/ */
protected boolean isCacheable(Resource resource) protected boolean isCacheable(Resource resource)
{ {
if (_maxCachedFiles<=0) if (_maxCachedFiles <= 0)
return false; return false;
long len = resource.length(); long len = resource.length();
// Will it fit in the cache? // Will it fit in the cache?
return (len>0 && (_useFileMappedBuffer || (len<_maxCachedFileSize && len<_maxCacheSize))); return (len > 0 && (_useFileMappedBuffer || (len < _maxCachedFileSize && len < _maxCacheSize)));
} }
/* ------------------------------------------------------------ */
private HttpContent load(String pathInContext, Resource resource, int maxBufferSize) private HttpContent load(String pathInContext, Resource resource, int maxBufferSize)
throws IOException
{ {
if (resource == null || !resource.exists()) if (resource == null || !resource.exists())
return null; return null;
if (resource.isDirectory()) if (resource.isDirectory())
return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize()); return new ResourceHttpContent(resource, _mimeTypes.getMimeByExtension(resource.toString()), getMaxCachedFileSize());
// Will it fit in the cache? // Will it fit in the cache?
if (isCacheable(resource)) if (isCacheable(resource))
{ {
CachedHttpContent content = null; CachedHttpContent content;
// Look for precompressed resources // Look for precompressed resources
if (_precompressedFormats.length > 0) if (_precompressedFormats.length > 0)
@ -267,8 +244,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified() if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
&& compressedResource.length() < resource.length()) && compressedResource.length() < resource.length())
{ {
compressedContent = new CachedHttpContent(compressedPathInContext,compressedResource,null); compressedContent = new CachedHttpContent(compressedPathInContext, compressedResource, null);
CachedHttpContent added = _cache.putIfAbsent(compressedPathInContext,compressedContent); CachedHttpContent added = _cache.putIfAbsent(compressedPathInContext, compressedContent);
if (added != null) if (added != null)
{ {
compressedContent.invalidate(); compressedContent.invalidate();
@ -277,15 +254,15 @@ public class CachedContentFactory implements HttpContent.ContentFactory
} }
} }
if (compressedContent != null) if (compressedContent != null)
precompresssedContents.put(format,compressedContent); precompresssedContents.put(format, compressedContent);
} }
content = new CachedHttpContent(pathInContext,resource,precompresssedContents); content = new CachedHttpContent(pathInContext, resource, precompresssedContents);
} }
else else
content = new CachedHttpContent(pathInContext,resource,null); content = new CachedHttpContent(pathInContext, resource, null);
// Add it to the cache. // Add it to the cache.
CachedHttpContent added = _cache.putIfAbsent(pathInContext,content); CachedHttpContent added = _cache.putIfAbsent(pathInContext, content);
if (added != null) if (added != null)
{ {
content.invalidate(); content.invalidate();
@ -306,167 +283,153 @@ public class CachedContentFactory implements HttpContent.ContentFactory
String compressedPathInContext = pathInContext + format._extension; String compressedPathInContext = pathInContext + format._extension;
CachedHttpContent compressedContent = _cache.get(compressedPathInContext); CachedHttpContent compressedContent = _cache.get(compressedPathInContext);
if (compressedContent != null && compressedContent.isValid() && compressedContent.getResource().lastModified() >= resource.lastModified()) if (compressedContent != null && compressedContent.isValid() && compressedContent.getResource().lastModified() >= resource.lastModified())
compressedContents.put(format,compressedContent); compressedContents.put(format, compressedContent);
// Is there a precompressed resource? // Is there a precompressed resource?
Resource compressedResource = _factory.getResource(compressedPathInContext); Resource compressedResource = _factory.getResource(compressedPathInContext);
if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified() if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
&& compressedResource.length() < resource.length()) && compressedResource.length() < resource.length())
compressedContents.put(format, compressedContents.put(format,
new ResourceHttpContent(compressedResource,_mimeTypes.getMimeByExtension(compressedPathInContext),maxBufferSize)); new ResourceHttpContent(compressedResource, _mimeTypes.getMimeByExtension(compressedPathInContext), maxBufferSize));
} }
if (!compressedContents.isEmpty()) if (!compressedContents.isEmpty())
return new ResourceHttpContent(resource,mt,maxBufferSize,compressedContents); return new ResourceHttpContent(resource, mt, maxBufferSize, compressedContents);
} }
return new ResourceHttpContent(resource,mt,maxBufferSize); return new ResourceHttpContent(resource, mt, maxBufferSize);
} }
/* ------------------------------------------------------------ */
private void shrinkCache() private void shrinkCache()
{ {
// While we need to shrink // While we need to shrink
while (_cache.size()>0 && (_cachedFiles.get()>_maxCachedFiles || _cachedSize.get()>_maxCacheSize)) while (_cache.size() > 0 && (_cachedFiles.get() > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
{ {
// Scan the entire cache and generate an ordered list by last accessed time. // Scan the entire cache and generate an ordered list by last accessed time.
SortedSet<CachedHttpContent> sorted= new TreeSet<CachedHttpContent>( SortedSet<CachedHttpContent> sorted = new TreeSet<>((c1, c2) ->
new Comparator<CachedHttpContent>() {
{ if (c1._lastAccessed < c2._lastAccessed)
@Override return -1;
public int compare(CachedHttpContent c1, CachedHttpContent c2)
{ if (c1._lastAccessed > c2._lastAccessed)
if (c1._lastAccessed<c2._lastAccessed) return 1;
return -1;
if (c1._contentLengthValue < c2._contentLengthValue)
if (c1._lastAccessed>c2._lastAccessed) return -1;
return 1;
return c1._key.compareTo(c2._key);
});
sorted.addAll(_cache.values());
if (c1._contentLengthValue<c2._contentLengthValue)
return -1;
return c1._key.compareTo(c2._key);
}
});
for (CachedHttpContent content : _cache.values())
sorted.add(content);
// Invalidate least recently used first // Invalidate least recently used first
for (CachedHttpContent content : sorted) for (CachedHttpContent content : sorted)
{ {
if (_cachedFiles.get()<=_maxCachedFiles && _cachedSize.get()<=_maxCacheSize) if (_cachedFiles.get() <= _maxCachedFiles && _cachedSize.get() <= _maxCacheSize)
break; break;
if (content==_cache.remove(content.getKey())) if (content == _cache.remove(content.getKey()))
content.invalidate(); content.invalidate();
} }
} }
} }
/* ------------------------------------------------------------ */
protected ByteBuffer getIndirectBuffer(Resource resource) protected ByteBuffer getIndirectBuffer(Resource resource)
{ {
try try
{ {
return BufferUtil.toBuffer(resource,true); return BufferUtil.toBuffer(resource, true);
} }
catch(IOException|IllegalArgumentException e) catch (IOException | IllegalArgumentException e)
{ {
LOG.warn(e); LOG.warn(e);
return null; return null;
} }
} }
/* ------------------------------------------------------------ */
protected ByteBuffer getMappedBuffer(Resource resource) protected ByteBuffer getMappedBuffer(Resource resource)
{ {
// Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for // Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for
// a non shared resource. Also ignore max buffer size // a non shared resource. Also ignore max buffer size
try try
{ {
if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE) if (_useFileMappedBuffer && resource.getFile() != null && resource.length() < Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource.getFile()); return BufferUtil.toMappedBuffer(resource.getFile());
} }
catch(IOException|IllegalArgumentException e) catch (IOException | IllegalArgumentException e)
{ {
LOG.warn(e); LOG.warn(e);
} }
return null; return null;
} }
/* ------------------------------------------------------------ */
protected ByteBuffer getDirectBuffer(Resource resource) protected ByteBuffer getDirectBuffer(Resource resource)
{ {
try try
{ {
return BufferUtil.toBuffer(resource,true); return BufferUtil.toBuffer(resource, true);
} }
catch(IOException|IllegalArgumentException e) catch (IOException | IllegalArgumentException e)
{ {
LOG.warn(e); LOG.warn(e);
} }
return null; return null;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String toString() public String toString()
{ {
return "ResourceCache["+_parent+","+_factory+"]@"+hashCode(); return "ResourceCache[" + _parent + "," + _factory + "]@" + hashCode();
} }
/* ------------------------------------------------------------ */ /**
/* ------------------------------------------------------------ */ * MetaData associated with a context Resource.
/** MetaData associated with a context Resource.
*/ */
public class CachedHttpContent implements HttpContent public class CachedHttpContent implements HttpContent
{ {
final String _key; private final String _key;
final Resource _resource; private final Resource _resource;
final int _contentLengthValue; private final int _contentLengthValue;
final HttpField _contentType; private final HttpField _contentType;
final String _characterEncoding; private final String _characterEncoding;
final MimeTypes.Type _mimeType; private final MimeTypes.Type _mimeType;
final HttpField _contentLength; private final HttpField _contentLength;
final HttpField _lastModified; private final HttpField _lastModified;
final long _lastModifiedValue; private final long _lastModifiedValue;
final HttpField _etag; private final HttpField _etag;
final Map<CompressedContentFormat, CachedPrecompressedHttpContent> _precompressed; private final Map<CompressedContentFormat, CachedPrecompressedHttpContent> _precompressed;
private final AtomicReference<ByteBuffer> _indirectBuffer = new AtomicReference<>();
volatile long _lastAccessed; private final AtomicReference<ByteBuffer> _directBuffer = new AtomicReference<>();
AtomicReference<ByteBuffer> _indirectBuffer=new AtomicReference<ByteBuffer>(); private volatile long _lastAccessed;
AtomicReference<ByteBuffer> _directBuffer=new AtomicReference<ByteBuffer>();
/* ------------------------------------------------------------ */ CachedHttpContent(String pathInContext, Resource resource, Map<CompressedContentFormat, CachedHttpContent> precompressedResources)
CachedHttpContent(String pathInContext,Resource resource,Map<CompressedContentFormat, CachedHttpContent> precompressedResources)
{ {
_key=pathInContext; _key = pathInContext;
_resource=resource; _resource = resource;
String contentType = _mimeTypes.getMimeByExtension(_resource.toString()); String contentType = _mimeTypes.getMimeByExtension(_resource.toString());
_contentType=contentType==null?null:new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,contentType); _contentType = contentType == null ? null : new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, contentType);
_characterEncoding = _contentType==null?null:MimeTypes.getCharsetFromContentType(contentType); _characterEncoding = _contentType == null ? null : MimeTypes.getCharsetFromContentType(contentType);
_mimeType = _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(contentType)); _mimeType = _contentType == null ? null : MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(contentType));
boolean exists=resource.exists(); boolean exists = resource.exists();
_lastModifiedValue=exists?resource.lastModified():-1L; _lastModifiedValue = exists ? resource.lastModified() : -1L;
_lastModified=_lastModifiedValue==-1?null _lastModified = _lastModifiedValue == -1 ? null
:new PreEncodedHttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(_lastModifiedValue)); : new PreEncodedHttpField(HttpHeader.LAST_MODIFIED, DateGenerator.formatDate(_lastModifiedValue));
_contentLengthValue=exists?(int)resource.length():0; _contentLengthValue = exists ? (int)resource.length() : 0;
_contentLength=new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH,Long.toString(_contentLengthValue)); _contentLength = new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH, Long.toString(_contentLengthValue));
if (_cachedFiles.incrementAndGet()>_maxCachedFiles) if (_cachedFiles.incrementAndGet() > _maxCachedFiles)
shrinkCache(); shrinkCache();
_lastAccessed=System.currentTimeMillis(); _lastAccessed = System.currentTimeMillis();
_etag=CachedContentFactory.this._etags?new PreEncodedHttpField(HttpHeader.ETAG,resource.getWeakETag()):null; _etag = CachedContentFactory.this._etags ? new PreEncodedHttpField(HttpHeader.ETAG, resource.getWeakETag()) : null;
if (precompressedResources != null) if (precompressedResources != null)
{ {
_precompressed = new HashMap<>(precompressedResources.size()); _precompressed = new HashMap<>(precompressedResources.size());
for (Map.Entry<CompressedContentFormat, CachedHttpContent> entry : precompressedResources.entrySet()) for (Map.Entry<CompressedContentFormat, CachedHttpContent> entry : precompressedResources.entrySet())
{ {
_precompressed.put(entry.getKey(),new CachedPrecompressedHttpContent(this,entry.getValue(),entry.getKey())); _precompressed.put(entry.getKey(), new CachedPrecompressedHttpContent(this, entry.getValue(), entry.getKey()));
} }
} }
else else
@ -474,237 +437,206 @@ public class CachedContentFactory implements HttpContent.ContentFactory
_precompressed = NO_PRECOMPRESSED; _precompressed = NO_PRECOMPRESSED;
} }
} }
/* ------------------------------------------------------------ */
public String getKey() public String getKey()
{ {
return _key; return _key;
} }
/* ------------------------------------------------------------ */
public boolean isCached() public boolean isCached()
{ {
return _key!=null; return _key != null;
}
/* ------------------------------------------------------------ */
public boolean isMiss()
{
return false;
} }
/* ------------------------------------------------------------ */
@Override @Override
public Resource getResource() public Resource getResource()
{ {
return _resource; return _resource;
} }
/* ------------------------------------------------------------ */
@Override @Override
public HttpField getETag() public HttpField getETag()
{ {
return _etag; return _etag;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String getETagValue() public String getETagValue()
{ {
return _etag.getValue(); return _etag.getValue();
} }
/* ------------------------------------------------------------ */
boolean isValid() boolean isValid()
{ {
if (_lastModifiedValue==_resource.lastModified() && _contentLengthValue==_resource.length()) if (_lastModifiedValue == _resource.lastModified() && _contentLengthValue == _resource.length())
{ {
_lastAccessed=System.currentTimeMillis(); _lastAccessed = System.currentTimeMillis();
return true; return true;
} }
if (this==_cache.remove(_key)) if (this == _cache.remove(_key))
invalidate(); invalidate();
return false; return false;
} }
/* ------------------------------------------------------------ */
protected void invalidate() protected void invalidate()
{ {
ByteBuffer indirect=_indirectBuffer.get(); ByteBuffer indirect = _indirectBuffer.get();
if (indirect!=null && _indirectBuffer.compareAndSet(indirect,null)) if (indirect != null && _indirectBuffer.compareAndSet(indirect, null))
_cachedSize.addAndGet(-BufferUtil.length(indirect)); _cachedSize.addAndGet(-BufferUtil.length(indirect));
ByteBuffer direct=_directBuffer.get(); ByteBuffer direct = _directBuffer.get();
if (direct!=null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct,null)) if (direct != null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct, null))
_cachedSize.addAndGet(-BufferUtil.length(direct)); _cachedSize.addAndGet(-BufferUtil.length(direct));
_cachedFiles.decrementAndGet(); _cachedFiles.decrementAndGet();
_resource.close(); _resource.close();
} }
/* ------------------------------------------------------------ */
@Override @Override
public HttpField getLastModified() public HttpField getLastModified()
{ {
return _lastModified; return _lastModified;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String getLastModifiedValue() public String getLastModifiedValue()
{ {
return _lastModified==null?null:_lastModified.getValue(); return _lastModified == null ? null : _lastModified.getValue();
} }
/* ------------------------------------------------------------ */
@Override @Override
public HttpField getContentType() public HttpField getContentType()
{ {
return _contentType; return _contentType;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String getContentTypeValue() public String getContentTypeValue()
{ {
return _contentType==null?null:_contentType.getValue(); return _contentType == null ? null : _contentType.getValue();
} }
/* ------------------------------------------------------------ */
@Override @Override
public HttpField getContentEncoding() public HttpField getContentEncoding()
{ {
return null; return null;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String getContentEncodingValue() public String getContentEncodingValue()
{ {
return null; return null;
} }
/* ------------------------------------------------------------ */
@Override @Override
public String getCharacterEncoding() public String getCharacterEncoding()
{ {
return _characterEncoding; return _characterEncoding;
} }
/* ------------------------------------------------------------ */
@Override @Override
public Type getMimeType() public Type getMimeType()
{ {
return _mimeType; return _mimeType;
} }
/* ------------------------------------------------------------ */
@Override @Override
public void release() public void release()
{ {
} }
/* ------------------------------------------------------------ */
@Override @Override
public ByteBuffer getIndirectBuffer() public ByteBuffer getIndirectBuffer()
{ {
ByteBuffer buffer = _indirectBuffer.get(); ByteBuffer buffer = _indirectBuffer.get();
if (buffer==null) if (buffer == null)
{ {
ByteBuffer buffer2=CachedContentFactory.this.getIndirectBuffer(_resource); ByteBuffer buffer2 = CachedContentFactory.this.getIndirectBuffer(_resource);
if (buffer2==null) if (buffer2 == null)
LOG.warn("Could not load "+this); LOG.warn("Could not load " + this);
else if (_indirectBuffer.compareAndSet(null,buffer2)) else if (_indirectBuffer.compareAndSet(null, buffer2))
{ {
buffer=buffer2; buffer = buffer2;
if (_cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize) if (_cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize)
shrinkCache(); shrinkCache();
} }
else else
buffer=_indirectBuffer.get(); buffer = _indirectBuffer.get();
} }
if (buffer==null) if (buffer == null)
return null; return null;
return buffer.slice(); return buffer.slice();
} }
/* ------------------------------------------------------------ */
@Override @Override
public ByteBuffer getDirectBuffer() public ByteBuffer getDirectBuffer()
{ {
ByteBuffer buffer = _directBuffer.get(); ByteBuffer buffer = _directBuffer.get();
if (buffer==null) if (buffer == null)
{ {
ByteBuffer mapped = CachedContentFactory.this.getMappedBuffer(_resource); ByteBuffer mapped = CachedContentFactory.this.getMappedBuffer(_resource);
ByteBuffer direct = mapped==null?CachedContentFactory.this.getDirectBuffer(_resource):mapped; ByteBuffer direct = mapped == null ? CachedContentFactory.this.getDirectBuffer(_resource) : mapped;
if (direct==null) if (direct == null)
LOG.warn("Could not load "+this); LOG.warn("Could not load " + this);
else if (_directBuffer.compareAndSet(null,direct)) else if (_directBuffer.compareAndSet(null, direct))
{ {
buffer=direct; buffer = direct;
if (mapped==null && _cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize) if (mapped == null && _cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize)
shrinkCache(); shrinkCache();
} }
else else
buffer=_directBuffer.get(); buffer = _directBuffer.get();
} }
if (buffer==null) if (buffer == null)
return null; return null;
return buffer.asReadOnlyBuffer(); return buffer.asReadOnlyBuffer();
} }
/* ------------------------------------------------------------ */
@Override @Override
public HttpField getContentLength() public HttpField getContentLength()
{ {
return _contentLength; return _contentLength;
} }
/* ------------------------------------------------------------ */
@Override @Override
public long getContentLengthValue() public long getContentLengthValue()
{ {
return _contentLengthValue; return _contentLengthValue;
} }
/* ------------------------------------------------------------ */
@Override @Override
public InputStream getInputStream() throws IOException public InputStream getInputStream() throws IOException
{ {
ByteBuffer indirect = getIndirectBuffer(); ByteBuffer indirect = getIndirectBuffer();
if (indirect!=null && indirect.hasArray()) if (indirect != null && indirect.hasArray())
return new ByteArrayInputStream(indirect.array(),indirect.arrayOffset()+indirect.position(),indirect.remaining()); return new ByteArrayInputStream(indirect.array(), indirect.arrayOffset() + indirect.position(), indirect.remaining());
return _resource.getInputStream(); return _resource.getInputStream();
} }
/* ------------------------------------------------------------ */
@Override @Override
public ReadableByteChannel getReadableByteChannel() throws IOException public ReadableByteChannel getReadableByteChannel() throws IOException
{ {
return _resource.getReadableByteChannel(); return _resource.getReadableByteChannel();
} }
/* ------------------------------------------------------------ */
@Override @Override
public String toString() public String toString()
{ {
return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s,c=%d}",hashCode(),_resource,_resource.exists(),_lastModified,_contentType,_precompressed.size()); return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s,c=%d}", hashCode(), _resource, _resource.exists(), _lastModified, _contentType, _precompressed.size());
} }
/* ------------------------------------------------------------ */
@Override @Override
public Map<CompressedContentFormat,? extends HttpContent> getPrecompressedContents() public Map<CompressedContentFormat, ? extends HttpContent> getPrecompressedContents()
{ {
if (_precompressed.size()==0) if (_precompressed.size() == 0)
return null; return null;
Map<CompressedContentFormat, CachedPrecompressedHttpContent> ret=_precompressed; Map<CompressedContentFormat, CachedPrecompressedHttpContent> ret = _precompressed;
for (Map.Entry<CompressedContentFormat, CachedPrecompressedHttpContent> entry:_precompressed.entrySet()) for (Map.Entry<CompressedContentFormat, CachedPrecompressedHttpContent> entry : _precompressed.entrySet())
{ {
if (!entry.getValue().isValid()) if (!entry.getValue().isValid())
{ {
@ -717,22 +649,19 @@ public class CachedContentFactory implements HttpContent.ContentFactory
} }
} }
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
public class CachedPrecompressedHttpContent extends PrecompressedHttpContent public class CachedPrecompressedHttpContent extends PrecompressedHttpContent
{ {
private final CachedHttpContent _content; private final CachedHttpContent _content;
private final CachedHttpContent _precompressedContent; private final CachedHttpContent _precompressedContent;
private final HttpField _etag; private final HttpField _etag;
CachedPrecompressedHttpContent(CachedHttpContent content, CachedHttpContent precompressedContent, CompressedContentFormat format) CachedPrecompressedHttpContent(CachedHttpContent content, CachedHttpContent precompressedContent, CompressedContentFormat format)
{ {
super(content,precompressedContent,format); super(content, precompressedContent, format);
_content=content; _content = content;
_precompressedContent=precompressedContent; _precompressedContent = precompressedContent;
_etag=(CachedContentFactory.this._etags)?new PreEncodedHttpField(HttpHeader.ETAG,_content.getResource().getWeakETag(format._etag)):null; _etag = (CachedContentFactory.this._etags) ? new PreEncodedHttpField(HttpHeader.ETAG, _content.getResource().getWeakETag(format._etag)) : null;
} }
public boolean isValid() public boolean isValid()
@ -743,7 +672,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
@Override @Override
public HttpField getETag() public HttpField getETag()
{ {
if (_etag!=null) if (_etag != null)
return _etag; return _etag;
return super.getETag(); return super.getETag();
} }
@ -751,16 +680,15 @@ public class CachedContentFactory implements HttpContent.ContentFactory
@Override @Override
public String getETagValue() public String getETagValue()
{ {
if (_etag!=null) if (_etag != null)
return _etag.getValue(); return _etag.getValue();
return super.getETagValue(); return super.getETagValue();
} }
@Override @Override
public String toString() public String toString()
{ {
return "Cached"+super.toString(); return "Cached" + super.toString();
} }
} }
} }