[maven-release-plugin]  copy for tag cocoon-servlet-service-impl-1.2.0

git-svn-id: https://svn.apache.org/repos/asf/cocoon/tags/cocoon-servlet-service@761938 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/LICENSE.txt b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/LICENSE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/LICENSE.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/NOTICE.txt b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/NOTICE.txt
new file mode 100644
index 0000000..bb0f11b
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/NOTICE.txt
@@ -0,0 +1,5 @@
+Apache Cocoon
+Copyright 1999-2008 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/pom.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/pom.xml
new file mode 100644
index 0000000..5f5837e
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/pom.xml
@@ -0,0 +1,198 @@
+<?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.
+-->
+<!-- Id: pom.xml 638085 2008-03-17 22:01:25Z reinhard $ -->
+<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>
+    <artifactId>cocoon</artifactId>
+    <groupId>org.apache.cocoon</groupId>
+    <version>8</version>
+    <relativePath>../../../parent/pom.xml</relativePath>
+  </parent>
+  <artifactId>cocoon-servlet-service-impl</artifactId>
+  <packaging>jar</packaging>
+  <version>1.2.0</version>
+  <name>Cocoon Servlet Service Implementation</name>
+  <description>
+    The servlet service framework makes it easy to use servlets as Spring components.
+    It also contains functionality so that a servlet service can call other servlet
+    services that it is connected to in the Spring configuration.
+  </description>
+  <url>http://cocoon.apache.org/${docs.m.servlet-service-impl.relPath}</url>
+
+  <properties>
+    <docs.name>${project.name}</docs.name>
+    <docs.version>${docs.m.servlet-service-impl.version}</docs.version>
+    <docs.urlRelativizer>../../../../../</docs.urlRelativizer>
+  </properties>
+
+  <distributionManagement>
+    <site>
+      <id>website</id>
+      <url>${docs.deploymentBaseUrl}/${docs.m.servlet-service-impl.relPath}</url>
+    </site>
+  </distributionManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cocoon</groupId>
+      <artifactId>cocoon-spring-configurator</artifactId>
+      <version>2.1.0</version>
+      <scope>compile</scope>
+    </dependency>
+    <!-- Spring Framework -->
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-aop</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.aspectj</groupId>
+      <artifactId>aspectjrt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.aspectj</groupId>
+      <artifactId>aspectjweaver</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cocoon</groupId>
+      <artifactId>cocoon-jnet</artifactId>
+      <version>1.1.0</version>
+    </dependency>
+    <!-- commons -->
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    <!-- test -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-release-plugin</artifactId>
+        <configuration>
+          <tagBase>https://svn.apache.org/repos/asf/cocoon/tags/cocoon-servlet-service/${project.artifactId}</tagBase>
+        </configuration>
+      </plugin>
+    </plugins>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+      <resource>
+        <directory>.</directory>
+        <targetPath>META-INF</targetPath>
+        <includes>
+          <include>LICENSE.txt</include>
+          <include>NOTICE.txt</include>
+        </includes>
+      </resource>
+    </resources>
+  </build>
+
+  <scm>
+    <connection>scm:svn:https://svn.apache.org/repos/asf/cocoon/tags/cocoon-servlet-service/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/cocoon/tags/cocoon-servlet-service/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0</developerConnection>
+    <url>https://svn.apache.org/repos/asf/cocoon/tags/cocoon-servlet-service/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0</url>
+  </scm>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>project-team</report>
+              <report>dependencies</report>
+              <report>license</report>
+              <report>summary</report>
+              <report>index</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <profiles>
+    <profile>
+      <id>daisy</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.daisycms</groupId>
+            <artifactId>daisy-maven-plugin</artifactId>
+            <configuration>
+              <navDocId>1413</navDocId>
+              <collection>cdocs-servlet-service-impl</collection>
+              <skipFirstNavigationDocumentLevel>false</skipFirstNavigationDocumentLevel>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/changes/changes.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/changes/changes.xml
new file mode 100644
index 0000000..e0fbc79
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/changes/changes.xml
@@ -0,0 +1,105 @@
+<?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.
+-->
+<!--
+  - See http://maven.apache.org/plugins/maven-changes-plugin/usage.html
+  -
+  - $Id$
+-->
+<document>
+  <body>
+    <release version="1.2.0-SNAPSHOT" date="2008-??-??" description="unreleased">
+      <action dev="reinhard" type="add">
+        ServletUrlConnection correctly implements #getHeaderFields() instead of relying on the NOP implementation of HttpURLConnection.
+      </action>
+      <action dev="gkossakowski" type="fix">
+        Fixed NPE thrown by HttpServletResponseBufferingWrapper and ServletServiceResponse after resetBuffer() method was called.
+      </action>
+      <action dev="gkossakowski" type="update">
+        Java 5 as minimum requirement.
+      </action>    
+      <action dev="gkossakowski" type="fix" issue="COCOON-2237">
+        Fixed HttpServletResponseBufferingWrapper implementation so it does not throw IllegalStateException
+        when resestBufferedResponse is being called.
+      </action>
+      <action dev="gkossakowski" type="fix" issue="COCOON-2236">
+        ServletFactoryBean will install JNet handlers before calling init() method
+        of Servlet that is being created. This should make SSF compatible with Cocoon Core 2.2.0 again.
+      </action>
+    </release>
+    <release version="1.1.0" date="2008-08-09" description="released">
+      <action dev="reinhard" type="fix">
+        The dependency on the Cocoon SourceResolver, that introduced a circular dependency with Cocoon 2.2, was
+        removed. The Cocoon SourceResolver was used to resolve URLs in the context-path attribute of a servlet
+        bean definition. After the change the Servlet-Service framework only relies on the default URL handling
+        of the JVM. In order to dynamically support different URLStreamHandlers, it is recommended to use 
+        Cocoon JNet.
+      </action>    
+      <action dev="reinhard" type="fix">
+        Fix the lastModified() method of the ServletConnection: make sure that there is an existing connection 
+        before reading the Last-Modified header 
+      </action>    
+      <action dev="reinhard" type="add">
+        Add a ServletURLConnection, ServletURLStreamHandler and a ServletURLStreamHandlerFactory to provide 
+        support for service: URLs.
+      </action>    
+      <action dev="gkossakowski" type="fix" issue="COCOON-2150">
+        Fixed bug in ServletServiceContext that was responsible for errors on resetting response that was already committed.
+        Now the Servlet-Service framework buffers response but only if 404 status code has been set.
+        This allows to reset the response safely.
+      </action>
+    </release>
+    <release version="1.0.0" date="2008-04-07" description="unreleased">      
+      <action dev="gkossakowski" type="update">
+        Made attributes 'mount-path' and 'context-path' of servlet-context tag required.
+      </action>
+      <action dev="reinhard" type="add">
+        The "+" character is not allowed at the end of connection names anymore. Starting
+        Cocoon will fail hard with a RuntimeException if this rule is broken. See
+        org.apache.cocoon.servletservice.spring.ServletDecorator.
+      </action>
+      <action dev="reinhard" type="add" issue="COCOON-2154">
+        Add support for absolute ServetConnections.
+      </action>
+      <action dev="reinhard" type="add" issue="COCOON-1831">
+        The ServletServiceResponse inherits the request attributes, request parameters and the session
+        from the caller.
+      </action>
+      <action dev="gkossakowski" type="add" issue="COCOON-2036" due-to="Alexander Klimetschek" due-to-email="alexander.klimetschek@googlemail.com">
+        Throw an exception when circular dependencies in servlet connections are detected.
+      </action>
+      <action dev="gkossakowski" type="fix">
+      	DispatcherServlet does not throw an exception if it fails to find suitable servlet for processing incomming request.
+      	It returns 404 error and puts information to log about the failure, instead.
+      </action>
+    </release>
+    <release version="1.0.0-RC1" date="2007-10-29" description="released">
+      <action dev="gkossakowski" type="add" issue="COCOON-2038">
+        Implemented true Object Oriented approach for handling servlet calls.
+        This change removes the need for explicit super calls.
+      </action>
+      <action dev="gkossakowski" type="fix" issue="COCOON-1939">
+        Fixed handling of multilevel inheritance that could cause stack overflow.
+      </action>
+      <action dev="gkossakowski" type="fix" issue="COCOON-2121">
+        Fixed bug in DispatcherServlet that caused servlet (blocks) mounted at "/" to be handled improperly.
+      </action>
+    </release>
+  </body>
+</document>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallFrame.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallFrame.java
new file mode 100644
index 0000000..76b6d22
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallFrame.java
@@ -0,0 +1,73 @@
+/*
+ * 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.callstack;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Attributes in the call frame and destruction callbacks that should be
+ * executed when the call frame is left.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class CallFrame {
+    private Map attributes;
+    private Map destructionCallbacks;
+
+    public boolean hasAttribute(String name) {
+        return this.attributes != null && this.attributes.containsKey(name);
+    }
+
+    public Object getAttribute(String name) {
+        return this.attributes != null ? this.attributes.get(name) : null;
+    }
+
+    public void setAttribute(String name, Object value) {
+        if (this.attributes == null) {
+            this.attributes = new HashMap();
+        }
+
+        this.attributes.put(name, value);
+    }
+
+    public Object removeAttribute(String name) {
+        return this.attributes != null ? this.attributes.remove(name) : null;
+    }
+
+    public void registerDestructionCallback(String name, Runnable callback) {
+        if (this.destructionCallbacks == null) {
+            this.destructionCallbacks = new HashMap();
+        }
+
+        this.destructionCallbacks.put(name, callback);
+    }
+
+    void executeDestructionCallbacks() {
+        if (this.destructionCallbacks == null) {
+            return;
+        }
+
+        Iterator i = this.destructionCallbacks.values().iterator();
+        while (i.hasNext()) {
+            ((Runnable) i.next()).run();
+        }
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallScope.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallScope.java
new file mode 100644
index 0000000..a2e0076
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallScope.java
@@ -0,0 +1,61 @@
+/*
+ * 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.callstack;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.config.Scope;
+
+/**
+ * Stack based scope implementation. It is based on the CallStack and
+ * an object is in scope when it is in the top frame of the stack.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class CallScope implements Scope {
+
+    public Object get(String name, ObjectFactory objectFactory) {
+        CallFrame frame = CallStack.getCurrentFrame();
+        Object scopedObject = frame.getAttribute(name);
+        if (scopedObject == null) {
+            scopedObject = objectFactory.getObject();
+            frame.setAttribute(name, scopedObject);
+        }
+
+        return scopedObject;
+    }
+
+    public Object remove(String name) {
+        CallFrame frame = CallStack.getCurrentFrame();
+        Object scopedObject = frame.getAttribute(name);
+        if (scopedObject != null) {
+            frame.removeAttribute(name);
+        }
+
+        return scopedObject;
+    }
+
+    public String getConversationId() {
+        // There is no conversation id concept for the call stack
+        return null;
+    }
+
+    public void registerDestructionCallback(String name, Runnable callback) {
+        CallStack.getCurrentFrame().registerDestructionCallback(name, callback);
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallStack.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallStack.java
new file mode 100644
index 0000000..f021099
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/CallStack.java
@@ -0,0 +1,88 @@
+/*
+ * 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.callstack;
+
+import java.util.Stack;
+
+/**
+ * Stack used for storing objects in the current call frame.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class CallStack {
+
+    /** The call stack */
+    private static final ThreadLocal callStack = new ThreadLocal();
+
+    /**
+     * This hook must be called each time a call frame is entered.
+     */
+    public static void enter() {
+        Stack stack = (Stack) callStack.get();
+        if (stack == null) {
+            stack = new Stack();
+            callStack.set(stack);
+        }
+
+        CallFrame info = new CallFrame();
+        stack.push(info);
+    }
+
+    /**
+     * This hook must be called each time a call frame is left.
+     *
+     * <p>It's the counterpart to the {@link #enter()}
+     * method.</p>
+     */
+    public static void leave() {
+        final Stack stack = (Stack) callStack.get();
+        CallFrame info = (CallFrame) stack.pop();
+        info.executeDestructionCallbacks();
+    }
+
+    /**
+     * Use this method for getting the current call frame
+     * @return a call frame
+     */
+    public static CallFrame getCurrentFrame() {
+        final Stack stack = (Stack) callStack.get();
+        if (stack != null && !stack.isEmpty()) {
+            return (CallFrame) stack.peek();
+        }
+
+        return null;
+    }
+
+    /**
+     * @return the size of the call stack
+     */
+    public static int size() {
+        final Stack stack = (Stack) callStack.get();
+        return stack != null ? stack.size() : 0;
+    }
+
+    /**
+     * Get the frame at the i:th position in the call stack
+     * @param i
+     * @return
+     */
+    public static CallFrame frameAt(int i) {
+        final Stack stack = (Stack) callStack.get();
+        return (CallFrame) (stack != null ? stack.elementAt(i) : null);
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/CallFrameHelper.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/CallFrameHelper.java
new file mode 100644
index 0000000..97d6b8d
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/CallFrameHelper.java
@@ -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.callstack.environment;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cocoon.callstack.CallFrame;
+import org.apache.cocoon.callstack.CallStack;
+
+/**
+ * A set of constants and methods to access the content of the call frame.
+ *
+ * <p>
+ * The call frame is used to pass information about the Request, Response and
+ * Context of the calling environment to components used while the call frame
+ * is active.</p>
+ *
+ * @version $Id$
+ */
+public abstract class CallFrameHelper {
+
+    /** Key for the environment {@link HttpServletRequest} in the call frame. */
+    public final static String REQUEST_OBJECT  = "request";
+
+    /** Key for the environment {@link HttpServletResponse} in the call frame. */
+    public final static String RESPONSE_OBJECT = "response";
+
+    /** Key for the environment {@link ServletContext} in the call frame. */
+    public final static String CONTEXT_OBJECT  = "context";
+
+    public static final void setEnvironment(HttpServletRequest request, HttpServletResponse response, ServletContext context) {
+        CallFrame frame = CallStack.getCurrentFrame();
+        frame.setAttribute(REQUEST_OBJECT, request);
+        frame.setAttribute(RESPONSE_OBJECT, response);
+        frame.setAttribute(CONTEXT_OBJECT, context);
+    }
+
+    public static final HttpServletRequest getRequest() {
+        CallFrame currentCallFrame = CallStack.getCurrentFrame();
+        
+        if(currentCallFrame == null) {
+            return null;
+        }
+        
+        return (HttpServletRequest) currentCallFrame.getAttribute(REQUEST_OBJECT);
+    }
+
+    public static final void setRequest(HttpServletRequest request) {
+        CallStack.getCurrentFrame().setAttribute(REQUEST_OBJECT, request);
+    }
+
+    public static final HttpServletResponse getResponse() {
+        CallFrame currentCallFrame = CallStack.getCurrentFrame();
+        
+        if(currentCallFrame == null) {
+            return null;
+        }
+        
+        return (HttpServletResponse) currentCallFrame.getAttribute(RESPONSE_OBJECT);
+    }
+
+    public static final void setResponse(HttpServletResponse response) {
+        CallStack.getCurrentFrame().setAttribute(RESPONSE_OBJECT, response);
+    }
+
+    public static final ServletContext getContext() {
+        CallFrame currentCallFrame = CallStack.getCurrentFrame();
+        
+        if(currentCallFrame == null) {
+            return null;
+        }        
+        
+        return (ServletContext) currentCallFrame.getAttribute(CONTEXT_OBJECT);
+    }
+
+    public static final void setContext(ServletContext context) {
+        CallStack.getCurrentFrame().setAttribute(CONTEXT_OBJECT, context);
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletRequestFactoryBean.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletRequestFactoryBean.java
new file mode 100644
index 0000000..b554f59
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletRequestFactoryBean.java
@@ -0,0 +1,43 @@
+/*
+ * 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.callstack.environment;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * {@link FactoryBean} that exposes the {@link HttpServletRequest} in the
+ * current call frame. It will typically be used together with the call scope.
+ *
+ * @version $Id$
+ */
+public final class HttpServletRequestFactoryBean implements FactoryBean {
+
+    public Object getObject() throws Exception {
+        return CallFrameHelper.getRequest();
+    }
+
+    public Class getObjectType() {
+        return HttpServletRequest.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletResponseFactoryBean.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletResponseFactoryBean.java
new file mode 100644
index 0000000..7a1a932
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/HttpServletResponseFactoryBean.java
@@ -0,0 +1,44 @@
+/*
+ * 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.callstack.environment;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * {@link FactoryBean} that exposes the {@link HttpServletResponse} in the
+ * current call frame. It will typically be used together with the call scope.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public final class HttpServletResponseFactoryBean implements FactoryBean {
+
+    public Object getObject() throws Exception {
+        return CallFrameHelper.getResponse();
+    }
+
+    public Class getObjectType() {
+        return HttpServletResponse.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/ServletContextFactoryBean.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/ServletContextFactoryBean.java
new file mode 100644
index 0000000..44a3145
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/callstack/environment/ServletContextFactoryBean.java
@@ -0,0 +1,47 @@
+/*
+ * 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.callstack.environment;
+
+import javax.servlet.ServletContext;
+
+import org.apache.cocoon.servletservice.ServletServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * {@link FactoryBean} that exposes the {@link ServletContext} in the current call
+ * frame. It will typically be used together with the call scope.
+ *
+ * @version $Id$
+ */
+public final class ServletContextFactoryBean implements FactoryBean {
+
+
+    public Object getObject() throws Exception {
+        return CallFrameHelper.getContext();
+    }
+
+    public Class getObjectType() {
+        // A ServletServiceContext rather than a ServletContext is needed to make the
+        // Absolutizable interface available through the ScopedProxyFactoryBean
+        return ServletServiceContext.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletscope/ServletScope.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletscope/ServletScope.java
new file mode 100644
index 0000000..d94144b
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletscope/ServletScope.java
@@ -0,0 +1,112 @@
+/*
+ * 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.servletscope;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.config.Scope;
+
+
+/**
+ * Stack based scope implementation. It is based on the CallStack and
+ * an object is in scope when it is in the top frame of the stack.
+ *
+ * @version $Id: CallScope.java 562806 2007-08-05 02:26:41Z vgritsenko $
+ * @since 2.2 
+ */
+public class ServletScope implements Scope {
+    
+    static private String destructionCallbacksAttributeName = ServletScope.class.getName() + "/destructionCallbacks";
+    
+    private ServletContext servletContext;
+    
+    public void setServletContext(ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
+
+    /* (non-Javadoc)
+     * @see org.springframework.beans.factory.config.Scope#get(java.lang.String, org.springframework.beans.factory.ObjectFactory)
+     */
+    public Object get(String name, ObjectFactory objectFactory) {
+        Object scopedObject = servletContext.getAttribute(name);
+        if (scopedObject == null) {
+            scopedObject = objectFactory.getObject();
+            servletContext.setAttribute(name, scopedObject);
+        }
+
+        return scopedObject;
+    }
+
+    /* (non-Javadoc)
+     * @see org.springframework.beans.factory.config.Scope#remove(java.lang.String)
+     */
+    public Object remove(String name) {
+        Object scopedObject = servletContext.getAttribute(name);
+        if (scopedObject != null) {
+            servletContext.removeAttribute(name);
+        }
+
+        return scopedObject;
+    }
+
+    /* (non-Javadoc)
+     * @see org.springframework.beans.factory.config.Scope#getConversationId()
+     */
+    public String getConversationId() {
+        // There is no conversation id concept for the call stack
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String, java.lang.Runnable)
+     */
+    public void registerDestructionCallback(String name, Runnable callback) {
+        Map destructionCallbacks = getDestructionCallbacks(servletContext);
+        destructionCallbacks.put(name, callback);
+    }
+    
+    /**
+     * @param servletContext
+     * @return the destruction callbacks map that is stored as a attribute of servletContext
+     */
+    private static Map getDestructionCallbacks(ServletContext servletContext) {
+        Map destructionCallbacks = (Map)servletContext.getAttribute(destructionCallbacksAttributeName);
+        if (destructionCallbacks == null) {
+            destructionCallbacks = new HashMap();
+            servletContext.setAttribute(destructionCallbacksAttributeName, destructionCallbacks);
+        }
+        return destructionCallbacks;
+    }
+    
+    /**
+     * Executes destruction callbacks of beans from servlet scope. This method should be called once the Servlet that the scope
+     * is tied to is being destroyed.
+     * @param servletContext
+     */
+    public static void executeDestructionCallbacks(ServletContext servletContext) {
+        Map destructionCallbacks = getDestructionCallbacks(servletContext);
+        Iterator i = destructionCallbacks.values().iterator();
+        while (i.hasNext()) {
+            ((Runnable) i.next()).run();
+        }
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbsoluteServletConnection.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbsoluteServletConnection.java
new file mode 100644
index 0000000..8a47bf8
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbsoluteServletConnection.java
@@ -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.servletservice;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import org.apache.cocoon.callstack.environment.CallFrameHelper;
+import org.apache.cocoon.servletservice.util.ServletServiceRequest;
+import org.apache.cocoon.servletservice.util.ServletServiceResponse;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Create a connection to a servlet service. In order to use it, the fully qualified service name must be available.
+ * 
+ * @version $Id$
+ * @since 1.0.0
+ */
+public final class AbsoluteServletConnection extends AbstractServletConnection {
+
+    public static String ABSOLUTE_SERVLET_SOURCE_POSTFIX = "+";
+
+    private Servlet servlet;
+
+    /**
+     * Create an absolute connection to a servlet service.
+     * 
+     * @param serviceName The fully qualified service name (= the name of the Spring bean).
+     * @param path The requested path of the service.
+     * @param queryString The query parameters formatted as HTTP request query string.
+     */
+    public AbsoluteServletConnection(String serviceName, String path, String queryString) {
+        if (serviceName == null) {
+            throw new IllegalArgumentException("The serviceName parameter must be passed.");
+        }
+        this.context = CallStackHelper.getBaseServletContext();
+        final ApplicationContext applicationContext = WebApplicationContextUtils
+                .getRequiredWebApplicationContext(this.context);
+        try {
+            this.servlet = (Servlet) applicationContext.getBean(serviceName);
+        } catch (ClassCastException cce) {
+            throw new IllegalArgumentException("The service '" + serviceName + "' is not of type "
+                    + Servlet.class.getName() + ".");
+        }
+        if (this.servlet == null) {
+            throw new IllegalArgumentException("The service '" + serviceName + "' does not exist.");
+        }
+
+        URI reqUri = null;
+        try {
+            this.uri = new URI(serviceName + ABSOLUTE_SERVLET_SOURCE_POSTFIX, null, path, queryString, null);
+            this.uri = new URI("servlet", this.uri.toASCIIString(), null);
+            reqUri = new URI("servlet", null, path, queryString, null);
+        } catch (URISyntaxException e) {
+            IllegalArgumentException iae = new IllegalArgumentException("Can't create a URI using the passed path '"
+                    + path + "' and query string '" + queryString + "' values.");
+            iae.initCause(e);
+            throw iae;
+        }
+        this.request = new ServletServiceRequest(reqUri, CallFrameHelper.getRequest());
+        this.response = new ServletServiceResponse();
+    }
+
+    /**
+     * Perform the actual connect that invokes the servlet service.
+     */
+    protected void performConnect() throws ServletException, IOException {
+        try {
+            CallStackHelper.enterServlet(this.context, this.request, this.response);
+            this.servlet.service(this.request, this.response);
+        } finally {
+            CallStackHelper.leaveServlet();
+        }
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Absolutizable.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Absolutizable.java
new file mode 100644
index 0000000..36a56c6
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Absolutizable.java
@@ -0,0 +1,57 @@
+/*
+ * 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.servletservice;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * By this interface, a {@link ServletServiceContext} provides absolute information
+ * about a mounted servlet service.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public interface Absolutizable {
+
+    /**
+     * Takes the scheme specific part of a servlet service URI (the scheme is the
+     * responsibilty of the ServletSource) and resolve it with respect to the
+     * servlets mount point.
+     *
+     * @param uri relative uri
+     * @return absolutized uri
+     * @throws URISyntaxException
+     */
+    URI absolutizeURI(URI uri) throws URISyntaxException;
+
+    /**
+     * Get the fully qualified servlet service name of a connected service.
+     *
+     * @param connectionName
+     * @return The fully qualified servlet service name of a connected service.
+     */
+    String getServiceName(String connectionName);
+
+    /**
+     * Get the fully qualifed service name.
+     *
+     * @return The fully qualified servlet service name.
+     */
+    String getServiceName();
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbstractServletConnection.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbstractServletConnection.java
new file mode 100644
index 0000000..fb695ea
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/AbstractServletConnection.java
@@ -0,0 +1,209 @@
+/*
+ * 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.servletservice;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.cocoon.servletservice.util.ServletServiceRequest;
+import org.apache.cocoon.servletservice.util.ServletServiceResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @version $Id$
+ * @since 1.0.0
+ */
+public abstract class AbstractServletConnection implements ServletConnection {
+
+    /** By default we use the logger for this class. */
+    protected final Log logger = LogFactory.getLog(this.getClass());
+
+    /** Connection request */
+    protected ServletServiceRequest request;
+
+    /** Connection response */
+    protected ServletServiceResponse response;
+
+    /** The current block context */
+    protected ServletContext context;
+
+    /** If already connected */
+    protected boolean connected;
+
+    protected ByteArrayOutputStream requestBody;
+
+    protected InputStream responseBody;
+
+    protected URI uri;
+
+    public void connect() throws IOException, ServletException {
+        // if already connected, do nothing
+        if (this.connected) {
+            return;
+        }
+
+        this.request.setContext(this.context);
+
+        if (this.requestBody != null) {
+            this.request.setMethod("POST");
+            this.request.setInputStream(new ByteArrayInputStream(this.requestBody.toByteArray()));
+        }
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        this.response.setOutputStream(os);
+
+        try {
+            this.performConnect();
+            this.response.flushBuffer();
+            this.responseBody = new ByteArrayInputStream(os.toByteArray());
+        } finally {
+            os.close();
+        }
+
+        this.connected = true;
+    }
+
+    /**
+     * Access the servlet and fill the response object.
+     * 
+     * @throws ServletException
+     * @throws IOException
+     */
+    protected abstract void performConnect() throws ServletException, IOException;
+
+    /**
+     * Return an <code>InputStream</code> object to read from the source.
+     * 
+     * @throws IOException
+     * @throws ServletException
+     */
+    public InputStream getInputStream() throws IOException, ServletException {
+        this.connect();
+        return this.responseBody;
+    }
+
+    public void setIfModifiedSince(long ifmodifiedsince) {
+        if (this.connected) {
+            throw new IllegalStateException("Already connected");
+        }
+
+        this.request.setDateHeader("If-Modified-Since", ifmodifiedsince);
+    }
+
+    public long getLastModified() {
+        return this.getDateHeader("Last-Modified", 0);
+    }
+
+    public String getContentType() {
+        return this.getHeaderField("Content-Type");
+    }
+
+    public long getDateHeader(String name, long defaultValue) {
+        try {
+            return this.response.getDateHeader(name);
+        } catch (Exception e) {
+            this.logger.warn("Exception while reading the response header '" + name + "'.");
+        }
+
+        return defaultValue;
+    }
+
+    public String getHeaderField(String name) {
+        try {
+            this.connect();
+        } catch (Exception e) {
+            this.logger.warn("Exception while reading the response header '" + name + "'.");
+            return null;
+        }
+
+        return this.response.getHeader(name);
+    }
+
+    public long getHeaderFieldDate(String name, long defaultValue) {
+        try {
+            return this.response.getDateHeader(name);
+        } catch (Exception e) {
+            this.logger.warn("Exception while reading the response header '" + name + "'.");
+        }
+
+        return defaultValue;
+    }
+
+    public Map getHeaders() {
+        try {
+            this.connect();
+        } catch (Exception e) {
+            this.logger.warn("Exception while reading the response headers.");
+            return null;
+        }
+
+        return this.response.getHeaders();
+    }
+
+    public int getResponseCode() throws IOException {
+        try {
+            this.connect();
+        } catch (ServletException e) {
+            throw new IOException("Could not get response status code");
+        }
+
+        return this.response.getStatus();
+    }
+
+    /**
+     * Returns an output stream that writes as POST to this connection.
+     * 
+     * @return an output stream that writes as POST to this connection.
+     * @throws IllegalStateException - if already connected
+     */
+    public OutputStream getOutputStream() throws IllegalStateException {
+        if (this.connected) {
+            throw new IllegalStateException("You cannot write to the connection already connected.");
+        }
+
+        if (this.requestBody == null) {
+            this.requestBody = new ByteArrayOutputStream();
+        }
+        return this.requestBody;
+
+    }
+
+    public URI getURI() {
+        return this.uri;
+    }
+
+    /**
+     * A special exception indicating that there is no servlet context available.
+     */
+    protected static class NoServletContextAvailableException extends RuntimeException {
+
+        private static final long serialVersionUID = 1L;
+
+        public NoServletContextAvailableException(String message) {
+            super(message);
+        }
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/CallStackHelper.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/CallStackHelper.java
new file mode 100644
index 0000000..dbf8cff
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/CallStackHelper.java
@@ -0,0 +1,114 @@
+/*
+ * 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.servletservice;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cocoon.callstack.CallFrame;
+import org.apache.cocoon.callstack.CallStack;
+import org.apache.cocoon.callstack.environment.CallFrameHelper;
+
+/**
+ * Helper class used for geting hold on the current servlet service
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class CallStackHelper {
+
+    /** Key for a value determing wether a call frame contains a super call or not */
+    public final static String SUPER_CALL = "super";
+
+    /**
+     * This hook must be called each time a servlet service is entered.
+     *
+     * <p>This method should never raise an exception, except when the
+     * parameters are not set!</p>
+     *
+     * @throws ServletException if at least one of the parameters is null
+     */
+    public static void enterServlet(ServletContext context, HttpServletRequest request, HttpServletResponse response)
+    throws ServletException {
+        enterServlet(context, request, response, false);
+    }
+
+    /**
+     * This hook must be called each time a super servlet service is entered.
+     *
+     * <p>This method should never raise an exception, except when the
+     * parameters are not set!</p>
+     *
+     * @throws ServletException if at least one of the parameters is null
+     */
+    public static void enterSuperServlet(ServletContext context, HttpServletRequest request, HttpServletResponse response)
+    throws ServletException {
+        enterServlet(context, request, response, true);
+    }
+
+    private static void enterServlet(ServletContext context, HttpServletRequest request, HttpServletResponse response, boolean superCall)
+    throws ServletException {
+        if (null == context) throw new ServletException("The context is not set.");
+        if (null == request) throw new ServletException("The request is not set.");
+        if (null == response) throw new ServletException("The response is not set.");
+
+
+        CallStack.enter();
+        CallStack.getCurrentFrame().setAttribute(SUPER_CALL, Boolean.valueOf(superCall));
+        CallFrameHelper.setContext(context);
+        CallFrameHelper.setRequest(request);
+        CallFrameHelper.setResponse(response);
+    }
+
+    /**
+     * This hook must be called each time a servlet service is left.
+     *
+     * <p>It's the counterpart to the {@link #enterServlet} method.</p>
+     */
+    public static void leaveServlet() {
+        CallStack.leave();
+    }
+
+    /**
+     * Use this method for getting the context that should be used for
+     * resolving a polymorphic servlet protocol call.
+     *
+     * @return a servlet context
+     */
+    public static ServletContext getBaseServletContext() {
+        for (int i = CallStack.size() - 1; i >= 0; i--) {
+            CallFrame frame = CallStack.frameAt(i);
+            if (frame.hasAttribute(SUPER_CALL) && !((Boolean) frame.getAttribute(SUPER_CALL)).booleanValue()) {
+                return (ServletContext) frame.getAttribute(CallFrameHelper.CONTEXT_OBJECT);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Use this method for getting the context that should be used for
+     * resolving a servlet protocol call to a super servlet service.
+     *
+     * @return a servlet context
+     */
+    public static ServletContext getCurrentServletContext() {
+        return CallFrameHelper.getContext();
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DispatcherServlet.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DispatcherServlet.java
new file mode 100644
index 0000000..88ab98b
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DispatcherServlet.java
@@ -0,0 +1,143 @@
+/*
+ * 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.servletservice;
+
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * A servlet that dispatch to managed sevlets from the context Spring container.
+ * It dispatch to servlets that has the property mountPath, and dispatches to the
+ * servlet with the longest prefix of the request pathInfo.
+ *
+ * This servlet will also initialize and destroy all the servlets that it finds
+ * from the context container. This means that there must only be one dispatcher
+ * servlet, otherwise the managed servlets will be initialized several times.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class DispatcherServlet extends HttpServlet {
+
+    /** By default we use the logger for this class. */
+    private final Log logger = LogFactory.getLog(getClass());
+
+    /**
+     * The startup date of the Spring application context used to setup the  {@link #blockServletCollector}.
+     * TODO: Use a better way to reload {@link #blockServletCollector} when RCL is used, see COCOON-2076
+     */
+    private long applicationContextStartDate;
+
+    /** The servlet collector bean */
+    private Map blockServletCollector;
+
+    public void init() throws ServletException {
+        this.log("Block dispatcher was initialized successfully.");
+    }
+
+    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
+        final Map mountableServlets = getBlockServletMap();
+        String path = req.getPathInfo();
+        if (path == null) {
+            path = "";
+        }
+
+        // find the servlet which mount path is the longest prefix of the path info
+        int index = path.length();
+        Servlet servlet = null;
+        while (servlet == null && index != -1) {
+            path = path.substring(0, index);
+            servlet = (Servlet) mountableServlets.get(path);
+            index = path.lastIndexOf('/');
+        }
+        //case when servlet is mounted at "/" must be handled separately
+        servlet = servlet == null ? (Servlet) mountableServlets.get("/") : servlet;
+        if (servlet == null) {
+            String message = "No block for " + req.getPathInfo();
+            res.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+            this.logger.info(message);
+            return;
+        }
+
+        // Create a dynamic proxy class that overwrites the getServletPath and
+        // getPathInfo methods to provide reasonable values in the called servlet
+        // the dynamic proxy implements all interfaces of the original request
+        HttpServletRequest request = (HttpServletRequest) Proxy.newProxyInstance(
+                req.getClass().getClassLoader(),
+                getInterfaces(req.getClass()),
+                new DynamicProxyRequestHandler(req, path));
+
+        if (this.logger.isDebugEnabled()) {
+            this.logger.debug("DispatcherServlet: service servlet=" + servlet +
+                              " mountPath=" + path +
+                              " servletPath=" + request.getServletPath() +
+                              " pathInfo=" + request.getPathInfo());
+        }
+
+        servlet.service(request, res);
+    }
+
+    private void getInterfaces(Set interfaces, Class clazz) {
+        Class[] clazzInterfaces = clazz.getInterfaces();
+        for (int i = 0; i < clazzInterfaces.length; i++) {
+            //add all interfaces extended by this interface or directly
+            //implemented by this class
+            getInterfaces(interfaces, clazzInterfaces[i]);
+        }
+
+        // the superclazz is null if class is instanceof Object, is
+        // an interface, a primitive type or void
+        Class superclazz = clazz.getSuperclass();
+        if (superclazz != null) {
+            //add all interfaces of the superclass to the list
+            getInterfaces(interfaces, superclazz);
+        }
+
+        interfaces.addAll(Arrays.asList(clazzInterfaces));
+    }
+
+    private Class[] getInterfaces(final Class clazz) {
+        Set interfaces = new LinkedHashSet();
+        getInterfaces(interfaces, clazz);
+        return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
+    }
+
+    public Map getBlockServletMap() {
+        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+        if (this.blockServletCollector == null || applicationContext.getStartupDate() != this.applicationContextStartDate) {
+            this.applicationContextStartDate = applicationContext.getStartupDate();
+            this.blockServletCollector = (Map) applicationContext.getBean("org.apache.cocoon.servletservice.spring.BlockServletMap");
+        }
+        return blockServletCollector;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DynamicProxyRequestHandler.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DynamicProxyRequestHandler.java
new file mode 100644
index 0000000..70bdd99
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/DynamicProxyRequestHandler.java
@@ -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.cocoon.servletservice;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * A dynamic wrapper for servlet requests that overwrites the
+ * getContextPath, getServletPath and getPathInfo methods to
+ * reflect the mount path of the block servlet.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class DynamicProxyRequestHandler implements InvocationHandler {
+    private final HttpServletRequest wrapped;
+    private final String mountPath;
+
+    private static final Method getContextPathMethod;
+    private static final Method getServletPathMethod;
+    private static final Method getPathInfoMethod;
+
+    static {
+        getContextPathMethod = getHttpServletRequestMethod("getContextPath");
+        getServletPathMethod = getHttpServletRequestMethod("getServletPath");
+        getPathInfoMethod = getHttpServletRequestMethod("getPathInfo");
+    }
+
+    /**
+     * Helper method for getting methods of the HttpServletRequest interface
+     *
+     * @param name name of the method
+     * @return the method object
+     */
+    static private Method getHttpServletRequestMethod(String name) {
+        Class[] paramTypes = new Class[]{};
+        try {
+            return HttpServletRequest.class.getMethod(name, paramTypes);
+        } catch (SecurityException e) {
+            throw new RuntimeException("could not get method: " +
+                                       name + " from class: " + HttpServletRequest.class);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException("could not get method: " +
+                                       name + " from class: " + HttpServletRequest.class);
+        }
+    }
+
+    /**
+     * Creates a new request wrapper from a specified proxied request and
+     * the mount path of the block servlet
+     * @param req the request to proxy
+     * @param mountPath the mount path of the servlet
+     */
+    public DynamicProxyRequestHandler(HttpServletRequest req, String mountPath) {
+        this.wrapped = req;
+        this.mountPath = mountPath;
+    }
+
+    /**
+     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+     */
+    public Object invoke(Object proxy, Method method, Object[] arguments)
+    throws Throwable {
+        if (method.equals(getContextPathMethod)) {
+            return wrapped.getContextPath() + wrapped.getServletPath();
+        } else if (method.equals(getServletPathMethod)) {
+            return mountPath;
+        } else if (method.equals(getPathInfoMethod)) {
+            String pathInfo = wrapped.getPathInfo().substring(mountPath.length());
+            return pathInfo.length() == 0 ? null : pathInfo;
+        } else {
+            return method.invoke(wrapped, arguments);
+        }
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapper.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapper.java
new file mode 100644
index 0000000..05451dd
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapper.java
@@ -0,0 +1,311 @@
+/*
+ * 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.servletservice;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>THIS IS INTERNAL CLASS OF SERVLET SERVICE FRAMEWORK AND SHOULDN'T BE USED ELSEWHERE!</p>
+ * 
+ * <p>This class works in two modes:</p>
+ * <ol>
+ * <li>If status code has been set to value different than <code>404</code> (<code>SC_NOT_FOUND</code>) then this class 
+ *     acts completely transparently by forwarding all method calls to wrapped response object.</li>
+ * <li>If status code has been set to <code>404</code> then this class acts like a buffer. It buffers all method calls 
+ *     that would commit wrapped response. Buffering of such calls is being performed in order to assure that wrapped 
+ *     response can be always reseted if needed. It's worth mentioning the fact that buffer for {@link OutputStream}
+ *     returned by {@link #getOutputStream()} is limited to the size specified in
+ *     {@link #BUFFER_LIMIT} field.</li>
+ *
+ *  <p>Additionally, this class lets the access to statusCode code that has been set through the 
+ *     {@link #getStatusCode()} method.</p> 
+ */
+class HttpServletResponseBufferingWrapper extends HttpServletResponseWrapper {
+
+    /**
+     * Limit for a buffer for output stream returned by {@link #getOutputStream()} method.
+     * This is a hard limit, if exceeded an exception is thrown.
+     */
+    static private int BUFFER_LIMIT = 1024 * 1024; //= 1MB
+    static private String ALREADY_COMMITTED_EXCEPTION = "The response has been already committed.";
+    
+    private boolean bufferResponse;
+    private boolean committed;
+    private String message;
+    private int statusCode;
+    private boolean sendError;
+
+    private ForwardingOrLimitingServletOutputStream outputStream;
+    private PrintWriter printWriter;
+
+    public HttpServletResponseBufferingWrapper(HttpServletResponse response) {
+        super(response);
+        resetBufferedResponse();
+    }
+
+    public void addCookie(Cookie cookie) {
+        if (isCommitted())
+            return;
+        super.addCookie(cookie);
+    }
+
+    public void sendError(int sc) throws IOException {
+        if (isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        if (sc != SC_NOT_FOUND)
+            super.sendError(sc);
+        else {
+            bufferResponse = true;
+            committed = true;
+            sendError = true;
+        }
+        statusCode = sc;
+    }
+
+    public void sendError(int sc, String msg) throws IOException {
+        if (isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        if (sc != SC_NOT_FOUND)
+            super.sendError(sc, msg);
+        else {
+            bufferResponse = true;
+            committed = true;
+            message = msg;
+            sendError = true;
+        }
+        statusCode = sc;
+    }
+
+    public void sendRedirect(String location) throws IOException {
+        if (isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        super.sendRedirect(location);
+        statusCode = HttpServletResponse.SC_TEMPORARY_REDIRECT;
+    }
+
+    public void setDateHeader(String name, long date) {
+        if (isCommitted())
+            return;
+        super.setDateHeader(name, date);
+    }
+
+    public void addDateHeader(String name, long date) {
+        if (isCommitted())
+            return;
+        super.addDateHeader(name, date);
+    }
+
+    public void setHeader(String name, String value) {
+        if (isCommitted())
+            return;
+        super.setHeader(name, value);
+    }
+
+    public void addHeader(String name, String value) {
+        if (isCommitted())
+            return;
+        super.addHeader(name, value);
+    }
+
+    public void setIntHeader(String name, int value) {
+        if (isCommitted())
+            return;
+        super.setIntHeader(name, value);
+    }
+
+    public void addIntHeader(String name, int value) {
+        if (isCommitted())
+            return;
+        super.addIntHeader(name, value);
+    }
+
+    public void setStatus(int sc) {
+        if (isCommitted())
+            return;
+        if (sc != SC_NOT_FOUND)
+            super.setStatus(sc);
+        else {
+            bufferResponse = true;
+        }
+        statusCode = sc;
+    }
+
+    public void setStatus(int sc, String sm) {
+        throw new UnsupportedOperationException(
+                "This method has been deprecated.");
+    }
+
+    public ServletOutputStream getOutputStream() throws IOException {
+        if (outputStream == null)
+            this.outputStream = new ForwardingOrLimitingServletOutputStream(BUFFER_LIMIT, super.getOutputStream());
+        return outputStream;
+    }
+
+    public PrintWriter getWriter() throws IOException {
+        if (this.outputStream != null)
+            throw new IllegalStateException(
+                    "Output buffer has been already obtained. You can use either output buffer or print writer at one time.");
+        if (this.printWriter == null)
+            this.printWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), getCharacterEncoding()));
+        return printWriter;
+    }
+
+    public void flushBuffer() throws IOException {
+        if (!bufferResponse)
+            super.flushBuffer();
+        else
+            committed = true;
+    }
+
+    public boolean isCommitted() {
+        return committed || super.isCommitted();
+    }
+
+    public void resetBuffer() {
+        if (isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        if (!bufferResponse)
+            super.resetBuffer();
+        else if (outputStream != null)
+            outputStream.reset();
+    }
+
+    public void reset() {
+        if (isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        super.reset();
+        bufferResponse = false;
+        message = null;
+    }
+
+    public void flushBufferedResponse() throws IOException {
+        if (bufferResponse) {
+            if (sendError) {
+                try {
+                    if (message != null)
+                        super.sendError(SC_NOT_FOUND, message);
+                    else
+                        super.setStatus(SC_NOT_FOUND);
+                } catch (IOException e) {
+                    // this should never occur
+                    throw new IllegalStateException(
+                            "FATAL ERROR! This situation should never occur because it's a job of "
+                                    + getClass().getName() + " class to "
+                                    + "prevent such situation.");
+                }
+            } else {
+                if (message != null)
+                    super.setStatus(SC_NOT_FOUND, message);
+                else
+                    super.setStatus(SC_NOT_FOUND);
+            }
+        }
+        
+        //since all data goes through ForwardingOrLimitingServletOutputStream then flushing
+        //must be performed in *every* case now
+        if (this.printWriter != null) {
+            if (this.printWriter.checkError())
+                throw new IOException(
+                        "Error occured while writing to printWriter.");
+            this.printWriter.close();
+        } else if (outputStream != null)
+            outputStream.writeTo(super.getOutputStream());
+        
+        super.flushBuffer();
+    }
+
+    public void resetBufferedResponse() {
+        if (super.isCommitted())
+            throw new IllegalStateException(ALREADY_COMMITTED_EXCEPTION);
+        if (bufferResponse) {
+            message = null;
+            bufferResponse = false;
+            committed = false;
+            sendError = false;
+        }
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    /**
+     * Simple class acting like a {@link ServletOutputStream} but limiting (if it does not forward) number of bytes that 
+     * can be written to the stream.
+     */
+    private class ForwardingOrLimitingServletOutputStream extends ServletOutputStream {
+        
+        private Log log = LogFactory.getLog(getClass());
+
+        private int writeLimit;
+        private ByteArrayOutputStream outputStream;
+        
+        private OutputStream forwardTo;
+
+        public ForwardingOrLimitingServletOutputStream(int writeLimit, OutputStream forwardTo) {
+            this.writeLimit = writeLimit;
+            this.forwardTo = forwardTo;
+            reset();
+        }
+
+        public void write(int b) throws IOException {
+            HttpServletResponseBufferingWrapper.this.committed = true;
+            
+            if (isForwarding())
+                forwardTo.write(b);
+            else {
+                if (this.outputStream.size() < this.writeLimit)
+                    this.outputStream.write(b);
+                else {
+                    RuntimeException e = new RuntimeException(
+                            "The buffering limit (" + writeLimit+ ") has been reached. If you encounter this exception it means that you to "
+                            + "write a big response body for response that has error code set as status code. This is always a bad "
+                            + "idea and in such case you should reconsider your design.");
+                    log.fatal("Fatal error occured in writing to response", e);
+                    throw e;
+                }
+            }
+        }
+
+        public void reset() {
+            this.outputStream = new ByteArrayOutputStream(writeLimit);
+        }
+
+        public void writeTo(OutputStream outputStream) throws IOException {
+            if (this.outputStream.size() > 0)
+                this.outputStream.writeTo(outputStream);
+        }
+        
+        private boolean isForwarding() {
+            return !HttpServletResponseBufferingWrapper.this.bufferResponse;
+        }
+
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Mountable.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Mountable.java
new file mode 100644
index 0000000..4c34278
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/Mountable.java
@@ -0,0 +1,37 @@
+/*
+ * 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.servletservice;
+
+/**
+ * Interface for servlet services that are mounted on a specific path.
+ * The inteface is not needed for using the {@link DispatcherServlet}
+ * as it mounts all servlet beans that has a property named mountPath.
+ * The main use for the interface is to b e able to create an AOP mixin
+ * with an ordinary Java proxy.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public interface Mountable {
+
+    /**
+     * The mount path of the servlet.
+     *
+     * @return servlet mount path
+     */
+    public String getMountPath();
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/NoCallingServletServiceRequestAvailableException.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/NoCallingServletServiceRequestAvailableException.java
new file mode 100644
index 0000000..9faa7c0
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/NoCallingServletServiceRequestAvailableException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.servletservice;
+
+public class NoCallingServletServiceRequestAvailableException extends RuntimeException {
+
+    public NoCallingServletServiceRequestAvailableException(String message) {
+        super(message);
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/RelativeServletConnection.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/RelativeServletConnection.java
new file mode 100644
index 0000000..b78ff62
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/RelativeServletConnection.java
@@ -0,0 +1,106 @@
+/*
+ * 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.servletservice;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+
+import org.apache.cocoon.callstack.environment.CallFrameHelper;
+import org.apache.cocoon.servletservice.util.ServletServiceRequest;
+import org.apache.cocoon.servletservice.util.ServletServiceResponse;
+
+/**
+ * Implementation of a {@link ServletConnection} that gets its content by
+ * invoking the servlet service. It works based on the context of the current
+ * servlet context and its connections.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public final class RelativeServletConnection extends AbstractServletConnection {
+
+    private String connectionName;
+
+    public RelativeServletConnection(String connectionName, String path, String queryString) {
+        // path validation
+        if (path == null) {
+            throw new IllegalArgumentException("Path musn't be null.");
+        }
+        if (!path.startsWith("/")) {
+            throw new IllegalArgumentException(
+                            "The path has to start with a slash '/' because it is always absolute within this servlet context.");
+        }
+
+        this.connectionName = connectionName;
+
+        // setup URI
+        URI reqUri;
+        try {
+            this.uri = new URI((connectionName != null ? connectionName : "local"), null, path, queryString, null);
+            this.uri = new URI("servlet", this.uri.toASCIIString(), null);
+            reqUri =  new URI("servlet", null, path, queryString, null);
+        } catch (URISyntaxException e) {
+            String message = "Invalid relative servlet service URI created.";
+            this.logger.error(message, e);
+            throw new RuntimeException(message, e);
+        }
+
+        // lookup the servlet context
+        if (ServletServiceContext.SUPER.equals(this.connectionName)) {
+            // Super calls are resolved relative the current context and ordinary
+            // calls relative to the last non super call in the call chain
+            this.context = CallStackHelper.getCurrentServletContext();
+        } else {
+            this.context = CallStackHelper.getBaseServletContext();
+        }
+        if (this.context == null) {
+            throw new NoServletContextAvailableException(
+                            "A servlet connection can only be used with an available servlet context. [" + this.uri
+                                            + "]");
+        }
+
+        // prepare request and response objects
+        this.request = new ServletServiceRequest(reqUri, CallFrameHelper.getRequest());
+        this.response = new ServletServiceResponse();
+
+        if(this.logger.isDebugEnabled()) {
+            this.logger.debug("Resolving relative servlet URI " + this.uri.toASCIIString());
+        }
+    }
+
+    /**
+     * Perform the actual connect that invokes the servlet service.
+     */
+    protected void performConnect() throws ServletException, IOException {
+        final RequestDispatcher dispatcher;
+        if (this.connectionName == null) {
+            dispatcher = this.context.getRequestDispatcher(null);
+        } else {
+            dispatcher = this.context.getNamedDispatcher(this.connectionName);
+        }
+
+        if (dispatcher == null) {
+            throw new ServletException("No dispatcher for connection" + this.connectionName);
+        }
+        dispatcher.forward(this.request, this.response);
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletConnection.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletConnection.java
new file mode 100644
index 0000000..8b6209d
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletConnection.java
@@ -0,0 +1,125 @@
+/*
+ * 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.servletservice;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URLConnection;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+
+/**
+ * <p>
+ * Contract to connect to a servlet service. The implementing classes differ from how they look up
+ * the servlet service.
+ * </p>
+ * <p>
+ * This class was designed similar to {@link URLConnection}.
+ * </p>
+ * 
+ * @version $Id$
+ * @since 1.0.0
+ */
+public interface ServletConnection {
+
+    // ~~~~~~~~~~~~~~~~~~~~~~~~ Pre-connect methods ~~~~~~~~~~~~~~~~~~
+
+    /**
+     * Set the last modification date if you want to make use of caching. This method has to be
+     * called before any of the other methods of this interface is invoked.
+     * 
+     * @param ifmodifiedsince The timestamp of the last known resource.
+     */
+    void setIfModifiedSince(long ifmodifiedsince);
+
+    /**
+     * Get an output stream that writes as POST to this connection.
+     * 
+     * @return An output stream that writes as POST to this connection.
+     */
+    OutputStream getOutputStream();
+
+    // ~~~~~~~~~~~~~~~~~~~~~~~~ connect method ~~~~~~~~~~~~~~~~~~
+
+    /**
+     * Connect to the servlet service. Establishing a connection means that the service is executed
+     * and the response is available.
+     * 
+     * @throws IOException The connection to the servlet service can't be established.
+     * @throws ServletException Any other problem when connecting to a servlet service.
+     */
+    void connect() throws IOException, ServletException;
+
+    // ~~~~~~~~~~~~~~~~~~~~~~~~ Post-connect methods ~~~~~~~~~~~~~~~~~~
+
+    /**
+     * Read the input stream from the servlet service response.
+     * 
+     * @return An input stream on the servlet service response.
+     * @throws IOException The connection to the servlet service can't be established.
+     * @throws ServletException Any other problem when connecting to a servlet service.
+     */
+    InputStream getInputStream() throws IOException, ServletException;
+
+    /**
+     * 
+     * @return The HTTP status code returned by the servlet service.
+     * @throws IOException
+     */
+    int getResponseCode() throws IOException;
+
+    /**
+     * Get the last modification date of the servlet service.
+     * 
+     * @return The last modification date of the servlet service.
+     */
+    long getLastModified();
+
+    /**
+     * Get the mime-type of the servlet-service.
+     * 
+     * @return The mime-type of the servlet-service.
+     */
+    String getContentType();
+
+    // ~~~~~~~~~~~~~~~~~~~~~~~~ Idempotent methods ~~~~~~~~~~~~~~~~~~
+
+    /**
+     * Get a URI representing this servlet connection.
+     * 
+     * @return a URI representing this servlet connection.
+     */
+    URI getURI();
+
+    /**
+     * Get a response header with the given name.
+     * 
+     * @param name The name of the header parameter
+     * @return The value of the header parameter
+     */
+    String getHeaderField(String name);
+
+    /**
+     * Get all response header fields.
+     * 
+     * @return A {@link Map} that contains all response headers.
+     */
+    Map<String, String> getHeaders();
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletServiceContext.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletServiceContext.java
new file mode 100644
index 0000000..6b59b6a
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/ServletServiceContext.java
@@ -0,0 +1,508 @@
+/*
+ * 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.servletservice;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+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.cocoon.servletservice.util.ServletContextWrapper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletServiceContext extends ServletContextWrapper implements Absolutizable {
+
+    public static final String SUPER = "super";
+
+    private final Log logger = LogFactory.getLog(ServletServiceContext.class);
+
+    private Map attributes = new Hashtable();
+    private Servlet servlet;
+    private String mountPath;
+    private String contextPath;
+    private URL contextPathURL;
+    private Map properties;
+    private Map connections;
+    private Map connectionServiceNames;
+    private String serviceName;
+
+    /*
+     * TODO inheritance of attributes from the parent context is only partly implemented: removeAttribute and
+     * getAttributeNames doesn't respect inheritance yet.
+     */
+    public Object getAttribute(String name) {
+        Object value = this.attributes.get(name);
+        return value != null ? value : super.getAttribute(name);
+    }
+
+    public void setAttribute(String name, Object value) {
+        this.attributes.put(name, value);
+    }
+
+    public void removeAttribute(String name) {
+        this.attributes.remove(name);
+    }
+
+    public Enumeration getAttributeNames() {
+        return Collections.enumeration(this.attributes.keySet());
+    }
+
+    /**
+     * @param map the attributes to set
+     */
+    public void setAttributes(Map map) {
+        if (map != null) {
+            this.attributes = map;
+        }
+    }
+
+    public URL getResource(String path) throws MalformedURLException {
+        if (path == null || !path.startsWith("/")) {
+            throw new MalformedURLException("The path must begin with a '/' and is interpreted "
+                    + "as relative to the current context root.");
+        }
+
+        // lazy initialization of the base URL
+        synchronized (this) {
+            if (this.contextPathURL == null) {
+                this.contextPathURL = new URL(this.contextPath);
+            }
+        }
+
+        return new URL(this.contextPathURL, path.substring(1));
+    }
+
+    public String getRealPath(String path) {
+        // We better don't assume that blocks are unpacked
+        return null;
+    }
+
+    // FIXME, this should be defined in the config instead
+    public String getInitParameter(String name) {
+        if (this.properties == null) {
+            return null;
+        }
+
+        String value = (String) this.properties.get(name);
+        // Ask the super servlet for the property
+        if (value == null) {
+            ServletContext superContext = this.getNamedContext(SUPER);
+            if (superContext != null) {
+                value = superContext.getInitParameter(name);
+            }
+        }
+
+        // Ask the parent context
+        if (value == null) {
+            value = super.getInitParameter(name);
+        }
+
+        return value;
+    }
+
+    public Enumeration getInitParameterNames() {
+        Vector names = new Vector();
+
+        // add all names of the parent servlet context
+        Enumeration enumeration = super.getInitParameterNames();
+        while (enumeration.hasMoreElements()) {
+            names.add(enumeration.nextElement());
+        }
+
+        // add names of the super servlet
+        ServletContext superContext = this.getNamedContext(SUPER);
+        if (superContext != null) {
+            enumeration = superContext.getInitParameterNames();
+            while (enumeration.hasMoreElements()) {
+                names.add(enumeration.nextElement());
+            }
+        }
+
+        // add property names of this servlet
+        if (this.properties != null) {
+            names.addAll(this.properties.keySet());
+        }
+
+        return names.elements();
+    }
+
+    public InputStream getResourceAsStream(String path) {
+        try {
+            return this.getResource(path).openStream();
+        } catch (IOException e) {
+            this.logger.error("Can't open stream on " + path, e);
+            return null;
+        }
+    }
+
+    public ServletContext getContext(String uripath) {
+        return null;
+    }
+
+    public int getMajorVersion() {
+        return 2;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see javax.servlet.ServletContext#getMinorVersion()
+     */
+    public int getMinorVersion() {
+        return 3;
+    }
+
+    private Collection getDirectoryList(File file, String pathPrefix) {
+        ArrayList filenames = new ArrayList();
+
+        if (!file.isDirectory()) {
+            filenames.add("/" + file.toString().substring(pathPrefix.length() - 1));
+            return filenames;
+        }
+
+        File[] files = file.listFiles();
+
+        for (int i = 0; i < files.length; i++) {
+            File subfile = files[i];
+            filenames.addAll(this.getDirectoryList(subfile, pathPrefix));
+        }
+
+        return filenames;
+    }
+
+    public Set getResourcePaths(String path) {
+        if (path == null) {
+            return Collections.EMPTY_SET;
+        }
+
+        String pathPrefix;
+        if (this.contextPath.startsWith("file:")) {
+            pathPrefix = this.contextPath.substring("file:".length());
+        } else {
+            pathPrefix = this.contextPath;
+        }
+
+        path = pathPrefix + path;
+
+        File file = new File(path);
+
+        if (!file.exists()) {
+            return Collections.EMPTY_SET;
+        }
+
+        HashSet set = new HashSet();
+        set.addAll(this.getDirectoryList(file, pathPrefix));
+
+        return set;
+    }
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        PathDispatcher dispatcher = new PathDispatcher(path);
+        return dispatcher.exists() ? dispatcher : null;
+    }
+
+    public RequestDispatcher getNamedDispatcher(String name) {
+        NamedDispatcher dispatcher = new NamedDispatcher(name);
+        return dispatcher.exists() ? dispatcher : null;
+    }
+
+    public String getServerInfo() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getServletContextName() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    // Servlet service specific methods
+
+    /**
+     * Set the servlet of the context
+     * 
+     * @param servlet
+     */
+    public void setServlet(Servlet servlet) {
+        this.servlet = servlet;
+    }
+
+    /**
+     * Takes the scheme specific part of a servlet service URI (the scheme is the responsibilty of the ServletSource)
+     * and resolve it with respect to the servlets mount point.
+     */
+    public URI absolutizeURI(URI uri) throws URISyntaxException {
+        String servletServiceName = uri.getScheme();
+        ServletServiceContext servletServiceContext;
+        if (servletServiceName == null) {
+            // this servlet service
+            servletServiceContext = this;
+        } else {
+            // another servlet service
+            servletServiceContext = (ServletServiceContext) this.getNamedContext(servletServiceName);
+            if (servletServiceContext == null) {
+                throw new URISyntaxException(uri.toString(), "Unknown servlet service name");
+            }
+        }
+
+        String mountPath = servletServiceContext.getMountPath();
+        if (mountPath == null) {
+            throw new URISyntaxException(uri.toString(), "No mount point for this URI");
+        }
+        if (mountPath.endsWith("/")) {
+            mountPath = mountPath.substring(0, mountPath.length() - 1);
+        }
+
+        String absoluteURI = mountPath + uri.getSchemeSpecificPart();
+        if (this.logger.isInfoEnabled()) {
+            this.logger.info("Resolving " + uri.toString() + " to " + absoluteURI);
+        }
+
+        return new URI(absoluteURI);
+    }
+
+    public String getServiceName(String connectionName) {
+        return (String) this.connectionServiceNames.get(connectionName);
+    }
+
+    public String getServiceName() {
+        return this.serviceName;
+    }
+
+    /**
+     * Get the context of a servlet service with a given name.
+     */
+    // FIXME implement NPE handling
+    public ServletContext getNamedContext(String name) {
+        if (this.connections == null) {
+            return null;
+        }
+
+        Servlet servlet = (Servlet) this.connections.get(name);
+        if (servlet == null && !name.equals(SUPER)) {
+            Servlet _super = (Servlet) this.connections.get(SUPER);
+            if (_super != null) {
+                ServletContext c = _super.getServletConfig().getServletContext();
+                if (c instanceof ServletServiceContext) {
+                    return ((ServletServiceContext) c).getNamedContext(name);
+                }
+
+                return null;
+            }
+        }
+        return servlet != null ? servlet.getServletConfig().getServletContext() : null;
+    }
+
+    /**
+     * @param mountPath The mountPath to set.
+     */
+    public void setMountPath(String mountPath) {
+        this.mountPath = mountPath;
+    }
+
+    /**
+     * Get the mount path of the servlet service context
+     */
+    public String getMountPath() {
+        return this.mountPath;
+    }
+
+    /**
+     * @param contextPath
+     */
+    public void setContextPath(String contextPath) {
+        if (contextPath == null) {
+            throw new IllegalArgumentException("Context path must not be null.");
+        }
+
+        if (contextPath.endsWith("/")) {
+            this.contextPath = contextPath;
+        } else {
+            this.contextPath = contextPath + "/";
+        }
+    }
+
+    /**
+     * @param properties The properties to set.
+     */
+    public void setInitParams(Map properties) {
+        this.properties = properties;
+    }
+
+    /**
+     * @param connections the connections to set
+     */
+    public void setConnections(Map connections) {
+        this.connections = connections;
+    }
+
+    /**
+     * @param connections the service names of the connections
+     */
+    public void setConnectionServiceNames(Map connectionServletServiceNames) {
+        this.connectionServiceNames = connectionServletServiceNames;
+    }
+
+    /**
+     * @param serviceName the name of the
+     */
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+
+    protected class NamedDispatcher implements RequestDispatcher {
+
+        private final String servletServiceName;
+
+        private final boolean superCall;
+
+        private final ServletContext context;
+
+        public NamedDispatcher(String servletServiceName) {
+            this.servletServiceName = servletServiceName;
+            this.superCall = SUPER.equals(this.servletServiceName);
+
+            // Call to a named servlet service that exists in the current
+            // context
+            this.context = ServletServiceContext.this.getNamedContext(this.servletServiceName);
+        }
+
+        protected boolean exists() {
+            return this.context != null;
+        }
+
+        public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+            // Call to named servlet service
+
+            if (ServletServiceContext.this.logger.isInfoEnabled()) {
+                ServletServiceContext.this.logger
+                        .info("Enter processing in servlet service " + this.servletServiceName);
+            }
+            RequestDispatcher dispatcher = this.context.getRequestDispatcher(((HttpServletRequest) request)
+                    .getPathInfo());
+            if (dispatcher != null && dispatcher instanceof PathDispatcher) {
+                ((PathDispatcher) dispatcher).forward(request, response, this.superCall);
+            } else {
+                // Cannot happen
+                throw new IllegalStateException();
+            }
+            if (ServletServiceContext.this.logger.isInfoEnabled()) {
+                ServletServiceContext.this.logger.info("Leaving processing in servlet service "
+                        + this.servletServiceName);
+            }
+        }
+
+        public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Limited functionality, assumes that there is at most one servlet in the context
+     */
+    private class PathDispatcher implements RequestDispatcher {
+
+        // Ignores path, as the assumed only servlet within the context is
+        // implicitly mounted on '/*'
+        private PathDispatcher(String path) {
+        }
+
+        private boolean exists() {
+            return ServletServiceContext.this.servlet != null;
+        }
+
+        public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+            this.forward(request, response, false);
+        }
+
+        protected void forward(ServletRequest request, ServletResponse response, boolean superCall)
+                throws ServletException, IOException {
+            try {
+                HttpServletResponseBufferingWrapper wrappedResponse = new HttpServletResponseBufferingWrapper(
+                        (HttpServletResponse) response);
+                // FIXME: I think that Cocoon should always set status code on
+                // its own
+                wrappedResponse.setStatus(HttpServletResponse.SC_OK);
+                if (!superCall) {
+                    // It is important to set the current context each time
+                    // a new context is entered, this is used for the servlet
+                    // protocol
+                    CallStackHelper.enterServlet(ServletServiceContext.this, (HttpServletRequest) request,
+                            wrappedResponse);
+                } else {
+                    // A super servlet service should be called in the context
+                    // of the called servlet service to get polymorphic calls
+                    // resolved in the right way. We still need to register the
+                    // current context for resolving super calls relative it.
+                    CallStackHelper.enterSuperServlet(ServletServiceContext.this, (HttpServletRequest) request,
+                            wrappedResponse);
+                }
+
+                ServletServiceContext.this.servlet.service(request, wrappedResponse);
+
+                int status = wrappedResponse.getStatusCode();
+                NamedDispatcher _super = (NamedDispatcher) ServletServiceContext.this.getNamedDispatcher(SUPER);
+                if (status == HttpServletResponse.SC_NOT_FOUND && _super != null) {
+                    // if servlet returned NOT_FOUND (404) and has super servlet declared let's reset everything and ask
+                    // the super servlet
+
+                    // wrapping object resets underlying response as well
+                    wrappedResponse.resetBufferedResponse();
+                    // here we don't need to pass wrappedResponse object because it's not our concern to buffer response
+                    // anymore
+                    // this avoids many overlapping buffers
+                    _super.forward(request, response);
+                } else {
+                    wrappedResponse.flushBufferedResponse();
+                }
+            } finally {
+                CallStackHelper.leaveServlet();
+            }
+        }
+
+        public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/BaseServletContextFactoryBean.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/BaseServletContextFactoryBean.java
new file mode 100644
index 0000000..59737e1
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/BaseServletContextFactoryBean.java
@@ -0,0 +1,46 @@
+/*
+ * 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.servletservice.spring;
+
+import org.apache.cocoon.servletservice.CallStackHelper;
+import org.apache.cocoon.servletservice.ServletServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * {@link FactoryBean} that exposes the {@link ServletServiceContext} in the current base call frame.
+ * It will typically be used together with the call scope for servlet services.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public final class BaseServletContextFactoryBean implements FactoryBean {
+
+    public Object getObject() throws Exception {
+        return CallStackHelper.getBaseServletContext();
+    }
+
+    public Class getObjectType() {
+        // A ServletServiceContext rather than a ServletContext is needed to make the
+        // Absolutizable interface available through the ScopedProxyFactoryBean
+        return ServletServiceContext.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletDecorator.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletDecorator.java
new file mode 100644
index 0000000..5745ad6
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletDecorator.java
@@ -0,0 +1,127 @@
+/*
+ * 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.servletservice.spring;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.config.TypedStringValue;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * <p>
+ * This {@link BeanDefinitionDecorator} deals with the
+ * <code>http://cocoon.apache.org/schema/servlet</code> namespace which
+ * defines following elements: <code>context</code> : with optional attributes
+ * <code>mountPath</code> and <code>contextPath</code>. With optional sub
+ * elements <code>init-params", "context-params" and "connections".</p>
+ * <p>
+ * The actual creation of the servlet service (= a bean) is done by {@link ServletFactoryBean}.</p>
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletDecorator implements BeanDefinitionDecorator {
+
+    public BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder holder, ParserContext ctx) {
+        String embeddedServletBeanName = registerEmbeddedServletBean(holder, ctx);
+        return createServletFactoryBeanDefinition((Element) source, holder, ctx, embeddedServletBeanName);
+    }
+
+    private String registerEmbeddedServletBean(BeanDefinitionHolder holder, ParserContext ctx) {
+        String beanName = holder.getBeanName() + "/embedded";
+
+        AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition());
+        ctx.getRegistry().registerBeanDefinition(beanName, definition);
+
+        return beanName;
+    }
+
+    private BeanDefinitionHolder createServletFactoryBeanDefinition(Element source, BeanDefinitionHolder holder,
+                    ParserContext ctx, String embeddedServletBeanName) {
+        String ns = source.getNamespaceURI();
+        if (!source.hasAttribute("mount-path"))
+            throw new RuntimeException("The mount-path attribute is required.");
+        String mountPath = source.getAttribute("mount-path");
+        if (!source.hasAttribute("context-path"))
+            throw new RuntimeException("The context-path attribute is required.");
+        String contextPath = source.getAttribute("context-path");
+
+        Element initParamsElem = (Element) source.getElementsByTagNameNS(ns, "init-params").item(0);
+        Element contextParamsElem = (Element) source.getElementsByTagNameNS(ns, "context-params").item(0);
+        Element connectionsElem = (Element) source.getElementsByTagNameNS(ns, "connections").item(0);
+
+        BeanDefinitionBuilder servletFactoryDefBuilder = BeanDefinitionBuilder
+                        .rootBeanDefinition(ServletFactoryBean.class);
+        servletFactoryDefBuilder.setSource(ctx.extractSource(source));
+        servletFactoryDefBuilder.addPropertyReference("embeddedServlet", embeddedServletBeanName);
+        servletFactoryDefBuilder.setInitMethodName("init");
+        servletFactoryDefBuilder.setDestroyMethodName("destroy");
+        servletFactoryDefBuilder.addPropertyValue("serviceName", holder.getBeanName());
+        //this dependency is needed because JNet must be called manually when init() method is called on servlet
+        //see COCOON-2236
+        servletFactoryDefBuilder.addPropertyReference("urlHandlerFactoryCollector", "org.apache.cocoon.jnet.URLHandlerFactoryCollector");
+
+        servletFactoryDefBuilder.addPropertyValue("mountPath", mountPath);
+        servletFactoryDefBuilder.addPropertyValue("contextPath", contextPath);
+        if (initParamsElem != null) {
+            Map initParams = ctx.getDelegate().parseMapElement(initParamsElem, null);
+            servletFactoryDefBuilder.addPropertyValue("initParams", initParams);
+        }
+        if (contextParamsElem != null) {
+            Map contextParams = ctx.getDelegate().parseMapElement(contextParamsElem, null);
+            servletFactoryDefBuilder.addPropertyValue("contextParams", contextParams);
+        }
+        if (connectionsElem != null) {
+            Map connections = ctx.getDelegate().parseMapElement(connectionsElem, null);
+            servletFactoryDefBuilder.addPropertyValue("connections", connections);
+            Map connectionNames = new HashMap();
+            for (Iterator it = connections.keySet().iterator(); it.hasNext();) {
+                TypedStringValue key = (TypedStringValue) it.next();
+                if (key.getValue().endsWith("+")) {
+                    throw new InvalidBeanReferenceNameException(
+                                    "The key of a servlet connection mustn't use '+' as its last character. "
+                                                    + "This is reserved for absolute references in servlet sources.");
+                }
+                RuntimeBeanReference beanNameReference = (RuntimeBeanReference) connections.get(key);
+                connectionNames.put(key.getValue(), beanNameReference.getBeanName());
+            }
+            servletFactoryDefBuilder.addPropertyValue("connectionServiceNames", connectionNames);
+        }
+
+        return new BeanDefinitionHolder(servletFactoryDefBuilder.getBeanDefinition(), holder.getBeanName());
+    }
+
+    private class InvalidBeanReferenceNameException extends RuntimeException {
+
+        public InvalidBeanReferenceNameException(String message) {
+            super(message);
+        }
+
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletFactoryBean.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletFactoryBean.java
new file mode 100644
index 0000000..bfb53c5
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletFactoryBean.java
@@ -0,0 +1,278 @@
+/*
+ * 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.servletservice.spring;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.cocoon.jnet.URLHandlerFactoryCollector;
+import org.apache.cocoon.servletservice.Mountable;
+import org.apache.cocoon.servletservice.ServletServiceContext;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.support.DefaultIntroductionAdvisor;
+import org.springframework.aop.support.DelegatingIntroductionInterceptor;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.FactoryBeanNotInitializedException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.web.context.ServletContextAware;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletFactoryBean implements FactoryBean, ApplicationContextAware,
+                                           ServletContextAware, BeanNameAware {
+
+    private ApplicationContext parentContainer;
+    private ServletContext servletContext;
+    private String beanName;
+
+    private Servlet embeddedServlet;
+
+    private String mountPath;
+    private String contextPath;
+
+    private Map initParams;
+    private Map contextParams;
+    private Map connections;
+    private Map connectionServiceNames;
+    private String serviceName;
+
+    private ServletServiceContext servletServiceContext;
+    
+    private URLHandlerFactoryCollector urlHandlerFactoryCollector;
+
+    public ServletFactoryBean() {
+    }
+
+    public void init() throws Exception {
+        this.servletServiceContext = new ServletServiceContext();
+        this.servletServiceContext.setServletContext(this.servletContext);
+
+        this.servletServiceContext.setMountPath(this.mountPath);
+
+        this.servletServiceContext.setInitParams(this.initParams);
+        this.servletServiceContext.setAttributes(this.contextParams);
+        this.servletServiceContext.setConnections(this.connections);
+        this.servletServiceContext.setConnectionServiceNames(this.connectionServiceNames);
+        this.servletServiceContext.setServiceName(this.serviceName);
+
+        // create a sub container that resolves paths relative to the servlet
+        // service context rather than the parent context and make it available
+        // in a context attribute
+        if (this.parentContainer == null) {
+            this.parentContainer = WebApplicationContextUtils.getRequiredWebApplicationContext(this.servletContext);
+        }
+
+        // set the context path
+        this.servletServiceContext.setContextPath(this.contextPath);
+
+        // create servlet-service specific Spring web application context
+        GenericWebApplicationContext container = new GenericWebApplicationContext();
+        container.setParent(this.parentContainer);
+        container.setServletContext(this.servletServiceContext);
+        container.refresh();
+        this.servletServiceContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, container);
+
+        // create a servlet config based on the block servlet context
+        ServletConfig blockServletConfig =
+                new ServletConfig() {
+
+                    public String getInitParameter(String name) {
+                        return ServletFactoryBean.this.servletServiceContext.getInitParameter(name);
+                    }
+
+                    public Enumeration getInitParameterNames() {
+                        return ServletFactoryBean.this.servletServiceContext.getInitParameterNames();
+                    }
+
+                    public ServletContext getServletContext() {
+                        return ServletFactoryBean.this.servletServiceContext;
+                    }
+
+                    public String getServletName() {
+                        return ServletFactoryBean.this.beanName;
+                    }
+                };
+
+        // create and initialize the embedded servlet
+        try {
+            //manual call to pushUrlHandlerFactories is needed due to issue COCOON-2236
+            urlHandlerFactoryCollector.pushUrlHandlerFactories();
+            this.embeddedServlet.init(blockServletConfig);
+        } finally {
+            urlHandlerFactoryCollector.popUrlHandlerFactories();
+        }
+        
+        this.servletServiceContext.setServlet(this.embeddedServlet);
+    }
+
+    public void destroy() {
+        this.embeddedServlet.destroy();
+    }
+
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.parentContainer = applicationContext;
+    }
+
+    public void setServletContext(ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
+
+    public void setBeanName(String beanName) {
+        this.beanName = beanName;
+    }
+
+    /**
+     * @param embeddedServlet the embeddedServlet to set
+     */
+    public void setEmbeddedServlet(Servlet embeddedServlet) {
+        this.embeddedServlet = embeddedServlet;
+    }
+
+    /**
+     * @param mountPath
+     */
+    public void setMountPath(String mountPath) {
+        this.mountPath = mountPath;
+    }
+
+    /**
+     * The path to the blocks resources relative to the servlet context URL,
+     * must start with an '/'.
+     * @param contextPath
+     */
+    public void setContextPath(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    /**
+     * @param initParams
+     */
+    public void setInitParams(Map initParams) {
+        this.initParams = initParams;
+    }
+
+    /**
+     * @param contextParams the contextParams to set
+     */
+    public void setContextParams(Map contextParams) {
+        this.contextParams = contextParams;
+    }
+
+    /**
+     * @param connections
+     */
+    public void setConnections(Map connections) {
+        this.connections = connections;
+    }
+
+    /**
+     * @param connectionServiceNames
+     */
+    public void setConnectionServiceNames(Map connectionServiceNames) {
+        this.connectionServiceNames = connectionServiceNames;
+    }
+
+    public void setServiceName(String name) {
+        this.serviceName = name;
+    }
+
+    public Object getObject() throws Exception {
+        if (this.embeddedServlet == null) {
+            throw new FactoryBeanNotInitializedException("There might be a circular dependency inside the servlet connections.");
+        }
+        ProxyFactory proxyFactory = new ProxyFactory(this.embeddedServlet);
+        proxyFactory.addAdvice(new ServiceInterceptor());
+        if (this.mountPath != null) {
+            proxyFactory.addAdvisor(new MountableMixinAdvisor());
+        }
+        return proxyFactory.getProxy();
+    }
+
+    public Class getObjectType() {
+        if (this.embeddedServlet == null) {
+            //if embeddedServlet is null we don't know exactly what ObjectType this Factory will return but at least
+            //we are sure it is a class implementing Servlet interface so it's better to return it instead of null
+            return Servlet.class;
+        }
+
+        return this.embeddedServlet != null ? this.embeddedServlet.getClass() : null;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    private class ServiceInterceptor implements MethodInterceptor {
+
+        public Object invoke(MethodInvocation invocation) throws Throwable {
+            if ("service".equals(invocation.getMethod().getName())) {
+                Object[] arguments = invocation.getArguments();
+                HttpServletRequest request = (HttpServletRequest) arguments[0];
+                HttpServletResponse response = (HttpServletResponse) arguments[1];
+                RequestDispatcher dispatcher =
+                        ServletFactoryBean.this.servletServiceContext.getRequestDispatcher(request.getPathInfo());
+                dispatcher.forward(request, response);
+                return null;
+            } else if ("init".equals(invocation.getMethod().getName())) {
+                // The embedded servlet is initialized by this factory bean, ignore other containers
+                return null;
+            } else if ("destroy".equals(invocation.getMethod().getName())) {
+                // The embedded servlet is destroyed up by this factory bean, ignore other containers
+                return null;
+            }
+
+            return invocation.proceed();
+        }
+    }
+
+    private class MountableMixin extends DelegatingIntroductionInterceptor
+                                 implements Mountable {
+
+        public String getMountPath() {
+            return ServletFactoryBean.this.mountPath;
+        }
+    }
+
+    private class MountableMixinAdvisor extends DefaultIntroductionAdvisor {
+
+        public MountableMixinAdvisor() {
+            super(new MountableMixin(), Mountable.class);
+        }
+    }
+
+    public void setUrlHandlerFactoryCollector(URLHandlerFactoryCollector urlHandlerFactoryCollector) {
+        this.urlHandlerFactoryCollector = urlHandlerFactoryCollector;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletNamespaceHandler.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletNamespaceHandler.java
new file mode 100644
index 0000000..5cbe6a4
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/spring/ServletNamespaceHandler.java
@@ -0,0 +1,38 @@
+/*
+ * 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.servletservice.spring;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+/**
+ * <p>
+ * Spring namespace handler for the Cocoon servlet namespace (<code>http://cocoon.apache.org/schema/servlet</code>).
+ * The {@link ServletDecorator} deals with the implementation details.
+ *
+ * @version $Id: ServletNamespaceHandler.java 562806 2007-08-05 02:26:41Z
+ *          vgritsenko $
+ * @since 1.0.0
+ */
+public class ServletNamespaceHandler extends NamespaceHandlerSupport {
+
+    public void init() {
+        registerBeanDefinitionDecorator("context", new ServletDecorator());
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLConnection.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLConnection.java
new file mode 100644
index 0000000..b541da6
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLConnection.java
@@ -0,0 +1,247 @@
+/*
+ * 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.servletservice.url;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.ServletException;
+
+import org.apache.cocoon.servletservice.AbsoluteServletConnection;
+import org.apache.cocoon.servletservice.Absolutizable;
+import org.apache.cocoon.servletservice.CallStackHelper;
+import org.apache.cocoon.servletservice.NoCallingServletServiceRequestAvailableException;
+import org.apache.cocoon.servletservice.ServletConnection;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ServletURLConnection extends HttpURLConnection {
+
+    private final ServletConnection servletConnection;
+
+    private final URL url;
+
+    private final Log logger = LogFactory.getLog(this.getClass());
+
+    protected ServletURLConnection(URL url) throws URISyntaxException {
+        super(url);
+
+        this.url = url;
+
+        URI locationUri = null;
+        String query = url.getQuery();
+        if (query != null) {
+            locationUri = new URI(url.getPath() + "?" + url.getQuery());
+        } else {
+            locationUri = new URI(url.getPath());
+        }
+
+        final String servletReference = locationUri.getScheme();
+        final Absolutizable absolutizable = (Absolutizable) CallStackHelper.getCurrentServletContext();
+        final String servletName;
+
+        // find out the type of the reference and create a service name
+        if (servletReference == null) {
+            // self-reference
+            if (absolutizable == null) {
+                throw new NoCallingServletServiceRequestAvailableException(
+                        "A self-reference requires an active servlet request.");
+            }
+
+            servletName = absolutizable.getServiceName();
+        } else if (servletReference.endsWith(AbsoluteServletConnection.ABSOLUTE_SERVLET_SOURCE_POSTFIX)) {
+            // absolute reference
+            servletName = servletReference.substring(0, servletReference.length() - 1);
+        } else {
+            // relative reference
+            if (absolutizable == null) {
+                throw new NoCallingServletServiceRequestAvailableException(
+                        "A relative servlet call requires an active servlet request.");
+            }
+
+            servletName = absolutizable.getServiceName(servletReference);
+        }
+
+        this.servletConnection = new AbsoluteServletConnection(servletName, locationUri.getRawPath(), locationUri
+                .getRawQuery());
+        this.servletConnection.setIfModifiedSince(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#connect()
+     */
+    @Override
+    public void connect() throws IOException {
+        try {
+            if (this.connected) {
+                return;
+            }
+
+            this.servletConnection.connect();
+
+            this.connected = true;
+        } catch (ServletException e) {
+            IOException ioException = new IOException("Can't connect to servlet URL " + this.url + ".");
+            ioException.initCause(e);
+            throw ioException;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.HttpURLConnection#getErrorStream()
+     */
+    @Override
+    public InputStream getErrorStream() {
+        if (!this.connected) {
+            return null;
+        }
+
+        try {
+            return this.servletConnection.getInputStream();
+        } catch (Exception e) {
+            this.logger.warn(e);
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#getInputStream()
+     */
+    @Override
+    public InputStream getInputStream() throws IOException {
+        try {
+            this.connect();
+
+            return this.servletConnection.getInputStream();
+        } catch (ServletException e) {
+            IOException ioException = new IOException("Can't read from servlet URL " + this.url + ".");
+            ioException.initCause(e);
+            throw ioException;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#getLastModified()
+     */
+    @Override
+    public long getLastModified() {
+        try {
+            this.connect();
+        } catch (IOException e) {
+            return 0;
+        }
+
+        return this.servletConnection.getLastModified();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#getOutputStream()
+     */
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        return this.servletConnection.getOutputStream();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#getContentType()
+     */
+    @Override
+    public String getContentType() {
+        return this.servletConnection.getContentType();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.HttpURLConnection#getResponseCode()
+     */
+    @Override
+    public int getResponseCode() {
+        try {
+            this.connect();
+
+            return this.servletConnection.getResponseCode();
+        } catch (IOException e) {
+            return 500;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.HttpURLConnection#disconnect()
+     */
+    @Override
+    public void disconnect() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.HttpURLConnection#usingProxy()
+     */
+    @Override
+    public boolean usingProxy() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.net.URLConnection#getHeaderFields()
+     */
+    @Override
+    public Map<String, List<String>> getHeaderFields() {
+        Map<String, List<String>> result = new HashMap<String, List<String>>();
+
+        Map<String, String> headers = this.servletConnection.getHeaders();
+        for (Entry<String, String> eachHeader : headers.entrySet()) {
+            List<String> values = new ArrayList<String>();
+            values.add(eachHeader.getValue());
+            result.put(eachHeader.getKey(), Collections.unmodifiableList(values));
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+}
\ No newline at end of file
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandler.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandler.java
new file mode 100644
index 0000000..bc86771
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandler.java
@@ -0,0 +1,37 @@
+/*
+ * 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.servletservice.url;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+public class ServletURLStreamHandler extends URLStreamHandler {
+
+    protected URLConnection openConnection(URL url) throws IOException {
+        try {
+            return new ServletURLConnection(url);
+        } catch (Throwable e) {
+            IOException ioException = new IOException("Can't create ServletURLConnection " + url + ".");
+            ioException.initCause(e);
+            throw ioException;
+        }
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandlerFactory.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandlerFactory.java
new file mode 100644
index 0000000..091f605
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/url/ServletURLStreamHandlerFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.servletservice.url;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+
+public class ServletURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
+     */
+    public URLStreamHandler createURLStreamHandler(String protocol) {
+        if ("servlet".equalsIgnoreCase(protocol)) {
+            return new ServletURLStreamHandler();
+        }
+
+        return null;
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/NullServletInputStream.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/NullServletInputStream.java
new file mode 100644
index 0000000..2aed563
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/NullServletInputStream.java
@@ -0,0 +1,37 @@
+/*
+ * 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.servletservice.util;
+
+import javax.servlet.ServletInputStream;
+
+import java.io.IOException;
+
+/**
+ * Always empty stream.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class NullServletInputStream extends ServletInputStream {
+
+    public static final NullServletInputStream INSTANCE = new NullServletInputStream();
+
+    public int read() throws IOException {
+        return -1;
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/RequestParameters.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/RequestParameters.java
new file mode 100644
index 0000000..88656d4
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/RequestParameters.java
@@ -0,0 +1,231 @@
+/*
+ * 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.servletservice.util;
+
+import org.apache.commons.collections.iterators.IteratorEnumeration;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This class is used by the <code>RequestWrapper</code>. It parses
+ * a query string, decodes request parameters, and creates a parameter map
+ * ready for use by the <code>Request</code> object.
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public final class RequestParameters implements Serializable {
+
+    /**
+     * The parameter names are the keys and the value is a String array object
+     */
+    private final Map values;
+
+    /**
+     * Construct a new object from a queryString
+     *
+     * @param queryString request query string
+     */
+    public RequestParameters(String queryString) {
+        this.values = new HashMap(5);
+
+        if (queryString != null) {
+            StringTokenizer st = new StringTokenizer(queryString, "&");
+            while (st.hasMoreTokens()) {
+                String pair = st.nextToken();
+                int pos = pair.indexOf('=');
+                if (pos != -1) {
+                    setParameter(decode(pair.substring(0, pos)),
+                                 decode(pair.substring(pos + 1, pair.length())));
+                } else {
+                    setParameter(decode(pair), "");
+                }
+            }
+        }
+    }
+
+    /**
+     * Add a parameter.
+     * The parameter is added with the given value.
+     *
+     * @param name   The name of the parameter.
+     * @param value  The value of the parameter.
+     */
+    private void setParameter(String name, String value) {
+        String[] values = (String[]) this.values.get(name);
+        if (values == null) {
+            values = new String[] { value };
+        } else {
+            String[] v2 = new String[values.length + 1];
+            System.arraycopy(values, 0, v2, 0, values.length);
+            v2[values.length] = value;
+            values = v2;
+        }
+
+        this.values.put(name, values);
+    }
+
+    /**
+     * Get the value of a parameter.
+     *
+     * @param name   The name of the parameter.
+     * @return       The value of the first parameter with the name
+     *               or <CODE>null</CODE>
+     */
+    public String getParameter(String name) {
+        String[] values = (String[]) this.values.get(name);
+        if (values != null) {
+            return values[0];
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the value of a parameter.
+     *
+     * @param name   The name of the parameter.
+     * @param defaultValue The default value if the parameter does not exist.
+     * @return       The value of the first parameter with the name
+     *               or <CODE>defaultValue</CODE>
+     */
+    public String getParameter(String name, String defaultValue) {
+        String[] values = (String[]) this.values.get(name);
+        if (values != null) {
+            return values[0];
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Get all values of a parameter.
+     *
+     * @param name   The name of the parameter.
+     * @return       Array of the (String) values or null if the parameter
+     *               is not defined.
+     */
+    public String[] getParameterValues(String name) {
+        return (String[]) values.get(name);
+    }
+
+    /**
+     * Get all parameter names.
+     *
+     * @return  Enumeration for the (String) parameter names.
+     */
+    public Enumeration getParameterNames() {
+        return new IteratorEnumeration(values.keySet().iterator());
+    }
+
+    /**
+     * Get map of parameter names to String array values
+     *
+     * @return map of parameter values
+     */
+    public Map getParameterMap() {
+        return Collections.unmodifiableMap(values);
+    }
+
+    /**
+     * Decodes URL encoded string. Supports decoding of '+', '%XX' encoding,
+     * and '%uXXXX' encoding.
+     *
+     * @param s URL encoded string
+     * @return decoded string
+     */
+    private static String decode(String s) {
+        byte[] decoded = new byte[s.length() / 3 + 1];
+        int decodedLength = 0;
+
+        final int length = s.length();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < length; ) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '+':
+                    sb.append(' ');
+                    i++;
+                    break;
+
+                case '%':
+                    // Check if this is a non-standard %u9999 encoding
+                    // (see COCOON-1950)
+                    try {
+                        if (s.charAt(i + 1) == 'u') {
+                            sb.append((char) Integer.parseInt(s.substring(i + 2, i + 6), 16));
+                            i += 6;
+                            break;
+                        }
+                    } catch (NumberFormatException e) {
+                        throw new IllegalArgumentException("Invalid query string. " +
+                                                           "Illegal hex characters in pattern %" + s.substring(i + 1, i + 6));
+                    } catch (StringIndexOutOfBoundsException e) {
+                        throw new IllegalArgumentException("Invalid query string. " +
+                                                           "% character should be followed by 2 hexadecimal characters.");
+                    }
+
+                    // Process sequence of %XX encoded bytes in one go since several bytes can represent
+                    // single character.
+                    while (i < length && s.charAt(i) == '%') {
+                        if (i + 2 >= length) {
+                            throw new IllegalArgumentException("Invalid query string. " +
+                                                               "% character should be followed by 2 hexadecimal characters.");
+                        }
+
+                        // If found %u9999, rollback '%' and finish this loop
+                        if (s.charAt(i + 1) == 'u') {
+                            i--;
+                            break;
+                        }
+
+                        try {
+                            decoded[decodedLength++] = (byte) Integer.parseInt(s.substring(i + 1, i + 3), 16);
+                        } catch (NumberFormatException e) {
+                            throw new IllegalArgumentException("Invalid query string. " +
+                                                               "Illegal hex characters in pattern %" + s.substring(i + 1, i + 3));
+                        }
+                        i += 3;
+                    }
+                    if (decodedLength > 0) {
+                        try {
+                            sb.append(new String(decoded, 0, decodedLength, "UTF-8"));
+                        } catch (UnsupportedEncodingException e) {
+                            // The situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception
+                            throw new RuntimeException("Problem in decode: UTF-8 encoding not supported.");
+                        }
+                        decodedLength = 0;
+                    }
+
+                    break;
+
+                default:
+                    sb.append(c);
+                    i++;
+                    break;
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletConfigurationWrapper.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletConfigurationWrapper.java
new file mode 100644
index 0000000..12a4ff5
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletConfigurationWrapper.java
@@ -0,0 +1,69 @@
+/*
+ * 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.servletservice.util;
+
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+/**
+ *
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletConfigurationWrapper implements ServletConfig {
+
+    protected ServletConfig servletConfig;
+
+    protected ServletContext servletContext;
+
+    /**
+     * @param servletConfig
+     */
+    public ServletConfigurationWrapper(ServletConfig servletConfig) {
+        this(servletConfig, null);
+    }
+
+    /**
+     * @param servletConfig
+     * @param servletContext
+     */
+    public ServletConfigurationWrapper(ServletConfig servletConfig,
+                                       ServletContext servletContext) {
+        this.servletConfig = servletConfig;
+        this.servletContext = servletContext;
+    }
+
+    public String getServletName() {
+        return this.servletConfig.getServletName();
+    }
+
+    public ServletContext getServletContext() {
+        return this.servletContext != null ? this.servletContext
+                : this.servletConfig.getServletContext();
+    }
+
+    public String getInitParameter(String name) {
+        return this.servletConfig.getInitParameter(name);
+    }
+
+    public Enumeration getInitParameterNames() {
+        return this.servletConfig.getInitParameterNames();
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletContextWrapper.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletContextWrapper.java
new file mode 100644
index 0000000..ebca9aa
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletContextWrapper.java
@@ -0,0 +1,141 @@
+/*
+ * 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.servletservice.util;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Set;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+/**
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletContextWrapper implements ServletContext {
+
+    protected ServletContext servletContext;
+
+    /**
+     * @param servletContext The servletContext to set.
+     */
+    public void setServletContext(ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
+
+    public ServletContext getContext(String uripath) {
+        return this.servletContext.getContext(uripath);
+    }
+
+    public int getMajorVersion() {
+        return this.servletContext.getMajorVersion();
+    }
+
+    public int getMinorVersion() {
+        return this.servletContext.getMinorVersion();
+    }
+
+    public String getMimeType(String file) {
+        return this.servletContext.getMimeType(file);
+    }
+
+    public Set getResourcePaths(String paths) {
+        return this.servletContext.getResourcePaths(paths);
+    }
+
+    public URL getResource(String path) throws MalformedURLException {
+        return this.servletContext.getResource(path);
+    }
+
+    public InputStream getResourceAsStream(String path) {
+        return this.servletContext.getResourceAsStream(path);
+    }
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return this.servletContext.getRequestDispatcher(path);
+    }
+
+    public RequestDispatcher getNamedDispatcher(String name) {
+        return this.servletContext.getNamedDispatcher(name);
+    }
+
+    public Servlet getServlet(String name) throws ServletException {
+        return this.servletContext.getServlet(name);
+    }
+
+    public Enumeration getServlets() {
+        return this.servletContext.getServlets();
+    }
+
+    public Enumeration getServletNames() {
+        return this.servletContext.getServletNames();
+    }
+
+    public void log(String msg) {
+        this.servletContext.log(msg);
+    }
+
+    public void log(Exception exception, String msg) {
+        this.servletContext.log(exception, msg);
+    }
+
+    public void log(String msg, Throwable throwable) {
+        this.servletContext.log(msg, throwable);
+    }
+
+    public String getRealPath(String path) {
+        return this.servletContext.getRealPath(path);
+    }
+
+    public String getServerInfo() {
+        return this.servletContext.getServerInfo();
+    }
+
+    public String getInitParameter(String path) {
+        return this.servletContext.getInitParameter(path);
+    }
+
+    public Enumeration getInitParameterNames() {
+        return this.servletContext.getInitParameterNames();
+    }
+
+    public Object getAttribute(String name) {
+        return this.servletContext.getAttribute(name);
+    }
+
+    public Enumeration getAttributeNames() {
+        return this.servletContext.getAttributeNames();
+    }
+
+    public void setAttribute(String name, Object value) {
+        this.servletContext.setAttribute(name, value);
+    }
+
+    public void removeAttribute(String name) {
+        this.servletContext.removeAttribute(name);
+    }
+
+    public String getServletContextName() {
+        return this.servletContext.getServletContextName();
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceRequest.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceRequest.java
new file mode 100644
index 0000000..30877d0
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceRequest.java
@@ -0,0 +1,835 @@
+/*
+ * 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.servletservice.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.security.Principal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+import org.apache.cocoon.callstack.CallFrame;
+import org.apache.cocoon.callstack.CallStack;
+import org.apache.cocoon.callstack.environment.CallFrameHelper;
+import org.apache.cocoon.servletservice.ServletServiceContext;
+import org.apache.commons.collections.iterators.IteratorEnumeration;
+
+/**
+ * <p>
+ * Create a {@link HttpServletRequest} from an URL, that is used while calling e.g. a
+ * servlet service. The current implementation forwards headers, attributes and
+ * parameters.
+ * </p>
+ *
+ * @version $Id: BlockCallHttpServletRequest.java 577519 2007-09-20 03:05:26Z
+ *          vgritsenko $
+ * @since 1.0.0
+ */
+public class ServletServiceRequest implements HttpServletRequest {
+
+    /**
+     * Protocol of block call requests.
+     */
+    private static final String PROTOCOL = "HTTP/1.1";
+
+    /**
+     * Date header format definied by RFC 822, see
+     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
+     */
+    private final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
+
+    /**
+     * The <code>parentRequest</code> holds reference to the request object
+     * that makes a servlet call.
+     */
+    private HttpServletRequest parentRequest;
+
+    /**
+     * Block call request URI
+     */
+    private final URI uri;
+
+    /**
+     * Request method. If not set via {@link #setMethod(String)}, defaults to
+     * <code>GET</code>.
+     */
+    private String method;
+
+    /**
+     * Request headers map
+     */
+    private final Headers headers;
+
+    /**
+     * Request character encoding.
+     */
+    private String encoding;
+
+    /**
+     * Length of the request body.
+     */
+    private int contentLength;
+
+    /**
+     * Request body.
+     */
+    private ServletInputStream content;
+
+    /**
+     * Request attributes map.
+     */
+    private final Attributes attributes;
+
+    private Parameters parameters;
+
+    private ServletServiceContext context;
+
+    /**
+     * @param uri
+     *            points to the called servlet
+     * @param parentRequest
+     *            reference to the request object that makes a servlet call
+     */
+    public ServletServiceRequest(URI uri, HttpServletRequest parentRequest) {
+        this.parentRequest = parentRequest;
+        this.uri = uri;
+        this.headers = new Headers();
+        this.method = "GET";
+        this.contentLength = -1;
+        this.content = NullServletInputStream.INSTANCE;
+        this.attributes = new Attributes();
+        this.parameters = new Parameters();
+    }
+
+    public String getProtocol() {
+        return PROTOCOL;
+    }
+
+    public String getMethod() {
+        return this.method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    //
+    // Request URI parts
+    //
+
+    public String getScheme() {
+        return this.uri.getScheme();
+    }
+
+    public String getServerName() {
+        return this.parentRequest.getServerName();
+    }
+
+    public int getServerPort() {
+        return this.parentRequest.getServerPort();
+    }
+
+    public String getContextPath() {
+        return this.parentRequest.getContextPath();
+    }
+
+    public String getServletPath() {
+        // TODO Is this right?
+        return "";
+    }
+
+    public String getPathInfo() {
+        return this.uri.getPath();
+    }
+
+    public String getPathTranslated() {
+        // TODO This is legal but more info might be possible
+        return null;
+    }
+
+    public String getQueryString() {
+        return this.uri.getQuery();
+    }
+
+    public String getRequestURI() {
+        // TODO Is this right?
+        return this.getContextPath() + this.getServletPath() + this.getPathInfo();
+    }
+
+    public StringBuffer getRequestURL() {
+        return new StringBuffer(this.getScheme()).append(':').append(this.getRequestURI());
+    }
+
+    //
+    // Request headers
+    //
+
+    public String getHeader(String name) {
+        return (String) this.headers.getValue(name);
+    }
+
+    public Enumeration getHeaders(String name) {
+        return this.headers.getNames();
+    }
+
+    public void setHeader(String name, String value) {
+        this.headers.setValue(name, value);
+    }
+
+    public long getDateHeader(String name) {
+        String header = this.getHeader(name);
+        if (header == null) {
+            return -1;
+        }
+
+        try {
+            return this.dateFormat.parse(header).getTime();
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void setDateHeader(String name, long date) {
+        this.setHeader(name, this.dateFormat.format(new Date(date)));
+    }
+
+    public int getIntHeader(String name) {
+        String header = this.getHeader(name);
+        if (header == null) {
+            return -1;
+        }
+
+        return Integer.parseInt(header);
+    }
+
+    public void setIntHeader(String name, int value) {
+        this.setHeader(name, String.valueOf(value));
+    }
+
+    public Enumeration getHeaderNames() {
+        return this.headers.getNames();
+    }
+
+    //
+    // Request parameters
+    //
+
+    public String getParameter(String name) {
+        return (String) this.parameters.getValue(name);
+    }
+
+    public String[] getParameterValues(String name) {
+        return this.parameters.getValues(name);
+    }
+
+    public Enumeration getParameterNames() {
+        return this.parameters.getNames();
+    }
+
+    public Map getParameterMap() {
+        return this.parameters.getValues();
+    }
+
+    //
+    // Request body
+    //
+
+    public String getCharacterEncoding() {
+        return this.encoding;
+    }
+
+    public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException {
+        this.encoding = encoding;
+    }
+
+    public int getContentLength() {
+        return this.contentLength;
+    }
+
+    public void setContentLength(int contentLength) {
+        this.contentLength = contentLength;
+    }
+
+    /*
+     * TODO Doesn't handle input streams yet
+     */
+    public String getContentType() {
+        return null;
+    }
+
+    public ServletInputStream getInputStream() throws IOException {
+        return this.content;
+    }
+
+    public void setInputStream(final InputStream inputStream) {
+        try {
+            this.contentLength = inputStream.available();
+        } catch (IOException e) {
+            this.contentLength = -1;
+        }
+
+        this.content = new ServletInputStream() {
+            public int read() throws IOException {
+                return inputStream.read();
+            }
+        };
+    }
+
+    public BufferedReader getReader() throws IOException {
+        Reader reader;
+        String encoding = this.getCharacterEncoding();
+        if (encoding == null) {
+            reader = new InputStreamReader(this.getInputStream());
+        } else {
+            reader = new InputStreamReader(this.getInputStream(), encoding);
+        }
+
+        return new BufferedReader(reader);
+    }
+
+    //
+    // Request attributes
+    //
+
+    public Object getAttribute(String name) {
+        return this.attributes.getValue(name);
+    }
+
+    public Enumeration getAttributeNames() {
+        return this.attributes.getNames();
+    }
+
+    public void setAttribute(String name, Object value) {
+        if (value != null) {
+            this.attributes.setValue(name, value);
+        } else {
+            this.removeAttribute(name);
+        }
+    }
+
+    public void removeAttribute(String name) {
+        this.attributes.remove(name);
+    }
+
+    public String getAuthType() {
+        return null;
+    }
+
+    public Cookie[] getCookies() {
+        return this.parentRequest.getCookies();
+    }
+
+    public Locale getLocale() {
+        return this.parentRequest.getLocale();
+    }
+
+    public Enumeration getLocales() {
+        return this.parentRequest.getLocales();
+    }
+
+    /**
+     * @deprecated
+     * @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
+     */
+    public String getRealPath(String path) {
+        return null;
+    }
+
+    public String getRemoteAddr() {
+        return this.parentRequest.getRemoteAddr();
+    }
+
+    public String getRemoteHost() {
+        return this.parentRequest.getRemoteHost();
+    }
+
+    public String getRemoteUser() {
+        return this.parentRequest.getRemoteUser();
+    }
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return this.context.getRequestDispatcher(path);
+    }
+
+
+    public String getRequestedSessionId() {
+        return this.parentRequest.getRequestedSessionId();
+    }
+
+    public HttpSession getSession() {
+        Session session = (Session) this.getSession(true);
+        session.setRequest(this);
+        return session;
+    }
+
+    public HttpSession getSession(boolean create) {
+
+        HttpServletRequest request = this.parentRequest;
+        while (request != null) {
+            if (request instanceof ServletServiceRequest) {
+                request = ((ServletServiceRequest) request).parentRequest;
+            } else {
+                break;
+            }
+        }
+        HttpSession outestSession = request.getSession();
+        Session session = null;
+        // each block's session object is stored in the outest session as an
+        // attribute
+        if (this != request) {
+            session = (Session) outestSession.getAttribute(HttpSession.class + "_" + this.context.getMountPath());
+        } else {
+            session = (Session) outestSession;
+        }
+
+        if (session == null && create) {
+            session = new Session(this.context);
+            outestSession.setAttribute(HttpSession.class + "_" + this.context.getMountPath(), session);
+        }
+
+        if (session != null) {
+            session.setRequest(this);
+        }
+
+        return session;
+    }
+
+    public void setContext(ServletContext context) {
+        this.context = (ServletServiceContext) context;
+    }
+
+    public Principal getUserPrincipal() {
+        return this.parentRequest.getUserPrincipal();
+    }
+
+    public boolean isRequestedSessionIdFromCookie() {
+        return this.parentRequest.isRequestedSessionIdFromCookie();
+    }
+
+    public boolean isRequestedSessionIdFromUrl() {
+        return this.isRequestedSessionIdFromURL();
+    }
+
+    public boolean isRequestedSessionIdFromURL() {
+        return this.parentRequest.isRequestedSessionIdFromURL();
+    }
+
+    public boolean isRequestedSessionIdValid() {
+        return this.parentRequest.isRequestedSessionIdValid();
+    }
+
+    public boolean isSecure() {
+        return this.parentRequest.isSecure();
+    }
+
+    public boolean isUserInRole(String role) {
+        return this.parentRequest.isUserInRole(role);
+    }
+
+    public String getLocalAddr() {
+        return this.parentRequest.getLocalAddr();
+    }
+
+    public String getLocalName() {
+        return this.parentRequest.getLocalName();
+    }
+
+    public int getLocalPort() {
+        return this.parentRequest.getLocalPort();
+    }
+
+    public int getRemotePort() {
+        return this.parentRequest.getRemotePort();
+    }
+
+    private abstract static class Values implements Serializable {
+
+        /** The parameter names are the keys and the value is a List object */
+        Map values = new HashMap();
+
+        public Values() {
+        }
+
+        protected void setValue(String name, Object value) {
+            List list;
+            if (this.values.containsKey(name)) {
+                list = (List) this.values.get(name);
+            } else {
+                list = new ArrayList();
+                this.values.put(name, list);
+            }
+            list.add(value);
+        }
+
+        public Object getValue(String name) {
+            if (this.values.containsKey(name)) {
+                return ((List) this.values.get(name)).get(0);
+            }
+
+            return this.getValueOfCaller(name);
+        }
+
+        protected abstract Object getValueOfCaller(String name);
+
+        protected abstract Enumeration namesOf(HttpServletRequest request);
+
+        public Enumeration getNames() {
+            Set names = new HashSet();
+            for (int i = 0; i < CallStack.size(); i++) {
+                CallFrame frame = CallStack.frameAt(i);
+                HttpServletRequest request = (HttpServletRequest) frame.getAttribute(CallFrameHelper.REQUEST_OBJECT);
+                if (request instanceof ServletServiceRequest) {
+                    names.addAll(this.values.keySet());
+                } else {
+                    for (Enumeration enumeration = this.namesOf(request); enumeration.hasMoreElements();) {
+                        names.add(enumeration.nextElement());
+                    }
+                }
+                if (request.equals(this.getRequest())) {
+                    break;
+                }
+            }
+
+            return new EnumerationFromIterator(names.iterator());
+        }
+
+        protected abstract ServletServiceRequest getRequest();
+
+        final class EnumerationFromIterator implements Enumeration {
+
+            private Iterator iterator;
+
+            EnumerationFromIterator(Iterator iter) {
+                this.iterator = iter;
+            }
+
+            public boolean hasMoreElements() {
+                return this.iterator.hasNext();
+            }
+
+            public Object nextElement() {
+                return this.iterator.next();
+            }
+        }
+
+    }
+
+    private class Parameters extends Values {
+
+        public Parameters() {
+            if (this.getRequest().uri.getQuery() != null) {
+                StringTokenizer st = new StringTokenizer(this.getRequest().uri.getQuery(), "&");
+                while (st.hasMoreTokens()) {
+                    String pair = st.nextToken();
+                    int pos = pair.indexOf('=');
+                    if (pos != -1) {
+                        this.setValue(this.parseName(pair.substring(0, pos)), this.parseName(pair.substring(pos + 1,
+                                        pair.length())));
+                    }
+                }
+            }
+        }
+
+        private String parseName(String s) {
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < s.length(); i++) {
+                char c = s.charAt(i);
+                switch (c) {
+                case '+':
+                    sb.append(' ');
+                    break;
+                case '%':
+                    try {
+                        if (s.charAt(i + 1) == 'u') {
+                            // working with multi-byte symbols in format %uXXXX
+                            sb.append((char) Integer.parseInt(s.substring(i + 2, i + 6), 16));
+                            i += 5; // 4 digits and 1 symbol u
+                        } else {
+                            // working with single-byte symbols in format %YY
+                            sb.append((char) Integer.parseInt(s.substring(i + 1, i + 3), 16));
+                            i += 2;
+                        }
+                    } catch (NumberFormatException e) {
+                        IllegalArgumentException iae = new IllegalArgumentException();
+                        iae.initCause(e);
+                        throw iae;
+                    } catch (StringIndexOutOfBoundsException e) {
+                        String rest = s.substring(i);
+                        sb.append(rest);
+                        if (rest.length() == 2) {
+                            i++;
+                        }
+                    }
+
+                    break;
+                default:
+                    sb.append(c);
+                    break;
+                }
+            }
+            return sb.toString();
+        }
+
+        public Map getValues() {
+            Map result = new HashMap();
+            for (int i = 0; i < CallStack.size(); i++) {
+                CallFrame frame = CallStack.frameAt(i);
+                HttpServletRequest request = (HttpServletRequest) frame.getAttribute(CallFrameHelper.REQUEST_OBJECT);
+                if (request instanceof ServletServiceRequest) {
+                    result.putAll(this.values);
+                } else {
+                    result.putAll(request.getParameterMap());
+                }
+                if (request.equals(this.getRequest())) {
+                    break;
+                }
+            }
+
+            return result;
+        }
+
+        public String[] getValues(String name) {
+            List list = (List) this.values.get(name);
+            if (list == null) {
+                return null;
+            }
+
+            String[] result = new String[list.size()];
+            for (int i = 0; i < list.size(); i++) {
+                result[i] = (String) list.get(i);
+            }
+            return result;
+        }
+
+        protected ServletServiceRequest getRequest() {
+            return ServletServiceRequest.this;
+        }
+
+        protected Object getValueOfCaller(String name) {
+            return this.getRequest().parentRequest.getParameter(name);
+        }
+
+        protected Enumeration namesOf(HttpServletRequest request) {
+            return request.getParameterNames();
+        }
+
+    }
+
+    private class Headers extends Values {
+
+        public Object getValueOfCaller(String name) {
+            return this.getRequest().parentRequest.getHeader(name);
+        }
+
+        public Enumeration getValues(String name) {
+            List list = (List) this.values.get(name);
+            if (list == null) {
+                return new Enumeration() {
+
+                    public boolean hasMoreElements() {
+                        return false;
+                    }
+
+                    public Object nextElement() {
+                        throw new NoSuchElementException();
+                    }
+
+                };
+            }
+
+            return new IteratorEnumeration(list.iterator());
+        }
+
+        protected ServletServiceRequest getRequest() {
+            return ServletServiceRequest.this;
+        }
+
+        protected Enumeration namesOf(HttpServletRequest request) {
+            return request.getHeaderNames();
+        }
+    }
+
+    private class Attributes extends Values {
+
+        public Object getValue(String name) {
+            if (this.values.containsKey(name)) {
+                return this.values.get(name);
+            }
+
+            return this.getValueOfCaller(name);
+        }
+
+        public Object getValueOfCaller(String name) {
+            return this.getRequest().parentRequest.getAttribute(name);
+        }
+
+        protected void setValue(String name, Object value) {
+            this.values.put(name, value);
+        }
+
+        public void remove(String name) {
+            if (this.values.containsKey(name)) {
+                this.values.remove(name);
+            } else {
+                this.getRequest().parentRequest.removeAttribute(name);
+            }
+        }
+
+        protected ServletServiceRequest getRequest() {
+            return ServletServiceRequest.this;
+        }
+
+        protected Enumeration namesOf(HttpServletRequest request) {
+            return request.getAttributeNames();
+        }
+
+    }
+
+    private static class Session extends Values implements HttpSession {
+
+        private ServletServiceContext context;
+
+        private transient ServletServiceRequest request;
+
+        public Session(ServletServiceContext context) {
+            this.context = context;
+        }
+
+        protected Object getValueOfCaller(String name) {
+            return this.getRequest().parentRequest.getSession().getAttribute(name);
+        }
+
+        protected Enumeration namesOf(HttpServletRequest request) {
+            return this.getRequest().parentRequest.getSession().getAttributeNames();
+        }
+
+        protected ServletServiceRequest getRequest() {
+            return this.request;
+        }
+
+        private void setRequest(ServletServiceRequest request) {
+            this.request = request;
+        }
+
+        public Object getAttribute(String name) {
+            if (this.values.containsKey(name)) {
+                return this.values.get(name);
+            }
+
+            return this.getValueOfCaller(name);
+        }
+
+        public Enumeration getAttributeNames() {
+            return this.getNames();
+        }
+
+        public long getCreationTime() {
+            return this.getRequest().parentRequest.getSession().getCreationTime();
+        }
+
+        public String getId() {
+            return this.getRequest().parentRequest.getSession().getId();
+        }
+
+        public long getLastAccessedTime() {
+            return this.getRequest().parentRequest.getSession().getLastAccessedTime();
+        }
+
+        public int getMaxInactiveInterval() {
+            return this.getRequest().parentRequest.getSession().getMaxInactiveInterval();
+        }
+
+        public ServletContext getServletContext() {
+            return this.context;
+        }
+
+        public HttpSessionContext getSessionContext() {
+            throw new UnsupportedOperationException();
+        }
+
+        public String[] getValueNames() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void invalidate() {
+            this.getRequest().parentRequest.getSession().invalidate();
+        }
+
+        public boolean isNew() {
+            return this.getRequest().parentRequest.getSession().isNew();
+        }
+
+        public void putValue(String name, Object value) {
+            this.setValue(name, value);
+        }
+
+        public void removeAttribute(String name) {
+            this.removeValue(name);
+        }
+
+        public void removeValue(String name) {
+            this.removeAttribute(name);
+        }
+
+        public void setAttribute(String name, Object value) {
+            this.setValue(name, value);
+        }
+
+        public void setMaxInactiveInterval(int interval) {
+            this.getRequest().parentRequest.getSession().setMaxInactiveInterval(interval);
+        }
+
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        // Override the setValue and getValue methods because session attributes
+        // are not arrays
+        protected void setValue(String name, Object value) {
+            this.values.put(name, value);
+        }
+
+        public Object getValue(String name) {
+            return this.values.get(name);
+        }
+
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceResponse.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceResponse.java
new file mode 100644
index 0000000..da8f2f4
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/java/org/apache/cocoon/servletservice/util/ServletServiceResponse.java
@@ -0,0 +1,279 @@
+/*
+ * 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.servletservice.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Creates a {@link HttpServletResponse} object that is usable for internal block calls.
+ * 
+ * @version $Id$
+ * @since 1.0.0
+ */
+public class ServletServiceResponse implements HttpServletResponse {
+
+    private OutputStream outputStream;
+    private ServletOutputStream servletStream;
+    private PrintWriter writer;
+    private boolean committed;
+    private Locale locale;
+    private int statusCode;
+
+    private Map<String, String> headers;
+
+    /**
+     * format definied by RFC 822, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
+     */
+    final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
+
+    public ServletServiceResponse() {
+        this.headers = new HashMap<String, String>();
+        this.statusCode = HttpServletResponse.SC_OK;
+    }
+
+    public void addCookie(Cookie cookie) {
+        // Ignore
+    }
+
+    public void addDateHeader(String name, long date) {
+        // this class does not support multivalue headers
+        this.setDateHeader(name, date);
+    }
+
+    public void addHeader(String name, String value) {
+        // this class does not support multivalue headers
+        this.setHeader(name, value);
+    }
+
+    public void addIntHeader(String name, int value) {
+        // this class does not support multivalue headers
+        this.setIntHeader(name, value);
+    }
+
+    public boolean containsHeader(String name) {
+        return this.headers.containsKey(name);
+    }
+
+    public String encodeRedirectUrl(String url) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String encodeRedirectURL(String url) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String encodeUrl(String url) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String encodeURL(String url) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void flushBuffer() throws IOException {
+        this.committed = true;
+    }
+
+    public int getBufferSize() {
+        return 0;
+    }
+
+    public String getCharacterEncoding() {
+        // TODO Let it depend on the actual response body
+        return "ISO-8859-1";
+    }
+
+    public Locale getLocale() {
+        return this.locale;
+    }
+
+    public ServletOutputStream getOutputStream() throws IOException {
+        if (this.writer != null) {
+            throw new IllegalStateException("Tried to create output stream; writer already exists");
+        }
+
+        if (this.servletStream == null) {
+            this.servletStream = new ServletOutputStream() {
+
+                @Override
+                public void flush() throws IOException {
+                    ServletServiceResponse.this.outputStream.flush();
+                }
+
+                @Override
+                public void write(int b) throws IOException {
+                    ServletServiceResponse.this.outputStream.write(b);
+                    ServletServiceResponse.this.committed = true;
+                }
+
+                /*
+                 * This method is probably never called, the close will be initiated directly on
+                 * this.outputStream by the one who set it via
+                 * BlockCallHttpServletResponse.setOutputStream()
+                 */
+                @Override
+                public void close() throws IOException {
+                    ServletServiceResponse.this.outputStream.close();
+                }
+
+            };
+        }
+
+        return this.servletStream;
+    }
+
+    public PrintWriter getWriter() throws IOException {
+        if (this.servletStream != null) {
+            throw new IllegalStateException("Tried to create writer; output stream already exists");
+        }
+
+        if (this.writer == null) {
+            this.writer = new PrintWriter(new OutputStreamWriter(this.outputStream, this.getCharacterEncoding()));
+        }
+
+        return this.writer;
+    }
+
+    public boolean isCommitted() {
+        return this.committed;
+    }
+
+    public void reset() {
+        this.resetBuffer();
+    }
+
+    public void resetBuffer() {
+        // this class does not buffer anything so if first byte is written to output stream
+        // there is no way to reset anything
+        // Servlet Service Framework uses for buffering a wrapper called
+        // HttpServletResponseBufferingWrapper
+        if (this.committed) {
+            throw new IllegalStateException("May not resetBuffer after response is committed");
+        }
+    }
+
+    public void sendError(int sc) throws IOException {
+        // TODO Auto-generated method stub
+    }
+
+    public void sendError(int sc, String msg) throws IOException {
+        // TODO Auto-generated method stub
+    }
+
+    public void sendRedirect(String location) throws IOException {
+        // TODO Auto-generated method stub
+    }
+
+    public void setBufferSize(int size) {
+        // TODO Implement buffering, for the moment ignore.
+    }
+
+    public void setContentLength(int len) {
+        // Ignore
+    }
+
+    public void setContentType(String type) {
+        this.setHeader("Content-Type", type);
+    }
+
+    public void setDateHeader(String name, long date) {
+        this.setHeader(name, this.dateFormat.format(new Date(date)));
+    }
+
+    public long getDateHeader(String name) {
+        String header = this.getHeader(name);
+        if (header == null) {
+            return -1;
+        }
+
+        try {
+            return this.dateFormat.parse(header).getTime();
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void setHeader(String name, String value) {
+        this.headers.put(name, value);
+    }
+
+    public String getHeader(String name) {
+        return this.headers.get(name);
+    }
+
+    public Map<String, String> getHeaders() {
+        return this.headers;
+    }
+
+    public void setIntHeader(String name, int value) {
+        this.setHeader(name, String.valueOf(value));
+    }
+
+    public int getIntHeader(String name) {
+        String header = this.getHeader(name);
+        if (header == null) {
+            return -1;
+        }
+
+        return Integer.parseInt(header);
+    }
+
+    public void setLocale(Locale loc) {
+        this.locale = loc;
+    }
+
+    public void setOutputStream(OutputStream outputStream) {
+        this.outputStream = outputStream;
+    }
+
+    public void setStatus(int sc) {
+        this.statusCode = sc;
+    }
+
+    public int getStatus() {
+        return this.statusCode;
+    }
+
+    public void setStatus(int sc, String sm) {
+        throw new UnsupportedOperationException("This method has been deprecated");
+    }
+
+    public String getContentType() {
+        return this.getHeader("Content-Type");
+    }
+
+    public void setCharacterEncoding(String arg0) {
+        // TODO Auto-generated method stub
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-callstack.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-callstack.xml
new file mode 100644
index 0000000..a9ad6bb
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-callstack.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+<!-- SVN $Id$ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+    <!-- Install the call stack custom scope -->
+    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
+        <property name="scopes">
+            <map>
+                <entry key="call">
+                    <bean class="org.apache.cocoon.callstack.CallScope"/>
+                </entry>
+                <entry key="servlet">
+                	<bean class="org.apache.cocoon.servletscope.ServletScope">
+                		<property name="servletContext" ref="javax.servlet.ServletContext/callstack"/>
+                	</bean>
+                </entry>
+            </map>
+        </property>
+    </bean>
+
+    <!-- The request object of the current call frame -->
+    <bean name="javax.servlet.http.HttpServletRequest/callstack"
+          class="org.apache.cocoon.callstack.environment.HttpServletRequestFactoryBean"
+          scope="call">
+        <aop:scoped-proxy proxy-target-class="false"/>
+    </bean>
+
+    <!-- The response object of the current call frame -->
+    <bean name="javax.servlet.http.HttpServletResponse/callstack"
+          class="org.apache.cocoon.callstack.environment.HttpServletResponseFactoryBean"
+          scope="call">
+        <aop:scoped-proxy proxy-target-class="false"/>
+    </bean>
+
+    <!-- The context object of the current call frame -->
+    <bean name="javax.servlet.ServletContext/callstack"
+          class="org.apache.cocoon.callstack.environment.ServletContextFactoryBean"
+          scope="call">
+        <aop:scoped-proxy proxy-target-class="false"/>
+    </bean>
+
+</beans>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-context.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-context.xml
new file mode 100644
index 0000000..d4089c8
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-context.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<!-- SVN $Id$ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+    <!-- The context object of the current base call frame -->
+    <bean name="javax.servlet.ServletContext/baseframe"
+      class="org.apache.cocoon.servletservice.spring.BaseServletContextFactoryBean" scope="call">
+      <aop:scoped-proxy proxy-target-class="false" />
+    </bean>
+
+</beans>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-protocol.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-protocol.xml
new file mode 100644
index 0000000..7449697
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-protocol.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<!-- $Id$ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+  <bean id="org.apache.cocoon.servletservice.url.ServletURLStreamHandlerFactory" class="org.apache.cocoon.servletservice.url.ServletURLStreamHandlerFactory"/>
+
+</beans>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-servlet-map.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-servlet-map.xml
new file mode 100644
index 0000000..5c0233e
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-servlet-map.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<!-- $Id$ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:configurator="http://cocoon.apache.org/schema/configurator"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+                           http://cocoon.apache.org/schema/configurator http://cocoon.apache.org/schema/configurator/cocoon-configurator-1.0.1.xsd">
+
+    <configurator:bean-map id="org.apache.cocoon.servletservice.spring.BlockServletMap" type="javax.servlet.Servlet"
+      has-properties="mountPath" key-property="mountPath" />
+
+</beans>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-urlhandler-advice.xml b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-urlhandler-advice.xml
new file mode 100644
index 0000000..080352d
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/cocoon/spring/cocoon-ssf-urlhandler-advice.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<!-- $Id$ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns:aop="http://www.springframework.org/schema/aop"
+  xsi:schemaLocation="
+    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+  <aop:config>
+    <aop:aspect id="installURL" ref="org.apache.cocoon.jnet.URLHandlerFactoryCollector">
+      <aop:pointcut id="servletServiceInvocation"
+        expression="execution(* javax.servlet.Servlet.service(..)) and bean(*/embedded)" />
+
+      <aop:around pointcut-ref="servletServiceInvocation" method="installURLHandlers" />
+    </aop:aspect>
+  </aop:config>
+
+</beans>
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.handlers b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000..88b23e9
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1,16 @@
+#  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.
+#
+http\://cocoon.apache.org/schema/servlet=org.apache.cocoon.servletservice.spring.ServletNamespaceHandler
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.schemas b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000..19f7e9f
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/META-INF/spring.schemas
@@ -0,0 +1,16 @@
+#  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.
+#
+http\://cocoon.apache.org/schema/servlet/cocoon-servlet-1.0.xsd=org/apache/cocoon/servletservice/schema/cocoon-servlet-1.0.xsd
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/org/apache/cocoon/servletservice/schema/cocoon-servlet-1.0.xsd b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/org/apache/cocoon/servletservice/schema/cocoon-servlet-1.0.xsd
new file mode 100644
index 0000000..cf11b45
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/main/resources/org/apache/cocoon/servletservice/schema/cocoon-servlet-1.0.xsd
@@ -0,0 +1,116 @@
+<?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.
+-->
+<!-- @version $Id$ -->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	targetNamespace="http://cocoon.apache.org/schema/servlet"
+	xmlns:tns="http://cocoon.apache.org/schema/servlet"
+	xmlns="http://cocoon.apache.org/schema/servlet">
+
+	<xsd:import namespace="http://www.springframework.org/schema/beans"
+	            schemaLocation="http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"/>
+
+	<xsd:annotation>
+		<xsd:documentation>
+			Schema for decorating servlet beans so that they are managed
+			by Spring and used in the servlet context configured by the
+			elements in this scheme.
+		</xsd:documentation>
+	</xsd:annotation>
+
+	<xsd:element name="context">
+		<xsd:annotation>
+			<xsd:documentation>
+				The top level element.
+			</xsd:documentation>
+		</xsd:annotation>
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element ref="init-params" minOccurs="0" maxOccurs="1" />
+				<xsd:element ref="context-params" minOccurs="0" maxOccurs="1" />
+				<xsd:element ref="connections" minOccurs="0" maxOccurs="1" />
+			</xsd:sequence>
+			<xsd:attribute name="mount-path" type="xsd:string" use="required">
+				<xsd:annotation>
+					<xsd:documentation>
+						Where the servlet should be mounted relative to
+						the context path of the embeding servlet
+						container. Use an empty string for mounting
+						directly at the context path. Non empty mount
+						paths must start with '/'. If the mountPath
+						attribute not is used, the servlet will not be
+						available though an URI, it will only be
+						avaliable through its bean name for servlet
+						beans connected to this servlet.
+					</xsd:documentation>
+				</xsd:annotation>
+			</xsd:attribute>
+			<xsd:attribute name="context-path" type="xsd:string" use="required">
+				<xsd:annotation>
+					<xsd:documentation>
+						The root path for the servlet context.
+					</xsd:documentation>
+				</xsd:annotation>
+			</xsd:attribute>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="init-params">
+		<xsd:annotation>
+			<xsd:documentation>
+				The init params for the servlet configuration used for
+				the servlet.
+			</xsd:documentation>
+		</xsd:annotation>
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="beans:mapType" />
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="context-params">
+		<xsd:annotation>
+			<xsd:documentation>
+				Context parameters for the servlet context.
+			</xsd:documentation>
+		</xsd:annotation>
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="beans:mapType" />
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+
+	<xsd:element name="connections">
+		<xsd:annotation>
+			<xsd:documentation>
+				Connections to other servlet services that are made
+				available through the named dispatcher of the servlet
+				context. Consist of mappings between a named connection
+				to another servlet and a reference to it.
+			</xsd:documentation>
+		</xsd:annotation>
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="beans:mapType" />
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+
+</xsd:schema>
\ No newline at end of file
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapperTestCase.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapperTestCase.java
new file mode 100644
index 0000000..1435ab0
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/HttpServletResponseBufferingWrapperTestCase.java
@@ -0,0 +1,210 @@
+/*
+ * 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.servletservice;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.easymock.MockControl;
+
+public class HttpServletResponseBufferingWrapperTestCase extends TestCase {
+    
+    public void testHeadersPassing() {
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.setHeader("test", "foo");
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        control.replay();
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setHeader("test", "foo");
+        control.verify();
+    }
+    
+    public void testStatusCodePassing() {
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        control.replay();
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_OK);
+        control.verify();
+    }
+    
+    public void testNoBuffering() throws IOException {
+        CountingServletOutputStream countingStream = new CountingServletOutputStream();
+        
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.getOutputStream();
+        control.setReturnValue(countingStream);
+        control.replay();
+        
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_OK);
+        OutputStream outputStream = responseWrapper.getOutputStream();
+        outputStream.write(0);
+        
+        assertEquals(1, countingStream.getCounter());
+        control.verify();
+    }
+    
+    public void testBuffering() throws IOException {
+        CountingServletOutputStream countingStream = new CountingServletOutputStream();
+        
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.getOutputStream();
+        control.setReturnValue(countingStream);
+        control.replay();
+        
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_NOT_FOUND);
+        OutputStream outputStream = responseWrapper.getOutputStream();
+        outputStream.write(0);
+        
+        assertEquals(0, countingStream.getCounter());
+        control.verify();
+    }
+    
+    public void testBufferOverflow() throws IOException {
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.getOutputStream();
+        control.setReturnValue(new CountingServletOutputStream());
+        control.replay();
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_NOT_FOUND);
+        OutputStream outputStream = responseWrapper.getOutputStream();
+        boolean catchedException = false;
+        byte[] b = new byte[1024*1024];
+        for (int i = 0; i < 2; i++) {
+            try {
+                outputStream.write(b);
+            } catch (RuntimeException e) {
+                //here we check whether we caught right exception. Is there any better method?
+                if (e.getMessage().indexOf("limit") != -1)
+                    catchedException = true;
+                else
+                    throw e;
+            }
+        }
+        control.verify();
+        assertTrue("Did not catch exception of overflowed buffer.", catchedException);
+    }
+    
+    public void testFlushBufferedResponseWhenBufferIsEmpty() throws IOException {
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+        response.flushBuffer();
+        control.replay();
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_NOT_FOUND);
+        responseWrapper.flushBufferedResponse();
+        control.verify();
+    }
+    
+    /**
+     * This method tests late setting of status code to 404. Late here means <b>after</b> getOutputStream method was called.
+     * @throws IOException
+     */
+    public void testLateSettingStatusCodeTo404() throws IOException {
+        CountingServletOutputStream countingStream = new CountingServletOutputStream();
+        
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.getOutputStream();
+        control.setReturnValue(countingStream);
+        control.replay();
+        
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_NOT_FOUND);
+        OutputStream outputStream = responseWrapper.getOutputStream();
+        outputStream.write(0);
+        
+        assertEquals(0, countingStream.getCounter());
+        responseWrapper.resetBufferedResponse();
+        assertEquals(0, countingStream.getCounter());
+        control.verify();
+    }
+    
+    /**
+     * This method tests if flushing of obtained writer is performed correctly in flushBufferedResponse.
+     * @throws Exception
+     */
+    public void testWriterFlushing() throws Exception {
+        CountingServletOutputStream countingStream = new CountingServletOutputStream();
+        
+        MockControl control = MockControl.createControl(HttpServletResponse.class);
+        HttpServletResponse response = (HttpServletResponse)control.getMock();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.getCharacterEncoding();
+        control.setReturnValue("ISO-8859-1");
+        response.isCommitted();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        response.getOutputStream();
+        control.setReturnValue(countingStream, MockControl.ONE_OR_MORE);
+        response.flushBuffer();
+        control.replay();
+        
+        HttpServletResponseBufferingWrapper responseWrapper = new HttpServletResponseBufferingWrapper(response);
+        responseWrapper.setStatus(HttpServletResponse.SC_OK);
+        PrintWriter writer = responseWrapper.getWriter();
+        writer.write("0");
+        responseWrapper.flushBufferedResponse();
+        
+        assertEquals(1, countingStream.getCounter());
+    }
+    
+    /**
+     * Simple ServletOutputStream that counts how many bytes were written.
+     *
+     */
+    private class CountingServletOutputStream extends ServletOutputStream {
+        
+        private int counter = 0;
+
+        public void write(int arg0) throws IOException {
+            counter++;
+        }
+        
+        public int getCounter() {
+            return counter;
+        }
+    }
+    
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/ServletServiceContextTestCase.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/ServletServiceContextTestCase.java
new file mode 100644
index 0000000..08e814f
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/ServletServiceContextTestCase.java
@@ -0,0 +1,358 @@
+/*
+* 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.servletservice;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.apache.cocoon.servletservice.util.ServletServiceRequest;
+import org.apache.cocoon.servletservice.util.ServletServiceResponse;
+
+/**
+ * @version $Id$
+ */
+public class ServletServiceContextTestCase extends TestCase {
+
+    private ServletServiceContext mainContext;
+    private HttpServlet servletA;
+    private HttpServlet servletB;
+    private HttpServlet servletC;
+
+    private ServletServiceContext servletAContext;
+    private ServletServiceContext servletBContext;
+    private ServletServiceContext servletCContext;
+
+    ServletServiceRequest request;
+    ServletServiceResponse response;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        this.mainContext = new ServletServiceContext();
+
+        request = new ServletServiceRequest(new URI("dummy"), null);
+        response = new ServletServiceResponse();
+
+        //creating ServletContexts
+        servletAContext = new ServletServiceContext();
+        servletBContext = new ServletServiceContext();
+        servletCContext = new ServletServiceContext();
+    }
+
+    /**
+     * Tests basic connection to the servlet.
+     *
+     * @throws Exception if test fails
+     */
+    public void testBasicConnection() throws Exception {
+        servletA = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletAContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                response.setStatus(HttpServletResponse.SC_OK);
+                response.flushBuffer();
+            }
+        };
+        servletAContext.setServlet(servletA);
+
+        setMainConnection(servletA, "servletA");
+
+        RequestDispatcher dispatcher = mainContext.getNamedDispatcher("servletA");
+        dispatcher.forward(request, response);
+
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+        assertTrue("Check if response has been committed", response.isCommitted());
+    }
+
+    /**
+     * <p>Tests if explicit super call works and if ServletContexts are properly set up when super call is performed.</p>
+     *
+     * <p>Servlets are connected that way:</p>
+     * <pre>
+     *    ServletB
+     *       ^
+     *       |
+     *    ServletA
+     * </pre>
+     * @throws Exception if test fails
+     */
+    public void testExplicitSuperCall() throws Exception {
+        servletA = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletAContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                ServletContext context = CallStackHelper.getCurrentServletContext();
+                RequestDispatcher dispatcher = context.getNamedDispatcher("super");
+                dispatcher.forward(request, response);
+            }
+
+        };
+
+        servletB = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletBContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                assertEquals(servletAContext, CallStackHelper.getBaseServletContext());
+                assertEquals(servletBContext, CallStackHelper.getCurrentServletContext());
+                response.setStatus(HttpServletResponse.SC_OK);
+                response.flushBuffer();
+            }
+        };
+
+        servletAContext.setServlet(servletA);
+        servletBContext.setServlet(servletB);
+
+        //connecting servlets
+        setMainConnection(servletA, "servletA");
+        connectServlets(servletA, servletB, "super");
+
+        RequestDispatcher dispatcher = mainContext.getNamedDispatcher("servletA");
+        dispatcher.forward(request, response);
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+        assertTrue("Check if response has been committed", response.isCommitted());
+    }
+
+    /**
+     * <p>Tests if ServletContext is properly set up in a servlet (C) that is called from super servlet (B) for another one(A).</p>
+     *
+     * <p>Servlets are connected that way:</p>
+     * <pre>
+     *    ServletB --> ServletC
+     *       ^
+     *       |
+     *    ServletA
+     * </pre>
+     *
+     * @throws Exception if test fails
+     */
+    public void testContextInServletCalledFromExplicitSuperCall() throws Exception {
+        servletA = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletAContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                ServletContext context = CallStackHelper.getCurrentServletContext();
+                RequestDispatcher dispatcher = context.getNamedDispatcher("super");
+                dispatcher.forward(request, response);
+            }
+        };
+
+        servletB = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletBContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                ServletContext context = CallStackHelper.getBaseServletContext();
+                RequestDispatcher dispatcher = context.getNamedDispatcher("servletC");
+                dispatcher.forward(request, response);
+            }
+        };
+
+        servletC = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletCContext); }
+
+            protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
+                super.service(req, response);
+                assertEquals(servletCContext, CallStackHelper.getBaseServletContext());
+                assertEquals(servletCContext, CallStackHelper.getCurrentServletContext());
+                res.setStatus(HttpServletResponse.SC_OK);
+                res.flushBuffer();
+            }
+        };
+        servletAContext.setServlet(servletA);
+        servletBContext.setServlet(servletB);
+        servletCContext.setServlet(servletC);
+
+        //connecting servlets
+        setMainConnection(servletA, "servletA");
+        connectServlets(servletA, servletB, "super");
+        connectServlets(servletB, servletC, "servletC");
+
+        RequestDispatcher dispatcher = mainContext.getNamedDispatcher("servletA");
+        dispatcher.forward(request, response);
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+        assertTrue("Check if response has been committed", response.isCommitted());
+    }
+
+    /**
+     * <p>This test is very similar to the {@link #testContextInServletCalledFromExplicitSuperCall()} but tries to use true OO approach so there is
+     *    no explicit super call. See COCOON-2038.</p>
+     *
+     * <p>Servlets are connected that way:</p>
+     * <pre>
+     *    ServletB --> ServletC
+     *       ^
+     *       |
+     *    ServletA
+     * </pre>
+     *
+     * @throws Exception if test fails
+     */
+    public void testTrueObjectOrientedBehaviour() throws Exception {
+        servletA = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletAContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                super.service(request, response);
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                response.flushBuffer();
+            }
+
+        };
+
+        servletB = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletBContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                ServletContext context = CallStackHelper.getBaseServletContext();
+                RequestDispatcher dispatcher = context.getNamedDispatcher("servletC");
+                dispatcher.forward(request, response);
+            }
+        };
+
+        servletC = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletCContext); }
+
+            protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
+                super.service(req, response);
+                assertEquals(servletCContext, CallStackHelper.getBaseServletContext());
+                assertEquals(servletCContext, CallStackHelper.getCurrentServletContext());
+                res.setStatus(HttpServletResponse.SC_OK);
+                res.flushBuffer();
+            }
+        };
+        servletAContext.setServlet(servletA);
+        servletBContext.setServlet(servletB);
+        servletCContext.setServlet(servletC);
+
+        //connecting servlets
+        setMainConnection(servletA, "servletA");
+        connectServlets(servletA, servletB, "super");
+        connectServlets(servletB, servletC, "servletC");
+
+        RequestDispatcher dispatcher = mainContext.getNamedDispatcher("servletA");
+        dispatcher.forward(request, response);
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+        assertTrue("Check if response has been committed", response.isCommitted());
+    }
+
+    /**
+     * <p>This test is for bug COCOON-1939 for more than 2 level of inheritance.
+     *
+     * <p>Servlets are connected that way:</p>
+     * <pre>
+     * 	  SerlvetC
+     * 		 ^
+     * 		 |
+     *    ServletB
+     *       ^
+     *       |
+     *    ServletA
+     * </pre>
+     *
+     * @throws Exception if test fails
+     */
+    public void testThreeLevelInheritance() throws Exception {
+        servletA = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletAContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+                super.service(request, response);
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                response.flushBuffer();
+            }
+
+        };
+
+        servletB = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletBContext); }
+
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+            	super.service(request, response);
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                response.flushBuffer();
+            }
+        };
+
+        servletC = new HttpServlet() {
+            public ServletConfig getServletConfig() { return new ServletConfigWithContext(servletCContext); }
+
+            protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
+                super.service(req, response);
+                assertEquals(servletAContext, CallStackHelper.getBaseServletContext());
+                assertEquals(servletCContext, CallStackHelper.getCurrentServletContext());
+                res.setStatus(HttpServletResponse.SC_OK);
+                res.flushBuffer();
+            }
+        };
+        servletAContext.setServlet(servletA);
+        servletBContext.setServlet(servletB);
+        servletCContext.setServlet(servletC);
+
+        //connecting servlets
+        setMainConnection(servletA, "servletA");
+        connectServlets(servletA, servletB, "super");
+        connectServlets(servletB, servletC, "super");
+
+        RequestDispatcher dispatcher = mainContext.getNamedDispatcher("servletA");
+        dispatcher.forward(request, response);
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+        assertTrue("Check if response has been committed", response.isCommitted());
+    }
+
+    //-----------------------------------------------------------------------------------------
+
+    private void connectServlets(HttpServlet connectFrom, HttpServlet connectTo, String connectionName) {
+        ServletServiceContext context = (ServletServiceContext)connectFrom.getServletConfig().getServletContext();
+        Map connections = new HashMap();
+        connections.put(connectionName, connectTo);
+        context.setConnections(connections);
+    }
+
+    private void setMainConnection(HttpServlet connectTo, String connectionName) {
+        Map connections = new HashMap();
+        connections.put(connectionName, connectTo);
+        mainContext.setConnections(connections);
+    }
+
+    private class ServletConfigWithContext implements ServletConfig {
+        private ServletContext context;
+
+        public ServletConfigWithContext(ServletContext context) {
+            this.context = context;
+        }
+
+        public String getInitParameter(String arg0) { return null; }
+        public Enumeration getInitParameterNames() { return null; }
+        public String getServletName() { return null; }
+
+        public ServletContext getServletContext() {
+            return context;
+        }
+    }
+
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/RequestParametersTestCase.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/RequestParametersTestCase.java
new file mode 100644
index 0000000..282c3d7
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/RequestParametersTestCase.java
@@ -0,0 +1,84 @@
+/*
+ * 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.servletservice.util;
+
+import junit.framework.TestCase;
+
+/**
+ * @version $Id$
+ */
+public class RequestParametersTestCase extends TestCase {
+
+    public void testParseMultiple() {
+        RequestParameters p = new RequestParameters("a=1&a=2&a=3&b=11&b=22");
+        String[] a = p.getParameterValues("a");
+        assertEquals(3, a.length);
+        assertEquals("1", a[0]);
+        assertEquals("2", a[1]);
+        assertEquals("3", a[2]);
+
+        String[] b = p.getParameterValues("b");
+        assertEquals(2, b.length);
+        assertEquals("11", b[0]);
+        assertEquals("22", b[1]);
+    }
+
+    public void testParseEncoded() {
+        RequestParameters p = new RequestParameters("a=one+two&b=one%3Ftwo&c=");
+        assertEquals("one two", p.getParameter("a"));
+        assertEquals("one?two", p.getParameter("b"));
+    }
+
+    public void testParseEncodedWrong() {
+        try {
+            new RequestParameters("a=one%");
+            fail();
+        } catch (IllegalArgumentException e) { }
+        try {
+            new RequestParameters("a=one%3");
+            fail();
+        } catch (IllegalArgumentException e) { }
+        try {
+            new RequestParameters("a=one%u");
+            fail();
+        } catch (IllegalArgumentException e) { }
+        try {
+            new RequestParameters("a=one%u0");
+            fail();
+        } catch (IllegalArgumentException e) { }
+        try {
+            new RequestParameters("a=one%u00");
+            fail();
+        } catch (IllegalArgumentException e) { }
+        try {
+            new RequestParameters("a=one%u003");
+            fail();
+        } catch (IllegalArgumentException e) { }
+    }
+
+    public void testParseUnicode() {
+        final char u = '\u11F3'; // Hangul character
+
+        RequestParameters p = new RequestParameters("a=a%E1%87%B3b&b=a%u11f3b");
+        assertEquals("a" + u + "b", p.getParameter("a"));
+        assertEquals("a" + u + "b", p.getParameter("b"));
+    }
+
+    public void testParseWSDL() {
+        assertEquals("", new RequestParameters("foo").getParameter("foo"));
+    }
+}
diff --git a/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/ServletServiceResponseTestCase.java b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/ServletServiceResponseTestCase.java
new file mode 100644
index 0000000..5bb105b
--- /dev/null
+++ b/cocoon-servlet-service-impl/cocoon-servlet-service-impl-1.2.0/src/test/java/org/apache/cocoon/servletservice/util/ServletServiceResponseTestCase.java
@@ -0,0 +1,45 @@
+/*
+* 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.servletservice.util;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+/**
+ * @version $Id$
+ */
+public class ServletServiceResponseTestCase extends TestCase {
+    
+    /**
+     * Tests if its possible to write to outputStream after
+     * calling resetBuffer() method.
+     * @throws Exception
+     */
+    public void testResetBuffer() throws Exception {
+        ServletServiceResponse response = new ServletServiceResponse();
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        response.setOutputStream(outputStream);
+
+        response.getOutputStream();
+        response.resetBuffer();
+        response.getOutputStream().write(0);
+        
+        assertEquals(1, outputStream.size());
+    }
+    
+}