You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by cz...@apache.org on 2007/01/01 17:40:07 UTC

svn commit: r491595 - in /cocoon/trunk/core: cocoon-core/src/main/resources/META-INF/cocoon/avalon/ cocoon-core/src/test/java/org/apache/cocoon/generation/ cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/

Author: cziegeler
Date: Mon Jan  1 08:40:06 2007
New Revision: 491595

URL: http://svn.apache.org/viewvc?view=rev&rev=491595
Log:
Restore avalon based components

Added:
    cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java   (with props)
    cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java   (with props)
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java   (with props)
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java   (with props)
Modified:
    cocoon/trunk/core/cocoon-core/src/main/resources/META-INF/cocoon/avalon/cocoon-core-sitemapcomponents.xconf
    cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorTestCase.java
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGenerator.java
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGenerator.java

Modified: cocoon/trunk/core/cocoon-core/src/main/resources/META-INF/cocoon/avalon/cocoon-core-sitemapcomponents.xconf
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/main/resources/META-INF/cocoon/avalon/cocoon-core-sitemapcomponents.xconf?view=diff&rev=491595&r1=491594&r2=491595
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/main/resources/META-INF/cocoon/avalon/cocoon-core-sitemapcomponents.xconf (original)
+++ cocoon/trunk/core/cocoon-core/src/main/resources/META-INF/cocoon/avalon/cocoon-core-sitemapcomponents.xconf Mon Jan  1 08:40:06 2007
@@ -53,6 +53,7 @@
      | All components follow this scheme.
      +-->
  <map:generators default="file">
+   <map:generator label="content" logger="sitemap.generator.file" name="file" pool-max="32" src="org.apache.cocoon.generation.FileGenerator"/>
    <map:generator label="content" logger="sitemap.generator.directory" name="directory" pool-max="16" src="org.apache.cocoon.generation.DirectoryGenerator"/>
    <map:generator label="content" logger="sitemap.generator.xpathdirectory" name="xpathdirectory" src="org.apache.cocoon.generation.XPathDirectoryGenerator"/>
    <map:generator label="content" logger="sitemap.generator.traversable" name="traversable" pool-max="16" src="org.apache.cocoon.generation.TraversableGenerator"/>

