You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by vg...@apache.org on 2004/11/18 01:16:55 UTC

svn commit: rev 76198 - in cocoon/trunk/src/java/org/apache/cocoon: components/pipeline components/treeprocessor/sitemap generation

Author: vgritsenko
Date: Wed Nov 17 16:16:54 2004
New Revision: 76198

Added:
   cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java   (contents, props changed)
   cocoon/trunk/src/java/org/apache/cocoon/generation/VirtualPipelineGenerator.java   (contents, props changed)
Modified:
   cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ComponentsNodeBuilder.java
Log:
first cut at virtual pipeline generator


Added: cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java
==============================================================================
--- (empty file)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java	Wed Nov 17 16:16:54 2004
@@ -0,0 +1,422 @@
+/*
+ * 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.cocoon.components.pipeline;
+
+import org.apache.avalon.excalibur.pool.Recyclable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.context.Context;
+
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.Processor;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.environment.internal.EnvironmentHelper;
+import org.apache.cocoon.generation.Generator;
+import org.apache.cocoon.serialization.Serializer;
+import org.apache.cocoon.sitemap.SitemapModelComponent;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.apache.cocoon.transformation.Transformer;
+import org.apache.cocoon.xml.XMLConsumer;
+import org.apache.cocoon.xml.XMLProducer;
+
+import org.apache.excalibur.source.SourceValidity;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Pipeline used by virtual pipeline components
+ *
+ * @version CVS $Id$
+ */
+public class VirtualProcessingPipeline extends AbstractLogEnabled
+                                       implements ProcessingPipeline, Recyclable, Serviceable {
+
+    // Resolver of the defining sitemap
+    private SourceResolver resolver;
+
+    // Generator stuff
+    protected Generator generator;
+    protected Parameters generatorParam;
+    protected String generatorSource;
+
+    // Transformer stuff
+    protected ArrayList transformers = new ArrayList();
+    protected ArrayList transformerParams = new ArrayList();
+    protected ArrayList transformerSources = new ArrayList();
+
+    // Serializer stuff
+    protected Serializer serializer;
+    protected Parameters serializerParam;
+    protected String serializerSource;
+    protected String serializerMimeType;
+
+    /**
+     * True when pipeline has been prepared.
+     */
+    private boolean prepared;
+
+    /**
+     * This is the last component in the pipeline, either the serializer
+     * or a custom xmlconsumer for the cocoon: protocol etc.
+     */
+    protected XMLConsumer lastConsumer;
+
+    /** The component manager set with compose() */
+    protected ServiceManager manager;
+
+    /** The component manager set with compose() and recompose() */
+    protected ServiceManager newManager;
+
+    /** The current Processor */
+    protected Processor processor;
+
+
+    public VirtualProcessingPipeline(Context context) throws Exception {
+        this.resolver = (EnvironmentHelper) context.get(Constants.CONTEXT_ENV_HELPER);
+    }
+
+    public void service (ServiceManager manager)
+    throws ServiceException {
+        this.manager = manager;
+        this.newManager = manager;
+    }
+
+    /**
+     * Set the processor's service manager
+     */
+    public void setProcessorManager (ServiceManager manager) {
+        this.newManager = manager;
+    }
+
+    /**
+     * Setup this component
+     */
+    public void setup(Parameters params) {
+    }
+
+    /**
+     * Get the generator - used for content aggregation
+     */
+    public Generator getGenerator() {
+        return this.generator;
+    }
+
+    /**
+     * Informs pipeline we have come across a branch point
+     * Default Behaviour is do nothing
+     */
+    public void informBranchPoint() {
+        // this can be overwritten in subclasses
+    }
+
+    /**
+     * 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>ServiceManager</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 org.apache.cocoon.ProcessingException if the generator couldn't be obtained.
+     */
+    public void setGenerator (String role, String source, Parameters param, Parameters hintParam)
+    throws ProcessingException {
+        if (this.generator != null) {
+            throw new ProcessingException ("Generator already set. Cannot set generator '" + role +
+                                           "' at " + getLocation(param));
+        }
+
+        try {
+            this.generator = (Generator) this.newManager.lookup(Generator.ROLE + '/' + role);
+        } catch (ServiceException ce) {
+            throw new ProcessingException("Lookup of generator '" + role + "' failed at " + getLocation(param), ce);
+        }
+
+        this.generatorSource = source;
+        this.generatorParam = param;
+    }
+
+    /**
+     * 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>ServiceManager</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 org.apache.cocoon.ProcessingException if the generator couldn't be obtained.
+     */
+    public void addTransformer (String role, String source, Parameters param, Parameters hintParam)
+    throws ProcessingException {
+        if (this.generator == null) {
+            throw new ProcessingException ("Must set a generator before adding transformer '" + role +
+                                           "' at " + getLocation(param));
+        }
+
+        try {
+            this.transformers.add(this.newManager.lookup(Transformer.ROLE + '/' + role));
+        } catch (ServiceException ce) {
+            throw new ProcessingException("Lookup of transformer '"+role+"' failed at " + getLocation(param), 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, Parameters hintParam, String mimeType)
+    throws ProcessingException {
+        if (this.serializer != null) {
+            // Should normally not happen as adding a serializer starts pipeline processing
+            throw new ProcessingException ("Serializer already set. Cannot set serializer '" + role +
+                                           "' at " + getLocation(param));
+        }
+
+        if (this.generator == null) {
+            throw new ProcessingException ("Must set a generator before setting serializer '" + role +
+                                           "' at " + getLocation(param));
+        }
+
+        try {
+            this.serializer = (Serializer)this.newManager.lookup(Serializer.ROLE + '/' + role);
+        } catch (ServiceException ce) {
+            throw new ProcessingException("Lookup of serializer '" + role + "' failed at " + getLocation(param), ce);
+        }
+        this.serializerSource = source;
+        this.serializerParam = param;
+        this.serializerMimeType = mimeType;
+        this.lastConsumer = this.serializer;
+    }
+
+    /**
+     * Sanity check
+     * @return true if the pipeline is 'sane', false otherwise.
+     */
+    protected boolean checkPipeline() {
+        if (this.generator == null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Setup pipeline components.
+     */
+    protected void setupPipeline(Environment environment)
+    throws ProcessingException {
+        try {
+            // SourceResolver resolver = this.processor.getSourceResolver();
+
+            // setup the generator
+            this.generator.setup(
+                resolver,
+                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(resolver,
+                            environment.getObjectModel(),
+                            (String)transformerSourceItt.next(),
+                            (Parameters)transformerParamItt.next()
+                );
+            }
+
+            if (this.serializer instanceof SitemapModelComponent) {
+                ((SitemapModelComponent)this.serializer).setup(
+                    resolver,
+                    environment.getObjectModel(),
+                    this.serializerSource,
+                    this.serializerParam
+                );
+            }
+
+        } catch (SAXException e) {
+            throw new ProcessingException("Could not setup pipeline.", e);
+        } catch (IOException e) {
+            throw new ProcessingException("Could not setup pipeline.", e);
+        }
+    }
+
+    /**
+     * Connect the next component
+     */
+    protected void connect(Environment environment,
+                           XMLProducer producer,
+                           XMLConsumer consumer)
+    throws ProcessingException {
+        // Connect next component.
+        producer.setConsumer(consumer);
+    }
+
+    /**
+     * Connect the XML pipeline.
+     */
+    protected void connectPipeline(Environment environment)
+    throws ProcessingException {
+        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);
+    }
+
+    /**
+     * Prepare the pipeline
+     */
+    protected void preparePipeline(Environment environment)
+    throws ProcessingException {
+        // TODO (CZ) Get the processor set via IoC
+        this.processor = EnvironmentHelper.getCurrentProcessor();
+        if (!checkPipeline()) {
+            throw new ProcessingException("Attempted to process incomplete pipeline.");
+        }
+
+        if (this.prepared) {
+            throw new ProcessingException("Duplicate preparePipeline call caught.");
+        }
+
+        setupPipeline(environment);
+        this.prepared = true;
+    }
+
+    /**
+     * Prepare an internal processing
+     * @param environment          The current environment.
+     * @throws org.apache.cocoon.ProcessingException
+     */
+    public void prepareInternal(Environment environment)
+    throws ProcessingException {
+        this.lastConsumer = null;
+        preparePipeline(environment);
+    }
+
+    public void setReader(String role, String source, Parameters param, String mimeType) throws ProcessingException {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean process(Environment environment) throws ProcessingException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Process the SAX event pipeline
+     */
+    protected boolean processXMLPipeline(Environment environment)
+    throws ProcessingException {
+
+        try {
+            this.generator.generate();
+        } catch (ProcessingException e) {
+            throw e;
+        } catch (Exception e) {
+            // TODO: Unwrap SAXException ?
+            throw new ProcessingException("Failed to execute pipeline.", e);
+        }
+        return true;
+    }
+
+
+    public void recycle() {
+        this.prepared = false;
+
+        if (this.generator != null) {
+            // Release generator.
+            this.newManager.release(this.generator);
+            this.generator = null;
+            this.generatorParam = null;
+        }
+
+        // Release transformers
+        int size = this.transformers.size();
+        for (int i = 0; i < size; i++) {
+            this.newManager.release(this.transformers.get(i));
+        }
+        this.transformers.clear();
+        this.transformerParams.clear();
+        this.transformerSources.clear();
+
+        // Release serializer
+        if (this.serializer != null) {
+            this.newManager.release(this.serializer);
+            this.serializerParam = null;
+        }
+        this.serializer = null;
+        this.processor = null;
+        this.lastConsumer = null;
+    }
+
+    /**
+     * 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)
+    throws ProcessingException {
+        this.lastConsumer = consumer;
+        connectPipeline(environment);
+        return processXMLPipeline(environment);
+    }
+
+    /**
+     * 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>
+     */
+    public SourceValidity getValidityForEventPipeline() {
+        return null;
+    }
+
+    public String getKeyForEventPipeline() {
+        return null;
+    }
+
+    protected String getLocation(Parameters param) {
+        String value = null;
+        if (param instanceof SitemapParameters) {
+            value = ((SitemapParameters) param).getStatementLocation();
+        }
+        if (value == null) {
+            value = "[unknown location]";
+        }
+        return value;
+    }
+}

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ComponentsNodeBuilder.java
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ComponentsNodeBuilder.java	(original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ComponentsNodeBuilder.java	Wed Nov 17 16:16:54 2004
@@ -1,12 +1,12 @@
 /*
  * 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.
@@ -16,18 +16,30 @@
 package org.apache.cocoon.components.treeprocessor.sitemap;
 
 import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.context.DefaultContext;
 
+import org.apache.cocoon.Constants;
 import org.apache.cocoon.components.treeprocessor.AbstractProcessingNodeBuilder;
 import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.generation.VirtualPipelineGenerator;
 
 /**
  * Handles &lt;map:components&gt;. It doesn't actually create a <code>ProcessingNode</code>.
  *
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
- * @version CVS $Id: ComponentsNodeBuilder.java,v 1.2 2004/03/05 13:02:51 bdelacretaz Exp $
+ * @version CVS $Id$
  */
+public class ComponentsNodeBuilder extends AbstractProcessingNodeBuilder
+                                   implements Contextualizable {
 
-public class ComponentsNodeBuilder extends AbstractProcessingNodeBuilder {
+    private DefaultContext context;
+
+    public void contextualize(Context context) throws ContextException {
+        this.context = (DefaultContext) context;
+    }
 
     /** This builder has no parameters -- return <code>false</code> */
     protected boolean hasParameters() {
@@ -35,8 +47,28 @@
     }
 
     public ProcessingNode buildNode(Configuration config) throws Exception {
+        // Check for component configurations
+        Configuration child = config.getChild("generators", false);
+        if (child != null) {
+            Configuration[] generators = child.getChildren("generator");
+            for (int i = 0; i < generators.length; i++) {
+                Configuration generator = generators[i];
+
+                String clazz = generator.getAttribute("src");
+                if (VirtualPipelineGenerator.class.getName().equals(clazz)) {
+                    // Got it
+                    PipelineNodeBuilder builder = new PipelineNodeBuilder();
+                    builder.setBuilder(this.treeBuilder);
+                    ProcessingNode node = builder.buildNode(generator);
+
+                    // Stuff this node into the context of current Sitemap
+                    // so that VirtualPipelineComponent can find it.
+                    String name = generator.getAttribute("name");
+                    context.put(Constants.CONTEXT_VPC_PREFIX + "generator-" + name, node);
+                }
+            }
+        }
 
-        // Nothing more here. To be removed ;)
         return null;
     }
 }

Added: cocoon/trunk/src/java/org/apache/cocoon/generation/VirtualPipelineGenerator.java
==============================================================================
--- (empty file)
+++ cocoon/trunk/src/java/org/apache/cocoon/generation/VirtualPipelineGenerator.java	Wed Nov 17 16:16:54 2004
@@ -0,0 +1,138 @@
+/*
+ * 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.cocoon.generation;
+
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.pipeline.ProcessingPipeline;
+import org.apache.cocoon.components.pipeline.VirtualProcessingPipeline;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.environment.internal.EnvironmentHelper;
+import org.apache.cocoon.xml.XMLConsumer;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * TODO List:
+ * <ul>
+ * <li>Implement parameters support
+ * <li>Resolve src parameter and pass to the pipeline
+ * <li>Refactor ProcessingPipelines implementations
+ * <li>Implement caching
+ * </ul>
+ */
+public class VirtualPipelineGenerator implements Generator, Serviceable,
+                                                 Contextualizable, Configurable {
+
+    private Context context;
+    private ServiceManager manager;
+    private XMLConsumer consumer;
+    private ProcessingNode node;
+    private ProcessingPipeline pipeline;
+
+
+    private class MyInvokeContext extends InvokeContext {
+        public MyInvokeContext() throws Exception {
+            super(true);
+            super.processingPipeline = new VirtualProcessingPipeline(VirtualPipelineGenerator.this.context);
+        }
+    }
+
+    public void contextualize(Context context) throws ContextException {
+        this.context = context;
+    }
+
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+    }
+
+    public void configure(Configuration configuration) throws ConfigurationException {
+        String name = configuration.getAttribute("name");
+        try {
+            this.node = (ProcessingNode) this.context.get(Constants.CONTEXT_VPC_PREFIX + "generator-" + name);
+        } catch (ContextException e) {
+            throw new ConfigurationException("Can not find VirtualPipelineGenerator '" + name + "' configuration");
+        }
+    }
+
+    public void setConsumer(XMLConsumer consumer) {
+        this.consumer = consumer;
+    }
+
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
+    throws ProcessingException, SAXException, IOException {
+
+        Environment env = EnvironmentHelper.getCurrentEnvironment();
+        String oldPrefix = env.getURIPrefix();
+        String oldURI    = env.getURI();
+        try {
+            String uri = (String) this.context.get(Constants.CONTEXT_ENV_URI);
+            String prefix = (String) this.context.get(Constants.CONTEXT_ENV_URI);
+            env.setURI(prefix, uri);
+
+            MyInvokeContext invoker = new MyInvokeContext();
+            invoker.service(this.manager);
+            this.node.invoke(env, invoker);
+            this.pipeline = invoker.getProcessingPipeline();
+        } catch (Exception e) {
+            throw new ProcessingException("Oops", e);
+        } finally {
+            // Restore context
+            env.setURI(oldPrefix, oldURI);
+        }
+    }
+
+    public void generate()
+    throws IOException, SAXException, ProcessingException {
+
+        // Should use SourceResolver of the this components' sitemap, not caller sitemap
+        // Have to switch to another environment...
+        Environment env = EnvironmentHelper.getCurrentEnvironment();
+        String oldPrefix = env.getURIPrefix();
+        String oldURI    = env.getURI();
+        try {
+            String uri = (String) this.context.get(Constants.CONTEXT_ENV_URI);
+            String prefix = (String) this.context.get(Constants.CONTEXT_ENV_URI);
+            env.setURI(prefix, uri);
+
+            this.pipeline.prepareInternal(env);
+        } catch (Exception e) {
+            throw new ProcessingException("Oops", e);
+        } finally {
+            // Restore context
+            env.setURI(oldPrefix, oldURI);
+        }
+
+        this.pipeline.process(env, this.consumer);
+    }
+}