Author: markt Date: Wed Sep 26 21:29:22 2012 New Revision: 1390733 URL: http://svn.apache.org/viewvc?rev=1390733&view=rev Log: Add the initial Cache implementation. Validation of individual resources against a TTL is implemented but there are several configuration and cache cleaning TODOs.
Added: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java (with props) tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java (with props) Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java Added: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java?rev=1390733&view=auto ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java (added) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java Wed Sep 26 21:29:22 2012 @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.webresources; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.catalina.WebResource; + +public class Cache { + + private final StandardRoot root; + + private ConcurrentMap<String,CachedResource> resourceCache = + new ConcurrentHashMap<>(); + + public Cache(StandardRoot root) { + this.root = root; + } + + protected WebResource getResource(String path) { + // Multiple concurrent callers will end up with the same CachedResource + // instance + // TODO Config for TTL + CachedResource newCacheEntry = new CachedResource(root, path, 5000); + CachedResource result = + resourceCache.putIfAbsent(path, newCacheEntry); + + if (result == null) { + result = newCacheEntry; + } + + // TODO check cache size and do minimum necessary to make room + // TODO Cache size configuration + result.validate(); + + return result; + } + + // TODO add background expiration +} Propchange: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java?rev=1390733&view=auto ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java (added) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java Wed Sep 26 21:29:22 2012 @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.webresources; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URL; + +import org.apache.catalina.WebResource; +import org.apache.catalina.WebResourceRoot; + +/** + * This class is designed to wrap a 'raw' WebResource and providing caching for + * expensive operations. Inexpensive operations may be passed through to the + * underlying resource. + */ +public class CachedResource implements WebResource { + + private final StandardRoot root; + private final String webAppPath; + private final long ttl; + + private volatile WebResource webResource; + private volatile long nextCheck; + + private volatile Long cachedLastModified = null; + private volatile String cachedLastModifiedHttp = null; + private volatile byte[] cachedContent = null; + private volatile Boolean cachedIsFile = null; + private volatile Boolean cachedIsDirectory = null; + private volatile Boolean cachedExists = null; + private volatile Long cachedContentLength = null; + + + public CachedResource(StandardRoot root, String path, long ttl) { + this.root = root; + this.webAppPath = path; + this.ttl = ttl; + } + + protected void validate() { + long now = System.currentTimeMillis(); + + if (webResource == null) { + synchronized (this) { + if (webResource == null) { + WebResource result = root.getResourceInternal(webAppPath); + webResource = result; + nextCheck = ttl + now; + return; + } + } + } + + if (now < nextCheck) { + return; + } + + synchronized (this) { + if (now < nextCheck) { + return; + } + + if (webResource.getLastModified() + ttl >= nextCheck) { + WebResource result = root.getResourceInternal(webAppPath); + webResource = result; + + cachedContent = null; + cachedContentLength = null; + cachedExists = null; + cachedIsDirectory = null; + cachedIsFile = null; + cachedLastModified = null; + cachedLastModifiedHttp = null; + } + nextCheck = ttl + now; + } + } + + + @Override + public long getLastModified() { + Long cachedLastModified = this.cachedLastModified; + if (cachedLastModified == null) { + cachedLastModified = + Long.valueOf(webResource.getLastModified()); + this.cachedLastModified = cachedLastModified; + } + return cachedLastModified.longValue(); + } + + @Override + public String getLastModifiedHttp() { + String cachedLastModifiedHttp = this.cachedLastModifiedHttp; + if (cachedLastModifiedHttp == null) { + cachedLastModifiedHttp = webResource.getLastModifiedHttp(); + this.cachedLastModifiedHttp = cachedLastModifiedHttp; + } + return cachedLastModifiedHttp; + } + + @Override + public boolean exists() { + Boolean cachedExists = this.cachedExists; + if (cachedExists == null) { + cachedExists = Boolean.valueOf(webResource.exists()); + this.cachedExists = cachedExists; + } + return cachedExists.booleanValue(); + } + + @Override + public boolean isDirectory() { + Boolean cachedIsDirectory = this.cachedIsDirectory; + if (cachedIsDirectory == null) { + cachedIsDirectory = Boolean.valueOf(webResource.isDirectory()); + this.cachedIsDirectory = cachedIsDirectory; + } + return cachedIsDirectory.booleanValue(); + } + + @Override + public boolean isFile() { + Boolean cachedIsFile = this.cachedIsFile; + if (cachedIsFile == null) { + cachedIsFile = Boolean.valueOf(webResource.isFile()); + this.cachedIsFile = cachedIsFile; + } + return cachedIsFile.booleanValue(); + } + + @Override + public boolean delete() { + return webResource.delete(); + } + + @Override + public String getName() { + return webResource.getName(); + } + + @Override + public long getContentLength() { + Long cachedContentLength = this.cachedContentLength; + if (cachedContentLength == null) { + cachedContentLength = Long.valueOf(webResource.getContentLength()); + this.cachedContentLength = cachedContentLength; + } + return cachedContentLength.longValue(); + } + + @Override + public String getCanonicalPath() { + return webResource.getCanonicalPath(); + } + + @Override + public boolean canRead() { + return webResource.canRead(); + } + + @Override + public String getWebappPath() { + return webAppPath; + } + + @Override + public String getETag() { + return webResource.getETag(); + } + + @Override + public void setMimeType(String mimeType) { + webResource.setMimeType(mimeType); + } + + @Override + public String getMimeType() { + return webResource.getMimeType(); + } + + @Override + public InputStream getInputStream() { + byte[] content = cachedContent; + if (content == null) { + // Can't cache InputStreams + return webResource.getInputStream(); + } + return new ByteArrayInputStream(content); + } + + @Override + public byte[] getContent() { + byte[] cachedContent = this.cachedContent; + if (cachedContent == null) { + cachedContent = webResource.getContent(); + this.cachedContent = cachedContent; + } + return cachedContent; + } + + @Override + public long getCreation() { + return webResource.getCreation(); + } + + @Override + public URL getURL() { + return webResource.getURL(); + } + + @Override + public WebResourceRoot getWebResourceRoot() { + return webResource.getWebResourceRoot(); + } +} Propchange: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java?rev=1390733&r1=1390732&r2=1390733&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java Wed Sep 26 21:29:22 2012 @@ -61,6 +61,8 @@ public class StandardRoot extends Lifecy private ArrayList<WebResourceSet> jarResources = new ArrayList<>(); private ArrayList<WebResourceSet> postResources = new ArrayList<>(); + private Cache cache = new Cache(this); + // Constructs to make iteration over all WebResourceSets simpler private ArrayList<WebResourceSet> mainResources = new ArrayList<>(); private ArrayList<ArrayList<WebResourceSet>> allResources = @@ -156,6 +158,10 @@ public class StandardRoot extends Lifecy @Override public WebResource getResource(String path) { + return cache.getResource(path); + } + + protected WebResource getResourceInternal(String path) { checkState(); WebResource result = null; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org