Added: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java?view=auto&rev=491595
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java (added)
+++ cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java Mon Jan  1 08:40:06 2007
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cocoon.generation;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.core.xml.impl.JaxpSAXParser;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.WhitespaceFilter;
+import org.apache.cocoon.xml.dom.DOMBuilder;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.impl.ResourceSource;
+import org.apache.excalibur.xml.sax.SAXParser;
+import org.custommonkey.xmlunit.Diff;
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+import org.w3c.dom.Document;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ *
+ * @version $Id$
+ */
+public class FileGeneratorBeanTestCase extends MockObjectTestCase {
+    private Map objectModel = new HashMap();
+    private SAXParser parser;
+    private Mock manager = new Mock(ServiceManager.class);
+    
+    public void setUp() throws SAXException {
+        final XMLReader xmlReader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
+        parser = new SAXParser() {
+
+            public void parse(InputSource src, 
+                              ContentHandler contentHandler) throws SAXException, IOException {
+                xmlReader.setContentHandler(contentHandler);
+                xmlReader.parse(src);
+            }
+
+            public void parse(InputSource src, 
+                              ContentHandler contentHandler, 
+                              LexicalHandler lexicalHandler) throws SAXException, IOException {
+                parse(src, contentHandler);
+            }
+            
+        };
+    }
+    
+    public void testFileGenerator() throws Exception {
+        String src = "resource://org/apache/cocoon/generation/FileGeneratorTestCase.source.xml";
+        Parameters parameters = new Parameters();
+        String result = "resource://org/apache/cocoon/generation/FileGeneratorTestCase.source.xml";
+        FileGeneratorBean generator = new FileGeneratorBean();
+        manager.expects(atLeastOnce()).method("lookup").with(same(SAXParser.ROLE)).
+                will(returnValue(parser));
+        manager.expects(once()).method("release").with(same(parser));
+        Mock resolver = new Mock(SourceResolver.class);
+        Source source = new ResourceSource(src);
+        resolver.expects(once()).method("resolveURI").with(same(src)).
+                will(returnValue(source));
+        resolver.expects(once()).method("release").with(same(source));
+        generator.setParser(new JaxpSAXParser());
+        generator.setup((SourceResolver) resolver.proxy(), objectModel, src, parameters);
+        DOMBuilder builder = new DOMBuilder();
+        generator.setConsumer(new WhitespaceFilter(builder));
+        generator.generate();
+        assertEqual(load(result), builder.getDocument());
+    }
+
+    protected Document load(String src) throws ProcessingException, SAXException, IOException {
+        Source source = new ResourceSource(src);
+        manager.expects(atLeastOnce()).method("lookup").with(same(SAXParser.ROLE)).
+        will(returnValue(parser));
+        manager.expects(once()).method("release").with(same(parser));
+        DOMBuilder builder = new DOMBuilder();
+        SourceUtil.parse((ServiceManager) manager.proxy(), source, new WhitespaceFilter(builder));
+        return builder.getDocument();
+    }
+    
+    /**
+     * Compare two XML documents provided as strings
+     * @param control Control document
+     * @param test Document to test
+     * @return Diff object describing differences in documents
+     */
+    public final Diff compareXML(Document control, Document test) {
+        return new Diff(control, test);
+    }
+
+    /**
+     * Assert that the result of an XML comparison is similar.
+     *
+     * @param msg The assertion message
+     * @param expected The expected XML document
+     * @param actual The actual XML Document
+     */
+    public final void assertEqual(String msg, Document expected, Document actual) {
+
+        expected.getDocumentElement().normalize();
+        actual.getDocumentElement().normalize();
+
+        Diff diff = compareXML(expected, actual);
+
+        assertEquals(msg + ", " + diff.toString(), true, diff.similar());
+    }
+
+    /**
+     * Assert that the result of an XML comparison is similar.
+     *
+     * @param expected The expected XML document
+     * @param actual The actual XML Document
+     */  
+    public final void assertEqual(Document expected, Document actual) {
+
+        expected.getDocumentElement().normalize();
+        actual.getDocumentElement().normalize();
+
+        Diff diff = compareXML(expected, actual);
+
+        assertEquals("Test if the assertion document is equal, " + diff.toString(), true, diff.similar());
+    }
+
+    /**
+     * Assert that the result of an XML comparison is identical.
+     *
+     * @param msg The assertion message
+     * @param expected The expected XML document
+     * @param actual The actual XML Document
+     */
+    public final void assertIdentical(String msg, Document expected, Document actual) {
+
+        expected.getDocumentElement().normalize();
+        actual.getDocumentElement().normalize();
+
+        Diff diff = compareXML(expected, actual);
+
+        assertEquals(msg + ", " + diff.toString(), true, diff.identical());
+    }
+
+    /**
+     * Assert that the result of an XML comparison is identical.
+     *
+     * @param expected The expected XML document
+     * @param actual The actual XML Document
+     */
+    public final void assertIdentical(Document expected, Document actual) {
+
+        expected.getDocumentElement().normalize();
+        actual.getDocumentElement().normalize();
+
+        Diff diff = compareXML(expected, actual);
+
+        assertEquals("Test if the assertion document is equal, " + diff.toString(), true, diff.identical());
+    }
+    
+}

Propchange: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorBeanTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorTestCase.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorTestCase.java?view=diff&rev=491595&r1=491594&r2=491595
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorTestCase.java (original)
+++ cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/FileGeneratorTestCase.java Mon Jan  1 08:40:06 2007
@@ -23,9 +23,9 @@
 
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.MockLogger;
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.components.source.SourceUtil;
-import org.apache.cocoon.core.xml.impl.JaxpSAXParser;
 import org.apache.cocoon.environment.SourceResolver;
 import org.apache.cocoon.xml.WhitespaceFilter;
 import org.apache.cocoon.xml.dom.DOMBuilder;
@@ -76,6 +76,7 @@
         Parameters parameters = new Parameters();
         String result = "resource://org/apache/cocoon/generation/FileGeneratorTestCase.source.xml";
         FileGenerator generator = new FileGenerator();
+        generator.enableLogging(new MockLogger(generator.getClass()));
         manager.expects(atLeastOnce()).method("lookup").with(same(SAXParser.ROLE)).
                 will(returnValue(parser));
         manager.expects(once()).method("release").with(same(parser));
@@ -84,7 +85,7 @@
         resolver.expects(once()).method("resolveURI").with(same(src)).
                 will(returnValue(source));
         resolver.expects(once()).method("release").with(same(source));
-        generator.setParser(new JaxpSAXParser());
+        generator.service((ServiceManager) manager.proxy());
         generator.setup((SourceResolver) resolver.proxy(), objectModel, src, parameters);
         DOMBuilder builder = new DOMBuilder();
         generator.setConsumer(new WhitespaceFilter(builder));

