cziegeler 02/05/02 02:31:26 Added: src/java/org/apache/cocoon/components/pipeline AbstractProcessingPipeline.java ProcessingPipeline.java Log: The beginning of the new ProcessingPipeline combining stream and event pipeline Revision Changes Path 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java Index: AbstractProcessingPipeline.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.pipeline; import org.apache.avalon.excalibur.pool.Recyclable; import org.apache.avalon.framework.component.Component; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.component.ComponentSelector; import org.apache.avalon.framework.logger.AbstractLoggable; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.components.pipeline.OutputComponentSelector; import org.apache.cocoon.components.saxconnector.SAXConnector; import org.apache.cocoon.environment.Environment; import org.apache.cocoon.generation.Generator; import org.apache.cocoon.reading.Reader; import org.apache.cocoon.serialization.Serializer; import org.apache.cocoon.transformation.Transformer; import org.apache.cocoon.xml.AbstractXMLProducer; import org.apache.cocoon.xml.XMLConsumer; import org.apache.cocoon.xml.XMLProducer; import org.xml.sax.SAXException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; /** * This is the base for all implementations of a <code>ProcessingPipeline</code>. * * 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> * * <p> * A <code>ProcessingPipeline</code> is <code>Recomposable</code> since the * <code>ComponentManager</code> used to get the generato, transformers etc. * depends on the pipeline assembly engine where they are defined (i.e. a given * sitemap file). * * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> * @version CVS $Id: AbstractProcessingPipeline.java,v 1.1 2002/05/02 09:31:26 cziegeler Exp $ */ public abstract class AbstractProcessingPipeline extends AbstractLoggable implements ProcessingPipeline, Recyclable { // Generator stuff protected Generator generator; protected Parameters generatorParam; protected String generatorSource; protected ComponentSelector generatorSelector; // Transformer stuff protected ArrayList transformers = new ArrayList(); protected ArrayList transformerParams = new ArrayList(); protected ArrayList transformerSources = new ArrayList(); protected ArrayList transformerSelectors = new ArrayList(); // Serializer stuff protected Serializer serializer; protected Parameters serializerParam; protected String serializerSource; protected String serializerMimeType; protected String sitemapSerializerMimeType; protected OutputComponentSelector serializerSelector; // Reader stuff protected Reader reader; protected Parameters readerParam; protected String readerSource; protected String readerMimeType; protected String sitemapReaderMimeType; protected OutputComponentSelector readerSelector; // The SAX Connectors protected ArrayList connectors = new ArrayList(); /** the component manager set with compose() */ protected ComponentManager manager; /** is a SAXConnector configured? */ protected boolean configuredSAXConnector; /** the component manager set with compose() and recompose() */ protected ComponentManager newManager; /** * Composable Interface */ public void compose (ComponentManager manager) throws ComponentException { this.manager = manager; // cache this test for a little bit performance this.configuredSAXConnector = this.manager.hasComponent(SAXConnector.ROLE); this.newManager = manager; } /** * Recomposable Interface */ public void recompose (ComponentManager manager) throws ComponentException { this.newManager = manager; } /** * 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 Exception if the generator couldn't be obtained. */ public void setGenerator (String role, String source, Parameters param) throws ProcessingException { if (this.generator != null) { throw new ProcessingException ("Generator already set. You can only select one Generator (" + role + ")"); } if (this.reader != null) { throw new ProcessingException ("Reader already set. You cannot use a reader and a generator for one pipeline."); } try { this.generatorSelector = (ComponentSelector) this.newManager.lookup(Generator.ROLE + "Selector"); } catch (ComponentException ce) { throw new ProcessingException("Lookup of generator selector failed.", ce); } try { this.generator = (Generator) this.generatorSelector.select(role); } catch (ComponentException ce) { throw new ProcessingException("Lookup of generator for role '"+role+"' failed.", ce); } this.generatorSource = source; this.generatorParam = param; } /** * Get the current Generator */ public Generator getGenerator() { return this.generator; } /** * 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 Exception if the generator couldn't be obtained. */ public void addTransformer (String role, String source, Parameters param) throws ProcessingException { if (this.reader != null) { throw new ProcessingException ("Reader already set. You cannot use a transformer with a reader."); } if (this.generator == null) { throw new ProcessingException ("You must set a generator first before you can use a transformer."); } ComponentSelector selector = null; try { selector = (ComponentSelector) this.newManager.lookup(Transformer.ROLE + "Selector"); this.transformerSelectors.add(selector); } catch (ComponentException ce) { throw new ProcessingException("Lookup of transformer selector failed.", ce); } try { this.transformers.add((Transformer)selector.select(role)); } catch (ComponentException ce) { throw new ProcessingException("Lookup of transformer for role '"+role+"' failed.", ce); } this.transformerSources.add(source); this.transformerParams.add(param); } /** * Set the serializer for this pipeline * @param mimeType Can be null */ public void setSerializer (String role, String source, Parameters param, String mimeType) throws ProcessingException { if (this.serializer != null) { throw new ProcessingException ("Serializer already set. You can only select one Serializer (" + role + ")"); } if (this.reader != null) { throw new ProcessingException ("Reader already set. You cannot use a serializer with a reader."); } if (this.generator == null) { throw new ProcessingException ("You must set a generator first before you can use a serializer."); } try { this.serializerSelector = (OutputComponentSelector) this.newManager.lookup(Serializer.ROLE + "Selector"); } catch (ComponentException ce) { throw new ProcessingException("Lookup of serializer selector failed.", ce); } try { this.serializer = (Serializer)serializerSelector.select(role); } catch (ComponentException ce) { throw new ProcessingException("Lookup of serializer for role '"+role+"' failed.", ce); } this.serializerSource = source; this.serializerParam = param; this.serializerMimeType = mimeType; this.sitemapSerializerMimeType = serializerSelector.getMimeTypeForHint(role); } /** * Set the reader for this pipeline * @param mimeType Can be null */ public void setReader (String role, String source, Parameters param, String mimeType) throws ProcessingException { if (this.reader != null) { throw new ProcessingException ("Reader already set. You can only select one Reader (" + role + ")"); } if (this.generator != null) { throw new ProcessingException ("Generator already set. You cannot use a reader and a generator for one pipeline."); } try { this.readerSelector = (OutputComponentSelector) this.newManager.lookup(Reader.ROLE + "Selector"); } catch (ComponentException ce) { throw new ProcessingException("Lookup of reader selector failed.", ce); } try { this.reader = (Reader)readerSelector.select(role); } catch (ComponentException ce) { throw new ProcessingException("Lookup of reader for role '"+role+"' failed.", ce); } this.readerSource = source; this.readerParam = param; this.readerMimeType = mimeType; this.sitemapReaderMimeType = readerSelector.getMimeTypeForHint(role); } /** * 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; } /** * Setup pipeline components. */ protected void setupPipeline(Environment environment) throws ProcessingException { try { // setup the generator this.generator.setup( environment, environment.getObjectModel(), generatorSource, generatorParam ); Iterator transformerItt = this.transformers.iterator(); Iterator transformerSourceItt = this.transformerSources.iterator(); Iterator transformerParamItt = this.transformerParams.iterator(); while ( transformerItt.hasNext() ) { Transformer trans = (Transformer)transformerItt.next(); trans.setup( environment, environment.getObjectModel(), (String)transformerSourceItt.next(), (Parameters)transformerParamItt.next() ); } String mimeType = this.serializer.getMimeType(); if (mimeType != null) { // we have a mimeType from the component itself environment.setContentType (mimeType); } else if (serializerMimeType != null) { // there was a mimeType specified in the sitemap pipeline environment.setContentType (serializerMimeType); } else if (this.sitemapSerializerMimeType != null) { // use the mimeType specified in the sitemap component declaration environment.setContentType (this.sitemapSerializerMimeType); } else { // No mimeType available String message = "Unable to determine MIME type for " + environment.getURIPrefix() + "/" + environment.getURI(); getLogger().error(message); throw new ProcessingException(message); } } catch (SAXException e) { throw new ProcessingException( "Could not setup pipeline.", e ); } catch (IOException e) { throw new ProcessingException( "Could not setup pipeline.", e ); } } /** * Connect the XML pipeline. */ protected void connectPipeline(Environment environment) throws ProcessingException { XMLProducer prev = (XMLProducer)this.generator; XMLConsumer next; try { Iterator itt = this.transformers.iterator(); while ( itt.hasNext() ) { if (this.configuredSAXConnector) { // connect SAXConnector SAXConnector connect = (SAXConnector) this.manager.lookup(SAXConnector.ROLE); connect.setup(environment,environment.getObjectModel(), null, null); this.connectors.add(connect); next = connect; prev.setConsumer(next); prev = connect; } // Connect next component. Transformer trans = (Transformer) itt.next(); next = trans; prev.setConsumer(next); prev = trans; } if (this.configuredSAXConnector) { // insert SAXConnector SAXConnector connect = (SAXConnector) this.manager.lookup(SAXConnector.ROLE); connect.setup(environment,environment.getObjectModel(), null, null); this.connectors.add(connect); next = connect; prev.setConsumer(next); prev = connect; } // insert the serializer prev.setConsumer(this.serializer); } catch ( IOException e ) { throw new ProcessingException( "Could not connect pipeline.", e ); } catch ( SAXException e ) { throw new ProcessingException( "Could not connect pipeline.", e ); } catch ( ComponentException e ) { throw new ProcessingException( "Could not connect pipeline.", e ); } } /** * Process the given <code>Environment</code>, producing the output. */ public boolean process(Environment environment) throws ProcessingException { if ( !checkPipeline() ) { throw new ProcessingException("Attempted to process incomplete pipeline."); } if ( this.reader != null ) { return this.processReader(environment); } else { return this.processXMLPipeline(environment); } } /** * Process the SAX event pipeline */ protected boolean processXMLPipeline(Environment environment) throws ProcessingException { this.setupPipeline(environment); this.connectPipeline(environment); try { if (this.serializer.shouldSetContentLength()) { // set the output stream ByteArrayOutputStream os = new ByteArrayOutputStream(); this.serializer.setOutputStream(os); // execute the pipeline: this.generator.generate(); byte[] data = os.toByteArray(); environment.setContentLength(data.length); environment.getOutputStream().write(data); } else { // set the output stream this.serializer.setOutputStream(environment.getOutputStream()); // execute the pipeline: this.generator.generate(); } } catch ( ProcessingException e ) { throw e; } catch ( Exception e ) { getLogger().debug("Exception in process", e); throw new ProcessingException( "Failed to execute pipeline.", e ); } return true; } /** * Process the pipeline using a reader. * @throws ProcessingException if */ protected boolean processReader(Environment environment) throws ProcessingException { String mimeType; try { this.reader.setup(environment,environment.getObjectModel(),readerSource,readerParam); mimeType = this.reader.getMimeType(); if ( mimeType != null ) { environment.setContentType(mimeType); } else if ( readerMimeType != null ) { environment.setContentType(this.readerMimeType); } else { environment.setContentType(this.sitemapReaderMimeType); } // has the read resource been modified? long lastModified = this.reader.getLastModified(); if (lastModified != 0 && !environment.isResponseModified(lastModified)) { // environment supports this, so we are finished environment.setResponseIsNotModified(); return true; } if (this.reader.shouldSetContentLength()) { ByteArrayOutputStream os = new ByteArrayOutputStream(); this.reader.setOutputStream(os); this.reader.generate(); byte[] data = os.toByteArray(); environment.setContentLength(data.length); environment.getOutputStream().write(data); } else { this.reader.setOutputStream(environment.getOutputStream()); this.reader.generate(); } } catch ( ProcessingException e ) { throw e; } catch ( Exception e ) { throw new ProcessingException("Error reading resource",e); } return true; } public void recycle() { // release reader. if ( this.readerSelector != null) { this.readerSelector.release(this.reader); this.newManager.release( this.readerSelector ); this.readerSelector = null; this.reader = null; this.readerParam = null; } // Release generator. if ( this.generatorSelector != null) { this.generatorSelector.release( this.generator ); this.newManager.release( this.generatorSelector ); this.generatorSelector = null; this.generator = null; this.generatorParam = null; } // Release transformers int size = this.transformerSelectors.size(); for (int i = 0; i < size; i++) { final ComponentSelector selector = (ComponentSelector)this.transformerSelectors.get(i); selector.release( (Component)this.transformers.get(i) ); this.newManager.release( selector ); } this.transformerSelectors.clear(); this.transformers.clear(); this.transformerParams.clear(); this.transformerSources.clear(); // release serializer if ( this.serializerSelector != null ) { this.serializerSelector.release(this.serializer); this.newManager.release( this.serializerSelector ); this.serializerSelector = null; this.serializer = null; this.serializerParam = null; } // Release connectors Iterator itc = this.connectors.iterator(); while ( itc.hasNext() ) { this.manager.release((Component) itc.next()); } this.connectors.clear(); } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/ProcessingPipeline.java Index: ProcessingPipeline.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.pipeline; import org.apache.avalon.framework.component.Component; import org.apache.avalon.framework.component.Recomposable; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.environment.Environment; /** * 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> * * <p> * A <code>ProcessingPipeline</code> is <code>Recomposable</code> since the * <code>ComponentManager</code> used to get the generato, transformers etc. * depends on the pipeline assembly engine where they are defined (i.e. a given * sitemap file). * * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> * @author <a href="mailto:[EMAIL PROTECTED]">Giacomo Pati</a> * @version CVS $Id: ProcessingPipeline.java,v 1.1 2002/05/02 09:31:26 cziegeler Exp $ */ public interface ProcessingPipeline extends Component, Recomposable { String ROLE = ProcessingPipeline.class.getName(); /** * 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 Exception if the generator couldn't be obtained. */ void setGenerator (String role, String source, Parameters param) throws ProcessingException; /** * Get the generator used by this pipeline. Access to the generator is needed for * content aggregation since the aggregation generator is fed by the pipeline engine * with the different parts. * * @return the generator Generator getGenerator (); */ /** * 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 Exception if the generator couldn't be obtained. */ void addTransformer (String role, String source, Parameters param) throws ProcessingException; /** * Set the serializer for this pipeline * @param mimeType Can be null */ void setSerializer (String role, String source, Parameters param, String mimeType) throws ProcessingException; /** * Set the reader for this pipeline * @param mimeType Can be null */ void setReader (String role, String source, Parameters param, String mimeType) throws ProcessingException; /** * Process the given <code>Environment</code>, producing the output. */ boolean process(Environment environment) throws ProcessingException; }
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]