You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by re...@apache.org on 2008/11/29 18:09:09 UTC

svn commit: r721690 - in /cocoon/cocoon3/trunk: cocoon-docs/src/changes/ cocoon-docs/src/site/apt/ cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/ cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ cocoon-sample/src/main/java/o...

Author: reinhard
Date: Sat Nov 29 09:09:08 2008
New Revision: 721690

URL: http://svn.apache.org/viewvc?rev=721690&view=rev
Log:
<action dev="steven" type="add">
   [cocoon-pipeline] Support expires caching: CachingPipeline and AsyncCachingPipeline can be configured to
   be valid for a particular period. This 'expires caching' doesn't check if any of the pipeline components
   would produce a valid result or not and it isn't even necessary that the pipeline components are cacheable
   by implementing the org.apache.cocoon.pipeline.component.CachingPipelineComponent interface.
</action>

Added:
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java   (with props)
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java   (with props)
    cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java   (contents, props changed)
      - copied, changed from r721274, cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/TimestampGenerator.java
Removed:
    cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-optional-fop.xml
Modified:
    cocoon/cocoon3/trunk/cocoon-docs/src/changes/changes.xml
    cocoon/cocoon3/trunk/cocoon-docs/src/site/apt/roadmap.apt
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AbstractPipeline.java
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AsyncCachePipeline.java
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/CachingPipeline.java
    cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/Pipeline.java
    cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/overview.html
    cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap
    cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-sample-sitemap-components.xml
    cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/Invocation.java
    cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/InvocationImpl.java
    cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/node/PipelineNode.java

Modified: cocoon/cocoon3/trunk/cocoon-docs/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-docs/src/changes/changes.xml?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-docs/src/changes/changes.xml (original)
+++ cocoon/cocoon3/trunk/cocoon-docs/src/changes/changes.xml Sat Nov 29 09:09:08 2008
@@ -25,6 +25,12 @@
 <document>
   <body>
     <release version="3.0.0-alpha-2" date="2008-00-00" description="unreleased">
+      <action dev="steven" type="add">
+        [cocoon-pipeline] Support expires caching: CachingPipeline and AsyncCachingPipeline can be configured to
+        be valid for a particular period. This 'expires caching' doesn't check if any of the pipeline components
+        would produce a valid result or not and it isn't even necessary that the pipeline components are cacheable
+        by implementing the org.apache.cocoon.pipeline.component.CachingPipelineComponent interface.
+      </action>
       <action dev="reinhard" type="update">
         [cocoon-rest] Introduce the interface org.apache.cocoon.rest.controller.response.StreamingResponse that
         can be used for controller results. The most prominent use case for it is the 

Modified: cocoon/cocoon3/trunk/cocoon-docs/src/site/apt/roadmap.apt
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-docs/src/site/apt/roadmap.apt?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-docs/src/site/apt/roadmap.apt (original)
+++ cocoon/cocoon3/trunk/cocoon-docs/src/site/apt/roadmap.apt Sat Nov 29 09:09:08 2008
@@ -21,8 +21,6 @@
     
     * Improved error handling in XSLT transformer (cocoon-pipeline)
 
-    * Expires-caching in pipelines - A pipeline is valid for a certain period of time (cocoon-pipeline) 
-    
     * EHCache integration for caching pipelines (cocoon-pipeline)
     
     * Support custom matchers (<<<\<map:match type="my-custom-matcher"/\>>>>)