Added: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java?view=auto&rev=491595
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java (added)
+++ cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java Mon Jan  1 08:40:06 2007
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.generation;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.SourceResolver;
+import org.xml.sax.SAXException;
+
+/**
+ * This generator extends the usual FileGenerator with a pause parameter.
+ * During generation of the content, this generator pauses for the given
+ * amount of time.
+ * This is very usefull for caching tests.
+ * 
+ * @version $Id$
+ * @since   2.2
+ */
+public class PauseGeneratorBean 
+    extends FileGeneratorBean {
+
+    protected long secs;
+
+    /**
+     * @see org.apache.cocoon.generation.FileGenerator#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
+     */
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, par);
+        this.secs = par.getParameterAsLong("pause", 60);
+    }
+
+    /**
+     * @see org.apache.cocoon.generation.FileGenerator#generate()
+     */
+    public void generate()
+    throws IOException, SAXException, ProcessingException {
+        if ( this.getLogger().isDebugEnabled() ) {
+            this.getLogger().debug("Waiting for " + secs + " secs.");
+        }
+        try {
+            Thread.sleep(secs * 1000);
+        } catch (InterruptedException ie) {
+            // ignore
+        }
+        if ( this.getLogger().isDebugEnabled() ) {
+            this.getLogger().debug("Finished waiting.");
+        }
+        super.generate();
+    }
+
+
+}

Propchange: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/core/cocoon-core/src/test/java/org/apache/cocoon/generation/PauseGeneratorBean.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGenerator.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGenerator.java?view=diff&rev=491595&r1=491594&r2=491595
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGenerator.java (original)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGenerator.java Mon Jan  1 08:40:06 2007
@@ -31,7 +31,6 @@
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.environment.SourceResolver;
 import org.apache.cocoon.xml.AttributesImpl;
-import org.apache.cocoon.xml.XMLUtils;
 import org.apache.excalibur.source.Source;
 import org.xml.sax.Attributes;
 import org.xml.sax.Locator;
@@ -148,11 +147,11 @@
     }
 
     /**
-     * @see org.apache.cocoon.generation.FileGenerator#dispose()
+     * <p>Recycle this component.</p>.
      */
