This looks pretty cool. I like the idea of using the Servlet interface
instead of Callable/Runnable.

I have two comments:

1) The request/response pair passed to the servlet should be entirely
synthetic. This is true in general AFAIK[1]; in Sling it is especially
true because request.getResourceResolver() will return a closed resource
resolver.

2) Even with synthetic request/response objects, I suspect that not all
servlets are going to work in the background (or s/going to/should/).
Thus, what about using a marker interface on the servlet to declare that
it should be run in the background. Or... to declare that it can be run
in the background.

Justin

[1] that is, the ServletRequest and ServletResponse objects are not
meant to be used outside of the request thread owned by the servlet
container.

On 7/13/10 7:58 AM, [email protected] wrote:
> Author: bdelacretaz
> Date: Tue Jul 13 11:58:51 2010
> New Revision: 963686
> 
> URL: http://svn.apache.org/viewvc?rev=963686&view=rev
> Log:
> SLING-550 - first shot at background servlets engine, works for some simple 
> cases, no job control yet
> 
> Added:
>     sling/trunk/contrib/extensions/bgservlets/   (with props)
>     sling/trunk/contrib/extensions/bgservlets/pom.xml   (with props)
>     sling/trunk/contrib/extensions/bgservlets/src/
>     sling/trunk/contrib/extensions/bgservlets/src/main/
>     sling/trunk/contrib/extensions/bgservlets/src/main/java/
>     sling/trunk/contrib/extensions/bgservlets/src/main/java/org/
>     sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/
>     sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
>    (with props)
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
>    (with props)
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
>    (with props)
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
>    (with props)
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
>    (with props)
>     
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
>    (with props)
> 
> Propchange: sling/trunk/contrib/extensions/bgservlets/
> ------------------------------------------------------------------------------
> --- svn:ignore (added)
> +++ svn:ignore Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,13 @@
> +target
> +bin
> +derby.log
> +*.iml
> +*.ipr
> +*.iws
> +.settings
> +.project
> +.classpath
> +.externalToolBuilders
> +maven-eclipse.xml
> +
> +
> 
> Added: sling/trunk/contrib/extensions/bgservlets/pom.xml
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/pom.xml?rev=963686&view=auto
> ==============================================================================
> --- sling/trunk/contrib/extensions/bgservlets/pom.xml (added)
> +++ sling/trunk/contrib/extensions/bgservlets/pom.xml Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,94 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +  <!--
> +    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.
> +  -->
> +<project xmlns="http://maven.apache.org/POM/4.0.0"; 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
> +  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
> http://maven.apache.org/maven-v4_0_0.xsd";>
> +
> +  <modelVersion>4.0.0</modelVersion>
> +  <parent>
> +    <groupId>org.apache.sling</groupId>
> +    <artifactId>sling</artifactId>
> +    <version>9</version>
> +    <relativePath>../../../parent/pom.xml</relativePath>
> +  </parent>
> +
> +  <artifactId>org.apache.sling.bgservlets</artifactId>
> +  <version>0.0.1-SNAPSHOT</version>
> +  <packaging>bundle</packaging>
> +
> +  <name>Apache Sling Background Servlets Engine</name>
> +  <description> 
> +    Allows scripts and servlets to run as background tasks
> +    which can be suspended, resumed, stopped and restarted.
> +  </description>
> +
> +  <scm>
> +    
> <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/bgservlets</connection>
> +    
> <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/bgservlets</developerConnection>
> +    
> <url>http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/bgservlets</url>
> +  </scm>
> +
> +  <build>
> +    <plugins>
> +      <plugin>
> +        <groupId>org.apache.felix</groupId>
> +        <artifactId>maven-scr-plugin</artifactId>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.felix</groupId>
> +        <artifactId>maven-bundle-plugin</artifactId>
> +        <extensions>true</extensions>
> +        <configuration>
> +          <instructions>
> +            <Export-Package>org.apache.sling.bgservlets</Export-Package>
> +            
> <Private-Package>org.apache.sling.bgservlets.impl.*</Private-Package>
> +          </instructions>
> +        </configuration>
> +      </plugin>
> +    </plugins>
> +  </build>
> +
> +  <dependencies>
> +    <dependency>
> +      <groupId>org.osgi</groupId>
> +      <artifactId>org.osgi.core</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.osgi</groupId>
> +      <artifactId>org.osgi.compendium</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.apache.felix</groupId>
> +      <artifactId>org.apache.felix.scr.annotations</artifactId>
> +      <version>1.2.0</version>
> +      <scope>compile</scope>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.apache.sling</groupId>
> +      <artifactId>org.apache.sling.api</artifactId>
> +      <version>2.0.8</version>
> +      <scope>provided</scope>
> +    </dependency>
> +    <dependency>
> +      <groupId>javax.servlet</groupId>
> +      <artifactId>servlet-api</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.slf4j</groupId>
> +      <artifactId>slf4j-api</artifactId>
> +    </dependency>
> +  </dependencies>
> +</project>
> \ No newline at end of file
> 
> Propchange: sling/trunk/contrib/extensions/bgservlets/pom.xml
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,28 @@
> +/*
> + * 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.sling.bgservlets;
> +
> +/** Service that executes Runnables, will later allow
> + *   them to be suspended, resumed, stopped and restarted.
> + */
> +public interface ExecutionEngine {
> +     
> +     /** Add a job to the execution queue */
> +     void queueForExecution(Runnable job);
> +}
> \ No newline at end of file
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/ExecutionEngine.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,91 @@
> +/*
> + * 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.sling.bgservlets.impl;
> +
> +import java.io.IOException;
> +
> +import javax.servlet.Filter;
> +import javax.servlet.FilterChain;
> +import javax.servlet.FilterConfig;
> +import javax.servlet.ServletException;
> +import javax.servlet.ServletRequest;
> +import javax.servlet.ServletResponse;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +
> +import org.apache.felix.scr.annotations.Component;
> +import org.apache.felix.scr.annotations.Properties;
> +import org.apache.felix.scr.annotations.Property;
> +import org.apache.felix.scr.annotations.Reference;
> +import org.apache.felix.scr.annotations.Service;
> +import org.apache.sling.bgservlets.ExecutionEngine;
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +
> +/** Filter that runs the current request in the background
> + *   if specific request parameters are set.
> + *  TODO: define the position of this filter in the chain,
> + *  and how do we enforce it?
> + */
> +...@component
> +...@service
> +...@properties({
> +     @Property(name="filter.scope", value="request"),
> +     @Property(name="filter.order", intValue=java.lang.Integer.MIN_VALUE)
> +})
> +public class BackgroundServletStarterFilter implements Filter{
> +
> +     private final Logger log = LoggerFactory.getLogger(getClass());
> +     
> +     @Reference
> +     private ExecutionEngine executionEngine;
> +     
> +     /** 
> +      * Request runs in the background if this request parameter is present 
> +      * TODO should be configurable, and maybe use other decision methods */
> +     public static final String BG_PARAM = "sling:bg";
> +     
> +     public void doFilter(final ServletRequest sreq, final ServletResponse 
> sresp, 
> +                     final FilterChain chain) throws IOException, 
> ServletException {
> +             if(!(sreq instanceof HttpServletRequest)) {
> +                     throw new ServletException("request is not an 
> HttpServletRequest: " + sresp.getClass().getName());
> +             }
> +             if(!(sresp instanceof HttpServletResponse)) {
> +                     throw new ServletException("response is not an 
> HttpServletResponse: " + sresp.getClass().getName());
> +             }
> +             final HttpServletRequest request = (HttpServletRequest)sreq;
> +             final HttpServletResponse response = 
> (HttpServletResponse)sresp; 
> +             if(sreq.getParameter(BG_PARAM) != null) {
> +                     final FilterChainExecutionJob job = new 
> FilterChainExecutionJob(chain, request, response);
> +                     log.debug("{} request parameter present, running 
> request in the background using {}", BG_PARAM, job);
> +                     executionEngine.queueForExecution(job);
> +                     
> +                     // TODO not really an error, should send a nicer message
> +                     response.sendError(HttpServletResponse.SC_ACCEPTED, 
> "Running request in the background using " + job);
> +             } else {
> +                     chain.doFilter(sreq, sresp);
> +             }
> +     }
> +
> +     public void destroy() {
> +     }
> +
> +     public void init(FilterConfig cfg) throws ServletException {
> +     }
> +}
> \ No newline at end of file
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundServletStarterFilter.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,78 @@
> +/*
> + * 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.sling.bgservlets.impl;
> +
> +import java.io.IOException;
> +import java.io.PrintWriter;
> +
> +import javax.servlet.ServletException;
> +
> +import org.apache.felix.scr.annotations.Component;
> +import org.apache.felix.scr.annotations.Property;
> +import org.apache.felix.scr.annotations.Service;
> +import org.apache.sling.api.SlingHttpServletRequest;
> +import org.apache.sling.api.SlingHttpServletResponse;
> +import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
> +
> +/** Servlet used for interactive testing of the background
> + *   servlets engine.
> + *   TODO remove once we have better tests.
> + */
> +...@component
> +...@service
> +...@suppresswarnings("serial")
> +...@property(name="sling.servlet.paths", value="/system/bgservlets/test")
> +public class BackgroundTestServlet extends SlingSafeMethodsServlet {
> +
> +     @Override
> +     protected void doGet(SlingHttpServletRequest request,
> +                     SlingHttpServletResponse response) throws 
> ServletException,
> +                     IOException {
> +             response.setContentType("text/plain");
> +             final PrintWriter w = response.getWriter();
> +             
> +             final int cycles = getIntParam(request, "cycles", 10);
> +             final int interval = getIntParam(request, "interval", 1);
> +             final int flushEvery = getIntParam(request, "flushEvery", 2);
> +             
> +             for(int i=1; i <= cycles; i++) {
> +                     if(i % flushEvery == 0) {
> +                             w.println("Flushing output");
> +                             w.flush();
> +                     }
> +                     w.printf("Cycle %d of %d\n", i, cycles);
> +                     try {
> +                             Thread.sleep(interval * 1000);
> +                     } catch(InterruptedException iex) {
> +                             throw new 
> ServletException("InterruptedException", iex);
> +                     }
> +             }
> +             w.println("All done.");
> +             w.flush();
> +     }
> +     
> +     private int getIntParam(SlingHttpServletRequest request, String name, 
> int defaultValue) {
> +             int result = defaultValue;
> +             final String str = request.getParameter(name);
> +             if(str != null) {
> +                     result = Integer.parseInt(str);
> +             }
> +             return result;
> +     }
> +}
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/BackgroundTestServlet.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,74 @@
> +/*
> + * 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.sling.bgservlets.impl;
> +
> +import java.util.concurrent.ArrayBlockingQueue;
> +import java.util.concurrent.BlockingQueue;
> +import java.util.concurrent.Executor;
> +import java.util.concurrent.RejectedExecutionHandler;
> +import java.util.concurrent.ThreadPoolExecutor;
> +import java.util.concurrent.TimeUnit;
> +
> +import org.apache.felix.scr.annotations.Component;
> +import org.apache.felix.scr.annotations.Service;
> +import org.apache.sling.api.SlingException;
> +import org.apache.sling.bgservlets.ExecutionEngine;
> +import org.osgi.service.component.ComponentContext;
> +
> +/** Simple ExecutionEngine
> + *   TODO should use Sling's thread pool, and check synergies
> + *   with scheduler services */
> +...@component
> +...@service
> +public class ExecutionEngineImpl implements ExecutionEngine {
> +
> +     private Executor executor;
> +     
> +     @SuppressWarnings("serial")
> +     public static class QueueFullException extends SlingException {
> +             QueueFullException(Runnable r) {
> +                     super("Execution queue is full, cannot execute " + r);
> +             }
> +     }
> +     
> +     public void activate(ComponentContext context) {
> +             // TODO configurable!
> +             final int corePoolSize = 2;
> +        int maximumPoolSize = 2;
> +        long keepAliveTime = 30;
> +        TimeUnit unit = TimeUnit.SECONDS;
> +        BlockingQueue<Runnable> workQueue = new 
> ArrayBlockingQueue<Runnable>(4); 
> +        RejectedExecutionHandler handler = new RejectedExecutionHandler() {
> +                     public void rejectedExecution(Runnable r, 
> ThreadPoolExecutor executor) {
> +                             throw new QueueFullException(r);
> +                     }
> +             };
> +        executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 
> keepAliveTime, unit, workQueue, handler); 
> +     }
> +     
> +     public void deactivate(ComponentContext context) {
> +             // TODO how to shutdown executor?
> +             executor = null;
> +     }
> +     
> +     public void queueForExecution(Runnable job) {
> +             // TODO wrap job in our own Runnable to detect start/end etc.
> +             executor.execute(job);
> +     }
> +}
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ExecutionEngineImpl.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,68 @@
> +/*
> + * 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.sling.bgservlets.impl;
> +
> +import java.io.IOException;
> +
> +import javax.servlet.FilterChain;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +
> +/** Runnable that executes a FilterChain, using 
> + *   a ServletResponseWrapper to capture the output.
> + */
> +class FilterChainExecutionJob implements Runnable {
> +     private final Logger log = LoggerFactory.getLogger(getClass());
> +     private final FilterChain chain;
> +     private final ServletResponseWrapper response;
> +     
> +     // TODO is it ok to keep a reference to the request until run() is 
> called??
> +     private final HttpServletRequest request;
> +     
> +     FilterChainExecutionJob(FilterChain chain, HttpServletRequest request, 
> HttpServletResponse hsr) throws IOException {
> +             this.chain = chain;
> +             this.request = request;
> +             response  = new ServletResponseWrapper(hsr);
> +     }
> +     
> +     public String toString() {
> +             return "Background request job: " + response;
> +     }
> +     
> +     public void run() {
> +             log.info("{} execution starts", this);
> +             try {
> +                     chain.doFilter(request, response);
> +             } catch(Exception e) {
> +                     // TODO report errors in the background job's output
> +                     log.error("chain.doFilter failed", e);
> +             } finally {
> +                     try {
> +                             response.cleanup();
> +                     } catch(IOException ioe) {
> +                             // TODO report errors in the background job's 
> output
> +                             log.error("ServletResponseWrapper cleanup 
> failed", ioe);
> +                     }
> +             }
> +             log.info("{} execution ends", this);
> +     }
> +}
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/FilterChainExecutionJob.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> Added: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
> URL: 
> http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java?rev=963686&view=auto
> ==============================================================================
> --- 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
>  (added)
> +++ 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
>  Tue Jul 13 11:58:51 2010
> @@ -0,0 +1,93 @@
> +/*
> + * 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.sling.bgservlets.impl;
> +
> +import java.io.File;
> +import java.io.FileOutputStream;
> +import java.io.IOException;
> +import java.io.OutputStream;
> +import java.io.OutputStreamWriter;
> +import java.io.PrintWriter;
> +
> +import javax.servlet.ServletOutputStream;
> +import javax.servlet.http.HttpServletResponse;
> +import javax.servlet.http.HttpServletResponseWrapper;
> +
> +/** Wraps an HttpServletResponse for background processing */
> +class ServletResponseWrapper extends HttpServletResponseWrapper {
> +
> +     private final String outputPath;
> +     private final ServletOutputStream stream;
> +     private final PrintWriter writer;
> +     
> +     static class CustomOutputStream extends ServletOutputStream {
> +
> +             private final OutputStream os;
> +             
> +             CustomOutputStream(OutputStream os) {
> +                     this.os = os;
> +             }
> +             
> +             @Override
> +             public void write(int b) throws IOException {
> +                     os.write(b);
> +             }
> +
> +             @Override
> +             public void close() throws IOException {
> +                     os.close();
> +             }
> +
> +             @Override
> +             public void flush() throws IOException {
> +                     os.flush();
> +             }
> +             
> +     }
> +     
> +     ServletResponseWrapper(HttpServletResponse response) throws IOException 
> {
> +             super(response);
> +             // TODO write output to the Sling repository. For now: just a 
> temp file
> +             final File output = 
> File.createTempFile(getClass().getSimpleName(), ".data");
> +             output.deleteOnExit();
> +             outputPath = output.getAbsolutePath();
> +             stream = new CustomOutputStream(new FileOutputStream(output));
> +             writer = new PrintWriter(new OutputStreamWriter(stream));
> +     }
> +     
> +     public String toString() {
> +             return getClass().getName() + ":" + outputPath;
> +     }
> +     
> +     void cleanup() throws IOException {
> +             stream.flush();
> +             stream.close();
> +     }
> +     
> +     @Override
> +     public ServletOutputStream getOutputStream() throws IOException {
> +             return stream;
> +     }
> +
> +     @Override
> +     public PrintWriter getWriter() throws IOException {
> +             return writer;
> +     }
> +
> +}
> \ No newline at end of file
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Propchange: 
> sling/trunk/contrib/extensions/bgservlets/src/main/java/org/apache/sling/bgservlets/impl/ServletResponseWrapper.java
> ------------------------------------------------------------------------------
>     svn:keywords = Author Date Id Revision Rev URL
> 
> 

Reply via email to