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

Reply via email to