cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From u..@apache.org
Subject svn commit: rev 30863 - in cocoon/branches: . bin bin/org bin/org/apache bin/org/apache/butterfly bin/org/apache/butterfly/components bin/org/apache/butterfly/components/pipeline bin/org/apache/butterfly/components/pipeline/impl bin/org/apache/butterfly/environment bin/org/apache/butterfly/generation bin/org/apache/butterfly/reading bin/org/apache/butterfly/serialization bin/org/apache/butterfly/sitemap bin/org/apache/butterfly/source bin/org/apache/butterfly/source/impl bin/org/apache/butterfly/source/impl/validity bin/org/apache/butterfly/test bin/org/apache/butterfly/transformation bin/org/apache/butterfly/xml bin/org/apache/butterfly/xml/dom bin/org/apache/butterfly/xml/xslt lib lib/endorsed src src/java src/java/org src/java/org/apache src/java/org/apache/butterfly src/java/org/apache/butterfly/components src/java/org/apache/butterfly/components/pipeline src/java/org/apache/butterfly/components/pipeline/impl src/java/org/apache/butterfly/environment src/java/org/apache/butterfly/generation src/java/org/apache/butterfly/reading src/java/org/apache/butterfly/serialization src/java/org/apache/butterfly/sitemap src/java/org/apache/butterfly/source src/java/org/apache/butterfly/source/impl src/java/org/apache/butterfly/source/impl/validity src/java/org/apache/butterfly/transformation src/java/org/apache/butterfly/xml src/java/org/apache/butterfly/xml/dom src/java/org/apache/butterfly/xml/xslt src/test src/test/org src/test/org/apache src/test/org/apache/butterfly src/test/org/apache/butterfly/components src/test/org/apache/butterfly/components/pipeline src/test/org/apache/butterfly/components/pipeline/impl src/test/org/apache/butterfly/generation src/test/org/apache/butterfly/serialization src/test/org/apache/butterfly/source src/test/org/apache/butterfly/test src/test/org/apache/butterfly/transformation testdata tools tools/lib
Date Wed, 28 Jul 2004 20:25:44 GMT
Author: ugo
Date: Wed Jul 28 13:25:41 2004
New Revision: 30863

Added:
   cocoon/branches/.classpath
   cocoon/branches/.project
   cocoon/branches/LICENSE.txt
   cocoon/branches/NOTICE.txt
   cocoon/branches/bin/
   cocoon/branches/bin/beans.xml
   cocoon/branches/bin/log4j.properties
   cocoon/branches/bin/org/
   cocoon/branches/bin/org/apache/
   cocoon/branches/bin/org/apache/butterfly/
   cocoon/branches/bin/org/apache/butterfly/components/
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/InvalidPipelineException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/PipelineException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/PipelineProcessingException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/ProcessingPipeline.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/GroovySitemapTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipeline.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$1.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$2.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$3.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$4.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy
   cocoon/branches/bin/org/apache/butterfly/environment/
   cocoon/branches/bin/org/apache/butterfly/environment/Environment.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/generation/
   cocoon/branches/bin/org/apache/butterfly/generation/FileGenerator.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/generation/FileGeneratorTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/generation/Generator.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/reading/
   cocoon/branches/bin/org/apache/butterfly/reading/Reader.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/serialization/
   cocoon/branches/bin/org/apache/butterfly/serialization/Serializer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/serialization/XMLSerializer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/serialization/XMLSerializerTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/sitemap/
   cocoon/branches/bin/org/apache/butterfly/sitemap/SitemapOutputComponent.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/
   cocoon/branches/bin/org/apache/butterfly/source/Source.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceFactory.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceNotFoundException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceResolver.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceResolverTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceUtil.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/SourceValidity.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/URIAbsolutizer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/impl/
   cocoon/branches/bin/org/apache/butterfly/source/impl/FileSource.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/impl/FileSourceFactory.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/impl/URLSource.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/impl/URLSourceFactory.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/source/impl/validity/
   cocoon/branches/bin/org/apache/butterfly/source/impl/validity/FileTimeStampValidity.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/test/
   cocoon/branches/bin/org/apache/butterfly/test/SitemapComponentTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/transformation/
   cocoon/branches/bin/org/apache/butterfly/transformation/Transformer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/transformation/TraxTransformer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/transformation/TraxTransformerTestCase.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/
   cocoon/branches/bin/org/apache/butterfly/xml/AbstractXMLPipe.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/AbstractXMLProducer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/EmbeddedXMLPipe.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/Parser.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/WhitespaceFilter.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/XMLConsumer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/XMLException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/XMLPipe.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/XMLProducer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMBuilder$Listener.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMBuilder.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$DefaultDOMStreamer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$NamespaceNormalizingDOMStreamer$ElementInfo.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$NamespaceNormalizingDOMStreamer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/xslt/
   cocoon/branches/bin/org/apache/butterfly/xml/xslt/TraxException.class   (contents, props changed)
   cocoon/branches/bin/org/apache/butterfly/xml/xslt/TraxTransformerFactory.class   (contents, props changed)
   cocoon/branches/lib/
   cocoon/branches/lib/aopalliance.jar   (contents, props changed)
   cocoon/branches/lib/asm-1.4.1.jar   (contents, props changed)
   cocoon/branches/lib/asm-util-1.4.3.jar   (contents, props changed)
   cocoon/branches/lib/commons-lang-2.0.jar   (contents, props changed)
   cocoon/branches/lib/commons-logging-1.0.4.jar   (contents, props changed)
   cocoon/branches/lib/endorsed/
   cocoon/branches/lib/endorsed/jakarta-bcel-20040329.jar   (contents, props changed)
   cocoon/branches/lib/endorsed/jakarta-regexp-1.3.jar   (contents, props changed)
   cocoon/branches/lib/endorsed/xalan-2.6.0.jar   (contents, props changed)
   cocoon/branches/lib/endorsed/xercesImpl-2.6.2.jar   (contents, props changed)
   cocoon/branches/lib/endorsed/xml-apis.jar   (contents, props changed)
   cocoon/branches/lib/groovy-1.0-beta-6.jar   (contents, props changed)
   cocoon/branches/lib/log4j-1.2.8.jar   (contents, props changed)
   cocoon/branches/lib/spring-aop.jar   (contents, props changed)
   cocoon/branches/lib/spring-context.jar   (contents, props changed)
   cocoon/branches/lib/spring-core.jar   (contents, props changed)
   cocoon/branches/src/
   cocoon/branches/src/java/
   cocoon/branches/src/java/org/
   cocoon/branches/src/java/org/apache/
   cocoon/branches/src/java/org/apache/butterfly/
   cocoon/branches/src/java/org/apache/butterfly/components/
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/InvalidPipelineException.java
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineException.java
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineProcessingException.java
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/ProcessingPipeline.java
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/impl/
   cocoon/branches/src/java/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipeline.java
   cocoon/branches/src/java/org/apache/butterfly/environment/
   cocoon/branches/src/java/org/apache/butterfly/environment/Environment.java
   cocoon/branches/src/java/org/apache/butterfly/generation/
   cocoon/branches/src/java/org/apache/butterfly/generation/FileGenerator.java
   cocoon/branches/src/java/org/apache/butterfly/generation/Generator.java
   cocoon/branches/src/java/org/apache/butterfly/reading/
   cocoon/branches/src/java/org/apache/butterfly/reading/Reader.java
   cocoon/branches/src/java/org/apache/butterfly/serialization/
   cocoon/branches/src/java/org/apache/butterfly/serialization/Serializer.java
   cocoon/branches/src/java/org/apache/butterfly/serialization/XMLSerializer.java
   cocoon/branches/src/java/org/apache/butterfly/sitemap/
   cocoon/branches/src/java/org/apache/butterfly/sitemap/SitemapOutputComponent.java
   cocoon/branches/src/java/org/apache/butterfly/source/
   cocoon/branches/src/java/org/apache/butterfly/source/Source.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceException.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceFactory.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceNotFoundException.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceResolver.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceUtil.java
   cocoon/branches/src/java/org/apache/butterfly/source/SourceValidity.java
   cocoon/branches/src/java/org/apache/butterfly/source/URIAbsolutizer.java
   cocoon/branches/src/java/org/apache/butterfly/source/impl/
   cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSource.java
   cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSourceFactory.java
   cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSource.java
   cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSourceFactory.java
   cocoon/branches/src/java/org/apache/butterfly/source/impl/validity/
   cocoon/branches/src/java/org/apache/butterfly/source/impl/validity/FileTimeStampValidity.java
   cocoon/branches/src/java/org/apache/butterfly/transformation/
   cocoon/branches/src/java/org/apache/butterfly/transformation/Transformer.java
   cocoon/branches/src/java/org/apache/butterfly/transformation/TraxTransformer.java
   cocoon/branches/src/java/org/apache/butterfly/xml/
   cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLPipe.java
   cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLProducer.java
   cocoon/branches/src/java/org/apache/butterfly/xml/EmbeddedXMLPipe.java
   cocoon/branches/src/java/org/apache/butterfly/xml/Parser.java
   cocoon/branches/src/java/org/apache/butterfly/xml/WhitespaceFilter.java
   cocoon/branches/src/java/org/apache/butterfly/xml/XMLConsumer.java
   cocoon/branches/src/java/org/apache/butterfly/xml/XMLException.java
   cocoon/branches/src/java/org/apache/butterfly/xml/XMLPipe.java
   cocoon/branches/src/java/org/apache/butterfly/xml/XMLProducer.java
   cocoon/branches/src/java/org/apache/butterfly/xml/dom/
   cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMBuilder.java
   cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMStreamer.java
   cocoon/branches/src/java/org/apache/butterfly/xml/xslt/
   cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxException.java
   cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxTransformerFactory.java
   cocoon/branches/src/test/
   cocoon/branches/src/test/beans.xml
   cocoon/branches/src/test/log4j.properties
   cocoon/branches/src/test/org/
   cocoon/branches/src/test/org/apache/
   cocoon/branches/src/test/org/apache/butterfly/
   cocoon/branches/src/test/org/apache/butterfly/components/
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/GroovySitemapTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy
   cocoon/branches/src/test/org/apache/butterfly/generation/
   cocoon/branches/src/test/org/apache/butterfly/generation/FileGeneratorTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/serialization/
   cocoon/branches/src/test/org/apache/butterfly/serialization/XMLSerializerTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/source/
   cocoon/branches/src/test/org/apache/butterfly/source/SourceResolverTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/test/
   cocoon/branches/src/test/org/apache/butterfly/test/SitemapComponentTestCase.java
   cocoon/branches/src/test/org/apache/butterfly/transformation/
   cocoon/branches/src/test/org/apache/butterfly/transformation/TraxTransformerTestCase.java
   cocoon/branches/testdata/
   cocoon/branches/testdata/test1.xml
   cocoon/branches/testdata/traxtest-input.xml
   cocoon/branches/testdata/traxtest-result.xml
   cocoon/branches/testdata/traxtest-style.xsl
   cocoon/branches/tools/
   cocoon/branches/tools/lib/
   cocoon/branches/tools/lib/jmock-1.0.1.jar   (contents, props changed)
   cocoon/branches/tools/lib/xmlunit1.0.jar   (contents, props changed)
Log:
Initial impport of Butterfly

Added: cocoon/branches/.classpath
==============================================================================
--- (empty file)
+++ cocoon/branches/.classpath	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/java"/>
+	<classpathentry kind="src" path="src/test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry sourcepath="ECLIPSE_HOME/plugins/org.eclipse.jdt.source_3.0.0/src/org.junit_3.8.1/junitsrc.zip" kind="var" path="JUNIT_HOME/junit.jar"/>
+	<classpathentry kind="lib" path="lib/log4j-1.2.8.jar"/>
+	<classpathentry kind="lib" path="lib/aopalliance.jar"/>
+	<classpathentry kind="lib" path="lib/commons-logging-1.0.4.jar"/>
+	<classpathentry kind="lib" path="tools/lib/xmlunit1.0.jar"/>
+	<classpathentry kind="lib" path="lib/endorsed/xml-apis.jar"/>
+	<classpathentry kind="lib" path="lib/endorsed/xercesImpl-2.6.2.jar"/>
+	<classpathentry kind="lib" path="lib/commons-lang-2.0.jar"/>
+	<classpathentry kind="lib" path="lib/spring-core.jar"/>
+	<classpathentry kind="lib" path="lib/spring-context.jar"/>
+	<classpathentry kind="lib" path="lib/spring-aop.jar"/>
+	<classpathentry kind="lib" path="tools/lib/jmock-1.0.1.jar"/>
+	<classpathentry kind="lib" path="lib/groovy-1.0-beta-6.jar"/>
+	<classpathentry kind="lib" path="lib/asm-util-1.4.3.jar"/>
+	<classpathentry kind="lib" path="lib/asm-1.4.1.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: cocoon/branches/.project
==============================================================================
--- (empty file)
+++ cocoon/branches/.project	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>Butterfly</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: cocoon/branches/LICENSE.txt
==============================================================================
--- (empty file)
+++ cocoon/branches/LICENSE.txt	Wed Jul 28 13:25:41 2004
@@ -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.

Added: cocoon/branches/NOTICE.txt
==============================================================================
--- (empty file)
+++ cocoon/branches/NOTICE.txt	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).

Added: cocoon/branches/bin/beans.xml
==============================================================================
--- (empty file)
+++ cocoon/branches/bin/beans.xml	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright 2004, Ugo Cei
+
+  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.
+-->
+
+<!--+
+    | Spring's bean factory configuration file.
+    |
+    |  $Id: beans.xml,v 1.1 2004/07/23 08:47:20 ugo Exp $
+    +-->
+  
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+ 
+<beans>
+  
+  <bean id="fileSourceFactory" class="org.apache.butterfly.source.impl.FileSourceFactory"/>
+  <bean id="urlSourceFactory" class="org.apache.butterfly.source.impl.URLSourceFactory"/>
+  
+  <bean id="sourceResolver" class="org.apache.butterfly.source.SourceResolver">
+    <property name="factories">
+      <map>
+      	<entry key="file">
+      		<ref bean="fileSourceFactory"/>
+      	</entry>
+      	<entry key="*">
+      		<ref bean="urlSourceFactory"/>
+      	</entry>
+      </map>    
+    </property>
+  </bean>
+  
+  <!-- The XML Parser. Should probably be pooled. -->
+  <bean id="xmlParser" class="org.apache.butterfly.xml.Parser"
+     singleton="false" init-method="initialize">
+     <property name="saxDriver">
+       <value>org.apache.xerces.parsers.SAXParser</value>
+     </property>
+  </bean>
+  
+  <bean id="fileGenerator" class="org.apache.butterfly.generation.FileGenerator" singleton="false">
+    <property name="sourceResolver">
+      <ref bean="sourceResolver"/>
+    </property>  
+    <property name="parser">
+      <ref bean="xmlParser"/>
+    </property>
+  </bean>
+  
+  <bean id="traxTransformerFactory" class="org.apache.butterfly.xml.xslt.TraxTransformerFactory">
+    <property name="sourceResolver">
+      <ref bean="sourceResolver"/>
+    </property>  
+  </bean>
+
+  <bean id="xmlSerializer" class="org.apache.butterfly.serialization.XMLSerializer" singleton="false">
+    <property name="traxTransformerFactory">
+      <ref bean="traxTransformerFactory"/>
+    </property>
+    <property name="encoding">
+      <value>UTF-8</value>
+    </property>
+  </bean>
+    
+</beans>

Added: cocoon/branches/bin/log4j.properties
==============================================================================
--- (empty file)
+++ cocoon/branches/bin/log4j.properties	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,15 @@
+# Configure logging for testing
+
+log4j.rootCategory=WARN, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
+
+#log4j.category.org.springframework.aop.framework.ProxyFactoryBean=DEBUG
+
+log4j.category.org.springframework.enterpriseservices=DEBUG
+
+log4j.category.org.springframework.transaction.interceptor=INFO
+
+log4j.category.org.springframework.beans.factory=INFO

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/InvalidPipelineException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/PipelineException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/PipelineProcessingException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/ProcessingPipeline.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/GroovySitemapTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy
==============================================================================
--- (empty file)
+++ cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,13 @@
+class MyPipeline extends Pipeline {
+  
+    void define(String requestPath) {
+        if (requestPath =~ ".*\.html") {
+            generate "testdata/traxtest-input.xml"
+            transform "trax", "testdata/traxtest-style.xsl" 
+            serialize "xml"
+        }
+        else {
+            println("No matches for " + requestPath);
+        }
+    }
+}
\ No newline at end of file

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipeline.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$1.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$2.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$3.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase$4.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy
==============================================================================
--- (empty file)
+++ cocoon/branches/bin/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,34 @@
+import org.apache.butterfly.xml.dom.DOMBuilder
+import org.apache.butterfly.components.pipeline.impl.NonCachingProcessingPipeline
+
+class Pipeline {
+    public beanFactory;
+    private pipeline;
+    
+    protected Pipeline() {
+        this.pipeline = new NonCachingProcessingPipeline()
+    }
+            
+    protected void generate(src) {
+        generator = beanFactory.getBean("fileGenerator")
+        generator.inputSource = src
+        this.pipeline.generator = generator
+    }
+    
+    protected void transform(type, src) {
+        factory = beanFactory.getBean(type + "TransformerFactory")
+        transformer = factory.getTransformer(src)
+        this.pipeline.addTransformer(transformer)
+    }
+    
+    protected void serialize(type) {
+        serializer = beanFactory.getBean(type + "Serializer")
+        this.pipeline.serializer = serializer
+    }
+    
+    public void process() {
+        builder = new DOMBuilder()
+        this.pipeline.process(null, builder)
+        println(builder.document.documentElement)
+    }
+}
\ No newline at end of file