-    public void dispose() {
-        super.dispose();
-
+    public void recycle() {
+        super.recycle();
+        
         this.encoding = DEFAULT_ENCODING;
         this.separator = DEFAULT_SEPARATOR.charAt(0);
         this.escape = DEFAULT_ESCAPE.charAt(0);
@@ -209,9 +208,9 @@
 
         try {
             /* Start the document */
-            this.consumer.setDocumentLocator(csv);
-            this.consumer.startDocument();
-            this.consumer.startPrefixMapping(NAMESPACE_PREFIX, NAMESPACE_URI);
+            this.contentHandler.setDocumentLocator(csv);
+            this.contentHandler.startDocument();
+            this.contentHandler.startPrefixMapping(NAMESPACE_PREFIX, NAMESPACE_URI);
             this.indent(0);
             this.startElement("document");
 
@@ -267,8 +266,8 @@
             /* Terminate the document */
             this.indent(0);
             this.endElement("document");
-            this.consumer.endPrefixMapping(NAMESPACE_PREFIX);
-            this.consumer.endDocument();
+            this.contentHandler.endPrefixMapping(NAMESPACE_PREFIX);
+            this.contentHandler.endDocument();
 
         } finally {
             csv.close();
@@ -317,7 +316,7 @@
         }
 
         this.startElement(element, attributes);
-        this.consumer.characters(array, 0, array.length);
+        this.contentHandler.characters(array, 0, array.length);
         this.endElement(element);
         this.buffer.reset();
 
@@ -340,25 +339,26 @@
 
     private void indent(int level)
     throws SAXException {
-        this.consumer.characters(INDENT_STRING, 0, level + 1);
+        this.contentHandler.characters(INDENT_STRING, 0, level + 1);
     }
 
     private void startElement(String name)
     throws SAXException {
-        this.startElement(name, XMLUtils.EMPTY_ATTRIBUTES);
+        this.startElement(name, new AttributesImpl());
     }
 
     private void startElement(String name, Attributes atts)
     throws SAXException {
         if (name == null) throw new NullPointerException("Null name");
+        if (atts == null) atts = new AttributesImpl();
         String qual = NAMESPACE_PREFIX + ':' + name;
-        this.consumer.startElement(NAMESPACE_URI, name, qual, (atts == null ? XMLUtils.EMPTY_ATTRIBUTES : atts));
+        this.contentHandler.startElement(NAMESPACE_URI, name, qual, atts);
     }
 
     private void endElement(String name)
     throws SAXException {
         String qual = NAMESPACE_PREFIX + ':' + name;
-        this.consumer.endElement(NAMESPACE_URI, name, qual);
+        this.contentHandler.endElement(NAMESPACE_URI, name, qual);
     }
 
     private static final class CSVReader extends Reader implements Locator {

Added: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java?view=auto&rev=491595
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java (added)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java Mon Jan  1 08:40:06 2007
@@ -0,0 +1,440 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.cocoon.generation;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.excalibur.source.Source;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>A simple parser converting a Comma Separated Values (CSV) file into XML.</p>
+ * 
+ * <p>This parser is controlled by the following sitemap parameters:</p>
+ * 
+ * <ul>
+ *   <li>
+ *     <b>process-headers</b>: whether the first line in the CSV is considered
+ *     to be the header defining column names (the resulting output will be
+ *     different if this is <i>true</i> or <i>false</i> (default: <i>false</i>).
+ *   </li>
+ *   <li>
+ *     <b>max-records</b>: the maximum number of records to read
+ *     (default: <i>-1</i> read all records).
+ *   </li>
+ *   <li>
+ *     <b>encoding</b>: the character encoding (UTF-8, ISO8859-1, ...) used to
+ *     interpret the input CSV source file (default: <i>system default</i>).
+ *   </li>
+ *   <li>
+ *     <b>separator</b>: the field-separator character in the CSV file (comma,
+ *     tab, ...) (default: <i>,</i> <small>comma</small>).
+ *   </li>
+ *   <li>
+ *     <b>escape</b>: the character used to escape fields, or part of them, in
+ *     the CSV file (default: <i>"</i> <small>quote</small>).
+ *   </li>
+ *   <li>
+ *     <b>buffer-size</b>: the size of the buffer used for reading the source
+ *     CSV file (default: <i>4096 bytes</i>).
+ *   </li>
+ * </ul>
+ *
+ * <p>The generated output will look something like the following:</p>
+ * 
+ * <pre>
+ * &lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+ * &lt;csv:document xmlns:csv="http://apache.org/cocoon/csv/1.0"&gt;
+ *   &lt;csv:header&gt;
+ *     &lt;csv:column number="1"&gt;Column A&lt;/csv:column&gt;
+ *     &lt;csv:column number="2"&gt;Column B&lt;/csv:column&gt;
+ *     &lt;csv:column number="3"&gt;Column C&lt;/csv:column&gt;
+ *   &lt;/csv:header&gt;
+ *   &lt;csv:record number="1"&gt;
+ *     &lt;csv:field number="1" column="Column A"&gt;Field A1&lt;/csv:field&gt;
+ *     &lt;csv:field number="2" column="Column B"&gt;Field B1&lt;/csv:field&gt;
+ *     &lt;csv:field number="3" column="Column C"&gt;Field C1&lt;/csv:field&gt;
+ *   &lt;/csv:record&gt;
+ *   &lt;csv:record number="2"&gt;
+ *     &lt;csv:field number="1" column="Column A"&gt;Field A2&lt;/csv:field&gt;
+ *     &lt;csv:field number="2" column="Column B"&gt;Field B2&lt;/csv:field&gt;
+ *     &lt;csv:field number="3" column="Column C"&gt;Field C2&lt;/csv:field&gt;
+ *   &lt;/csv:record&gt;
+ * &lt;/csv:document&gt;
+ * </pre>
+ *
+ * <p>Note that this generator has been thoroughly tested with CSV files generated
+ * by <a href="http://office.microsoft.com/" target="_new">Microsoft Excel</a>.
+ * Unfortunately no official CSV specification has ever been published by
+ * any standard body, so the interpretation of the format might be slightly
+ * different in cases.</p>
+ */
+public class CSVGeneratorBean extends FileGeneratorBean {
+
+    /** <p>The namespace URI of XML generated by this instance.</p> */
+    public static final String NAMESPACE_URI = "http://apache.org/cocoon/csv/1.0";
+    /** <p>The namespace prefix of XML generated by this instance.</p> */
+    public static final String NAMESPACE_PREFIX = "csv";
+
+    /** <p>The default encoding configured in the Java VM.</p> */
+    private static final String DEFAULT_ENCODING = 
+        new InputStreamReader(new ByteArrayInputStream(new byte[0])).getEncoding();
+    /** <p>The default field separator character.</p> */
+    private static final String DEFAULT_SEPARATOR = ",";
+    /** <p>The default field separator character.</p> */
+    private static final String DEFAULT_ESCAPE = "\"";
+    /** <p>The default field separator character.</p> */
+    private static final int DEFAULT_BUFFER_SIZE = 4096;
+    private static final int UNLIMITED_MAXRECORDS = -1;
+    /** <p>A string used for indenting.</p> */
+    private static final char INDENT_STRING[] = "\n          ".toCharArray();
+
+    /** <p>The encoding used to read the CSV resource from a stream.</p> */
+    private String encoding = DEFAULT_ENCODING;
+    /** <p>The character used to separate fields.</p> */
+    private char separator = DEFAULT_SEPARATOR.charAt(0);
+    /** <p>The character used to initiate and terminate esacaped sequences.</p> */
+    private char escape = DEFAULT_ESCAPE.charAt(0);
+    /** <p>The size of the buffer used to read the input.</p> */
+    private int buffersize = DEFAULT_BUFFER_SIZE;
+    /** <p>The current field (column) number in the current record.</p> */
+    private int fieldnumber = 1;
+    /** <p>The current record (line) number in the current CSV.</p> */
+    private int recordnumber = 1;
+    /** <p>The maximum number of records to read (-1 = read all records)</p> */
+    private int maxrecords;
+    /** <p>A flag indicating whether the &lt;record&gt; tag was opened.</p> */
+    private boolean openrecord = false;
+    /** <p>The character buffer for the current field.</p> */
+    private CharArrayWriter buffer = null;
+    /** <p>A map of all known columns or null if no headers are processed.</p> */
+    private Map columns = null;
+
+    /**
+     * <p>Create a new {@link CSVGeneratorBean} instance.</p>
+     */
+    public CSVGeneratorBean() {
+        super();
+    }
+
+    /**
+     * @see org.apache.cocoon.generation.FileGenerator#dispose()
+     */
+    public void dispose() {
+        super.dispose();
+
+        this.encoding = DEFAULT_ENCODING;
+        this.separator = DEFAULT_SEPARATOR.charAt(0);
+        this.escape = DEFAULT_ESCAPE.charAt(0);
+        this.buffersize = DEFAULT_BUFFER_SIZE;
+        this.buffer = null;
+        this.columns = null;
+        this.recordnumber = 1;
+        this.fieldnumber = 1;
+        this.openrecord = false;
+    }
+
+    /**
+     * <p>Setup this {@link CSVGeneratorBean} instance.</p>
+     */
+    public void setup(SourceResolver resolver, Map object_model, String source,
+                      Parameters parameters)
+    throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, object_model, source, parameters);
+
+        boolean header = parameters.getParameterAsBoolean("process-headers", false);
+
+        this.encoding = parameters.getParameter("encoding", DEFAULT_ENCODING);
+        this.separator = parameters.getParameter("separator", DEFAULT_SEPARATOR).charAt(0);
+        this.escape = parameters.getParameter("escape", DEFAULT_ESCAPE).charAt(0);
+        this.buffersize = parameters.getParameterAsInteger("buffer-size", DEFAULT_BUFFER_SIZE);
+        this.maxrecords = parameters.getParameterAsInteger("max-records", UNLIMITED_MAXRECORDS);
+        this.buffer = new CharArrayWriter();
+        this.columns =  (header ? new HashMap() : null);
+        this.recordnumber = (header ? 0 : 1);
+        this.fieldnumber = 1;
+        this.openrecord = false;
+    }
+
+    /**
+     * <p>Generate the unique key.</p>
+     */
+    public Serializable getKey() {
+        StringBuffer key = new StringBuffer(this.inputSource.getURI());
+        if (this.columns != null) key.append("headers");
+        key.append(separator);
+        key.append(maxrecords);
+        key.append(escape);
+        return key;
+    }
+
+    /**
+     * <p>Generate XML data from a Comma Separated Value resource.</p>.
+     */
+    public void generate()
+    throws IOException, SAXException, ProcessingException {
+
+        /* Create a new Reader correctly decoding the source stream */
+        CSVReader csv = new CSVReader(this.inputSource, this.encoding, this.buffersize);
+
+        try {
+            /* Start the document */
+            this.consumer.setDocumentLocator(csv);
+            this.consumer.startDocument();
+            this.consumer.startPrefixMapping(NAMESPACE_PREFIX, NAMESPACE_URI);
+            this.indent(0);
+            this.startElement("document");
+
+            /* Allocate buffer and status for parsing */
+            boolean unescaped = true;
+            int prev = -1;
+            int curr = -1;
+
+            /* Parse the file reading characters one-by-one */
+            while ((curr = csv.read()) >= 0 && (this.maxrecords == UNLIMITED_MAXRECORDS || recordnumber <= this.maxrecords)) {
+
+                /* Process any occurrence of the escape character */
+                if (curr == this.escape) {
+                    if ((unescaped) && (prev == this.escape)) {
+                        this.buffer.write(this.escape);
+                    }
+                    unescaped = ! unescaped;
+                    prev = curr;
+                    continue;
+                }
+
+                /* Process any occurrence of the field separator */
+                if ((unescaped) && (curr == this.separator)) {
+                    this.dumpField();
+                    prev = curr;
+                    continue;
+                }
+
+                /* Process newline characters */
+                if ((unescaped) && ((curr == '\r') || (curr == '\n'))) {
+                    this.dumpField();
+                    this.dumpRecord();
+
+                    /* Record numbering */
+                    if (((curr == '\n') && (prev != '\r')) || (curr == '\r')) {
+                        this.recordnumber ++;
+                    }
+                    
+                    /* Nothing else to do */
+                    prev = curr;
+                    continue;
+                }
+
+                /* Any other character simply gets added to the buffer */
+                this.buffer.write(curr);
+                prev = curr;
+            }
+
+            /* Terminate any hanging open record element (just in case) */
+            this.dumpField();
+            this.dumpRecord();
+
+            /* Terminate the document */
+            this.indent(0);
+            this.endElement("document");
+            this.consumer.endPrefixMapping(NAMESPACE_PREFIX);
+            this.consumer.endDocument();
+
+        } finally {
+            csv.close();
+        }
+    }
+
+    
+    private void dumpField()
+    throws SAXException {
+        if (this.buffer.size() < 1) {
+            this.fieldnumber ++;
+            return;
+        }
+
+        if (! this.openrecord) {
+            this.indent(4);
+
+            if (this.recordnumber > 0) {
+                AttributesImpl attributes = new AttributesImpl();
+                String value = Integer.toString(this.recordnumber);
+                attributes.addCDATAAttribute("number", value);
+                this.startElement("record", attributes);
+            } else {
+                this.startElement("header");
+            }
+            this.openrecord = true;
+        }
+
+        /* Enclode the field in the proper element */
+        String element = "field";
+        char array[] = this.buffer.toCharArray();
+        this.indent(8);
+
+        AttributesImpl attributes = new AttributesImpl();
+        String value = Integer.toString(this.fieldnumber);
+        attributes.addCDATAAttribute("number", value);
+
+        if (this.recordnumber < 1) {
+            this.columns.put(new Integer(this.fieldnumber), new String(array));
+            element = "column";
+        } else if (this.columns != null) {
+            String header = (String) this.columns.get(new Integer(this.fieldnumber));
+            if (header != null) {
+                attributes.addCDATAAttribute("column", header);
+            }
+        }
+
+        this.startElement(element, attributes);
+        this.consumer.characters(array, 0, array.length);
+        this.endElement(element);
+        this.buffer.reset();
+
+        this.fieldnumber ++;
+    }
+
+    private void dumpRecord()
+    throws SAXException {
+        if (this.openrecord) {
+            this.indent(4);
+            if (this.recordnumber > 0) {
+                this.endElement("record");
+            } else {
+                this.endElement("header");
+            }
+            this.openrecord = false;
+        }
+        this.fieldnumber = 1;
+    }
+
+    private void indent(int level)
+    throws SAXException {
+        this.consumer.characters(INDENT_STRING, 0, level + 1);
+    }
+
+    private void startElement(String name)
+    throws SAXException {
+        this.startElement(name, XMLUtils.EMPTY_ATTRIBUTES);
+    }
+
+    private void startElement(String name, Attributes atts)
+    throws SAXException {
+        if (name == null) throw new NullPointerException("Null name");
+        String qual = NAMESPACE_PREFIX + ':' + name;
+        this.consumer.startElement(NAMESPACE_URI, name, qual, (atts == null ? XMLUtils.EMPTY_ATTRIBUTES : atts));
+    }
+
+    private void endElement(String name)
+    throws SAXException {
+        String qual = NAMESPACE_PREFIX + ':' + name;
+        this.consumer.endElement(NAMESPACE_URI, name, qual);
+    }
+
+    private static final class CSVReader extends Reader implements Locator {
+        
+        private String uri = null;
+        private Reader input = null;
+        private int column = 1;
+        private int line = 1;
+        private int last = -1;
+
+        protected CSVReader(Source source, String encoding, int buffer)
+        throws IOException {
+            InputStream stream = source.getInputStream();
+            Reader reader = new InputStreamReader(stream, encoding);
+            this.input = new BufferedReader(reader, buffer);
+            this.uri = source.getURI();
+        }
+
+        public String getPublicId() {
+            return null;
+        }
+
+        public String getSystemId() {
+            return this.uri;
+        }
+
+        public int getLineNumber() {
+            return this.line;
+        }
+
+        public int getColumnNumber() {
+            return this.column;
+        }
+
+        public void close()
+        throws IOException {
+            this.input.close();
+        }
+        
+        public int read()
+        throws IOException {
+            int c = this.input.read();
+            if (c < 0) return c;
+
+            if (((c == '\n') && (this.last != '\r')) || (c == '\r')) {
+                this.column = 1;
+                this.line ++;
+            }
+
+            this.last = c;
+            return c;
+        }
+
+        public int read(char b[], int o, int l)
+        throws IOException {
+            if (b == null) throw new NullPointerException();
+            if ((o<0)||(o>b.length)||(l<0)||((o+l)>b.length)||((o+l)<0)) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (l == 0) return 0;
+
+            int c = read();
+            if (c == -1) return -1;
+            b[o] = (char)c;
+
+            int i = 1;
+            try {
+                for (i = 1; i < l ; i++) {
+                    c = read();
+                    if (c == -1) break;
+                    b[o + i] = (char)c;
+                }
+            } catch (IOException ee) {
+                return i;
+            }
+            return i;
+        }
+    }
+}

Propchange: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/CSVGeneratorBean.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGenerator.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGenerator.java?view=diff&rev=491595&r1=491594&r2=491595
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGenerator.java (original)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGenerator.java Mon Jan  1 08:40:06 2007
@@ -20,11 +20,7 @@
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.caching.CacheableProcessingComponent;
 import org.apache.cocoon.components.source.util.SourceUtil;
-import org.apache.cocoon.core.xml.SAXParser;
 import org.apache.cocoon.environment.SourceResolver;
-import org.apache.cocoon.sitemap.DisposableSitemapComponent;
-import org.apache.cocoon.util.AbstractLogEnabled;
-import org.apache.cocoon.xml.XMLConsumer;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceException;
 import org.apache.excalibur.source.SourceValidity;
@@ -48,54 +44,38 @@
  *
  * @version $Id$
  */
-public class FileGenerator
-    extends AbstractLogEnabled
-    implements Generator, CacheableProcessingComponent, DisposableSitemapComponent {
+public class FileGenerator extends ServiceableGenerator
+                           implements CacheableProcessingComponent {
 
     /** The input source */
     protected Source inputSource;
 
-    /** The source resolver. */
-    protected SourceResolver resolver;
-
-    /** The consumer. */
-    protected XMLConsumer consumer;
-
-    /** The SAX Parser. */
-    protected SAXParser parser;
-
-    public void setParser(SAXParser parser) {
-        this.parser = parser;
-    }
-
     /**
-     * @see org.apache.cocoon.sitemap.DisposableSitemapComponent#dispose()
+     * Recycle this component.
+     * All instance variables are set to <code>null</code>.
      */
-    public void dispose() {
-        if ( this.inputSource != null ) {
-            this.resolver.release(this.inputSource);
+    public void recycle() {
+        if (null != this.inputSource) {
+            super.resolver.release(this.inputSource);
             this.inputSource = null;
         }
-        this.resolver = null;
-        this.consumer = null;
+        super.recycle();
     }
 
     /**
      * Setup the file generator.
      * Try to get the last modification date of the source for caching.
-     *
-     * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
      */
     public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
     throws ProcessingException, SAXException, IOException {
-        this.resolver = resolver;
+        super.setup(resolver, objectModel, src, par);
         try {
-            this.inputSource = this.resolver.resolveURI(src);
+            this.inputSource = super.resolver.resolveURI(src);
         } catch (SourceException se) {
             throw SourceUtil.handle("Error during resolving of '" + src + "'.", se);
         }
         if (getLogger().isDebugEnabled()) {
-            getLogger().debug("Source " + src +
+            getLogger().debug("Source " + super.source +
                               " resolved to " + this.inputSource.getURI());
         }
     }
@@ -121,19 +101,12 @@
     }
 
     /**
-     * @see org.apache.cocoon.xml.XMLProducer#setConsumer(org.apache.cocoon.xml.XMLConsumer)
-     */
-    public void setConsumer(XMLConsumer consumer) {
-        this.consumer = consumer;
-    }
-
-    /**
      * Generate XML data.
      */
     public void generate()
     throws IOException, SAXException, ProcessingException {
         try {
-            this.parser.parse(SourceUtil.getInputSource(this.inputSource), this.consumer);
+            SourceUtil.parse(this.manager, this.inputSource, super.xmlConsumer);
         } catch (SAXException e) {
             SourceUtil.handleSAXException(this.inputSource.getURI(), e);
         }

Added: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java?view=auto&rev=491595
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java (added)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java Mon Jan  1 08:40:06 2007
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.generation;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.caching.CacheableProcessingComponent;
+import org.apache.cocoon.components.source.util.SourceUtil;
+import org.apache.cocoon.core.xml.SAXParser;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.sitemap.DisposableSitemapComponent;
+import org.apache.cocoon.util.AbstractLogEnabled;
+import org.apache.cocoon.xml.XMLConsumer;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceException;
+import org.apache.excalibur.source.SourceValidity;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * @cocoon.sitemap.component.documentation
+ * The <code>FileGenerator</code> is a class that reads XML from a source
+ * and generates SAX Events. The <code>FileGenerator</code> implements the
+ * <code>CacheableProcessingComponent</code> interface.
+ *
+ * @cocoon.sitemap.component.name   file
+ * @cocoon.sitemap.component.label  content
+ * @cocoon.sitemap.component.logger sitemap.generator.file
+ * @cocoon.sitemap.component.documentation.caching
+ *     Uses the last modification date of the xml document for validation
+ *
+ * @version $Id$
+ */
+public class FileGeneratorBean
+    extends AbstractLogEnabled
+    implements Generator, CacheableProcessingComponent, DisposableSitemapComponent {
+
+    /** The input source */
+    protected Source inputSource;
+
+    /** The source resolver. */
+    protected SourceResolver resolver;
+
+    /** The consumer. */
+    protected XMLConsumer consumer;
+
+    /** The SAX Parser. */
+    protected SAXParser parser;
+
+    public void setParser(SAXParser parser) {
+        this.parser = parser;
+    }
+
+    /**
+     * @see org.apache.cocoon.sitemap.DisposableSitemapComponent#dispose()
+     */
+    public void dispose() {
+        if ( this.inputSource != null ) {
+            this.resolver.release(this.inputSource);
+            this.inputSource = null;
+        }
+        this.resolver = null;
+        this.consumer = null;
+    }
+
+    /**
+     * Setup the file generator.
+     * Try to get the last modification date of the source for caching.
+     *
+     * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
+     */
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
+    throws ProcessingException, SAXException, IOException {
+        this.resolver = resolver;
+        try {
+            this.inputSource = this.resolver.resolveURI(src);
+        } catch (SourceException se) {
+            throw SourceUtil.handle("Error during resolving of '" + src + "'.", se);
+        }
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Source " + src +
+                              " resolved to " + this.inputSource.getURI());
+        }
+    }
+
+    /**
+     * Generate the unique key.
+     * This key must be unique inside the space of this component.
+     *
+     * @return The generated key hashes the src
+     */
+    public Serializable getKey() {
+        return this.inputSource.getURI();
+    }
+
+    /**
+     * Generate the validity object.
+     *
+     * @return The generated validity object or <code>null</code> if the
+     *         component is currently not cacheable.
+     */
+    public SourceValidity getValidity() {
+        return this.inputSource.getValidity();
+    }
+
+    /**
+     * @see org.apache.cocoon.xml.XMLProducer#setConsumer(org.apache.cocoon.xml.XMLConsumer)
+     */
+    public void setConsumer(XMLConsumer consumer) {
+        this.consumer = consumer;
+    }
+
+    /**
+     * Generate XML data.
+     */
+    public void generate()
+    throws IOException, SAXException, ProcessingException {
+        try {
+            this.parser.parse(SourceUtil.getInputSource(this.inputSource), this.consumer);
+        } catch (SAXException e) {
+            SourceUtil.handleSAXException(this.inputSource.getURI(), e);
+        }
+    }
+}

Propchange: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-components/src/main/java/org/apache/cocoon/generation/FileGeneratorBean.java
------------------------------------------------------------------------------
    svn:keywords = Id