Modified: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AbstractPipeline.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AbstractPipeline.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AbstractPipeline.java (original)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AbstractPipeline.java Sat Nov 29 09:09:08 2008
@@ -37,10 +37,10 @@
  */
 public abstract class AbstractPipeline implements Pipeline {
 
-    private final Log logger = LogFactory.getLog(this.getClass());
-
     private final LinkedList<PipelineComponent> components = new LinkedList<PipelineComponent>();
 
+    private final Log logger = LogFactory.getLog(this.getClass());
+
     private boolean setupDone;
 
     /**
@@ -64,48 +64,66 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.apache.cocoon.pipeline.Pipeline#setup(java.io.OutputStream, java.util.Map)
+     * @see org.apache.cocoon.pipeline.Pipeline#execute()
      */
-    public void setup(OutputStream outputStream) {
-        this.setup(outputStream, null);
+    public void execute() throws Exception {
+        if (!this.setupDone) {
+            throw new ProcessingException(new IllegalStateException(
+                    "The pipeline wasn't setup correctly. Call #setup() first."));
+        }
+
+        this.invokeStarter();
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.apache.cocoon.pipeline.Pipeline#setup(java.io.OutputStream, java.util.Map)
+     * @see org.apache.cocoon.pipeline.Pipeline#getContentType()
      */
-    public void setup(OutputStream outputStream, Map<String, Object> parameters) {
-        if (outputStream == null) {
-            throw new SetupException("An output stream must be passed.");
-        }
+    public String getContentType() {
+        Finisher last = this.getFinisher();
+        return last.getContentType();
+    }
 
-        this.setupComponents(outputStream, parameters);
-        this.setupDone = true;
+    public long getLastModified() {
+        return -1;
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.apache.cocoon.pipeline.Pipeline#execute()
+     * @see org.apache.cocoon.pipeline.Pipeline#setConfiguration(java.util.Map)
      */
-    public void execute() throws Exception {
-        if (!this.setupDone) {
-            throw new ProcessingException(new IllegalStateException(
-                    "The pipeline wasn't setup correctly. Call #setup() first."));
-        }
+    public void setConfiguration(Map<String, ? extends Object> parameters) {
+        // do nothing
+    }
 
-        this.invokeStarter();
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.cocoon.pipeline.Pipeline#setup(java.io.OutputStream, java.util.Map)
+     */
+    public void setup(OutputStream outputStream) {
+        this.setup(outputStream, null);
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.apache.cocoon.pipeline.Pipeline#getContentType()
+     * @see org.apache.cocoon.pipeline.Pipeline#setup(java.io.OutputStream, java.util.Map)
      */
-    public String getContentType() {
-        Finisher last = this.getFinisher();
-        return last.getContentType();
+    public void setup(OutputStream outputStream, Map<String, Object> parameters) {
+        if (outputStream == null) {
+            throw new SetupException("An output stream must be passed.");
+        }
+
+        this.setupComponents(outputStream, parameters);
+        this.setupDone = true;
+    }
+
+    @Override
+    public String toString() {
+        return StringRepresentation.buildString(this, "components=" + this.getComponents());
     }
 
     protected LinkedList<PipelineComponent> getComponents() {
@@ -193,13 +211,4 @@
         // let the Producer accept the Consumer (the Producer might reject it)
         ((Producer) firstComponent).setConsumer((Consumer) secondComponent);
     }
-
-    public long getLastModified() {
-        return -1;
-    }
-
-    @Override
-    public String toString() {
-        return StringRepresentation.buildString(this, "components=" + this.getComponents());
-    }
 }

Modified: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AsyncCachePipeline.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AsyncCachePipeline.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AsyncCachePipeline.java (original)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/AsyncCachePipeline.java Sat Nov 29 09:09:08 2008
@@ -30,11 +30,10 @@
 
 /**
  * <p>
- * This {@link Pipeline} basically works like the {@link CachingPipeline}. The only difference is that when the the
- * cached result isn't valid anymore, the refresh is done in a separate thread. This means that the re-production of the
- * result doesn't block the initial request. The disadvantage of this approach is that until the result is being
- * reproduced, an out-dated result is being returned. If this is out of question for a use case, the
- * {@link CachingPipeline} has to be used.
+ * This {@link Pipeline} basically works like the {@link CachingPipeline}. The only difference is that when the cached
+ * result isn't valid anymore, the refresh is done in a separate thread. This means that the re-production of the result
+ * doesn't block the initial request. The disadvantage of this approach is that until the result is being reproduced, an
+ * out-dated result is returned. If this is out of question for a use case, the {@link CachingPipeline} has to be used.
  * </p>
  */
 public class AsyncCachePipeline extends CachingPipeline implements CacheRefreshJob {
@@ -48,7 +47,7 @@
 
     /**
      * {@inheritDoc}
-     *
+     * 
      * @see org.apache.cocoon.pipeline.CachingPipeline#execute()
      */
     @Override
@@ -69,7 +68,7 @@
             }
             cachedValue.writeTo(this.cachingOutputStream.getOutputStream());
 
-            if (!cachedValue.isValid(this.cacheKey)) {
+            if (!this.isCacheKeyValid(cachedValue)) {
                 if (this.logger.isDebugEnabled()) {
                     this.logger.debug("Cached value is not up to date. Delegating to " + this.cacheRefreshManager);
                 }
@@ -83,7 +82,9 @@
         // no cached value (not even an invalid one) was present -> execute the pipeline
         this.invokeStarter();
         // cache the result
-        this.setCachedValue(this.cacheKey, new CompleteCacheValue(cachingOutputStream.getContent(), this.cacheKey));
+        this
+                .setCachedValue(this.cacheKey, new CompleteCacheValue(this.cachingOutputStream.getContent(),
+                        this.cacheKey));
     }
 
     public CacheRefreshManager getCacheRefreshManager() {
@@ -92,7 +93,7 @@
 
     /**
      * {@inheritDoc}
-     *
+     * 
      * @see org.apache.cocoon.pipeline.caching.CacheRefreshJob#refresh(org.apache.cocoon.pipeline.caching.CacheKey)
      */
     public void refresh(CacheKey cacheKey) {

Modified: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/CachingPipeline.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/CachingPipeline.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/CachingPipeline.java (original)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/CachingPipeline.java Sat Nov 29 09:09:08 2008
@@ -26,6 +26,8 @@
 import org.apache.cocoon.pipeline.caching.CachingOutputStream;
 import org.apache.cocoon.pipeline.caching.CompleteCacheValue;
 import org.apache.cocoon.pipeline.caching.CompoundCacheKey;
+import org.apache.cocoon.pipeline.caching.ExpiresCacheKey;
+import org.apache.cocoon.pipeline.caching.InvalidCacheKey;
 import org.apache.cocoon.pipeline.caching.PipelineCache;
 import org.apache.cocoon.pipeline.component.CachingPipelineComponent;
 import org.apache.cocoon.pipeline.component.PipelineComponent;
@@ -40,25 +42,54 @@
  */
 public class CachingPipeline extends AbstractPipeline {
 
-    private final Log logger = LogFactory.getLog(this.getClass());
+    protected CacheKey cacheKey;
+
+    protected CachingOutputStream cachingOutputStream;
 
     protected PipelineCache pipelineCache;
 
-    protected CacheKey cacheKey;
+    private String expires;
 
-    protected CachingOutputStream cachingOutputStream;
+    private final Log logger = LogFactory.getLog(this.getClass());
 
-    @Override
-    public void setup(OutputStream outputStream) {
-        this.setup(outputStream);
-    }
+    public CacheKey constructCacheKey() {
+        CompoundCacheKey result = new CompoundCacheKey();
+        if (this.logger.isDebugEnabled()) {
+            this.logger.debug("Creating " + result + ": ");
+        }
 
-    @Override
-    public void setup(OutputStream outputStream, Map<String, Object> parameters) {
-        // create a caching output stream to intercept the result
-        this.cachingOutputStream = new CachingOutputStream(outputStream);
+        for (PipelineComponent pipelineComponent : this.getComponents()) {
+            if (pipelineComponent instanceof CachingPipelineComponent) {
+                CachingPipelineComponent cachablePipelineComponent = (CachingPipelineComponent) pipelineComponent;
 
-        super.setup(this.cachingOutputStream, parameters);
+                CacheKey cacheKey = cachablePipelineComponent.constructCacheKey();
+                result.addCacheKey(cacheKey);
+                if (this.logger.isDebugEnabled()) {
+                    this.logger.debug("  ~ adding " + cacheKey + " for component " + pipelineComponent);
+                }
+
+                continue;
+            }
+
+            // component does not support caching
+            if (this.logger.isDebugEnabled()) {
+                this.logger.debug("  ~ no caching: " + pipelineComponent);
+                this.logger.debug("Stop construction a cache key");
+            }
+
+            // support expires caching
+            if (this.expires != null) {
+                return new ExpiresCacheKey(new InvalidCacheKey(), this.expires);
+            }
+            return null;
+        }
+
+        // support expires caching
+        if (this.expires != null) {
+            return new ExpiresCacheKey(result, this.expires);
+        }
+
+        return result;
     }
 
     @Override
@@ -70,7 +101,7 @@
         this.cacheKey = this.constructCacheKey();
         // checked for a cached value first
         CacheValue cachedValue = this.getCachedValue(this.cacheKey);
-        if (cachedValue != null && cachedValue.isValid(this.cacheKey)) {
+        if (this.isCacheKeyValid(cachedValue)) {
             // cached value found
             if (this.logger.isDebugEnabled()) {
                 this.logger.debug("Write cache value to output stream: " + cachedValue);
@@ -84,13 +115,8 @@
         this.invokeStarter();
 
         // cache the result
-        this
-                .setCachedValue(this.cacheKey, new CompleteCacheValue(this.cachingOutputStream.getContent(),
-                        this.cacheKey));
-    }
-
-    public void setPipelineCache(PipelineCache pipelineCache) {
-        this.pipelineCache = pipelineCache;
+        CompleteCacheValue cacheValue = new CompleteCacheValue(this.cachingOutputStream.getContent(), this.cacheKey);
+        this.setCachedValue(this.cacheKey, cacheValue);
     }
 
     @Override
@@ -101,34 +127,33 @@
         return this.cacheKey.getLastModified();
     }
 
-    public CacheKey constructCacheKey() {
-        CompoundCacheKey result = new CompoundCacheKey();
-        if (this.logger.isDebugEnabled()) {
-            this.logger.debug("Creating " + result + ": ");
-        }
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.cocoon.pipeline.AbstractPipeline#setConfiguration(java.util.Map)
+     */
+    @Override
+    public void setConfiguration(Map<String, ? extends Object> parameters) {
+        this.expires = (String) parameters.get("expires");
 
-        for (PipelineComponent pipelineComponent : this.getComponents()) {
-            if (pipelineComponent instanceof CachingPipelineComponent) {
-                CachingPipelineComponent cachablePipelineComponent = (CachingPipelineComponent) pipelineComponent;
+        super.setConfiguration(parameters);
+    }
 
-                CacheKey cacheKey = cachablePipelineComponent.constructCacheKey();
-                result.addCacheKey(cacheKey);
-                if (this.logger.isDebugEnabled()) {
-                    this.logger.debug("  ~ adding " + cacheKey + " for component " + pipelineComponent);
-                }
+    public void setPipelineCache(PipelineCache pipelineCache) {
+        this.pipelineCache = pipelineCache;
+    }
 
-                continue;
-            }
+    @Override
+    public void setup(OutputStream outputStream) {
+        this.setup(outputStream);
+    }
 
-            // component does not support caching
-            if (this.logger.isDebugEnabled()) {
-                this.logger.debug("  ~ no caching: " + pipelineComponent);
-                this.logger.debug("Stop construction a cache key");
-            }
-            return null;
-        }
+    @Override
+    public void setup(OutputStream outputStream, Map<String, Object> parameters) {
+        // create a caching output stream to intercept the result
+        this.cachingOutputStream = new CachingOutputStream(outputStream);
 
-        return result;
+        super.setup(this.cachingOutputStream, parameters);
     }
 
     protected CacheValue getCachedValue(CacheKey cacheKey) {
@@ -147,6 +172,10 @@
         return cacheValue;
     }
 
+    protected boolean isCacheKeyValid(CacheValue cachedValue) {
+        return cachedValue != null && cachedValue.isValid(this.cacheKey);
+    }
+
     protected void setCachedValue(CacheKey cacheKey, CacheValue cacheValue) {
         if (cacheKey != null) {
             if (this.logger.isDebugEnabled()) {

Modified: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/Pipeline.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/Pipeline.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/Pipeline.java (original)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/Pipeline.java Sat Nov 29 09:09:08 2008
@@ -65,22 +65,6 @@
     void addComponent(PipelineComponent pipelineComponent);
 
     /**
-     * After the pipeline has been prepared ({@link #addComponent(PipelineComponent)}, this method can be invoked in
-     * order to setup and initialize the pipeline and its components.
-     * 
-     * @param outputStream An {@link OutputStream} where the pipeline execution result is written.
-     */
-    void setup(OutputStream outputStream);
-
-    /**
-     * The same as {@link #setup(OutputStream)} but also allows passing parameters to the pipeline components.
-     * 
-     * @param outputStream An {@link OutputStream} where the pipeline execution result is written.
-     * @param parameters A {@link Map} of parameters that are available to all {@link PipelineComponent}s.
-     */
-    void setup(OutputStream outputStream, Map<String, Object> parameters);
-
-    /**
      * After the pipeline has been setup ({@link #setup(OutputStream, Map)}, this method can be invoked in order to
      * produce the result.
      * 
@@ -101,4 +85,22 @@
      * @return The last modification date
      */
     long getLastModified();
+
+    /**
+     * After the pipeline has been prepared ({@link #addComponent(PipelineComponent)}, this method can be invoked in
+     * order to setup and initialize the pipeline and its components.
+     * 
+     * @param outputStream An {@link OutputStream} where the pipeline execution result is written.
+     */
+    void setup(OutputStream outputStream);
+
+    /**
+     * The same as {@link #setup(OutputStream)} but also allows passing parameters to the pipeline components.
+     * 
+     * @param outputStream An {@link OutputStream} where the pipeline execution result is written.
+     * @param parameters A {@link Map} of parameters that are available to all {@link PipelineComponent}s.
+     */
+    void setup(OutputStream outputStream, Map<String, Object> parameters);
+
+    void setConfiguration(Map<String, ? extends Object> parameters);
 }

Added: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java?rev=721690&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java (added)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java Sat Nov 29 09:09:08 2008
@@ -0,0 +1,95 @@
+/*
+ * 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.cocoon.pipeline.caching;
+
+/**
+ * A cache key implementation that expires after a defined number of seconds.
+ */
+public final class ExpiresCacheKey implements CacheKey {
+
+    private static final long serialVersionUID = 1L;
+    private final CacheKey cacheKey;
+    private final long timestamp;
+    private final long expirationTimestamp;
+
+    public ExpiresCacheKey(CacheKey cacheKey, String expires) {
+        this.cacheKey = cacheKey;
+        this.timestamp = System.currentTimeMillis();
+        this.expirationTimestamp = this.timestamp + Long.parseLong(expires) * 1000;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.cocoon.pipeline.caching.CacheKey#isValid(org.apache.cocoon.pipeline.caching.CacheKey)
+     */
+    public boolean isValid(CacheKey cacheKey) {
+        if (!(cacheKey instanceof ExpiresCacheKey)) {
+            return false;
+        }
+
+        ExpiresCacheKey other = (ExpiresCacheKey) cacheKey;
+
+        if (this.expirationTimestamp > other.timestamp) {
+            return true;
+        }
+
+        return this.cacheKey.isValid(other.cacheKey);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.cocoon.pipeline.caching.CacheKey#getLastModified()
+     */
+    public long getLastModified() {
+        return this.cacheKey.getLastModified();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ExpiresCacheKey)) {
+            return false;
+        }
+
+        ExpiresCacheKey other = (ExpiresCacheKey) obj;
+        return this.cacheKey.equals(other.cacheKey);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        int result = 1;
+
+        result = 31 * result + this.getClass().hashCode();
+        result = 31 * result + this.cacheKey.hashCode();
+
+        return result;
+    }
+}
\ No newline at end of file

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/ExpiresCacheKey.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java?rev=721690&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java (added)
+++ cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java Sat Nov 29 09:09:08 2008
@@ -0,0 +1,40 @@
+/*
+ * 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.cocoon.pipeline.caching;
+
+public class InvalidCacheKey implements CacheKey {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof InvalidCacheKey;
+    }
+
+    public long getLastModified() {
+        return -1;
+    }
+
+    @Override
+    public int hashCode() {
+        return InvalidCacheKey.class.hashCode();
+    }
+
+    public boolean isValid(CacheKey cacheKey) {
+        return false;
+    }
+}

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/cocoon3/trunk/cocoon-pipeline/src/main/java/org/apache/cocoon/pipeline/caching/InvalidCacheKey.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java (from r721274, cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/TimestampGenerator.java)
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java?p2=cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java&p1=cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/TimestampGenerator.java&r1=721274&r2=721690&rev=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/TimestampGenerator.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java Sat Nov 29 09:09:08 2008
@@ -16,34 +16,49 @@
  */
 package org.apache.cocoon.sample.generation;
 
-import org.apache.cocoon.pipeline.ProcessingException;
 import org.apache.cocoon.pipeline.caching.CacheKey;
-import org.apache.cocoon.pipeline.caching.SimpleCacheKey;
 import org.apache.cocoon.pipeline.component.CachingPipelineComponent;
-import org.apache.cocoon.pipeline.component.sax.AbstractGenerator;
-import org.apache.cocoon.pipeline.component.sax.XMLConsumer;
-import org.apache.cocoon.pipeline.util.ImmutableAttributesImpl;
-import org.xml.sax.SAXException;
-
-public class TimestampGenerator extends AbstractGenerator implements CachingPipelineComponent {
-
-    public void execute() {
-        XMLConsumer consumer = this.getXMLConsumer();
-        try {
-            consumer.startDocument();
-
-            consumer.startElement("", "timestamp", "timestamp", new ImmutableAttributesImpl());
-            String timestamp = Long.toString(System.currentTimeMillis());
-            consumer.characters(timestamp.toCharArray(), 0, timestamp.length());
-            consumer.endElement("", "timestamp", "timestamp");
-
-            consumer.endDocument();
-        } catch (SAXException e) {
-            throw new ProcessingException(e);
-        }
-    }
+
+public class CachingTimestampGenerator extends TimestampGenerator implements CachingPipelineComponent {
+
+    private static final int CACHING_PERIOD = 1500;
 
     public CacheKey constructCacheKey() {
-        return new SimpleCacheKey();
+        final long timestamp = System.currentTimeMillis() / CACHING_PERIOD * CACHING_PERIOD;
+
+        return new CacheKeyImplementation(timestamp);
+    }
+
+    private final class CacheKeyImplementation implements CacheKey {
+
+        private static final long serialVersionUID = 1L;
+        private final long timestamp;
+
+        private CacheKeyImplementation(long timestamp) {
+            this.timestamp = timestamp;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof CacheKeyImplementation;
+        }
+
+        public long getLastModified() {
+            return this.timestamp;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.getClass().hashCode();
+        }
+
+        public boolean isValid(CacheKey other) {
+            if (other instanceof CacheKeyImplementation) {
+                CacheKeyImplementation otherCacheKey = (CacheKeyImplementation) other;
+                return otherCacheKey.timestamp == this.timestamp;
+            }
+
+            return false;
+        }
     }
 }

Propchange: cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java
------------------------------------------------------------------------------
    svn:mergeinfo = 

Propchange: cocoon/cocoon3/trunk/cocoon-sample/src/main/java/org/apache/cocoon/sample/generation/CachingTimestampGenerator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/overview.html
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/overview.html?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/overview.html (original)
+++ cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/overview.html Sat Nov 29 09:09:08 2008
@@ -35,6 +35,13 @@
     <li><a href="sax-pipeline/simple-xsd">SAX Pipeline</a>: Same as before but creates XML as output format after validating the input.</li>
     <li><a href="sax-pipeline/unauthorized">Status code</a>: Set status code '401' at pipeline.</li>
   </ul>
+  <h2>Caching</h2>
+  <ul>
+  	<li><a href="caching-pipeline/on">Caching pipeline</a>: The result of the pipeline is cached forever.</li>
+  	<li><a href="caching-pipeline/off">Non-Caching pipeline</a>: The pipeline doesn't cache (although it's components support it)</li>
+  	<li><a href="async-caching-pipeline/on">Async-Caching pipeline</a>: </li>
+  	<li><a href="expires-caching-pipeline/on">Expires-Caching pipeline</a>: The pipeline returns a cached result for defined period.</li>
+  </ul>
   <h2>Error handling</h2>
   <ul>
     <li><a href="123456789123456789">ResourceNotFound</a>: The error handler catches all exceptions, in this case no matcher matches.</li>

Modified: cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap (original)
+++ cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap Sat Nov 29 09:09:08 2008
@@ -22,27 +22,6 @@
   xmlns:servlet="http://apache.org/cocoon/servlet" xmlns:controller="http://apache.org/cocoon/controller">
 
   <map:pipelines>
-  
-    <!-- ~~~~~~~~~~~~~~~~ exemplary image pipelines ~~~~~~~~~~~~~~~ -->
-    <map:pipeline type="async-caching">
-      <map:match pattern="images/simple">
-        <map:generate src="images/simple.jpg" type="image" />
-        <map:serialize type="image">
-          <map:parameter name="format" value="jpg" />
-        </map:serialize>
-      </map:match>
-      <map:match pattern="images/simple-gray">
-        <map:generate src="images/simple.jpg" type="image" />
-        <map:transform type="image-gray">
-          <map:parameter name="brighten" value="true" />
-          <map:parameter name="gray" value="10" />
-        </map:transform>
-        <map:serialize type="image">
-          <map:parameter name="format" value="jpg" />
-        </map:serialize>
-      </map:match>
-    </map:pipeline>
-
     <!-- ~~~~~~~~~~~~~~~~ map:read ~~~~~~~~~~~~~~~ -->
     <map:pipeline>
       <map:match pattern="">
@@ -96,17 +75,38 @@
     <!-- ~~~~~~~~~~~~~~~~ caching of pipelines ~~~~~~~~~~~~~~~ -->
     <map:pipeline>
       <map:match pattern="caching-pipeline/on">
-        <map:generate type="timestamp" />
+        <map:generate type="timestamp-caching" />
+        <map:serialize type="xml" />
+      </map:match>
+    </map:pipeline>
+    
+    <map:pipeline type="async-caching">
+      <map:match pattern="async-caching-pipeline/on">
+        <map:generate type="timestamp-caching" />
         <map:serialize type="xml" />
       </map:match>
     </map:pipeline>
 
     <map:pipeline type="noncaching">
       <map:match pattern="caching-pipeline/off">
-        <map:generate type="timestamp" />
+        <map:generate type="timestamp-caching" />
         <map:serialize type="xml" />
       </map:match>
     </map:pipeline>
+    
+    <map:pipeline expires="2">
+      <map:match pattern="expires/caching-pipeline/on">
+        <map:generate type="timestamp-noncaching" />
+        <map:serialize type="xml" />
+      </map:match>
+    </map:pipeline>    
+    
+    <map:pipeline type="async-caching" expires="2">
+      <map:match pattern="expires/async-caching-pipeline/on">
+        <map:generate type="timestamp-noncaching" />
+        <map:serialize type="xml" />
+      </map:match>
+    </map:pipeline>    
 
     <!-- ~~~~~~~~~~~~~~~~ servlet service framework ~~~~~~~~~~~~~~~ -->
     <map:pipeline>

Modified: cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-sample-sitemap-components.xml
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-sample-sitemap-components.xml?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-sample-sitemap-components.xml (original)
+++ cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/META-INF/cocoon/spring/cocoon-sample-sitemap-components.xml Sat Nov 29 09:09:08 2008
@@ -23,6 +23,7 @@
 
   <bean name="action:error-throwing" class="org.apache.cocoon.sample.action.ErrorThrowingAction" scope="prototype" />
   
-  <bean name="generator:timestamp" class="org.apache.cocoon.sample.generation.TimestampGenerator" scope="prototype" />
+  <bean name="generator:timestamp-caching" class="org.apache.cocoon.sample.generation.CachingTimestampGenerator" scope="prototype" />
   
+  <bean name="generator:timestamp-noncaching" class="org.apache.cocoon.sample.generation.TimestampGenerator" scope="prototype" />
 </beans>

Modified: cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/Invocation.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/Invocation.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/Invocation.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/Invocation.java Sat Nov 29 09:09:08 2008
@@ -42,7 +42,7 @@
 
     void installComponent(String type, Map<String, ? extends Object> parameters);
 
-    void installPipeline(String type);
+    void installPipeline(String type, Map<String, ? extends Object> parameters);
 
     boolean isErrorInvocation();
 

Modified: cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/InvocationImpl.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/InvocationImpl.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/InvocationImpl.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/InvocationImpl.java Sat Nov 29 09:09:08 2008
@@ -229,10 +229,12 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.apache.cocoon.sitemap.Invocation#installPipeline(java.lang.String)
+     * @see org.apache.cocoon.sitemap.Invocation#installPipeline(java.lang.String, java.util.Map)
      */
-    public void installPipeline(String type) {
+    public void installPipeline(String type, Map<String, ? extends Object> componentParameters) {
         this.pipeline = this.componentProvider.createPipeline(type);
+        Map<String, ? extends Object> resolvedParameters = this.resolveParameters(componentParameters);
+        this.pipeline.setConfiguration(resolvedParameters);
     }
 
     /**

Modified: cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/node/PipelineNode.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/node/PipelineNode.java?rev=721690&r1=721689&r2=721690&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/node/PipelineNode.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sitemap/src/main/java/org/apache/cocoon/sitemap/node/PipelineNode.java Sat Nov 29 09:09:08 2008
@@ -92,6 +92,6 @@
     }
 
     protected void installPipeline(Invocation invocation) {
-        invocation.installPipeline(PIPELINE_CATEGORY + this.type);
+        invocation.installPipeline(PIPELINE_CATEGORY + this.type, this.getParameters());
     }
 }