Added: cocoon/branches/bin/org/apache/butterfly/environment/Environment.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/generation/FileGenerator.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/generation/FileGeneratorTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/generation/Generator.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/reading/Reader.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/serialization/Serializer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/serialization/XMLSerializer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/serialization/XMLSerializerTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/sitemap/SitemapOutputComponent.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/Source.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceFactory.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceNotFoundException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceResolver.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceResolverTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceUtil.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/SourceValidity.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/URIAbsolutizer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/impl/FileSource.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/impl/FileSourceFactory.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/impl/URLSource.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/impl/URLSourceFactory.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/source/impl/validity/FileTimeStampValidity.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/test/SitemapComponentTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/transformation/Transformer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/transformation/TraxTransformer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/transformation/TraxTransformerTestCase.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/AbstractXMLPipe.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/AbstractXMLProducer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/EmbeddedXMLPipe.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/Parser.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/WhitespaceFilter.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/XMLConsumer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/XMLException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/XMLPipe.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/XMLProducer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMBuilder$Listener.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMBuilder.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$DefaultDOMStreamer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$NamespaceNormalizingDOMStreamer$ElementInfo.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer$NamespaceNormalizingDOMStreamer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/dom/DOMStreamer.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/xslt/TraxException.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/bin/org/apache/butterfly/xml/xslt/TraxTransformerFactory.class
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/aopalliance.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/asm-1.4.1.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/asm-util-1.4.3.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/commons-lang-2.0.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/commons-logging-1.0.4.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/endorsed/jakarta-bcel-20040329.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/endorsed/jakarta-regexp-1.3.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/endorsed/xalan-2.6.0.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/endorsed/xercesImpl-2.6.2.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/endorsed/xml-apis.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/groovy-1.0-beta-6.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/log4j-1.2.8.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/spring-aop.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/spring-context.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/lib/spring-core.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/src/java/org/apache/butterfly/components/pipeline/InvalidPipelineException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/components/pipeline/InvalidPipelineException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline;
+
+
+/**
+ * This exception is thrown whenever you try to assemble an invalid pipeline.
+ * 
+ * @version CVS $Id: InvalidPipelineException.java,v 1.1 2004/07/24 20:21:33 ugo Exp $
+ */
+public class InvalidPipelineException extends PipelineException {
+
+    /**
+     * 
+     */
+    public InvalidPipelineException() {
+        super();
+    }
+
+    /**
+     * @param arg0
+     */
+    public InvalidPipelineException(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public InvalidPipelineException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    /**
+     * @param arg0
+     */
+    public InvalidPipelineException(Throwable arg0) {
+        super(arg0);
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline;
+
+
+/**
+ * Base class for all exceptions thrown during pipeline processing.
+ * 
+ * @version CVS $Id: PipelineException.java,v 1.1 2004/07/24 20:21:33 ugo Exp $
+ */
+public abstract class PipelineException extends RuntimeException {
+
+    /**
+     * 
+     */
+    public PipelineException() {
+        super();
+    }
+
+    /**
+     * @param arg0
+     */
+    public PipelineException(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public PipelineException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    /**
+     * @param arg0
+     */
+    public PipelineException(Throwable arg0) {
+        super(arg0);
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineProcessingException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/components/pipeline/PipelineProcessingException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline;
+
+
+/**
+ * This exception can be thrown when executing a pipeline.
+ * 
+ * @version CVS $Id: PipelineProcessingException.java,v 1.1 2004/07/25 21:55:20 ugo Exp $
+ */
+public class PipelineProcessingException extends PipelineException {
+
+    /**
+     * 
+     */
+    public PipelineProcessingException() {
+        super();
+    }
+
+    /**
+     * @param arg0
+     */
+    public PipelineProcessingException(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public PipelineProcessingException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    /**
+     * @param arg0
+     */
+    public PipelineProcessingException(Throwable arg0) {
+        super(arg0);
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/components/pipeline/ProcessingPipeline.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/components/pipeline/ProcessingPipeline.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline;
+
+import org.apache.butterfly.environment.Environment;
+import org.apache.butterfly.generation.Generator;
+import org.apache.butterfly.reading.Reader;
+import org.apache.butterfly.serialization.Serializer;
+import org.apache.butterfly.source.SourceValidity;
+import org.apache.butterfly.transformation.Transformer;
+import org.apache.butterfly.xml.XMLConsumer;
+
+
+/**
+ * A <code>ProcessingPipeline<code> produces the response for a given request.
+ * It is assembled according to the commands in the sitemap and can either
+ * <ul>
+ *  <li>collect a <code>Reader</code> and let it produce a character stream</li>
+ *  <li>or connect a <code>Generator</code> with zero or more
+ *      <code>Transformer</code>s and a <code>Serializer</code> and let them
+ *      produce the byte stream. This pipeline uses SAX events for
+ *      communication.
+ *  </li>
+ * </ul>
+ *
+ * @version CVS $Id: ProcessingPipeline.java,v 1.2 2004/07/24 20:21:33 ugo Exp $
+ */
+public interface ProcessingPipeline {
+
+    /**
+     * Setup this component
+     */
+    // void setup(Parameters params);
+
+    /**
+     * Set the generator that will be used as the initial step in the pipeline.
+     * The generator role is given : the actual <code>Generator</code> is fetched
+     * from the latest <code>ComponentManager</code> given by <code>compose()</code>
+     * or <code>recompose()</code>.
+     *
+     * @param role the generator role in the component manager.
+     * @param source the source where to produce XML from, or <code>null</code> if no
+     *        source is given.
+     * @param param the parameters for the generator.
+     * @throws ProcessingException if the generator couldn't be obtained.
+     */
+    void setGenerator(Generator generator);
+
+    /**
+     * Get the generator - used for content aggregation
+     */
+    Generator getGenerator();
+
+    /**
+     * Informs pipeline we have come across a branch point
+     */
+    void informBranchPoint();
+
+    /**
+     * Add a transformer at the end of the pipeline.
+     * The transformer role is given : the actual <code>Transformer</code> is fetched
+     * from the latest <code>ComponentManager</code> given by <code>compose()</code>
+     * or <code>recompose()</code>.
+     *
+     * @param role the transformer role in the component manager.
+     * @param source the source used to setup the transformer (e.g. XSL file), or
+     *        <code>null</code> if no source is given.
+     * @param param the parameters for the transfomer.
+     * @throws ProcessingException if the generator couldn't be obtained.
+     */
+    void addTransformer(Transformer transformer);
+
+    /**
+     * Set the serializer for this pipeline
+     * @param mimeType Can be null
+     */
+    void setSerializer(Serializer serializer);
+
+    /**
+     * Set the reader for this pipeline
+     * @param mimeType Can be null
+     */
+    void setReader(Reader reader);
+
+    /**
+     * Process the given <code>Environment</code>, producing the output.
+     */
+    boolean process(Environment environment);
+
+    /**
+     * Prepare an internal processing
+     * @param environment          The current environment.
+     * @throws ProcessingException
+     */
+    void prepareInternal(Environment environment);
+
+    /**
+     * Process the given <code>Environment</code>, but do not use the
+     * serializer. Instead the sax events are streamed to the XMLConsumer.
+     * Make sure to call {@link #prepareInternal(Environment)} beforehand.
+     */
+    boolean process(Environment environment, XMLConsumer consumer);
+
+    /**
+     * Return valid validity objects for the event pipeline
+     * If the "event pipeline" (= the complete pipeline without the
+     * serializer) is cacheable and valid, return all validity objects.
+     * Otherwise return <code>null</code>
+     */
+    SourceValidity getValidityForEventPipeline();
+    
+    /**
+     * Return the key for the event pipeline
+     * If the "event pipeline" (= the complete pipeline without the
+     * serializer) is cacheable and valid, return a key.
+     * Otherwise return <code>null</code>
+     */
+    String getKeyForEventPipeline();
+}

Added: cocoon/branches/src/java/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipeline.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipeline.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.butterfly.components.pipeline.InvalidPipelineException;
+import org.apache.butterfly.components.pipeline.PipelineProcessingException;
+import org.apache.butterfly.components.pipeline.ProcessingPipeline;
+import org.apache.butterfly.environment.Environment;
+import org.apache.butterfly.generation.Generator;
+import org.apache.butterfly.reading.Reader;
+import org.apache.butterfly.serialization.Serializer;
+import org.apache.butterfly.source.SourceValidity;
+import org.apache.butterfly.transformation.Transformer;
+import org.apache.butterfly.xml.XMLConsumer;
+import org.apache.butterfly.xml.XMLProducer;
+
+
+/**
+ * Implementation of the non-caching pipeline.
+ * 
+ * TODO: change InvalidPipelineExceptions with PipelineExceptions
+ * 
+ * @version CVS $Id: NonCachingProcessingPipeline.java,v 1.7 2004/07/25 21:55:20 ugo Exp $
+ */
+public class NonCachingProcessingPipeline implements ProcessingPipeline {
+    
+    /** The generator */
+    protected Generator generator;
+    
+    /** The reader */
+    protected Reader reader;
+    
+    /** The transformers */
+    protected List transformers;
+    
+    /** The serializer */
+    protected Serializer serializer;
+
+    /** 
+     * This is the last component in the pipeline, either the serializer
+     * or a custom xmlconsumer for the cocoon: protocol etc.
+     */
+    protected XMLConsumer lastConsumer;
+    
+    /** Output Buffer Size */
+    protected int  outputBufferSize;
+    
+    /**
+     * Build a new pipeline.
+     */
+    public NonCachingProcessingPipeline() {
+        transformers = new ArrayList();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#setGenerator(org.apache.butterfly.generation.Generator)
+     */
+    public void setGenerator(Generator generator) {
+        if (this.generator != null) {
+            throw new InvalidPipelineException("Generator already set. Cannot set generator.");
+        }
+        if (this.reader != null) {
+            throw new InvalidPipelineException("Reader already set. Cannot set generator.");
+        }
+        this.generator = generator;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#setReader(org.apache.butterfly.reading.Reader)
+     */
+    public void setReader(Reader reader) {
+        if (this.generator != null) {
+            throw new InvalidPipelineException("Generator already set. Cannot set reader.");
+        }
+        if (this.reader != null) {
+            throw new InvalidPipelineException("Reader already set. Cannot set reader.");
+        }
+        this.reader = reader;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#getGenerator()
+     */
+    public Generator getGenerator() {
+        return this.generator;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#informBranchPoint()
+     */
+    public void informBranchPoint() {
+        // TODO Auto-generated method stub
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#addTransformer(javax.xml.transform.Transformer)
+     */
+    public void addTransformer(Transformer transformer) {
+        if (this.generator == null) {
+            throw new InvalidPipelineException("Generator not yet set. Cannot add transformer.");
+        }
+        if (this.reader != null) {
+            throw new InvalidPipelineException("Reader already set. Cannot add transformer.");
+        }
+        transformers.add(transformer);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#setSerializer(org.apache.butterfly.xml.XMLPipe)
+     */
+    public void setSerializer(Serializer serializer) {
+        if (this.serializer != null) {
+            // Should normally not happen as adding a serializer starts pipeline processing
+            throw new InvalidPipelineException ("Serializer already set. Cannot set serializer.");
+        }
+        if (this.reader != null) {
+            // Should normally never happen as setting a reader starts pipeline processing
+            throw new InvalidPipelineException ("Reader already set. Cannot set serializer.");
+        }
+        if (this.generator == null) {
+            throw new InvalidPipelineException ("Must set a generator before setting serializer");
+        }
+        this.serializer = serializer;
+        this.lastConsumer = serializer;
+    }
+
+    /**
+     * Sanity check
+     * @return true if the pipeline is 'sane', false otherwise.
+     */
+    protected boolean checkPipeline() {
+        if (this.generator == null && this.reader == null) {
+            return false;
+        }
+        if (this.generator != null && this.serializer == null) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#process()
+     */
+    public boolean process(Environment environment) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#prepareInternal()
+     */
+    public void prepareInternal(Environment environment) {
+        // TODO Auto-generated method stub
+
+    }
+
+    /**
+     * Process the given <code>Environment</code>, but do not use the
+     * serializer. Instead the sax events are streamed to the XMLConsumer.
+     */
+    public boolean process(Environment environment, XMLConsumer consumer) {
+        this.lastConsumer = consumer;
+        if (this.reader != null) {
+            throw new InvalidPipelineException("Streaming of an internal pipeline is not possible with a reader.");
+        } else {
+            connectPipeline(environment);
+            return processXMLPipeline(environment);
+        }
+    }
+    
+    /**
+     * Process the SAX event pipeline
+     */
+    protected boolean processXMLPipeline(Environment environment) {
+        if (this.serializer != this.lastConsumer) {
+            // internal processing
+            this.generator.generate();
+        } else {
+            if (this.serializer.shouldSetContentLength()) {
+                // set the output stream
+                ByteArrayOutputStream os = new ByteArrayOutputStream();
+                this.serializer.setOutputStream(os);
+
+                // execute the pipeline:
+                this.generator.generate();
+                environment.setContentLength(os.size());
+                try {
+                    os.writeTo(environment.getOutputStream(0));
+                } catch (IOException e) {
+                    throw new PipelineProcessingException("Cannot write to output stream", e);
+                }
+            } else {
+                // set the output stream
+                this.serializer.setOutputStream(environment.getOutputStream(this.outputBufferSize));
+                // execute the pipeline:
+                this.generator.generate();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Connect the next component
+     */
+    protected void connect(Environment environment,
+                           XMLProducer producer,
+                           XMLConsumer consumer) {
+        XMLProducer next = producer;
+        // Connect next component.
+        next.setConsumer(consumer);
+    }
+
+    /**
+     * Connect the XML pipeline.
+     */
+    protected void connectPipeline(Environment environment) {
+        XMLProducer prev = this.generator;
+
+        Iterator itt = this.transformers.iterator();
+        while (itt.hasNext()) {
+            Transformer next = (Transformer) itt.next();
+            connect(environment, prev, next);
+            prev = next;
+        }
+
+        // insert the serializer
+        connect(environment, prev, this.lastConsumer);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#getValidityForEventPipeline()
+     */
+    public SourceValidity getValidityForEventPipeline() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.components.pipeline.ProcessingPipeline#getKeyForEventPipeline()
+     */
+    public String getKeyForEventPipeline() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/environment/Environment.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/environment/Environment.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.environment;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * Base interface for an environment abstraction
+ *
+ * @version CVS $Id: Environment.java,v 1.2 2004/07/25 21:55:20 ugo Exp $
+ */
+public interface Environment {
+
+    /**
+     * Get the URI to process. The prefix is stripped off.
+     */
+    String getURI();
+
+    /**
+     * Get the prefix of the URI in progress.
+     */
+    String getURIPrefix();
+
+    /**
+     * Set the URI and the prefix to process.
+     */
+    void setURI(String prefix, String value);
+
+    /**
+     * Get the view to process
+     */
+    String getView();
+
+    /**
+     * Get the action to process
+     */
+    String getAction();
+
+    /**
+     * Redirect to the given URL
+     */
+    void redirect(String url, boolean global, boolean permanent) 
+    throws IOException;
+
+    /**
+     * Set the content type of the generated resource
+     */
+    void setContentType(String mimeType);
+
+    /**
+     * Get the content type of the resource
+     */
+    String getContentType();
+
+    /**
+     * Set the length of the generated content
+     */
+    void setContentLength(int length);
+
+    /**
+     * Set the response status code
+     */
+    void setStatus(int statusCode);
+
+    /**
+     * Get the output stream where to write the generated resource.
+     * The returned stream is buffered by the environment. If the
+     * buffer size is -1 then the complete output is buffered.
+     * If the buffer size is 0, no buffering takes place.
+     */
+    OutputStream getOutputStream(int bufferSize);
+
+    /**
+     * Get the underlying object model
+     */
+    Map getObjectModel();
+
+    /**
+     * Check if the response has been modified since the same
+     * "resource" was requested.
+     * The caller has to test if it is really the same "resource"
+     * which is requested.
+     * @return true if the response is modified or if the
+     *         environment is not able to test it
+     */
+    boolean isResponseModified(long lastModified);
+
+    /**
+     * Mark the response as not modified.
+     */
+    void setResponseIsNotModified();
+
+    /**
+     * Binds an object to this environment, using the name specified. This allows
+     * the pipeline assembly engine to store for its own use objects that souldn't
+     * be exposed to other components (generators, selectors, etc) and therefore
+     * cannot be put in the object model.
+     * <p>
+     * If an object of the same name is already bound, the object is replaced.
+     *
+     * @param name  the name to which the object is bound
+     * @param value the object to be bound
+     */
+    void setAttribute(String name, Object value);
+
+    /**
+     * Returns the object bound with the specified name, or <code>null</code>
+     * if no object is bound under the name.
+     *
+     * @param name                a string specifying the name of the object
+     * @return                    the object with the specified name
+     */
+    Object getAttribute(String name);
+
+    /**
+     * Removes the object bound with the specified name from
+     * this environment. If the environment does not have an object
+     * bound with the specified name, this method does nothing.
+     *
+     * @param name the name of the object to remove
+     */
+    void removeAttribute(String name);
+
+    /**
+     * Returns an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of all the objects bound to this environment.
+     *
+     * @return an <code>Enumeration</code> of <code>String</code>s.
+     */
+    Enumeration getAttributeNames();
+
+    /**
+     * Reset the response if possible. This allows error handlers to have
+     * a higher chance to produce clean output if the pipeline that raised
+     * the error has already output some data.
+     * If a buffered output stream is used, resetting is always successful.
+     *
+     * @return true if the response was successfully reset
+     */
+    boolean tryResetResponse() throws IOException;
+
+
+    /**
+     * Commit the response
+     */
+    void commitResponse() throws IOException;
+    
+    /**
+     * Notify that the processing starts.
+     */
+    void startingProcessing();
+    
+    /**
+     * Notify that the processing is finished
+     * This can be used to cleanup the environment object
+     */
+    void finishingProcessing();
+    
+    /**
+     * Is this environment external ? An external environment is one that 
+     * is created in response to an external request (http, commandline, etc.). 
+     * Environments created by the "cocoon:" protocol aren't external.
+     * 
+     * @return true if this environment is external
+     */
+    boolean isExternal();
+    
+    /**
+     * Is this an internal redirect?
+     * An environment is on internal redirect if it is an internal request
+     * (via the cocoon: protocol) and used for a redirect.
+     */
+    boolean isInternalRedirect();
+}
+

Added: cocoon/branches/src/java/org/apache/butterfly/generation/FileGenerator.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/generation/FileGenerator.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.generation;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceResolver;
+import org.apache.butterfly.xml.Parser;
+import org.apache.butterfly.xml.XMLConsumer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Description of FileGenerator.
+ * 
+ * @version CVS $Id: FileGenerator.java,v 1.2 2004/07/25 21:55:20 ugo Exp $
+ */
+public class FileGenerator implements Generator {
+    private Source inputSource;
+    private SourceResolver sourceResolver;
+    private Parser parser;
+    protected static final Log logger = LogFactory.getLog(FileGenerator.class);
+    
+    public void setParser(Parser parser) {
+        this.parser = parser;
+    }
+    
+    public void setInputSource(String source) {
+        this.inputSource = sourceResolver.resolveURI(source);
+    }
+    
+    /**
+     * @param sourceResolver The sourceResolver to set.
+     */
+    public void setSourceResolver(SourceResolver sourceResolver) {
+        this.sourceResolver = sourceResolver;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.generation.Generator#setContentHandler(org.xml.sax.ContentHandler)
+     */
+    public void setConsumer(XMLConsumer consumer) {
+        parser.setContentHandler(consumer);
+    }
+    
+    public void generate() {
+        parser.parse(this.inputSource);
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/generation/Generator.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/generation/Generator.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.generation;
+
+import org.apache.butterfly.xml.XMLProducer;
+
+
+/**
+ * Description of Generator.
+ * 
+ * @version CVS $Id: Generator.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface Generator extends XMLProducer {
+    public void generate();
+}

Added: cocoon/branches/src/java/org/apache/butterfly/reading/Reader.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/reading/Reader.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.reading;
+
+import org.apache.butterfly.sitemap.SitemapOutputComponent;
+
+
+
+/**
+ * A reader can be used to generate binary output for a request.
+ *
+ * @version CVS $Id: Reader.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface Reader extends SitemapOutputComponent {
+
+    String ROLE = Reader.class.getName();
+
+    /**
+     * Generate the response.
+     */
+    void generate();
+
+    /**
+     * @return the time the read source was last modified or 0 if it is not
+     *         possible to detect
+     */
+    long getLastModified();
+}

Added: cocoon/branches/src/java/org/apache/butterfly/serialization/Serializer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/serialization/Serializer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.serialization;
+
+import org.apache.butterfly.sitemap.SitemapOutputComponent;
+import org.apache.butterfly.xml.XMLConsumer;
+
+
+/**
+ * Description of Serializer.
+ * 
+ * @version CVS $Id: Serializer.java,v 1.1 2004/07/24 20:21:33 ugo Exp $
+ */
+public interface Serializer extends XMLConsumer, SitemapOutputComponent {
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/serialization/XMLSerializer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/serialization/XMLSerializer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.serialization;
+
+import java.io.OutputStream;
+import java.util.Properties;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.butterfly.xml.AbstractXMLPipe;
+import org.apache.butterfly.xml.xslt.TraxTransformerFactory;
+
+
+/**
+ * Description of XMLSerializer.
+ * 
+ * @version CVS $Id: XMLSerializer.java,v 1.2 2004/07/24 20:21:33 ugo Exp $
+ */
+public class XMLSerializer extends AbstractXMLPipe implements Serializer {
+
+    protected OutputStream output;
+    protected TraxTransformerFactory transformerFactory;
+
+    /**
+     * The <code>Properties</code> used by this serializer.
+     */
+    protected Properties format = new Properties();
+    
+    /**
+     * 
+     */
+    public XMLSerializer() {
+        this.format.put(OutputKeys.METHOD, "xml");
+    }
+
+    /**
+     * @param transformerFactory The transformerFactory to set.
+     */
+    public void setTraxTransformerFactory(TraxTransformerFactory transformerFactory) {
+        this.transformerFactory = transformerFactory;
+    }
+
+    public void setCdataSectionElements(String cdataSectionElements) {
+        format.put(OutputKeys.CDATA_SECTION_ELEMENTS, cdataSectionElements);
+    }
+    
+    public void setDoctypePublic(String dtPublic) {
+        format.put(OutputKeys.DOCTYPE_PUBLIC, dtPublic);
+    }
+    
+    public void setDocTypeSystem(String dtSystem) {
+        format.put(OutputKeys.DOCTYPE_SYSTEM, dtSystem);
+    }
+    
+    public void setEncoding(String encoding) {
+        format.put(OutputKeys.ENCODING, encoding);
+    }
+    
+    public void setIndent(String indent) {
+        format.put(OutputKeys.INDENT, indent);
+    }
+    
+    public void setMediaType(String mediaType) {
+        format.put(OutputKeys.MEDIA_TYPE, mediaType);
+    }
+    
+    public void setMethod(String method) {
+        format.put(OutputKeys.METHOD, method);
+    }
+    
+    public void setOmitXMLDeclaration(String omitXMLDeclaration) {
+        format.put(OutputKeys.OMIT_XML_DECLARATION, omitXMLDeclaration);
+    }
+    
+    public void setStandAlone(String standAlone) {
+        format.put(OutputKeys.STANDALONE, standAlone);
+    }
+    
+    public void setVersion(String version) {
+        format.put(OutputKeys.VERSION, version);
+    }
+    
+    /**
+     * Set the {@link OutputStream} where the requested resource should
+     * be serialized.
+     */
+    public void setOutputStream(OutputStream output) {
+        this.output = output;
+        TransformerHandler handler = this.transformerFactory.getTransformerHandler();
+        handler.getTransformer().setOutputProperties(this.format);
+        handler.setResult(new StreamResult(this.output));
+        this.setContentHandler(handler);
+        this.setLexicalHandler(handler);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.sitemap.SitemapOutputComponent#getMimeType()
+     */
+    public String getMimeType() {
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.sitemap.SitemapOutputComponent#shouldSetContentLength()
+     */
+    public boolean shouldSetContentLength() {
+        return false;
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/sitemap/SitemapOutputComponent.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/sitemap/SitemapOutputComponent.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.sitemap;
+
+import java.io.OutputStream;
+
+/**
+ * This interface marks a component as a sitemap component that produces
+ * a response, like a serializer or a reader.
+ * 
+ * @version CVS $Id: SitemapOutputComponent.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface SitemapOutputComponent {
+
+    /**
+     * Set the {@link OutputStream} where the requested resource should
+     * be serialized.
+     */
+    void setOutputStream(OutputStream out);
+
+    /**
+     * Get the mime-type of the output of this <code>Component</code>.
+     */
+    String getMimeType();
+
+    /**
+     * Test if the component wants to set the content length
+     */
+    boolean shouldSetContentLength();
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/Source.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/Source.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.InputStream;
+
+
+/**
+ * This interface provides a simple interface for accessing a source of data.
+ * <p>
+ * When the <code>Source</code> object is no longer needed
+ * it must be released using the {@link SourceResolver}. This is very similar to
+ * looking up components from a <code>ServiceSelector</code>.
+ * In fact a source object can implement most lifecycle interfaces
+ * like Composable, Initializable, Disposable etc.
+ * <p>
+ * The data content can be constant or change over time.
+ * Using the {@link #getInputStream()} method you get always the up-to-date content.
+ * <p>
+ * If you want to track changes of the source object, this interface
+ * offers you some support for it by providing a SourceValidity object.
+ * <p>
+ * How does the caching work?
+ * The first time you get a Source object, you simply ask
+ * it for it's content via getInputStream() and then get the validity
+ * object by invoking getValidity. (Further calls to getValidity always
+ * return the same object! This is not updated!)
+ * The caching algorithm can now store this validity object together
+ * with the system identifier of the source.
+ * The next time, the caching algorithm wants to check if the cached
+ * content is still valid. It has a validity object already to check
+ * against.
+ * <p>
+ * If it is still the same Source than the first time, you
+ * have to call refresh() in order to discard the stored validity
+ * in the Source object. If it is a new Source object,
+ * calling refresh() should do no harm.
+ * After that an up-to-date validity object can retrieved by calling
+ * getValidity(). This can be used to test if the content is still valid
+ * as discribed in the source validity documentation.
+ * If the content is still valid, the cache knows what to do, if not,
+ * the new content can be get using getInputStream().
+ * So either after a call to getValidity() or the getInputStream the
+ * validity object must be the same until refresh is called!
+ * 
+ * @version CVS $Id: Source.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface Source {
+    /**
+     * Does this source exist ?
+     * 
+     * @return true if the source exists
+     */
+    boolean exists();
+    
+    /**
+     * Return an <code>InputStream</code> to read from the source.
+     * This is the data at the point of invocation of this method,
+     * so if this is Modifiable, you might get different content
+     * from two different invocations.
+     * 
+     * @return the <code>InputStream</code> to read data from (never <code>null</code>).
+     */
+    InputStream getInputStream();
+
+    /**
+     * Get the absolute URI for this source.
+     * 
+     * @return the source URI.
+     */
+    String getURI();
+
+    /**
+     * Return the URI scheme identifier, i.e. the part preceding the fist ':' in the URI
+     * (see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>).
+     * <p>
+     * This scheme can be used to get the {@link SourceFactory} responsible for this object.
+     * 
+     * @return the URI scheme.
+     */
+    String getScheme();
+    
+    /**
+     * Get the Validity object. This can either wrap the last modification date or
+     * some expiry information or anything else describing this object's validity.
+     * <p>
+     * If it is currently not possible to calculate such an information,
+     * <code>null</code> is returned.
+     * 
+     * @return the validity, or <code>null</code>.
+     */
+    SourceValidity getValidity();
+
+    /**
+     * Refresh the content of this object after the underlying data content has changed.
+     * <p>
+     * Some implementations may cache some values to speedup sucessive calls. Refreshing
+     * ensures you get the latest information.
+     */
+    void refresh();
+
+    /**
+     * Get the mime-type of the content described by this object.
+     * If the source is not able to determine the mime-type by itself
+     * this can be <code>null</code>.
+     * 
+     * @return the source's mime-type or <code>null</code>.
+     */
+    String getMimeType();
+
+    /**
+     * Get the content length of this source's content or -1 if the length is
+     * unknown.
+     * 
+     * @return the source's content length or -1.
+     */
+    long getContentLength();
+
+    /**
+     * Get the last modification date of this source. The date is
+     * measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970),
+     * and is <code>0</code> if it's unknown.
+     * 
+     * @return the last modification date or <code>0</code>.
+     */
+    long getLastModified();
+    
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+
+/**
+ * Superclass of exceptions thrown by sources and source resolvers.
+ * 
+ * @version CVS $Id: SourceException.java,v 1.2 2004/07/25 21:55:20 ugo Exp $
+ */
+public class SourceException extends RuntimeException {
+
+    public SourceException() {
+        super();
+    }
+    
+    public SourceException(String arg0) {
+        super(arg0);
+    }
+
+    public SourceException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    public SourceException(Throwable arg0) {
+        super(arg0);
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceFactory.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceFactory.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ * A source factory creates new source objects.
+ * <p>
+ * Source factories are used to extend the source resolving mechanism
+ * with new URI schemes. A new source factory is added in order to
+ * handle a specific prototol. The {@link SourceResolver} delegates
+ * the handling of a URI containing this new scheme to the factory,
+ * and the factory can create a corresponding {@link Source} object.
+ * 
+ * @version CVS $Id: SourceFactory.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface SourceFactory {
+
+    /**
+     * Get a {@link Source} object.
+     * The factory creates a new {@link Source} object that can be used
+     * by the application. However, when this source object is not needed
+     * anymore it has to be released again using the {@link #release(Source)}
+     * method. This is achieved by using {@link SourceResolver#release(Source)} which
+     * finds the appropriate <code>SourceFactory</code>.
+     * 
+     * @param location   The URI to resolve - this URI includes the scheme.
+     * @param parameters additionnal named parameters (optionnal and can be <code>null</code>)
+     *        that drive the creation of the <code>Source</code> object. Each implementation
+     *        must specify what parameters it accepts.
+     * @return the created source object.
+     *
+     * @throws IOException if the source couldn't be created for some reason.
+     */
+    Source getSource(String location, Map parameters);
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceNotFoundException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceNotFoundException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+
+/**
+ * Description of SourceException.
+ * 
+ * @version CVS $Id: SourceNotFoundException.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class SourceNotFoundException extends RuntimeException {
+
+    public SourceNotFoundException() {
+        super();
+    }
+    
+    public SourceNotFoundException(String arg0) {
+        super(arg0);
+    }
+
+    public SourceNotFoundException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    public SourceNotFoundException(Throwable arg0) {
+        super(arg0);
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceResolver.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceResolver.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+
+/**
+ * Description of SourceResolver.
+ * 
+ * @version CVS $Id: SourceResolver.java,v 1.2 2004/07/25 21:55:20 ugo Exp $
+ */
+public class SourceResolver {
+    private Map factories;
+    URL baseURL;
+    
+    public SourceResolver() {
+        try {
+            // TODO: contextualize it
+            baseURL = new File(System.getProperty("user.dir")).toURL();
+        } catch (MalformedURLException e) {
+            throw new SourceException(e);
+        }
+    }
+    
+    /**
+     * @param factories The factories to set.
+     */
+    public void setFactories(Map factories) {
+        this.factories = factories;
+    }
+    
+    /**
+     * Get a <code>Source</code> object.
+     * @throws org.apache.excalibur.source.SourceNotFoundException if the source cannot be found
+     */
+    public Source resolveURI(String location) {
+        return this.resolveURI(location, null, null);
+    }
+
+    /**
+     * Get a <code>Source</code> object.
+     */
+    public Source resolveURI(String location,
+                             String baseURI,
+                             Map parameters)
+    {
+        if (null != baseURI && SourceUtil.indexOfSchemeColon(baseURI) == -1) {
+            throw new SourceException("BaseURI is not valid, it must contain a protocol: " + baseURI);
+        }
+
+        if( baseURI == null ) baseURI = baseURL.toExternalForm();
+
+        String systemID = location;
+        // special handling for windows file paths
+        if( location.length() > 1 && location.charAt( 1 ) == ':' )
+            systemID = "file:/" + location;
+        else if( location.length() > 2 && location.charAt(0) == '/' && location.charAt(2) == ':' )
+            systemID = "file:" + location;
+
+        // determine protocol (scheme): first try to get the one of the systemID, if that fails, take the one of the baseURI
+        String protocol;
+        int protocolPos = SourceUtil.indexOfSchemeColon(systemID);
+        if( protocolPos != -1 )
+        {
+            protocol = systemID.substring( 0, protocolPos );
+        }
+        else
+        {
+            protocolPos = SourceUtil.indexOfSchemeColon(baseURI);
+            if( protocolPos != -1 )
+                protocol = baseURI.substring( 0, protocolPos );
+            else
+                protocol = "*";
+        }
+
+        Source source = null;
+        // search for a SourceFactory implementing the protocol
+        SourceFactory factory = (SourceFactory) factories.get(protocol);
+        if (factory == null) {
+            factory = (SourceFactory) factories.get("*");
+            if (factory == null) {
+                throw new SourceException("Unable to select source factory for " + systemID);
+            }
+            systemID = absolutize(factory, baseURI, systemID);
+            return factory.getSource(systemID, parameters);
+        }
+        systemID = absolutize(factory, baseURI, systemID);
+        return factory.getSource(systemID, parameters);
+    }
+
+    /**
+     * Makes an absolute URI based on a baseURI and a relative URI.
+     */
+    private String absolutize( SourceFactory factory, String baseURI, String systemID )
+    {
+        if( factory instanceof URIAbsolutizer )
+            systemID = ((URIAbsolutizer) factory).absolutize(baseURI, systemID);
+        else
+            systemID = SourceUtil.absolutize(baseURI, systemID);
+        return systemID;
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceUtil.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceUtil.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Utility class for source resolving.
+ * 
+ * @version CVS $Id: SourceUtil.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class SourceUtil {
+
+    /**
+     * Get the position of the scheme-delimiting colon in an absolute URI, as specified
+     * by <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>, appendix A. This method is
+     * primarily useful for {@link Source} implementors that want to separate
+     * the scheme part from the specific part of an URI.
+     * <p>
+     * Use this method when you need both the scheme and the scheme-specific part of an URI,
+     * as calling successively {@link #getScheme(String)} and {@link #getSpecificPart(String)}
+     * will call this method twice, and as such won't be efficient.
+     *
+     * @param uri the URI
+     * @return int the scheme-delimiting colon, or <code>-1</code> if not found.
+     */
+    public static int indexOfSchemeColon(String uri)
+    {
+        // absoluteURI   = scheme ":" ( hier_part | opaque_part )
+        //
+        // scheme        = alpha *( alpha | digit | "+" | "-" | "." )
+        //
+        // alpha         = lowalpha | upalpha
+        //
+        // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+        //            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+        //            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+        //
+        // upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+        //            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+        //            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+        //
+        // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+        //            "8" | "9"
+
+        // Must have at least one character followed by a colon
+        if (uri == null || uri.length() < 2)
+        {
+            return -1;
+        }
+
+        // Check that first character is alpha
+        // (lowercase first since it's the most common case)
+        char ch = uri.charAt(0);
+        if ( (ch < 'a' || ch > 'z') &&
+             (ch < 'A' || ch > 'Z') )
+        {
+            // Invalid first character
+            return -1;
+        }
+
+        int pos = uri.indexOf(':');
+        if (pos != -1)
+        {
+            // Check that every character before the colon is in the allowed range
+            // (the first one was tested above)
+            for (int i = 1; i < pos; i++)
+            {
+                ch = uri.charAt(i);
+                if ( (ch < 'a' || ch > 'z') &&
+                     (ch < 'A' || ch > 'Z') &&
+                     (ch < '0' || ch > '9') &&
+                     ch != '+' && ch != '-' && ch != '.')
+                {
+                    return -1;
+                }
+            }
+        }
+
+        return pos;
+    }
+
+    /**
+     * Get the scheme of an absolute URI.
+     *
+     * @param uri the absolute URI
+     * @return the URI scheme
+     */
+    public static String getScheme(String uri)
+    {
+        int pos = indexOfSchemeColon(uri);
+        return (pos == -1) ? null : uri.substring(0, pos);
+    }
+
+    /**
+     * Get the scheme-specific part of an absolute URI. Note that this includes everything
+     * after the separating colon, including the fragment, if any (RFC 2396 separates it
+     * from the scheme-specific part).
+     *
+     * @param uri the absolute URI
+     * @return the scheme-specific part of the URI
+     */
+    public static String getSpecificPart(String uri)
+    {
+        int pos = indexOfSchemeColon(uri);
+        return (pos == -1) ? null : uri.substring(pos+1);
+    }
+
+    /**
+     * Calls absolutize(url1, url2, false).
+     */
+    public static String absolutize(String url1, String url2)
+    {
+        return absolutize(url1, url2, false, true);
+    }
+
+    /**
+     * Calls absolutize(url1, url2, false, true).
+     */
+    public static String absolutize(String url1, String url2, boolean treatAuthorityAsBelongingToPath)
+    {
+        return absolutize(url1, url2, treatAuthorityAsBelongingToPath, true);
+    }
+
+    /**
+     * Applies a location to a baseURI. This is done as described in RFC 2396 section 5.2.
+     *
+     * @param url1 the baseURI
+     * @param url2 the location
+     * @param treatAuthorityAsBelongingToPath considers the authority to belong to the path. These
+     * special kind of URIs are used in the Apache Cocoon project.
+     * @param normalizePath should the path be normalized, i.e. remove ../ and /./ etc.
+     */
+    public static String absolutize(String url1, String url2, boolean treatAuthorityAsBelongingToPath, boolean normalizePath)
+    {
+        if (url1 == null)
+            return url2;
+
+        // If the URL contains a scheme (and thus is already absolute), don't do any further work
+        if (getScheme(url2) != null)
+            return url2;
+
+        // parse the urls into parts
+        // if the second url contains a scheme, it is not relative so return it right away (part 3 of the algorithm)
+        String[] url1Parts = parseUrl(url1);
+        String[] url2Parts = parseUrl(url2);
+
+        if (treatAuthorityAsBelongingToPath)
+            return absolutizeWithoutAuthority(url1Parts, url2Parts);
+
+        // check if it is a reference to the current document (part 2 of the algorithm)
+        if (url2Parts[PATH].equals("") && url2Parts[QUERY] == null && url2Parts[AUTHORITY] == null)
+            return makeUrl(url1Parts[SCHEME], url1Parts[AUTHORITY], url1Parts[PATH], url1Parts[QUERY], url2Parts[FRAGMENT]);
+
+        // it is a network reference (part 4 of the algorithm)
+        if (url2Parts[AUTHORITY] != null)
+            return makeUrl(url1Parts[SCHEME], url2Parts[AUTHORITY], url2Parts[PATH], url2Parts[QUERY], url2Parts[QUERY]);
+
+        String url1Path = url1Parts[PATH];
+        String url2Path = url2Parts[PATH];
+
+        // if the path starts with a slash (part 5 of the algorithm)
+        if (url2Path != null && url2Path.length() > 0 && url2Path.charAt(0) == '/')
+            return makeUrl(url1Parts[SCHEME], url1Parts[AUTHORITY], url2Parts[PATH], url2Parts[QUERY], url2Parts[QUERY]);
+
+        // combine the 2 paths
+        String path = stripLastSegment(url1Path);
+        path = path + (path.endsWith("/") ? "" : "/") + url2Path;
+        if (normalizePath)
+            path = normalize(path);
+
+        return makeUrl(url1Parts[SCHEME], url1Parts[AUTHORITY], path, url2Parts[QUERY], url2Parts[FRAGMENT]);
+    }
+
+    /**
+     * Absolutizes URIs whereby the authority part is considered to be a part of the path.
+     * This special kind of URIs is used in the Apache Cocoon project for the cocoon and context protocols.
+     * This method is internally used by {@link #absolutize}.
+     */
+    private static String absolutizeWithoutAuthority(String[] url1Parts, String[] url2Parts)
+    {
+        String authority1 = url1Parts[AUTHORITY];
+        String authority2 = url2Parts[AUTHORITY];
+
+        String path1 = url1Parts[PATH];
+        String path2 = url2Parts[PATH];
+
+        if (authority1 != null)
+            path1 = "//" + authority1 + path1;
+        if (authority2 != null)
+            path2 = "//" + authority2 + path2;
+
+        String path = stripLastSegment(path1);
+        path = path + (path.endsWith("/") ? "" : "/") + path2;
+        path = normalize(path);
+
+        String scheme = url1Parts[SCHEME];
+        return scheme + ":" + path;
+    }
+
+    private static String stripLastSegment(String path)
+    {
+        int i = path.lastIndexOf('/');
+        if(i > -1)
+            return path.substring(0, i + 1);
+        return path;
+    }
+
+    /**
+     * Removes things like &lt;segment&gt;/../ or ./, as described in RFC 2396 in
+     * step 6 of section 5.2.
+     */
+    private static String normalize(String path)
+    {
+        // replace all /./ with /
+        int i = path.indexOf("/./");
+        while (i > -1)
+        {
+            path = path.substring(0, i + 1) + path.substring(i + 3);
+            i = path.indexOf("/./");
+        }
+
+        if (path.endsWith("/."))
+            path = path.substring(0, path.length() - 1);
+
+        int f = path.indexOf("/../");
+        while (f > 0)
+        {
+            int sb = path.lastIndexOf("/", f - 1);
+            if (sb > - 1)
+                path = path.substring(0, sb + 1) + (path.length() >= f + 4 ? path.substring(f + 4) : "");
+            f = path.indexOf("/../");
+        }
+
+        if (path.length() > 3 && path.endsWith("/.."))
+        {
+            int sb = path.lastIndexOf("/", path.length() - 4);
+            String segment = path.substring(sb, path.length() - 3);
+            if (!segment.equals(".."))
+            {
+                path = path.substring(0, sb + 1);
+            }
+        }
+
+        return path;
+    }
+
+    /**
+     * Assembles an URL from the given URL parts, each of these parts can be null.
+     * Used internally by {@link #absolutize}.
+     */
+    private static String makeUrl(String scheme, String authority, String path, String query, String fragment)
+    {
+        StringBuffer url = new StringBuffer();
+        if (scheme != null)
+            url.append(scheme).append(':');
+
+        if (authority != null)
+            url.append("//").append(authority);
+
+        if (path != null)
+            url.append(path);
+
+        if (query != null)
+            url.append('?').append(query);
+
+        if (fragment != null)
+            url.append('#').append(fragment);
+
+        return url.toString();
+    }
+
+    public static final int SCHEME = 0;
+    public static final int AUTHORITY = 1;
+    public static final int PATH = 2;
+    public static final int QUERY = 3;
+    public static final int FRAGMENT = 4;
+
+    /**
+     * Parses an URL into the following parts: scheme, authority, path, query and fragment identifier.
+     *
+     * <p>The parsing is designed to be robust in the sense that it will never fail, even when an invalid
+     * URL is given. The parser will simply look for the most important delimiter characters. Basically
+     * it does the same as what would be achieved using the following regular expression (from RFC 2396):
+     * <pre>
+     * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+     *  12            3  4          5       6  7        8 9
+     * </pre>
+     * but without actually using the regular expression.
+     *
+     * <p>The result is returned as a string array, use the constants SCHEME, AUTHORITY, PATH,
+     * QUERY and FRAGMENT_IDENTIFIER to access the different parts.
+     *
+     * <p>If a part is missing, its corresponding entry in the array will be null, except for the
+     * path, which will never be null.
+     */
+    public static String[] parseUrl(String url) {
+        char[] urlchars = url.toCharArray();
+
+        int pos = 0;
+
+        String scheme = null;
+        String authority = null;
+        String path = null;
+        String query = null;
+        String fragid = null;
+
+        //  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+
+        // the scheme
+        boolean keepgoing = true;
+        while (keepgoing && pos < urlchars.length)
+        {
+            switch (urlchars[pos])
+            {
+                case ':':
+                    if (pos >= 1)
+                    {
+                        scheme = new String(urlchars, 0, pos);
+                        keepgoing = false;
+                        pos++;
+                        break;
+                    }
+                case '/':
+                case '?':
+                case '#':
+                    keepgoing = false;
+                    break;
+                default:
+                    pos++;
+            }
+        }
+
+        if (scheme == null)
+            pos = 0;
+
+        //  the authority
+        if (pos + 1 < urlchars.length && urlchars[pos] == '/' && urlchars[pos+1] == '/')
+        {
+            pos += 2;
+            int authorityBeginPos = pos;
+            keepgoing = true;
+            while (keepgoing && pos < urlchars.length)
+            {
+                switch (urlchars[pos])
+                {
+                    case '/':
+                    case '?':
+                    case '#':
+                        keepgoing = false;
+                        break;
+                    default:
+                        pos++;
+                }
+            }
+            authority = new String(urlchars, authorityBeginPos, pos - authorityBeginPos);
+        }
+
+        //  the path
+        int pathBeginPos = pos;
+        keepgoing = true;
+        while (keepgoing && pos < urlchars.length)
+        {
+            switch (urlchars[pos])
+            {
+                case '?':
+                case '#':
+                    keepgoing = false;
+                    break;
+                default:
+                    pos++;
+            }
+        }
+        path = new String(urlchars, pathBeginPos, pos - pathBeginPos);
+
+        // the query
+        if (pos < urlchars.length && urlchars[pos] == '?')
+        {
+            pos++;
+            int queryBeginPos = pos;
+            keepgoing = true;
+            while (keepgoing && pos < urlchars.length)
+            {
+                switch (urlchars[pos])
+                {
+                    case '#':
+                        keepgoing = false;
+                        break;
+                    default:
+                        pos++;
+                }
+            }
+            query = new String(urlchars, queryBeginPos, pos - queryBeginPos);
+        }
+
+        // the fragment identifier
+        pos++;
+        if (pos < urlchars.length)
+            fragid = new String(urlchars, pos, urlchars.length - pos);
+
+        return new String[] {scheme, authority, path, query, fragid};
+    }
+
+    /**
+     * Decode a path.
+     *
+     * <p>Interprets %XX (where XX is hexadecimal number) as UTF-8 encoded bytes.
+     * <p>The validity of the input path is not checked (i.e. characters that
+     * were not encoded will not be reported as errors).
+     * <p>This method differs from URLDecoder.decode in that it always uses UTF-8
+     * (while URLDecoder uses the platform default encoding, often ISO-8859-1),
+     * and doesn't translate + characters to spaces.
+     *
+     * @param path the path to decode
+     * @return the decoded path
+     */
+    public static String decodePath(String path) {
+        StringBuffer translatedPath = new StringBuffer(path.length());
+        byte[] encodedchars = new byte[path.length() / 3];
+        int i = 0;
+        int length = path.length();
+        int encodedcharsLength = 0;
+        while (i < length) {
+            if (path.charAt(i) == '%') {
+                // we must process all consecutive %-encoded characters in one go, because they represent
+                // an UTF-8 encoded string, and in UTF-8 one character can be encoded as multiple bytes
+                while (i < length && path.charAt(i) == '%') {
+                    if (i + 2 < length) {
+                        try {
+                            byte x = (byte)Integer.parseInt(path.substring(i + 1, i + 3), 16);
+                            encodedchars[encodedcharsLength] = x;
+                        } catch (NumberFormatException e) {
+                            throw new IllegalArgumentException("Illegal hex characters in pattern %" + path.substring(i + 1, i + 3));
+                        }
+                        encodedcharsLength++;
+                        i += 3;
+                    } else {
+                        throw new IllegalArgumentException("% character should be followed by 2 hexadecimal characters.");
+                    }
+                }
+                try {
+                    String translatedPart = new String(encodedchars, 0, encodedcharsLength, "UTF-8");
+                    translatedPath.append(translatedPart);
+                } catch (UnsupportedEncodingException e) {
+                    // the situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception
+                    throw new RuntimeException("Problem in decodePath: UTF-8 encoding not supported.");
+                }
+                encodedcharsLength = 0;
+            } else {
+                // a normal character
+                translatedPath.append(path.charAt(i));
+                i++;
+            }
+        }
+        return translatedPath.toString();
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/SourceValidity.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/SourceValidity.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.Serializable;
+
+
+/**
+ * A <code>SourceValidity</code> object contains all information to check if a Source
+ * object is still valid.
+ * <p>
+ * There are two possibilities:
+ * <ul>
+ * <li>The validity object has all information to check by itself if it is valid
+ *     (e.g. given an expires date).</li>
+ * <li>The validity object possibility needs another (newer) validity object to compare
+ *     against (e.g. to test a last modification date).</li>
+ * </ul>
+ * To avoid testing what the actual implementation of the validity object supports,
+ * the invocation order is to first call {@link #isValid()} and only if this result
+ * is <code>0</code> (i.e. "don't know"), then to call {@link #isValid(SourceValidity)}.
+ * <p>
+ * Remember to call {@link #isValid(SourceValidity)} when {@link #isValid()} returned
+ * <code>0</code> !
+ * 
+ * @version CVS $Id: SourceValidity.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface SourceValidity extends Serializable {
+    final int VALID   = +1;
+    final int INVALID = -1;
+    final int UNKNOWN = 0;
+    
+    /**
+     * Check if the component is still valid. The possible results are :
+     * <ul>
+     * <li><code>-1</code>: invalid. The component isn't valid anymore.</li>
+     * <li><code>0</code>: don't know. This validity should be checked against a new
+     *     validity object using {@link #isValid(SourceValidity)}.</li>
+     * <li><code>1</code>: valid. The component is still valid.</li>
+     * </ul>
+     */
+    int isValid();
+
+    /**
+     * Check if the component is still valid. This is only true if the incoming Validity
+     * is of the same type and has the "same" values.
+     * <p>
+     * The invocation order is that the isValid
+     * method of the old Validity object is called with the new one as a
+     * parameter.
+     * @return -1 is returned, if the validity object is not valid anymore
+     *          +1 is returned, if the validity object is still valid
+     *          0  is returned, if the validity check could not be performed.
+     *             In this case, the new validity object is not usable. Examples
+     *             for this are: when the validity objects have different types,
+     *             or when one validity object for any reason is not able to
+     *             get the required information.
+     */
+    int isValid(SourceValidity newValidity);
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/URIAbsolutizer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/URIAbsolutizer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+
+/**
+ * Implemented by a SourceFactory when it supports applying a relative URI
+ * to a base URI to form an absolute URI.
+ *
+ * <p>If a source factory does not implement this interface, the standard
+ * algorithm (as described in RFC 2396) will be used. This interface only
+ * needs to be implemented for source-types which have a different behaviour.
+ * 
+ * @version CVS $Id: URIAbsolutizer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface URIAbsolutizer {
+
+    public String absolutize(String baseURI, String location);
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSource.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSource.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URLConnection;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceException;
+import org.apache.butterfly.source.SourceNotFoundException;
+import org.apache.butterfly.source.SourceUtil;
+import org.apache.butterfly.source.SourceValidity;
+import org.apache.butterfly.source.impl.validity.FileTimeStampValidity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Description of FileSource.
+ * 
+ * @version CVS $Id: FileSource.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class FileSource implements Source {
+
+    /** The file */
+    private File file;
+
+    /** The scheme */
+    private String scheme;
+
+    /** The URI of this source */
+    private String uri;
+    
+    /** The logger */
+    protected static final Log logger = LogFactory.getLog(FileSource.class);
+
+    public FileSource(String uri)  {
+        int pos = SourceUtil.indexOfSchemeColon(uri);
+        if (pos < 0) {
+            throw new SourceException("Invalid URI : " + uri);
+        }
+        String scheme = uri.substring(0, pos);
+        String fileName = uri.substring(pos + 1);
+        fileName = SourceUtil.decodePath(fileName);
+        init(scheme, new File(fileName));
+    }
+
+    /**
+     * Builds a FileSource, given an URI scheme and a File.
+     * 
+     * @param scheme
+     * @param file
+     * @throws SourceException
+     */
+    public FileSource(String scheme, File file) throws SourceException
+    {
+        init(scheme, file);
+    }
+
+    private void init(String scheme, File file) throws SourceException
+    {
+        this.scheme = scheme;
+
+        String uri;
+        try {
+            uri = file.toURL().toExternalForm();
+        } catch (MalformedURLException mue) {
+            // Can this really happen ?
+            throw new SourceException("Failed to get URL for file " + file, mue);
+        }
+        if (!uri.startsWith(scheme)) {
+            // Scheme is not "file:"
+            uri = scheme + ':' + uri.substring(uri.indexOf(':') + 1);
+        }
+        this.uri = uri;
+        this.file = file;
+    }
+
+    /**
+     * Get the associated file
+     */
+    public File getFile()
+    {
+        return this.file;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#exists()
+     */
+    public boolean exists() {
+        return getFile().exists();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getInputStream()
+     */
+    public InputStream getInputStream() {
+        try {
+            return new FileInputStream(this.file);
+        } catch (FileNotFoundException fnfe) {
+            throw new SourceNotFoundException(this.uri + " doesn't exist.", fnfe);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getURI()
+     */
+    public String getURI() {
+        return this.uri;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getScheme()
+     */
+    public String getScheme() {
+        return this.scheme;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getValidity()
+     */
+    public SourceValidity getValidity() {
+        if (this.file.exists()) {
+            return new FileTimeStampValidity(this.file);
+        } else {
+            return null;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#refresh()
+     */
+    public void refresh() {
+        // Nothing to do
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getMimeType()
+     */
+    public String getMimeType() {
+        return URLConnection.getFileNameMap().getContentTypeFor(this.file.getName());
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getContentLength()
+     */
+    public long getContentLength() {
+        return this.file.length();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getLastModified()
+     */
+    public long getLastModified() {
+        return this.file.lastModified();
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSourceFactory.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/impl/FileSourceFactory.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source.impl;
+
+import java.util.Map;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceFactory;
+import org.apache.butterfly.source.SourceUtil;
+import org.apache.butterfly.source.URIAbsolutizer;
+
+
+/**
+ * Description of FileSourceFactory.
+ * 
+ * @version CVS $Id: FileSourceFactory.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class FileSourceFactory implements SourceFactory, URIAbsolutizer {
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.SourceFactory#getSource(java.lang.String, java.util.Map)
+     */
+    public Source getSource(String location, Map parameters) {
+        return new FileSource(location);
+    }
+
+    public String absolutize(String baseURI, String location)
+    {
+        // Call the absolutize utility method with false for the normalizePath argument.
+        // This avoids the removal of "../" from the path.
+        // This way, the "../" will be resolved by the operating system, which might
+        // do things differently e.g. in case of symbolic links.
+        return SourceUtil.absolutize(baseURI, location, false, false);
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSource.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSource.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source.impl;
+
+import java.io.InputStream;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceValidity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Description of URLSource.
+ * 
+ * @version CVS $Id: URLSource.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class URLSource implements Source {
+    
+    /** The logger */
+    protected static final Log logger = LogFactory.getLog(URLSource.class);
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#exists()
+     */
+    public boolean exists() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getInputStream()
+     */
+    public InputStream getInputStream() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getURI()
+     */
+    public String getURI() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getScheme()
+     */
+    public String getScheme() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getValidity()
+     */
+    public SourceValidity getValidity() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#refresh()
+     */
+    public void refresh() {
+        // TODO Auto-generated method stub
+
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getMimeType()
+     */
+    public String getMimeType() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getContentLength()
+     */
+    public long getContentLength() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.Source#getLastModified()
+     */
+    public long getLastModified() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSourceFactory.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/impl/URLSourceFactory.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source.impl;
+
+import java.util.Map;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceFactory;
+
+
+/**
+ * Description of URLSourceFactory.
+ * 
+ * @version CVS $Id: URLSourceFactory.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class URLSourceFactory implements SourceFactory {
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.source.SourceFactory#getSource(java.lang.String, java.util.Map)
+     */
+    public Source getSource(String location, Map parameters) {
+        return new URLSource();
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/source/impl/validity/FileTimeStampValidity.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/source/impl/validity/FileTimeStampValidity.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source.impl.validity;
+
+import java.io.File;
+
+import org.apache.butterfly.source.SourceValidity;
+
+
+/**
+ * Description of FileTimeStampValidity.
+ * 
+ * @version CVS $Id: FileTimeStampValidity.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class FileTimeStampValidity implements SourceValidity {
+    private long timeStamp;
+    private File file;
+
+    public FileTimeStampValidity( final String filename )
+    {
+        this( new File( filename ) );
+    }
+
+    public FileTimeStampValidity( final File file )
+    {
+        this( file, file.lastModified() );
+    }
+
+    public FileTimeStampValidity( final File file,
+                                  final long timeStamp )
+    {
+        this.file = file;
+        this.timeStamp = timeStamp;
+    }
+
+    /**
+     * Check if the component is still valid.
+     * If <code>0</code> is returned the isValid(SourceValidity) must be
+     * called afterwards!
+     * If -1 is returned, the component is not valid anymore and if +1
+     * is returnd, the component is valid.
+     */
+    public int isValid()
+    {
+        return ( this.file.lastModified() == this.timeStamp ? 1 : -1 );
+    }
+
+    public int isValid( final SourceValidity newValidity )
+    {
+        if( newValidity instanceof FileTimeStampValidity )
+        {
+            final long timeStamp =
+                ( (FileTimeStampValidity)newValidity ).getTimeStamp();
+            return ( this.timeStamp == timeStamp ? 1 : -1);
+        }
+        return -1;
+    }
+
+    public File getFile()
+    {
+        return this.file;
+    }
+
+    public long getTimeStamp()
+    {
+        return this.timeStamp;
+    }
+
+    public String toString()
+    {
+        return "FileTimeStampValidity: " + this.file.getPath() + ": " + this.timeStamp;
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/transformation/Transformer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/transformation/Transformer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.transformation;
+
+import org.apache.butterfly.xml.XMLPipe;
+
+
+/**
+ * Description of Transformer.
+ * 
+ * @version CVS $Id: Transformer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface Transformer extends XMLPipe {
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/transformation/TraxTransformer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/transformation/TraxTransformer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.transformation;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.TransformerHandler;
+
+import org.apache.butterfly.source.Source;
+import org.apache.butterfly.source.SourceResolver;
+import org.apache.butterfly.xml.AbstractXMLPipe;
+import org.apache.butterfly.xml.XMLConsumer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Description of TraxTransformer.
+ * 
+ * @version CVS $Id: TraxTransformer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class TraxTransformer extends AbstractXMLPipe implements Transformer {    
+    private Source inputSource;
+    protected static final Log logger = LogFactory.getLog(TraxTransformer.class);
+    private SourceResolver sourceResolver;
+    private TransformerHandler transformerHandler;
+    
+    /**
+     * @param handler
+     * @param resolver
+     */
+    public TraxTransformer(TransformerHandler handler, SourceResolver resolver) {
+        this.transformerHandler = handler;
+        this.sourceResolver = resolver;
+    }
+
+    public void setInputSource(String source) throws MalformedURLException, IOException {
+        this.inputSource = sourceResolver.resolveURI(source);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.butterfly.xml.XMLProducer#setConsumer(org.apache.butterfly.xml.XMLConsumer)
+     */
+    public void setConsumer(XMLConsumer consumer) {
+        setContentHandler(this.transformerHandler);
+        setLexicalHandler(this.transformerHandler);
+        // According to TrAX specs, all TransformerHandlers are LexicalHandlers
+        final SAXResult result = new SAXResult(consumer);
+        result.setLexicalHandler(consumer);
+        this.transformerHandler.setResult(result);
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLPipe.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLPipe.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * This class provides a bridge class to connect to existing content
+ * handlers and lexical handlers.
+ *
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @version CVS $Id: AbstractXMLPipe.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public abstract class AbstractXMLPipe extends AbstractXMLProducer implements XMLPipe {
+
+    /**
+     * Receive an object for locating the origin of SAX document events.
+     *
+     * @param locator An object that can return the location of any SAX
+     *                document event.
+     */
+    public void setDocumentLocator(Locator locator) {
+        if (contentHandler != null) contentHandler.setDocumentLocator(locator);
+    }
+
+    /**
+     * Receive notification of the beginning of a document.
+     */
+    public void startDocument()
+    throws SAXException {
+        if (contentHandler != null) contentHandler.startDocument();
+    }
+
+    /**
+     * Receive notification of the end of a document.
+     */
+    public void endDocument()
+    throws SAXException {
+        if (contentHandler != null) contentHandler.endDocument();
+    }
+
+    /**
+     * Begin the scope of a prefix-URI Namespace mapping.
+     *
+     * @param prefix The Namespace prefix being declared.
+     * @param uri The Namespace URI the prefix is mapped to.
+     */
+    public void startPrefixMapping(String prefix, String uri)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.startPrefixMapping(prefix, uri);
+    }
+
+    /**
+     * End the scope of a prefix-URI mapping.
+     *
+     * @param prefix The prefix that was being mapping.
+     */
+    public void endPrefixMapping(String prefix)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.endPrefixMapping(prefix);
+    }
+
+    /**
+     * Receive notification of the beginning of an element.
+     *
+     * @param uri The Namespace URI, or the empty string if the element has no
+     *            Namespace URI or if Namespace
+     *            processing is not being performed.
+     * @param loc The local name (without prefix), or the empty string if
+     *            Namespace processing is not being performed.
+     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
+     *            raw names are not available.
+     * @param a The attributes attached to the element. If there are no
+     *          attributes, it shall be an empty Attributes object.
+     */
+    public void startElement(String uri, String loc, String raw, Attributes a)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.startElement(uri, loc, raw, a);
+    }
+
+
+    /**
+     * Receive notification of the end of an element.
+     *
+     * @param uri The Namespace URI, or the empty string if the element has no
+     *            Namespace URI or if Namespace
+     *            processing is not being performed.
+     * @param loc The local name (without prefix), or the empty string if
+     *            Namespace processing is not being performed.
+     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
+     *            raw names are not available.
+     */
+    public void endElement(String uri, String loc, String raw)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.endElement(uri, loc, raw);
+    }
+
+    /**
+     * Receive notification of character data.
+     *
+     * @param c The characters from the XML document.
+     * @param start The start position in the array.
+     * @param len The number of characters to read from the array.
+     */
+    public void characters(char c[], int start, int len)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.characters(c, start, len);
+    }
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * @param c The characters from the XML document.
+     * @param start The start position in the array.
+     * @param len The number of characters to read from the array.
+     */
+    public void ignorableWhitespace(char c[], int start, int len)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.ignorableWhitespace(c, start, len);
+    }
+
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * @param target The processing instruction target.
+     * @param data The processing instruction data, or null if none was
+     *             supplied.
+     */
+    public void processingInstruction(String target, String data)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.processingInstruction(target, data);
+    }
+
+    /**
+     * Receive notification of a skipped entity.
+     *
+     * @param name The name of the skipped entity.  If it is a  parameter
+     *             entity, the name will begin with '%'.
+     */
+    public void skippedEntity(String name)
+    throws SAXException {
+        if (contentHandler != null) contentHandler.skippedEntity(name);
+    }
+
+    /**
+     * Report the start of DTD declarations, if any.
+     *
+     * @param name The document type name.
+     * @param publicId The declared public identifier for the external DTD
+     *                 subset, or null if none was declared.
+     * @param systemId The declared system identifier for the external DTD
+     *                 subset, or null if none was declared.
+     */
+    public void startDTD(String name, String publicId, String systemId)
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.startDTD(name, publicId, systemId);
+    }
+
+    /**
+     * Report the end of DTD declarations.
+     */
+    public void endDTD()
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.endDTD();
+    }
+
+    /**
+     * Report the beginning of an entity.
+     *
+     * @param name The name of the entity. If it is a parameter entity, the
+     *             name will begin with '%'.
+     */
+    public void startEntity(String name)
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.startEntity(name);
+    }
+
+    /**
+     * Report the end of an entity.
+     *
+     * @param name The name of the entity that is ending.
+     */
+    public void endEntity(String name)
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.endEntity(name);
+    }
+
+    /**
+     * Report the start of a CDATA section.
+     */
+    public void startCDATA()
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.startCDATA();
+    }
+
+    /**
+     * Report the end of a CDATA section.
+     */
+    public void endCDATA()
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.endCDATA();
+    }
+
+    /**
+     * Report an XML comment anywhere in the document.
+     *
+     * @param ch An array holding the characters in the comment.
+     * @param start The starting position in the array.
+     * @param len The number of characters to use from the array.
+     */
+    public void comment(char ch[], int start, int len)
+    throws SAXException {
+        if (lexicalHandler != null) lexicalHandler.comment(ch, start, len);
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLProducer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/AbstractXMLProducer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * This abstract class provides default implementation of the methods specified
+ * by the <code>XMLProducer</code> interface.
+ *
+ * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
+ *         (Apache Software Foundation)
+ * @version CVS $Id: AbstractXMLProducer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public abstract class AbstractXMLProducer
+implements XMLProducer {
+
+    /** The <code>XMLConsumer</code> receiving SAX events. */
+    protected XMLConsumer xmlConsumer;
+
+    /** The <code>ContentHandler</code> receiving SAX events. */
+    protected ContentHandler contentHandler;
+
+    /** The <code>LexicalHandler</code> receiving SAX events. */
+    protected LexicalHandler lexicalHandler;
+
+    /**
+     * Set the <code>XMLConsumer</code> that will receive XML data.
+     * <br>
+     * This method will simply call <code>setContentHandler(consumer)</code>
+     * and <code>setLexicalHandler(consumer)</code>.
+     */
+    public void setConsumer(XMLConsumer consumer) {
+        this.xmlConsumer = consumer;
+        setContentHandler(consumer);
+        setLexicalHandler(consumer);
+    }
+
+    /**
+     * Set the <code>ContentHandler</code> that will receive XML data.
+     * <br>
+     * Subclasses may retrieve this <code>ContentHandler</code> instance
+     * accessing the protected <code>super.contentHandler</code> field.
+     */
+    public void setContentHandler(ContentHandler handler) {
+        this.contentHandler = handler;
+    }
+
+    /**
+     * Set the <code>LexicalHandler</code> that will receive XML data.
+     * <br>
+     * Subclasses may retrieve this <code>LexicalHandler</code> instance
+     * accessing the protected <code>super.lexicalHandler</code> field.
+     */
+    public void setLexicalHandler(LexicalHandler handler) {
+        this.lexicalHandler = handler;
+    }
+
+    /**
+     * Recycle the producer by removing references
+     */
+    public void recycle() {
+        this.xmlConsumer = null;
+        this.contentHandler = null;
+        this.lexicalHandler = null;
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/EmbeddedXMLPipe.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/EmbeddedXMLPipe.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * This class implements a ContentHandler for embedding a full SAX
+ * event stream into an existing stream of SAX events. An instance of
+ * this class will pass unmodified all the SAX events to the linked
+ * ContentHandler, but will ignore the startDocument and endDocument
+ * events.
+ *
+ * @version CVS $Id: EmbeddedXMLPipe.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class EmbeddedXMLPipe extends AbstractXMLPipe
+{
+    /**
+     * Creates an EmbeddedXMLPipe that writes into the given ContentHandler.
+     */
+    public EmbeddedXMLPipe(ContentHandler handler) {
+        setContentHandler(handler);
+    }
+
+    /**
+     * Ignore the <code>startDocument</code> event: this method does nothing.
+     *
+     * @exception SAXException if an error occurs
+     */
+    public void startDocument()
+    throws SAXException
+    {
+    }
+
+    /**
+     * Ignore the <code>endDocument</code> event: this method does nothing.
+     *
+     * @exception SAXException if an error occurs
+     */
+    public void endDocument()
+    throws SAXException
+    {
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/Parser.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/Parser.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import java.io.IOException;
+
+import org.apache.butterfly.source.Source;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+
+/**
+ * Wraps a {@link org.xml.sax.XMLReader}.
+ * 
+ * TODO: wrap all exceptions in runtime exceptions.
+ * 
+ * @version CVS $Id: Parser.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class Parser {
+    private XMLReader xmlReader;
+    private String saxDriver;
+    
+    protected static final Log logger = LogFactory.getLog(Parser.class);
+    
+    /**
+     * @param saxDriver The saxDriver to set.
+     */
+    public void setSaxDriver(String saxDriver) {
+        this.saxDriver = saxDriver;
+    }
+    
+    public void initialize() {
+        try {
+            xmlReader = XMLReaderFactory.createXMLReader(saxDriver);
+        } catch (SAXException e) {
+            throw new XMLException("Cannot initialize XML parser", e);
+        }
+    }
+    
+    public void parse(Source source) {
+        try {
+            xmlReader.parse(new InputSource(source.getInputStream()));
+        } catch (IOException e) {
+            // TODO log
+            throw new XMLException("I/O error while reading '" + source + "'", e);
+        } catch (SAXException e) {
+            // TODO log
+            throw new XMLException("SAX error while parsing '" + source + "'", e);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object arg0) {
+        return xmlReader.equals(arg0);
+    }
+    
+    /**
+     * @return
+     */
+    public ContentHandler getContentHandler() {
+        return xmlReader.getContentHandler();
+    }
+    
+    /**
+     * @return
+     */
+    public DTDHandler getDTDHandler() {
+        return xmlReader.getDTDHandler();
+    }
+    
+    /**
+     * @return
+     */
+    public EntityResolver getEntityResolver() {
+        return xmlReader.getEntityResolver();
+    }
+    
+    /**
+     * @return
+     */
+    public ErrorHandler getErrorHandler() {
+        return xmlReader.getErrorHandler();
+    }
+    
+    /**
+     * @param arg0
+     * @return
+     * @throws org.xml.sax.SAXNotRecognizedException
+     * @throws org.xml.sax.SAXNotSupportedException
+     */
+    public boolean getFeature(String arg0) throws SAXNotRecognizedException,
+            SAXNotSupportedException {
+        return xmlReader.getFeature(arg0);
+    }
+    
+    /**
+     * @param arg0
+     * @return
+     * @throws org.xml.sax.SAXNotRecognizedException
+     * @throws org.xml.sax.SAXNotSupportedException
+     */
+    public Object getProperty(String arg0) throws SAXNotRecognizedException,
+            SAXNotSupportedException {
+        return xmlReader.getProperty(arg0);
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return xmlReader.hashCode();
+    }
+    
+    /**
+     * @param arg0
+     * @throws java.io.IOException
+     * @throws org.xml.sax.SAXException
+     */
+    public void parse(String arg0) throws IOException, SAXException {
+        xmlReader.parse(arg0);
+    }
+    
+    /**
+     * @param arg0
+     * @throws java.io.IOException
+     * @throws org.xml.sax.SAXException
+     */
+    public void parse(InputSource arg0) throws IOException, SAXException {
+        xmlReader.parse(arg0);
+    }
+    
+    /**
+     * @param arg0
+     */
+    public void setContentHandler(ContentHandler arg0) {
+        xmlReader.setContentHandler(arg0);
+    }
+    
+    /**
+     * @param arg0
+     */
+    public void setDTDHandler(DTDHandler arg0) {
+        xmlReader.setDTDHandler(arg0);
+    }
+    
+    /**
+     * @param arg0
+     */
+    public void setEntityResolver(EntityResolver arg0) {
+        xmlReader.setEntityResolver(arg0);
+    }
+    
+    /**
+     * @param arg0
+     */
+    public void setErrorHandler(ErrorHandler arg0) {
+        xmlReader.setErrorHandler(arg0);
+    }
+    
+    /**
+     * @param arg0
+     * @param arg1
+     * @throws org.xml.sax.SAXNotRecognizedException
+     * @throws org.xml.sax.SAXNotSupportedException
+     */
+    public void setFeature(String arg0, boolean arg1)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        xmlReader.setFeature(arg0, arg1);
+    }
+    
+    /**
+     * @param arg0
+     * @param arg1
+     * @throws org.xml.sax.SAXNotRecognizedException
+     * @throws org.xml.sax.SAXNotSupportedException
+     */
+    public void setProperty(String arg0, Object arg1)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        xmlReader.setProperty(arg0, arg1);
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return xmlReader.toString();
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/WhitespaceFilter.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/WhitespaceFilter.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * A SAX filter to remove whitespace character, which disturb the
+ * XML matching process.
+ *
+ * @version CVS $Id: WhitespaceFilter.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class WhitespaceFilter extends AbstractXMLPipe {
+    private StringBuffer buffer = null;
+
+    /**
+     * Create a new WhitespaceFilter.
+     *
+     * @param handler Content handler.
+     */
+    public WhitespaceFilter(ContentHandler handler) {
+        setContentHandler(handler);
+    }
+
+    /**
+     * Receive notification of character data.
+     */
+    public void characters(char c[], int start, int len) throws SAXException {
+        if (contentHandler==null) {
+            return;
+        }
+
+        if (buffer==null) {
+            buffer = new StringBuffer();
+        }
+
+        buffer.append(c, start, len);
+    }
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     */
+    public void ignorableWhitespace(char c[], int start,
+                                    int len) throws SAXException {
+        // ignore
+    }
+
+    /**
+     * Receive notification of the beginning of an element.
+     */
+    public void startElement(String namespaceURI, String localName,
+                             String qName,
+                             Attributes atts) throws SAXException {
+
+        pushText();      
+        contentHandler.startElement(namespaceURI, localName, qName, atts);
+    }
+
+    /**
+     * Receive notification of the end of an element.
+     */
+    public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+
+        pushText();
+        contentHandler.endElement(uri, loc, raw);        
+    }
+
+    /**
+     * Receive notification of a processing instruction.
+     */
+    public void processingInstruction(String target, String data)
+        throws SAXException {
+
+        pushText();
+        contentHandler.processingInstruction(target, data);
+    }
+
+    /**
+     * Report an XML comment anywhere in the document.
+     *
+     * @param ch An array holding the characters in the comment.
+     * @param start The starting position in the array.
+     * @param len The number of characters to use from the array.
+     */
+    public void comment(char ch[], int start, int len)
+        throws SAXException {
+  
+        pushText();
+        super.comment(ch, start, len);
+    }
+
+
+    public void pushText() throws SAXException {
+
+        if (buffer!=null) {
+            String text = buffer.toString();
+
+            StringBuffer normalized = new StringBuffer();
+
+            for(int i=0; i<text.length(); i++) {
+                if (Character.isWhitespace(text.charAt(i))) {
+                    normalized.append(' ');
+                    while (((i+1)<text.length()) && (Character.isWhitespace(text.charAt(i+1))))
+                        i++;
+                } else {
+                    normalized.append(text.charAt(i));
+                }
+            }
+
+            text = normalized.toString().trim();
+
+            if (text.length()>0) {
+                contentHandler.characters(text.toCharArray(), 0,
+                                          text.length());
+            }
+
+            buffer = null;
+        }
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/XMLConsumer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/XMLConsumer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * This interfaces identifies classes that consume XML data, receiving
+ * notification of SAX events.
+ * <br>
+ * This interface unites the idea of SAX <code>ContentHandler</code> and
+ * <code>LexicalHandler</code>.
+ *
+ * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
+ *         (Apache Software Foundation)
+ * @version CVS $Id: XMLConsumer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface XMLConsumer extends ContentHandler, LexicalHandler {
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/XMLException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/XMLException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+
+/**
+ * Description of XMLException.
+ * 
+ * @version CVS $Id: XMLException.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class XMLException extends RuntimeException {
+
+    /**
+     * 
+     */
+    public XMLException() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     */
+    public XMLException(String arg0) {
+        super(arg0);
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public XMLException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     */
+    public XMLException(Throwable arg0) {
+        super(arg0);
+        // TODO Auto-generated constructor stub
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/XMLPipe.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/XMLPipe.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+/**
+ * This interface glues together an XML producer and consumer to create a
+ * SAX pipe.
+ *
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @version CVS $Id: XMLPipe.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+
+public interface XMLPipe extends XMLConsumer, XMLProducer {}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/XMLProducer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/XMLProducer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml;
+
+
+
+/**
+ * This interfaces identifies classes that produce XML data, sending SAX
+ * events to the configured <code>XMLConsumer</code>.
+ * <br>
+ * It's beyond the scope of this interface to specify a way in which the XML
+ * data production is started.
+ *
+ * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
+ *         (Apache Software Foundation)
+ * @version CVS $Id: XMLProducer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public interface XMLProducer {
+
+    /**
+     * Set the <code>XMLConsumer</code> that will receive XML data.
+     */
+    void setConsumer(XMLConsumer consumer);
+
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMBuilder.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMBuilder.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml.dom;
+
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+
+import org.apache.butterfly.xml.AbstractXMLPipe;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+/**
+ * The <code>DOMBuilder</code> is a utility class that will generate a W3C
+ * DOM Document from SAX events.
+ *
+ * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+ * @version CVS $Id: DOMBuilder.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class DOMBuilder extends AbstractXMLPipe {
+
+    /** The transformer factory shared by all instances */
+    protected static final SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance();
+
+    /** The listener */
+    protected Listener listener;
+
+    /** The result */
+    protected DOMResult result;
+
+    /** The parentNode */
+    protected Node parentNode;
+
+    /**
+     * Construct a new instance of this DOMBuilder.
+     */
+    public DOMBuilder() {
+        this( (Listener)null, (Node)null );
+    }
+
+    /**
+     * Construct a new instance of this DOMBuilder.
+     */
+    public DOMBuilder( Listener listener ) {
+        this(listener, null);
+    }
+
+    /**
+     * Construct a new instance of this DOMBuilder.
+     */
+    public DOMBuilder( Listener listener, Node parentNode ) {
+        super();
+        this.listener = listener;
+        try {
+            TransformerHandler handler = factory.newTransformerHandler();
+            this.setContentHandler(handler);
+            this.setLexicalHandler(handler);
+            this.parentNode = parentNode;
+            if (parentNode != null) {
+                this.result = new DOMResult( parentNode );
+            } else {
+                this.result = new DOMResult();
+            }
+            handler.setResult(this.result);
+        } catch (javax.xml.transform.TransformerException local) {
+            throw new RuntimeException("Fatal-Error: Unable to get transformer handler", local);
+        }
+    }
+
+    /**
+     * Constructs a new instance that appends nodes to the given parent node.<br/>
+     * Note : you cannot use a <code>Listener<code> when appending to a
+     * <code>Node</code>, because the notification occurs at <code>endDocument()</code>
+     * which does not happen here.
+     */
+    public DOMBuilder( Node parentNode ) {
+        this( null, parentNode);
+    }
+
+    /**
+     * Return the newly built Document.
+     */
+    public Document getDocument() {
+        if ((this.result == null) || (this.result.getNode()==null))  {
+            return null;
+        } else if (this.result.getNode().getNodeType() == Node.DOCUMENT_NODE) {
+            return ( (Document)this.result.getNode() );
+        } else {
+            return ( this.result.getNode().getOwnerDocument() );
+        }
+    }
+
+    /**
+     * Receive notification of the beginning of a document.
+     *
+     * @exception SAXException If this method was not called appropriately.
+     */
+    public void endDocument()
+    throws SAXException {
+        super.endDocument();
+
+        // Notify the listener
+        this.notifyListener();
+    }
+
+    /**
+     * Receive notification of a successfully completed DOM tree generation.
+     */
+    protected void notifyListener()
+    throws SAXException {
+        if ( this.listener != null ) this.listener.notify( this.getDocument() );
+    }
+
+    /**
+     * The Listener interface must be implemented by those objects willing to
+     * be notified of a successful DOM tree generation.
+     */
+    public interface Listener {
+
+        /**
+         * Receive notification of a successfully completed DOM tree generation.
+         */
+        void notify(Document doc)
+        throws SAXException;
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMStreamer.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/dom/DOMStreamer.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,720 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.xml.dom;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
+
+import org.apache.butterfly.xml.AbstractXMLProducer;
+import org.apache.butterfly.xml.EmbeddedXMLPipe;
+import org.apache.butterfly.xml.XMLConsumer;
+import org.apache.butterfly.xml.XMLProducer;
+import org.apache.commons.lang.StringUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * The <code>DOMStreamer</code> is a utility class that will generate SAX
+ * events from a W3C DOM Document.
+ *
+ * <p>The DOMStreamer uses a different strategy based on the value of the
+ * normalizeNamespaces property:
+ * <ul>
+ * <li>if true (the default), the DOMStreamer will normalize namespace
+ * declarations (i.e. add missing xmlns attributes or correct them). See
+ * also {@link NamespaceNormalizingDOMStreamer}.
+ * <li>if false, the standard JAXP identity transformer is used.
+ * </ul>
+ *
+ * @version CVS $Id: DOMStreamer.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class DOMStreamer implements XMLProducer {
+
+    /** Default value for normalizeNamespaces. */
+    private final boolean DEFAULT_NORMALIZE_NAMESPACES = true;
+
+    /** Indicates whether namespace normalization should happen. */
+    protected boolean normalizeNamespaces = DEFAULT_NORMALIZE_NAMESPACES;
+
+    /** DOMStreamer used in case of namespace normalization. */
+    protected NamespaceNormalizingDOMStreamer namespaceNormalizingDOMStreamer = new NamespaceNormalizingDOMStreamer();
+
+    /** DOMStreamer used when namespace normalization should not explicitely happen. */
+    protected DefaultDOMStreamer defaultDOMStreamer = new DefaultDOMStreamer();
+
+    /** The transformer factory shared by all instances (only used by DefaultDOMStreamer) */
+    protected static TransformerFactory factory = TransformerFactory.newInstance();
+
+    /**
+     * Create a new <code>DOMStreamer</code> instance.
+     */
+    public DOMStreamer() {
+        super();
+    }
+
+    /**
+     * Create a new <code>DOMStreamer</code> instance.
+     */
+    public DOMStreamer(XMLConsumer consumer) {
+        this(consumer, consumer);
+    }
+
+    /**
+     * Create a new <code>DOMStreamer</code> instance.
+     */
+    public DOMStreamer(ContentHandler content) {
+        this(content, null);
+        if (content instanceof LexicalHandler) {
+            defaultDOMStreamer.setLexicalHandler((LexicalHandler) content);
+            namespaceNormalizingDOMStreamer.setLexicalHandler((LexicalHandler) content);
+        }
+    }
+
+    /**
+     * Create a new <code>DOMStreamer</code> instance.
+     */
+    public DOMStreamer(ContentHandler content, LexicalHandler lexical) {
+        this();
+        defaultDOMStreamer.setContentHandler(content);
+        defaultDOMStreamer.setLexicalHandler(lexical);
+        namespaceNormalizingDOMStreamer.setContentHandler(content);
+        namespaceNormalizingDOMStreamer.setLexicalHandler(lexical);
+    }
+
+    /**
+     * Set the <code>XMLConsumer</code> that will receive XML data.
+     */
+    public void setConsumer(XMLConsumer consumer) {
+        defaultDOMStreamer.setContentHandler(consumer);
+        defaultDOMStreamer.setLexicalHandler(consumer);
+        namespaceNormalizingDOMStreamer.setContentHandler(consumer);
+        namespaceNormalizingDOMStreamer.setLexicalHandler(consumer);
+    }
+
+    /**
+     * Set the <code>ContentHandler</code> that will receive XML data.
+     */
+    public void setContentHandler(ContentHandler handler) {
+        defaultDOMStreamer.setContentHandler(handler);
+        namespaceNormalizingDOMStreamer.setContentHandler(handler);
+    }
+
+    /**
+     * Set the <code>LexicalHandler</code> that will receive XML data.
+     */
+    public void setLexicalHandler(LexicalHandler handler) {
+        defaultDOMStreamer.setLexicalHandler(handler);
+        namespaceNormalizingDOMStreamer.setLexicalHandler(handler);
+    }
+
+    /**
+     * Start the production of SAX events.
+     */
+    public void stream(Node node) throws SAXException {
+        if (normalizeNamespaces) {
+            namespaceNormalizingDOMStreamer.stream(node);
+        } else {
+            defaultDOMStreamer.stream(node);
+        }
+    }
+
+    public boolean isNormalizeNamespaces() {
+        return normalizeNamespaces;
+    }
+
+    public void setNormalizeNamespaces(boolean normalizeNamespaces) {
+        this.normalizeNamespaces = normalizeNamespaces;
+    }
+
+    /**
+     * Streams a DOM tree to SAX events and normalizes namespace declarations on the way.
+     *
+     * <p>The code in this class is based on the org.apache.xml.utils.TreeWalker class from Xalan,
+     * though it differs in some important ways.
+     *
+     * <p>This class will automatically fix up ("normalize") namespace declarations
+     * while streaming to SAX. The original DOM-tree is not modified. The algorithm
+     * used is described in
+     * <a href="http://www.w3.org/TR/2002/WD-DOM-Level-3-Core-20021022/namespaces-algorithms.html#normalizeDocumentAlgo">an appendix of the DOM Level 3 spec</a>.
+     *
+     * <p>This class will NOT check the correctness of namespaces, e.g. it will not
+     * check that the "xml" prefix is not misused etc.
+     *
+     * @author Bruno Dumon (bruno at outerthought dot org)
+     * @author Xalan team
+     */
+    public class NamespaceNormalizingDOMStreamer extends AbstractXMLProducer {
+        /**
+         * Information about the current element. Used to remember the localName, qName
+         * and namespaceURI for generating the endElement event, and holds the namespaces
+         * declared on the element. This extra class is needed because we don't want to
+         * modify the DOM-tree itself. The currentElementInfo has a pointer to its parent
+         * elementInfo.
+         */
+        protected NamespaceNormalizingDOMStreamer.ElementInfo currentElementInfo = null;
+
+        /** Counter used when generating new namespace prefixes. */
+        protected int newPrefixCounter = 0;
+
+        public void recycle() {
+            super.recycle();
+            currentElementInfo = null;
+            newPrefixCounter = 0;
+        }
+
+        /**
+         * Start the production of SAX events.
+         *
+         * <p>Perform a pre-order traversal non-recursive style.
+         *
+         * <p>Note that TreeWalker assumes that the subtree is intended to represent
+         * a complete (though not necessarily well-formed) document and, during a
+         * traversal, startDocument and endDocument will always be issued to the
+         * SAX listener.
+         *
+         * @param pos Node in the tree where to start traversal
+         *
+         */
+        protected void stream(Node pos) throws SAXException {
+
+            // Start document only if we're streaming a document
+            boolean isDoc = (pos.getNodeType() == Node.DOCUMENT_NODE);
+            if (isDoc) {
+              contentHandler.startDocument();
+            }
+
+            Node top = pos;
+            while (null != pos) {
+                startNode(pos);
+
+                Node nextNode = pos.getFirstChild();
+                while (null == nextNode) {
+                    endNode(pos);
+
+                    if (top.equals(pos)) {
+                        break;
+                    }
+
+                    nextNode = pos.getNextSibling();
+                    if (null == nextNode) {
+                        pos = pos.getParentNode();
+
+                        if ((null == pos) || (top.equals(pos))) {
+                            if (null != pos) {
+                                endNode(pos);
+                            }
+                            nextNode = null;
+
+                            break;
+                        }
+                    }
+                }
+
+                pos = nextNode;
+            }
+
+            if (isDoc) {
+            	contentHandler.endDocument();
+            }
+        }
+
+        private final void dispatchChars(Node node) throws SAXException {
+            String data = ((Text) node).getData();
+            contentHandler.characters(data.toCharArray(), 0, data.length());
+        }
+
+        /**
+         * Start processing given node
+         *
+         * @param node Node to process
+         */
+        protected void startNode(Node node) throws SAXException {
+
+            switch (node.getNodeType()) {
+                case Node.COMMENT_NODE:
+                    {
+                        if (lexicalHandler != null) {
+                            String data = ((Comment) node).getData();
+                            lexicalHandler.comment(data.toCharArray(), 0, data.length());
+                        }
+                    }
+                    break;
+                case Node.DOCUMENT_FRAGMENT_NODE:
+
+                    // ??;
+                    break;
+                case Node.DOCUMENT_NODE:
+
+                    break;
+                case Node.ELEMENT_NODE:
+                    NamedNodeMap atts = node.getAttributes();
+                    int nAttrs = atts.getLength();
+
+                    // create a list of localy declared namespace prefixes
+                    currentElementInfo = new NamespaceNormalizingDOMStreamer.ElementInfo(currentElementInfo);
+                    for (int i = 0; i < nAttrs; i++) {
+                        Node attr = atts.item(i);
+                        String attrName = attr.getNodeName();
+
+                        if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) {
+                            int index;
+                            String prefix = (index = attrName.indexOf(":")) < 0
+                                    ? "" : attrName.substring(index + 1);
+
+                            currentElementInfo.put(prefix, attr.getNodeValue());
+                        }
+                    }
+
+                    String namespaceURI = node.getNamespaceURI();
+                    String prefix = node.getPrefix();
+                    String localName = node.getLocalName();
+
+                    if (localName == null) {
+                        // this is an element created with createElement instead of createElementNS
+                        String[] prefixAndLocalName = getPrefixAndLocalName(node.getNodeName());
+                        prefix = prefixAndLocalName[0];
+                        localName = prefixAndLocalName[1];
+                        // note: if prefix is null, there can still be a default namespace...
+                        namespaceURI = getNamespaceForPrefix(prefix, (Element)node);
+                    }
+
+                    if (namespaceURI != null) {
+                        // no prefix means: make this the default namespace
+                        if (prefix == null) {
+                            prefix = "";
+                        }
+                        // check that is declared
+                        String uri = currentElementInfo.findNamespaceURI(prefix);
+                        if (StringUtils.equals(uri, namespaceURI)) {
+                            // System.out.println("namespace is declared");
+                            // prefix is declared correctly, do nothing
+                        } else if (uri != null) {
+                            // System.out.println("prefix is declared with other namespace, overwriting it");
+                            // prefix exists but is bound to another namespace, overwrite it
+                            currentElementInfo.put(prefix, namespaceURI);
+                        } else {
+                            // System.out.println("prefix is not yet declared, declaring it now");
+                            currentElementInfo.put(prefix, namespaceURI);
+                        }
+                    } else {
+                        // element has no namespace
+                        // check if there is a default namespace, if so undeclare it
+                        String uri = currentElementInfo.findNamespaceURI("");
+                        if (StringUtils.isNotEmpty(uri)) {
+                            // System.out.println("undeclaring default namespace");
+                            currentElementInfo.put("", "");
+                        }
+                    }
+
+                    // SAX uses empty string to denote no namespace, while DOM uses null.
+                    if (namespaceURI == null)
+                        namespaceURI = "";
+
+                    String qName;
+                    if (StringUtils.isNotEmpty(prefix)) {
+                        qName = prefix + ":" + localName;
+                    } else {
+                        qName = localName;
+                    }
+
+                    // make the attributes
+                    AttributesImpl newAttrs = new AttributesImpl();
+                    for (int i = 0; i < nAttrs; i++) {
+                        Node attr = atts.item(i);
+                        String attrName = attr.getNodeName();
+                        String assignedAttrPrefix = null;
+
+                        // only do non-namespace attributes
+                        if (!(attrName.equals("xmlns") || attrName.startsWith("xmlns:"))) {
+                            String attrPrefix;
+                            String attrLocalName;
+                            String attrNsURI;
+
+                            if (attr.getLocalName() == null) {
+                                // this is an attribute created with setAttribute instead of setAttributeNS
+                                String[] prefixAndLocalName = getPrefixAndLocalName(attrName);
+                                attrPrefix = prefixAndLocalName[0];
+                                // the statement below causes the attribute to keep its prefix even if it is not
+                                // bound to a namespace (to support pre-namespace XML).
+                                assignedAttrPrefix = attrPrefix;
+                                attrLocalName = prefixAndLocalName[1];
+                                // note: if prefix is null, the attribute has no namespace (namespace defaulting
+                                // does not apply to attributes)
+                                if (attrPrefix != null)
+                                    attrNsURI = getNamespaceForPrefix(attrPrefix, (Element)node);
+                                else
+                                    attrNsURI = null;
+                            } else {
+                                attrLocalName = attr.getLocalName();
+                                attrPrefix = attr.getPrefix();
+                                attrNsURI = attr.getNamespaceURI();
+                            }
+
+                            if (attrNsURI != null) {
+                                String declaredUri = currentElementInfo.findNamespaceURI(attrPrefix);
+                                // if the prefix is null, or the prefix has not been declared, or conflicts with an in-scope binding
+                                if (declaredUri == null || !declaredUri.equals(attrNsURI)) {
+                                    String availablePrefix = currentElementInfo.findPrefix(attrNsURI);
+                                    if (availablePrefix != null)
+                                        assignedAttrPrefix = availablePrefix;
+                                    else {
+                                        if (attrPrefix != null && declaredUri == null) {
+                                            // prefix is not null and is not yet declared: declare it
+                                            assignedAttrPrefix = attrPrefix;
+                                            currentElementInfo.put(assignedAttrPrefix, attrNsURI);
+                                        } else {
+                                            // attribute has no prefix (which is not allowed for namespaced attributes) or
+                                            // the prefix is already bound to something else: generate a new prefix
+                                            newPrefixCounter++;
+                                            assignedAttrPrefix = "NS" + newPrefixCounter;
+                                            currentElementInfo.put(assignedAttrPrefix, attrNsURI);
+                                        }
+                                    }
+                                } else {
+                                    assignedAttrPrefix = attrPrefix;
+                                }
+                            }
+
+                            String assignedAttrNsURI = attrNsURI != null ? attrNsURI : "";
+                            String attrQName;
+                            if (assignedAttrPrefix != null) {
+                                attrQName = assignedAttrPrefix + ":" + attrLocalName;
+                            } else {
+                                attrQName = attrLocalName;
+                            }
+                            newAttrs.addAttribute(assignedAttrNsURI, attrLocalName, attrQName, "CDATA", attr.getNodeValue());
+                        }
+                    }
+
+                    // add local namespace declaration and fire startPrefixMapping events
+                    if (currentElementInfo.namespaceDeclarations != null && currentElementInfo.namespaceDeclarations.size() > 0) {
+                        Iterator localNsDeclIt = currentElementInfo.namespaceDeclarations.entrySet().iterator();
+                        while (localNsDeclIt.hasNext()) {
+                            Map.Entry entry = (Map.Entry) localNsDeclIt.next();
+                            String pr = (String) entry.getKey();
+                            String ns = (String) entry.getValue();
+                            // the following lines enable the creation of explicit xmlns attributes
+                            //String pr1 = pr.equals("") ? "xmlns" : pr;
+                            //String qn = pr.equals("") ? "xmlns" : "xmlns:" + pr;
+                            //newAttrs.addAttribute("", pr1, qn, "CDATA", ns);
+                            // System.out.println("starting prefix mapping  for prefix " + pr + " for " + ns);
+                            contentHandler.startPrefixMapping(pr, ns);
+                        }
+                    }
+
+                    contentHandler.startElement(namespaceURI, localName, qName, newAttrs);
+
+                    currentElementInfo.localName = localName;
+                    currentElementInfo.namespaceURI = namespaceURI;
+                    currentElementInfo.qName = qName;
+                    break;
+                case Node.PROCESSING_INSTRUCTION_NODE:
+                    {
+                        ProcessingInstruction pi = (ProcessingInstruction) node;
+                        contentHandler.processingInstruction(pi.getNodeName(), pi.getData());
+                    }
+                    break;
+                case Node.CDATA_SECTION_NODE:
+                    {
+                        if (lexicalHandler != null)
+                            lexicalHandler.startCDATA();
+
+                        dispatchChars(node);
+
+                        if (lexicalHandler != null)
+                            lexicalHandler.endCDATA();
+                    }
+                    break;
+                case Node.TEXT_NODE:
+                    {
+                        dispatchChars(node);
+                    }
+                    break;
+                case Node.ENTITY_REFERENCE_NODE:
+                    {
+                        EntityReference eref = (EntityReference) node;
+
+                        if (lexicalHandler != null) {
+                            lexicalHandler.startEntity(eref.getNodeName());
+                        } else {
+                            // warning("Can not output entity to a pure SAX ContentHandler");
+                        }
+                    }
+                    break;
+                default :
+            }
+        }
+
+        /**
+         * Searches the namespace for a given namespace prefix starting from a
+         * given Element.
+         *
+         * <p>Note that this resolves the prefix in the orginal DOM-tree, not in
+         * the {@link ElementInfo} objects. This is used to resolve prefixes
+         * of elements or attributes created with createElement or setAttribute
+         * instead of createElementNS or setAttributeNS.
+         *
+         * <p>The code in this method is largely based on
+         * org.apache.xml.utils.DOMHelper.getNamespaceForPrefix() (from Xalan).
+         *
+         * @param prefix the prefix to look for, can be empty or null to find the
+         * default namespace
+         *
+         * @return the namespace, or null if not found.
+         */
+        public String getNamespaceForPrefix(String prefix, Element namespaceContext) {
+            int type;
+            Node parent = namespaceContext;
+            String namespace = null;
+
+            if (prefix == null)
+                prefix = "";
+
+            if (prefix.equals("xml")) {
+                namespace = "http://www.w3.org/XML/1998/namespace";
+            } else if(prefix.equals("xmlns")) {
+                namespace = "http://www.w3.org/2000/xmlns/";
+            } else {
+                // Attribute name for this prefix's declaration
+                String declname = (prefix == "") ? "xmlns" : "xmlns:" + prefix;
+
+                // Scan until we run out of Elements or have resolved the namespace
+                while ((null != parent) && (null == namespace)
+                   && (((type = parent.getNodeType()) == Node.ELEMENT_NODE)
+                       || (type == Node.ENTITY_REFERENCE_NODE))) {
+                    if (type == Node.ELEMENT_NODE) {
+                        Attr attr=((Element)parent).getAttributeNode(declname);
+                        if (attr != null) {
+                            namespace = attr.getNodeValue();
+                            break;
+                        }
+                    }
+                    parent = parent.getParentNode();
+                }
+            }
+            return namespace;
+        }
+
+        /**
+         * Splits a nodeName into a prefix and a localName
+         *
+         * @return an array containing two elements, the first one is the prefix (can be null), the
+         * second one is the localName
+         */
+        private String[] getPrefixAndLocalName(String nodeName) {
+            String prefix, localName;
+            int colonPos = nodeName.indexOf(":");
+            if (colonPos != -1) {
+                prefix = nodeName.substring(0, colonPos);
+                localName = nodeName.substring(colonPos + 1, nodeName.length());
+            } else {
+                prefix = null;
+                localName = nodeName;
+            }
+            return new String[] {prefix, localName};
+        }
+
+
+        /**
+         * End processing of given node
+         *
+         * @param node Node we just finished processing
+         */
+        protected void endNode(Node node) throws org.xml.sax.SAXException {
+
+            switch (node.getNodeType()) {
+                case Node.DOCUMENT_NODE:
+                    break;
+
+                case Node.ELEMENT_NODE:
+                    contentHandler.endElement(currentElementInfo.namespaceURI,
+                            currentElementInfo.localName, currentElementInfo.qName);
+
+                    // generate endPrefixMapping events if needed
+                    if (currentElementInfo.namespaceDeclarations != null && currentElementInfo.namespaceDeclarations.size() > 0) {
+                        Iterator namespaceIt = currentElementInfo.namespaceDeclarations.entrySet().iterator();
+                        while (namespaceIt.hasNext()) {
+                            Map.Entry entry = (Map.Entry) namespaceIt.next();
+                            contentHandler.endPrefixMapping((String) entry.getKey());
+                            //System.out.println("ending prefix mapping " + (String) entry.getKey());
+                        }
+                    }
+
+                    currentElementInfo = currentElementInfo.parent;
+                    break;
+                case Node.CDATA_SECTION_NODE:
+                    break;
+                case Node.ENTITY_REFERENCE_NODE:
+                    {
+                        EntityReference eref = (EntityReference) node;
+
+                        if (lexicalHandler != null) {
+                            lexicalHandler.endEntity(eref.getNodeName());
+                        }
+                    }
+                    break;
+                default :
+            }
+        }
+
+        public class ElementInfo {
+            public String localName;
+            public String namespaceURI;
+            public String qName;
+            public Map namespaceDeclarations = null;
+            public ElementInfo parent;
+
+            public ElementInfo(ElementInfo parent) {
+                this.parent = parent;
+            }
+
+            /**
+             * Declare a new namespace prefix on this element, possibly overriding
+             * an existing one.
+             */
+            public void put(String prefix, String namespaceURI) {
+                if (namespaceDeclarations == null)
+                    namespaceDeclarations = new HashMap();
+                namespaceDeclarations.put(prefix, namespaceURI);
+            }
+
+            /**
+             * Finds a prefix declared on this element.
+             */
+            public String getPrefix(String namespaceURI) {
+                if (namespaceDeclarations == null || namespaceDeclarations.size() == 0)
+                    return null;
+                // note: there could be more than one prefix for the same namespaceURI, but
+                // we return the first found one.
+                Iterator it = namespaceDeclarations.entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    if (entry.getValue().equals(namespaceURI))
+                        return (String) entry.getKey();
+                }
+                return null;
+            }
+
+            /**
+             * Finds a namespace URI declared on this element.
+             */
+            public String getNamespaceURI(String prefix) {
+                if (namespaceDeclarations == null || namespaceDeclarations.size() == 0)
+                    return null;
+
+                return (String) namespaceDeclarations.get(prefix);
+            }
+
+            /**
+             * Finds a prefix declaration on this element or containing elements.
+             */
+            public String findPrefix(String namespaceURI) {
+                if (namespaceDeclarations != null && namespaceDeclarations.size() != 0) {
+                    String prefix = getPrefix(namespaceURI);
+                    if (prefix != null) {
+                        return prefix;
+                    }
+                }
+                if (parent != null) {
+                    return parent.findPrefix(namespaceURI);
+                } else {
+                    return null;
+                }
+            }
+
+            /**
+             * Finds a namespace declaration on this element or containing elements.
+             */
+            public String findNamespaceURI(String prefix) {
+                if (namespaceDeclarations != null && namespaceDeclarations.size() != 0) {
+                    String uri = (String) namespaceDeclarations.get(prefix);
+                    if (uri != null) {
+                        return uri;
+                    }
+                }
+                if (parent != null)
+                    return parent.findNamespaceURI(prefix);
+                else
+                    return null;
+            }
+        }
+    }
+
+    /**
+     * The <code>DefaultDOMStreamer</code> is a utility class that will generate SAX
+     * events from a W3C DOM Document.
+     *
+     * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+     * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
+     *         (Apache Software Foundation)
+     */
+    public class DefaultDOMStreamer extends AbstractXMLProducer {
+
+        /** The private transformer for this instance */
+        protected Transformer transformer;
+
+        /**
+         * Start the production of SAX events.
+         */
+        public void stream(Node node)
+        throws SAXException {
+            if (this.transformer == null) {
+                try {
+                    this.transformer = factory.newTransformer();
+                } catch (TransformerConfigurationException e) {
+                    throw new SAXException(e);
+                }
+            }
+            DOMSource source = new DOMSource(node);
+
+            ContentHandler handler;
+            if (node.getNodeType() == Node.DOCUMENT_NODE) {
+                // Pass all SAX events
+                handler = contentHandler;
+            } else {
+                // Strip start/endDocument
+                handler = new EmbeddedXMLPipe(contentHandler);
+            }
+
+            SAXResult result = new SAXResult(handler);
+            result.setLexicalHandler(lexicalHandler);
+
+            try {
+                transformer.transform(source, result);
+            } catch (TransformerException e) {
+                throw new SAXException(e);
+            }
+        }
+    }
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxException.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxException.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.xml.xslt;
+
+
+/**
+ * Description of TraxException.
+ * 
+ * @version CVS $Id: TraxException.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class TraxException extends RuntimeException {
+
+    /**
+     * 
+     */
+    public TraxException() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     */
+    public TraxException(String arg0) {
+        super(arg0);
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public TraxException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+        // TODO Auto-generated constructor stub
+    }
+
+    /**
+     * @param arg0
+     */
+    public TraxException(Throwable arg0) {
+        super(arg0);
+        // TODO Auto-generated constructor stub
+    }
+
+}

Added: cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxTransformerFactory.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/java/org/apache/butterfly/xml/xslt/TraxTransformerFactory.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.xml.xslt;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.butterfly.source.SourceResolver;
+import org.apache.butterfly.transformation.TraxTransformer;
+
+
+/**
+ * Description of TraxTransformerFactory.
+ * 
+ * @version CVS $Id: TraxTransformerFactory.java,v 1.1 2004/07/23 08:47:20 ugo Exp $
+ */
+public class TraxTransformerFactory {
+    private SourceResolver sourceResolver;
+    private SAXTransformerFactory transformerFactory;
+    
+    /**
+     * 
+     */
+    public TraxTransformerFactory() {
+        this.transformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
+    }
+    
+    /**
+     * @param sourceResolver The sourceResolver to set.
+     */
+    public void setSourceResolver(SourceResolver sourceResolver) {
+        this.sourceResolver = sourceResolver;
+    }
+
+    public TraxTransformer getTransformer(String src) {
+        Source source = new StreamSource(sourceResolver.resolveURI(src).getInputStream());
+        synchronized (this.transformerFactory) {
+            try {
+                Templates stylesheet = this.transformerFactory.newTemplates(source);
+                // TODO: cache templates?
+                return new TraxTransformer(transformerFactory.newTransformerHandler(stylesheet),
+                        this.sourceResolver);
+            } catch (TransformerConfigurationException e) {
+                // TODO log?
+                throw new TraxException("Cannot create a new XSLT template.", e);
+            }
+        }
+    }
+    
+    public TransformerHandler getTransformerHandler() {
+        synchronized (this.transformerFactory) {
+            try {
+                return this.transformerFactory.newTransformerHandler();
+            } catch (TransformerConfigurationException e) {
+                // TODO log?
+                throw new TraxException("Cannot create a new TransformerHandler.", e);
+            }
+        }        
+    }
+}

Added: cocoon/branches/src/test/beans.xml
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/beans.xml	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright 2004, Ugo Cei
+
+  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.
+-->
+
+<!--+
+    | Spring's bean factory configuration file.
+    |
+    |  $Id: beans.xml,v 1.1 2004/07/23 08:47:20 ugo Exp $
+    +-->
+  
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+ 
+<beans>
+  
+  <bean id="fileSourceFactory" class="org.apache.butterfly.source.impl.FileSourceFactory"/>
+  <bean id="urlSourceFactory" class="org.apache.butterfly.source.impl.URLSourceFactory"/>
+  
+  <bean id="sourceResolver" class="org.apache.butterfly.source.SourceResolver">
+    <property name="factories">
+      <map>
+      	<entry key="file">
+      		<ref bean="fileSourceFactory"/>
+      	</entry>
+      	<entry key="*">
+      		<ref bean="urlSourceFactory"/>
+      	</entry>
+      </map>    
+    </property>
+  </bean>
+  
+  <!-- The XML Parser. Should probably be pooled. -->
+  <bean id="xmlParser" class="org.apache.butterfly.xml.Parser"
+     singleton="false" init-method="initialize">
+     <property name="saxDriver">
+       <value>org.apache.xerces.parsers.SAXParser</value>
+     </property>
+  </bean>
+  
+  <bean id="fileGenerator" class="org.apache.butterfly.generation.FileGenerator" singleton="false">
+    <property name="sourceResolver">
+      <ref bean="sourceResolver"/>
+    </property>  
+    <property name="parser">
+      <ref bean="xmlParser"/>
+    </property>
+  </bean>
+  
+  <bean id="traxTransformerFactory" class="org.apache.butterfly.xml.xslt.TraxTransformerFactory">
+    <property name="sourceResolver">
+      <ref bean="sourceResolver"/>
+    </property>  
+  </bean>
+
+  <bean id="xmlSerializer" class="org.apache.butterfly.serialization.XMLSerializer" singleton="false">
+    <property name="traxTransformerFactory">
+      <ref bean="traxTransformerFactory"/>
+    </property>
+    <property name="encoding">
+      <value>UTF-8</value>
+    </property>
+  </bean>
+    
+</beans>

Added: cocoon/branches/src/test/log4j.properties
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/log4j.properties	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,15 @@
+# Configure logging for testing
+
+log4j.rootCategory=WARN, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
+
+#log4j.category.org.springframework.aop.framework.ProxyFactoryBean=DEBUG
+
+log4j.category.org.springframework.enterpriseservices=DEBUG
+
+log4j.category.org.springframework.transaction.interceptor=INFO
+
+log4j.category.org.springframework.beans.factory=INFO

Added: cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/GroovySitemapTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/GroovySitemapTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,62 @@
+package org.apache.butterfly.components.pipeline.impl;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyObject;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.core.io.ClassPathResource;
+
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+
+/**
+ * Description of GroovySitemapTestCase.
+ * 
+ * @version CVS $Id: GroovySitemapTestCase.java,v 1.1 2004/07/27 20:54:17 ugo Exp $
+ */
+public class GroovySitemapTestCase extends TestCase {
+    
+    private BeanFactory beanFactory;
+
+    /**
+     * @param name
+     */
+    public GroovySitemapTestCase(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        ClassPathResource res = new ClassPathResource("beans.xml"); 
+        beanFactory = new XmlBeanFactory(res);
+    }
+
+    public void testGroovySitemap() throws CompilationFailedException, IOException, InstantiationException, IllegalAccessException {
+        ClassLoader parent = getClass().getClassLoader();
+        GroovyClassLoader loader = new GroovyClassLoader(parent);
+        Class pipelineClass = loader.parseClass(getClass().getResourceAsStream("Pipeline.groovy"));
+        Class myPipelineClass = loader.parseClass(getClass().getResourceAsStream("MyPipeline.groovy"));
+        GroovyObject pipeline = (GroovyObject) myPipelineClass.newInstance();
+        pipeline.setProperty("beanFactory", beanFactory);
+        Object[] args = { "index.html" };
+        pipeline.invokeMethod("define", args);
+        pipeline.invokeMethod("process", new Object[] {});
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/MyPipeline.groovy	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,13 @@
+class MyPipeline extends Pipeline {
+  
+    void define(String requestPath) {
+        if (requestPath =~ ".*\.html") {
+            generate "testdata/traxtest-input.xml"
+            transform "trax", "testdata/traxtest-style.xsl" 
+            serialize "xml"
+        }
+        else {
+            println("No matches for " + requestPath);
+        }
+    }
+}
\ No newline at end of file

Added: cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/NonCachingProcessingPipelineTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 
+ * 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.
+ */
+package org.apache.butterfly.components.pipeline.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.butterfly.components.pipeline.InvalidPipelineException;
+import org.apache.butterfly.generation.FileGenerator;
+import org.apache.butterfly.generation.Generator;
+import org.apache.butterfly.reading.Reader;
+import org.apache.butterfly.serialization.Serializer;
+import org.apache.butterfly.source.SourceResolver;
+import org.apache.butterfly.source.impl.FileSourceFactory;
+import org.apache.butterfly.transformation.Transformer;
+import org.apache.butterfly.transformation.TraxTransformer;
+import org.apache.butterfly.xml.Parser;
+import org.apache.butterfly.xml.WhitespaceFilter;
+import org.apache.butterfly.xml.XMLConsumer;
+import org.apache.butterfly.xml.dom.DOMBuilder;
+import org.apache.butterfly.xml.xslt.TraxTransformerFactory;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+
+/**
+ * test case for NonCachingProcessingPipeline.
+ * 
+ * @version CVS $Id: NonCachingProcessingPipelineTestCase.java,v 1.8 2004/07/26 22:44:18 ugo Exp $
+ */
+public class NonCachingProcessingPipelineTestCase extends MockObjectTestCase {
+    
+    private Generator stubGenerator;
+    private Reader stubReader;
+    private Transformer stubTransformer;
+    private Serializer stubSerializer;
+    private FileGenerator fileGenerator;
+    private TraxTransformerFactory transformerFactory;
+
+    public NonCachingProcessingPipelineTestCase(String name) {
+        super(name);
+    }
+    
+    public void setUp() {
+        // Set up stubs
+        stubGenerator = new Generator() {
+            public void generate() {}
+            public void setConsumer(XMLConsumer consumer) {}
+        };
+        
+        stubReader = new Reader() {
+            public void generate() {}
+            public long getLastModified() {
+                return 0;
+            }
+            public void setOutputStream(OutputStream out) {}
+            public String getMimeType() {
+                return null;
+            }
+            public boolean shouldSetContentLength() {
+                return false;
+            }
+        }; 
+        
+        stubTransformer = new Transformer() {
+            public void setDocumentLocator(Locator arg0) {}
+            public void startDocument() throws SAXException {}
+            public void endDocument() throws SAXException {}
+            public void startPrefixMapping(String arg0, String arg1) throws SAXException {}
+            public void endPrefixMapping(String arg0) throws SAXException {}
+            public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {}
+            public void endElement(String arg0, String arg1, String arg2) throws SAXException {}
+            public void characters(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void processingInstruction(String arg0, String arg1) throws SAXException {}
+            public void skippedEntity(String arg0) throws SAXException {}
+            public void startDTD(String arg0, String arg1, String arg2) throws SAXException {}
+            public void endDTD() throws SAXException {}
+            public void startEntity(String arg0) throws SAXException {}
+            public void endEntity(String arg0) throws SAXException {}
+            public void startCDATA() throws SAXException {}
+            public void endCDATA() throws SAXException {}
+            public void comment(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void setConsumer(XMLConsumer consumer) {}
+        };
+        
+        stubSerializer = new Serializer() {
+            public void setDocumentLocator(Locator arg0) {}
+            public void startDocument() throws SAXException {}
+            public void endDocument() throws SAXException {}
+            public void startPrefixMapping(String arg0, String arg1) throws SAXException {}
+            public void endPrefixMapping(String arg0) throws SAXException {}
+            public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {}
+            public void endElement(String arg0, String arg1, String arg2) throws SAXException {}
+            public void characters(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void processingInstruction(String arg0, String arg1) throws SAXException {}
+            public void skippedEntity(String arg0) throws SAXException {}
+            public void startDTD(String arg0, String arg1, String arg2) throws SAXException {}
+            public void endDTD() throws SAXException {}
+            public void startEntity(String arg0) throws SAXException {}
+            public void endEntity(String arg0) throws SAXException {}
+            public void startCDATA() throws SAXException {}
+            public void endCDATA() throws SAXException {}
+            public void comment(char[] arg0, int arg1, int arg2) throws SAXException {}
+            public void setConsumer(XMLConsumer consumer) {}
+            public void setOutputStream(OutputStream out) {}
+            public String getMimeType() {
+                return null;
+            }
+            public boolean shouldSetContentLength() {
+                return false;
+            }
+        };
+        
+        // Set up real compponents
+        SourceResolver sourceResolver = new SourceResolver();
+        Map sourceFactories = new HashMap();
+        sourceFactories.put("*", new FileSourceFactory());
+        sourceResolver.setFactories(sourceFactories);
+        Parser parser = new Parser();
+        parser.setSaxDriver("org.apache.xerces.parsers.SAXParser");
+        parser.initialize();
+        fileGenerator = new FileGenerator();
+        fileGenerator.setSourceResolver(sourceResolver);
+        fileGenerator.setParser(parser);
+        transformerFactory = new TraxTransformerFactory();
+        transformerFactory.setSourceResolver(sourceResolver);
+    }
+
+    /**
+     * Test if setting reader after having set the generator causes
+     * error.
+     */
+    public void testSetReaderAfterGenerator() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setGenerator(stubGenerator);
+        try {
+            pipeline.setReader(stubReader);
+            fail("Setting reader after generator did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if setting generator after having set the reader causes
+     * error.
+     */
+    public void testSetGeneratorAfterReader() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        try {
+            pipeline.setGenerator(stubGenerator);
+            fail("Setting generator after reader did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+
+    /**
+     * Test if setting generator twice causes error.
+     */
+    public void testSetGeneratorTwice() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setGenerator(stubGenerator);
+        try {
+            pipeline.setGenerator(stubGenerator);
+            fail("Setting generator twice did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+
+    /**
+     * Test if setting reader twice causes error.
+     */
+    public void testSetReaderTwice() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        try {
+            pipeline.setReader(stubReader);
+            fail("Setting reader twice did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if adding a transformer without having set the generator causes
+     * error.
+     */
+    public void testAddTransformerWithoutGenerator() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        try {
+            pipeline.addTransformer(stubTransformer);
+            fail("Adding transformer without a generator did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if adding a transformer after having set the reader causes
+     * error.
+     */
+    public void testAddTransformerAfterReader() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        try {
+            pipeline.addTransformer(stubTransformer);
+            fail("Adding transformer after reader did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if setting serializer after having set the reader causes
+     * error.
+     */
+    public void testSetSerializerAfterReader() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        try {
+            pipeline.setSerializer(stubSerializer);
+            fail("Setting generator after reader did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if setting serializer without having set the generator causes
+     * error.
+     */
+    public void testSetSerializerWithoutGenerator() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        try {
+            pipeline.setSerializer(stubSerializer);
+            fail("Setting generator after reader did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+
+    /**
+     * Test if setting serializer twice causes error.
+     */
+    public void testSetSerializerTwice() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setGenerator(stubGenerator);
+        pipeline.setSerializer(stubSerializer);
+        try {
+            pipeline.setSerializer(stubSerializer);
+            fail("Setting serializer twice did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+
+    /**
+     * Test if processing an internal pipeline with a reader causes error.
+     */
+    public void testProcessInternalWithReader() {
+        NonCachingProcessingPipeline pipeline = 
+            new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        try {
+            pipeline.process(null, null);
+            fail("Processing an internal pipeline with a reader did not cause an exception.");
+        } catch(InvalidPipelineException e) {}
+    }
+    
+    /**
+     * Test if the @link{NonCachingProcessingPipeline#connect(Environment)} method
+     * correctly connects pipeline components. 
+     */
+    public void testConnect() {
+        NonCachingProcessingPipeline pipeline = 
+            new NonCachingProcessingPipeline();
+        // Setup mocks
+        Mock mockGenerator = new Mock(Generator.class);
+        Mock mockTransformer1 = new Mock(Transformer.class);
+        Mock mockTransformer2 = new Mock(Transformer.class);
+        Mock mockSerializer = new Mock(Serializer.class);
+        mockGenerator.expects(once()).method("setConsumer").with(same(mockTransformer1.proxy()));
+        mockTransformer1.expects(once()).method("setConsumer").with(same(mockTransformer2.proxy()));
+        mockTransformer2.expects(once()).method("setConsumer").with(same(mockSerializer.proxy()));
+
+        pipeline.setGenerator((Generator) mockGenerator.proxy());
+        pipeline.addTransformer((Transformer) mockTransformer1.proxy());
+        pipeline.addTransformer((Transformer) mockTransformer2.proxy());
+        pipeline.setSerializer((Serializer) mockSerializer.proxy());
+        pipeline.connectPipeline(null);
+        
+        mockGenerator.verify();
+    }
+    
+    /**
+     * Test if sane pipeline passes check.
+     */
+    public void testCheckSanePipeline() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setGenerator(stubGenerator);
+        pipeline.addTransformer(stubTransformer);
+        pipeline.setSerializer(stubSerializer);
+        assertTrue("Pipeline should be sane.", pipeline.checkPipeline());
+    }
+    
+    /**
+     * Test if pipeline with reader passes check.
+     */
+    public void testCheckReaderPipeline() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setReader(stubReader);
+        assertTrue("Pipeline should be sane.", pipeline.checkPipeline());
+    }
+    
+    /**
+     * Verify that empty pipeline does not pass check.
+     */
+    public void testCheckEmptyPipeline() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        assertFalse("Pipeline should not be sane.", pipeline.checkPipeline());
+    }
+    
+    /**
+     * Verify that pipeline without serializer does not pass check.
+     */
+    public void testCheckPipelineWithoutSerializer() {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        pipeline.setGenerator(stubGenerator);
+        pipeline.addTransformer(stubTransformer);
+        assertFalse("Pipeline should not be sane.", pipeline.checkPipeline());
+    }
+    
+    /**
+     * Test event pipeline processing with only a generator.
+     * @throws ParserConfigurationException
+     * @throws SAXException
+     * @throws IOException
+     */
+    public void testProcessSimpleEventPipeline() throws IOException, SAXException, ParserConfigurationException {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        XMLUnit.setIgnoreWhitespace(true);
+        fileGenerator.setInputSource("testdata/test1.xml");
+        pipeline.setGenerator(fileGenerator);
+        pipeline.setSerializer(stubSerializer);
+        DOMBuilder builder = new DOMBuilder();
+        pipeline.process(null, new WhitespaceFilter(builder));
+        assertTrue("Output from pipeline does not match input file.",
+                XMLUnit.compareXML(
+                        XMLUnit.buildControlDocument(new InputSource("testdata/test1.xml")),
+                        builder.getDocument()).similar());
+    }
+    
+    /**
+     * Test event pipeline processing with a transformer.
+     * @throws ParserConfigurationException
+     * @throws SAXException
+     * @throws IOException
+     */
+    public void testProcessEventPipeline() throws IOException, SAXException, ParserConfigurationException {
+        NonCachingProcessingPipeline pipeline = 
+                new NonCachingProcessingPipeline();
+        XMLUnit.setIgnoreWhitespace(true);
+        fileGenerator.setInputSource("testdata/traxtest-input.xml");
+        pipeline.setGenerator(fileGenerator);
+        TraxTransformer transformer = transformerFactory.getTransformer("testdata/traxtest-style.xsl");
+        pipeline.addTransformer(transformer);
+        pipeline.setSerializer(stubSerializer);
+        DOMBuilder builder = new DOMBuilder();
+        pipeline.process(null, new WhitespaceFilter(builder));
+        assertTrue("Output from pipeline does not match control file.",
+                XMLUnit.compareXML(
+                        XMLUnit.buildControlDocument(new InputSource("testdata/traxtest-result.xml")),
+                        builder.getDocument()).similar());
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/components/pipeline/impl/Pipeline.groovy	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,34 @@
+import org.apache.butterfly.xml.dom.DOMBuilder
+import org.apache.butterfly.components.pipeline.impl.NonCachingProcessingPipeline
+
+class Pipeline {
+    public beanFactory;
+    private pipeline;
+    
+    protected Pipeline() {
+        this.pipeline = new NonCachingProcessingPipeline()
+    }
+            
+    protected void generate(src) {
+        generator = beanFactory.getBean("fileGenerator")
+        generator.inputSource = src
+        this.pipeline.generator = generator
+    }
+    
+    protected void transform(type, src) {
+        factory = beanFactory.getBean(type + "TransformerFactory")
+        transformer = factory.getTransformer(src)
+        this.pipeline.addTransformer(transformer)
+    }
+    
+    protected void serialize(type) {
+        serializer = beanFactory.getBean(type + "Serializer")
+        this.pipeline.serializer = serializer
+    }
+    
+    public void process() {
+        builder = new DOMBuilder()
+        this.pipeline.process(null, builder)
+        println(builder.document.documentElement)
+    }
+}
\ No newline at end of file

Added: cocoon/branches/src/test/org/apache/butterfly/generation/FileGeneratorTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/generation/FileGeneratorTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.generation;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.butterfly.test.SitemapComponentTestCase;
+import org.apache.butterfly.xml.WhitespaceFilter;
+import org.apache.butterfly.xml.dom.DOMBuilder;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Description of FileGeneratorTestCase.
+ * 
+ * @version CVS $Id: FileGeneratorTestCase.java,v 1.2 2004/07/24 20:31:57 ugo Exp $
+ */
+public class FileGeneratorTestCase extends SitemapComponentTestCase {
+
+    /**
+     * @param name
+     */
+    public FileGeneratorTestCase(String name) {
+        super(name);
+    }
+    
+    public void testSimpleXMLFile() throws IOException, SAXException, ParserConfigurationException {
+        XMLUnit.setIgnoreWhitespace(true);
+        FileGenerator generator = (FileGenerator) getBean("fileGenerator");
+        generator.setInputSource("testdata/test1.xml");
+        DOMBuilder builder = new DOMBuilder();
+        generator.setConsumer(new WhitespaceFilter(builder));
+        generator.generate();
+        this.assertXMLEqual("Output from generator does not match input file.",
+                XMLUnit.buildControlDocument(new InputSource("testdata/test1.xml")),
+                builder.getDocument());
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/serialization/XMLSerializerTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/serialization/XMLSerializerTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.serialization;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.butterfly.test.SitemapComponentTestCase;
+import org.apache.butterfly.xml.dom.DOMStreamer;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Description of XMLSerializerTestCase.
+ * 
+ * @version CVS $Id: XMLSerializerTestCase.java,v 1.2 2004/07/24 20:31:57 ugo Exp $
+ */
+public class XMLSerializerTestCase extends SitemapComponentTestCase {
+
+    /**
+     * @param arg0
+     */
+    public XMLSerializerTestCase(String name) {
+        super(name);
+    }
+
+    public void testSerialization() throws IOException, SAXException, ParserConfigurationException {
+        XMLSerializer serializer = (XMLSerializer) getBean("xmlSerializer");
+        DOMStreamer streamer = new DOMStreamer(serializer);
+        Document input = XMLUnit.buildControlDocument(new InputSource("testdata/traxtest-input.xml"));
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        serializer.setOutputStream(output);
+        streamer.stream(input);
+        Document test = XMLUnit.buildTestDocument(new InputSource(new StringReader(output.toString())));
+        this.assertXMLEqual("Output from serializer does not match input file.",
+                input, test);
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/source/SourceResolverTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/source/SourceResolverTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.source;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.apache.butterfly.source.impl.FileSource;
+import org.apache.butterfly.test.SitemapComponentTestCase;
+
+
+/**
+ * Description of SourceResolverTestCase.
+ * 
+ * @version CVS $Id: SourceResolverTestCase.java,v 1.2 2004/07/24 20:31:57 ugo Exp $
+ */
+public class SourceResolverTestCase extends SitemapComponentTestCase {
+
+    public SourceResolverTestCase(String name) {
+        super(name);
+    }
+    
+    public void testFileSourceExists() throws MalformedURLException, IOException {
+        SourceResolver resolver = (SourceResolver) getBean("sourceResolver");
+        Source src = resolver.resolveURI("testdata/test1.xml");
+        assertTrue("Source is not a FileSource", src instanceof FileSource);
+        assertTrue("FileSource does not exist", src.exists());
+    }
+    
+    public void testFileSourceLength() throws MalformedURLException, IOException {
+        SourceResolver resolver = (SourceResolver) getBean("sourceResolver");
+        Source src = resolver.resolveURI("testdata/test1.xml");
+        assertEquals("FileSource is not of the expected length", 138, src.getContentLength());
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/test/SitemapComponentTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/test/SitemapComponentTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.test;
+
+import org.custommonkey.xmlunit.XMLTestCase;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.core.io.ClassPathResource;
+
+
+/**
+ * A superclass for testcases of sitemap components.
+ * 
+ * @version CVS $Id: SitemapComponentTestCase.java,v 1.3 2004/07/27 20:54:17 ugo Exp $
+ */
+public class SitemapComponentTestCase extends XMLTestCase {
+    
+    protected BeanFactory beanFactory;
+
+    /**
+     * @param name
+     */
+    public SitemapComponentTestCase(String name) {
+        super(name);
+    }
+    
+    /* (non-Javadoc)
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        ClassPathResource res = new ClassPathResource("beans.xml"); 
+        beanFactory = new XmlBeanFactory(res);
+    }
+
+    protected Object getBean(String name) {
+        return beanFactory.getBean(name);
+    }
+}

Added: cocoon/branches/src/test/org/apache/butterfly/transformation/TraxTransformerTestCase.java
==============================================================================
--- (empty file)
+++ cocoon/branches/src/test/org/apache/butterfly/transformation/TraxTransformerTestCase.java	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2004, Ugo Cei.
+ * 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.
+ */
+package org.apache.butterfly.transformation;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.butterfly.test.SitemapComponentTestCase;
+import org.apache.butterfly.xml.WhitespaceFilter;
+import org.apache.butterfly.xml.dom.DOMBuilder;
+import org.apache.butterfly.xml.dom.DOMStreamer;
+import org.apache.butterfly.xml.xslt.TraxTransformerFactory;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Description of TraxTransformerTestCase.
+ * 
+ * @version CVS $Id: TraxTransformerTestCase.java,v 1.3 2004/07/26 22:44:18 ugo Exp $
+ */
+public class TraxTransformerTestCase extends SitemapComponentTestCase {
+    /**
+     * @param name
+     */
+    public TraxTransformerTestCase(String name) {
+        super(name);
+    }
+
+    public void testTransformation() throws IOException, SAXException, ParserConfigurationException {
+        XMLUnit.setIgnoreWhitespace(true);
+        TraxTransformerFactory factory = 
+                (TraxTransformerFactory) getBean("traxTransformerFactory");
+        TraxTransformer transformer = factory.getTransformer("testdata/traxtest-style.xsl");
+        DOMBuilder builder = new DOMBuilder();
+        transformer.setConsumer(new WhitespaceFilter(builder));
+        DOMStreamer streamer = new DOMStreamer(transformer);
+        Document control = XMLUnit.buildControlDocument(new InputSource("testdata/traxtest-result.xml"));
+        Document input = XMLUnit.buildTestDocument(new InputSource("testdata/traxtest-input.xml"));
+        streamer.stream(input);
+        this.assertXMLEqual("Output from transformer does not match control file.",
+                control, builder.getDocument());
+    }
+}

Added: cocoon/branches/testdata/test1.xml
==============================================================================
--- (empty file)
+++ cocoon/branches/testdata/test1.xml	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!-- A comment -->
+<root attribute="1">
+  <child id="X">Text</child>
+  Mixed content
+  <child id="Y"/>
+</root>
\ No newline at end of file

Added: cocoon/branches/testdata/traxtest-input.xml
==============================================================================
--- (empty file)
+++ cocoon/branches/testdata/traxtest-input.xml	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  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.
+-->
+<hello-world>
+ <title>Title of the example</title>
+ <some-text>This is a litte test file!</some-text>
+ <some-text>And will transformed into a HTML page.</some-text>
+</hello-world>
+

Added: cocoon/branches/testdata/traxtest-result.xml
==============================================================================
--- (empty file)
+++ cocoon/branches/testdata/traxtest-result.xml	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  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.
+-->
+<page>
+ <tab title="Overview" href="welcome"/>
+ <row>
+  <column title="Title of the example">
+   <p>This is a litte test file!</p>
+   <p>And will transformed into a HTML page.</p>
+  </column>
+ </row>
+</page>
+

Added: cocoon/branches/testdata/traxtest-style.xsl
==============================================================================
--- (empty file)
+++ cocoon/branches/testdata/traxtest-style.xsl	Wed Jul 28 13:25:41 2004
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  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.
+-->
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <xsl:template match="hello-world">
+  <page>
+   <tab title="Overview" href="welcome"/>
+
+   <row>
+    <column title="{title}">
+     <xsl:apply-templates select="some-text"/>
+    </column>
+   </row>
+ 
+  </page>
+ </xsl:template>
+
+ <xsl:template match="some-text">
+  <p>
+   <xsl:apply-templates/>
+  </p>
+ </xsl:template>
+
+</xsl:stylesheet>

Added: cocoon/branches/tools/lib/jmock-1.0.1.jar
==============================================================================
Binary file. No diff available.

Added: cocoon/branches/tools/lib/xmlunit1.0.jar
==============================================================================
Binary file. No diff available.

Mime
View raw message