You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2001/11/12 19:07:43 UTC

cvs commit: xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap PipelineNodeBuilder.java PipelinesNode.java PipelinesNodeBuilder.java ActionNode.java ComponentsNodeBuilder.java GeneratorNode.java GeneratorNodeBuilder.java PipelineNode.java SitemapNode.java SitemapNodeBuilder.java

sylvain     01/11/12 10:07:43

  Modified:    scratchpad/src/org/apache/cocoon/treeprocessor
                        AbstractParentProcessingNode.java
                        AbstractParentProcessingNodeBuilder.java
                        AbstractProcessingNode.java
                        AbstractProcessingNodeBuilder.java
                        EnvironmentSourceResolver.java
                        ListOfMapsResolver.java ProcessingNode.java
                        ProcessingNodeBuilder.java TreeBuilder.java
                        TreeBuilderComponentManager.java TreeProcessor.java
                        treeprocessor.xconf
               scratchpad/src/org/apache/cocoon/treeprocessor/sitemap
                        ActionNode.java ComponentsNodeBuilder.java
                        GeneratorNode.java GeneratorNodeBuilder.java
                        PipelineNode.java SitemapNode.java
                        SitemapNodeBuilder.java
  Added:       scratchpad/src/org/apache/cocoon/treeprocessor
                        ProcessingLanguageException.java
               scratchpad/src/org/apache/cocoon/treeprocessor/sitemap
                        PipelineNodeBuilder.java PipelinesNode.java
                        PipelinesNodeBuilder.java
  Log:
  Update to scratchpad
  
  Revision  Changes    Path
  1.2       +31 -26    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNode.java
  
  Index: AbstractParentProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractParentProcessingNode.java	2001/11/08 14:39:23	1.1
  +++ AbstractParentProcessingNode.java	2001/11/12 18:07:43	1.2
  @@ -19,58 +19,63 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public abstract class AbstractParentProcessingNode extends AbstractProcessingNode {
   
  -    protected ProcessingNode[] childNodes;
  -    
       /**
  -     * Invoke in order all children, until one fails.
  +     * Invoke all nodes of a node array in order, until one succeeds.
        *
        * @parameter currentMap the <code>Map<code> of parameters produced by this node,
  -     *            which is added to <code>listOfMap</code> if not null.
  +     *            which is added to <code>listOfMap</code>.
        */
  -    protected boolean invokeChildren (
  +    protected static final boolean invokeNodes (
  +        ProcessingNode[] nodes,
           Environment env,
           StreamPipeline pipeline,
           EventPipeline eventPipeline,
           List listOfMaps, Map currentMap)
         throws Exception {
           
  -        if (currentMap != null) {
  -            listOfMaps.add(currentMap);
  -        }
  +        listOfMaps.add(currentMap);
           
  -        boolean success = true;
  -        for (int i = 0; i < childNodes.length; i++) {
  -            if (! childNodes[i].invoke(env, pipeline, eventPipeline, listOfMaps)) {
  -                success = false;
  -                break;
  -            }
  -        }
  +        boolean success = invokeNodes(nodes, env, pipeline, eventPipeline, listOfMaps);
           
  -        if (currentMap != null) {
  -            listOfMaps.remove(listOfMaps.size() - 1);
  -        }
  +        listOfMaps.remove(listOfMaps.size() - 1);
           
           return success;
       }
       
       /**
  -     * Disposes all children of this node.
  +     * Invoke all nodes of a node array in order, until one succeeds.
        */
  -    protected void disposeChildren() {
  -        for (int i = 0; i < childNodes.length; i++) {
  -            childNodes[i].dispose();
  +    protected static final boolean invokeNodes (
  +        ProcessingNode[] nodes,
  +        Environment env,
  +        StreamPipeline pipeline,
  +        EventPipeline eventPipeline,
  +        List listOfMaps)
  +      throws Exception {
  +        
  +        for (int i = 0; i < nodes.length; i++) {
  +            if (nodes[i].invoke(env, pipeline, eventPipeline, listOfMaps)) {
  +                return true;
  +            }
           }
  +        
  +        return false;
       }
  -    
  +
       /**
  -     * Dispose this node. At this level, simply call <code>disposeChildren()</code>.
  +     * Dispose all nodes in an array.
        */
  -    public void dispose() {
  -        disposeChildren();
  +    protected static final void disposeNodes(ProcessingNode[] nodes) {
  +        if (nodes == null)
  +            return;
  +
  +        for (int i = 0; i < nodes.length; i++) {
  +            nodes[i].dispose();
  +        }
       }
   }
  
  
  
  1.2       +103 -1    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNodeBuilder.java
  
  Index: AbstractParentProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractParentProcessingNodeBuilder.java	2001/11/08 14:39:23	1.1
  +++ AbstractParentProcessingNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -10,12 +10,114 @@
   
   import org.apache.avalon.framework.logger.AbstractLoggable;
   
  +import java.util.*;
  +import org.apache.avalon.framework.configuration.Configurable;
  +import org.apache.avalon.framework.configuration.Configuration;
  +import org.apache.avalon.framework.configuration.ConfigurationException;
  +
  +import org.apache.cocoon.util.StringUtils;
  +
   /**
  + * Base class for parent <code>ProcessingNodeBuilders</code>, providing services for parsing
  + * children nodes.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
  +
  +public abstract class AbstractParentProcessingNodeBuilder extends AbstractProcessingNodeBuilder implements Configurable {
  +    
  +    protected Collection allowedChildren;
  +    
  +    protected Collection forbiddenChildren;
  +    
  +    protected Collection ignoredChildren;
  +    
  +    /**
  +     * Configure the sets of allowed, forbidden and ignored children nodes.
  +     */
  +    public void configure(Configuration config) throws ConfigurationException {
  +        this.allowedChildren   = getStringCollection(config.getChild("allowed-children"));
  +        this.forbiddenChildren = getStringCollection(config.getChild("forbidden-children"));
  +        this.ignoredChildren   = getStringCollection(config.getChild("ignored-children"));
  +    }
  +
  +    /**
  +     * Create the <code>ProcessingNodeBuilder</code>s for the children of a given node.
  +     * Child nodes are controlled to be actually allowed in this node.
  +     */
  +    protected List createChildBuilders(Configuration config, Map buildModel) throws Exception {
  +        
  +        Configuration[] children = config.getChildren();
  +        List result = new ArrayList();
  +        
  +        for (int i = 0; i < children.length; i++) {
  +            
  +            Configuration child = children[i];
  +            checkNamespace(child);
  +            String name = child.getName();
  +            
  +            // Is this element to be ignored ?
  +            if (ignoredChildren != null && ignoredChildren.contains(name)) {
  +                getLogger().debug("Element '" + name + "' is ignored for building children of element '" +
  +                    config.getName() + "'");
  +
  +                continue;
  +            }
  +            
  +            // Is it allowed ?
  +            if ( (allowedChildren != null && !allowedChildren.contains(name)) ||
  +                 (forbiddenChildren != null && forbiddenChildren.contains(name)) ) {
  +                throw new ConfigurationException("Element '" + name + "' is not allowed at " +
  +                    child.getLocation());
  +            }
  +            
  +            // OK : get a builder.
  +            ProcessingNodeBuilder childBuilder = this.treeBuilder.createNodeBuilder(child);
  +            childBuilder.buildNode(child, buildModel);
  +            result.add(childBuilder);
  +        }
  +        
  +        return result;
  +    }
  +    
  +    /**
  +     * Collect nodes from a list of builders, taking care of builders that may
  +     * return null nodes.
  +     */
  +    protected ProcessingNode[] getNodes(List builderList) throws Exception {
  +        
  +        List result = new ArrayList();
  +        
  +        Iterator iter = builderList.iterator();
  +        while(iter.hasNext()) {
  +            ProcessingNode node = ((ProcessingNodeBuilder)iter.next()).getNode();
  +            if (node != null) {
  +                result.add(node);
  +            }
  +        }
  +        
  +        return toNodeArray(result);
  +    }
  +    
  +    /**
  +     * Convenience function that converts a <code>List</code> of <code>ProcessingNode</code>s
  +     * to an array.
  +     */
  +    public static ProcessingNode[] toNodeArray(List list) {
  +        return (ProcessingNode[])list.toArray(new ProcessingNode[list.size()]);
  +    }
  +    
  +    /**
  +     * Splits the value of a Configuration in a Collection of Strings.
  +     *
  +     * @return a collection of Strings, or null if <code>config</code> has no value.
  +     */
  +    private Collection getStringCollection(Configuration config) {
  +        String s = config.getValue(null);
  +        
  +        return (s == null) ? null : Arrays.asList(StringUtils.split(s, ", "));
  +    }
   
  -public abstract class AbstractParentProcessingNodeBuilder extends AbstractProcessingNodeBuilder {
   }
  
  
  
  1.2       +26 -4     xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNode.java
  
  Index: AbstractProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractProcessingNode.java	2001/11/08 14:39:23	1.1
  +++ AbstractProcessingNode.java	2001/11/12 18:07:43	1.2
  @@ -26,20 +26,42 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public abstract class AbstractProcessingNode extends AbstractLoggable implements ProcessingNode {
   
  -    /** The node parameters, as a <code>Map</code> of <code>ListOfMapsResolver</code>. */
  +    /** The node parameters, as a <code>Map</code> of <code>ListOfMapsResolver</code>s. */
       protected Map parameters;
       
  -    protected SourceResolver getSourceResolver(Map objectModel) {
  +    protected String location = "unknown location";
  +    
  +    /**
  +     * Get the <code>SourceResolver</code> in an object model.
  +     */
  +    protected static final SourceResolver getSourceResolver(Map objectModel) {
           return (SourceResolver)objectModel.get(OBJECT_SOURCE_RESOLVER);
       }
  +    
  +    /**
  +     * Set the parameters of this node as a <code>Map</code> of <code>ListOfMapsResolver</code>s
  +     * that will be resolved at process-time.
  +     */
  +    public void setParameters(Map parameters) {
  +    }
  +    
  +    /**
  +     * Get the location of this node.
  +     */
  +    public String getLocation() {
  +        return this.location;
  +    }
       
  -    protected Redirector getRedirector(Map objectModel) {
  -        return (Redirector)objectModel.get(OBJECT_REDIRECTOR);
  +    /**
  +     * Set the location of this node.
  +     */
  +    public void setLocation(String location) {
  +        this.location = location;
       }
       
       /**
  
  
  
  1.2       +5 -5      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNodeBuilder.java
  
  Index: AbstractProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractProcessingNodeBuilder.java	2001/11/08 14:39:23	1.1
  +++ AbstractProcessingNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -24,21 +24,21 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   
   public abstract class AbstractProcessingNodeBuilder extends AbstractLoggable
     implements ProcessingNodeBuilder {
   
  -    protected TreeBuilder builder;
  +    protected TreeBuilder treeBuilder;
       
  -    public void setBuilder(TreeBuilder builder) {
  -        this.builder = builder;
  +    public void setBuilder(TreeBuilder treeBuilder) {
  +        this.treeBuilder = treeBuilder;
       }
   
       /**
  -     * Get &lt;xxx:parameter&gt; elements as a <ocd>Map</code> of </code>ListOfMapResolver</code>s,
  +     * Get &lt;xxx:parameter&gt; elements as a <code>Map</code> of </code>ListOfMapResolver</code>s,
        * that can be turned into parameters using <code>ListOfMapResolver.buildParameters()</code>.
        *
        * @return the Map of ListOfMapResolver, or <code>null</code> if there are no parameters.
  @@ -59,7 +59,7 @@
                       params.put(child.getAttribute("name"), ListOfMapsResolver.getResolver(value));
                   } catch(PatternException pe) {
                       throw new ConfigurationException("Invalid pattern '" + value +
  -                        ", at " + child.getLocation());
  +                        " at " + child.getLocation());
                   }
               }
           }
  
  
  
  1.2       +0 -0      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/EnvironmentSourceResolver.java
  
  Index: EnvironmentSourceResolver.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/EnvironmentSourceResolver.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- EnvironmentSourceResolver.java	2001/11/08 14:39:23	1.1
  +++ EnvironmentSourceResolver.java	2001/11/12 18:07:43	1.2
  @@ -26,7 +26,7 @@
    * A <code>SourceResolver</code> that resolves URIs relative to an <code>Environment</code>.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class EnvironmentSourceResolver implements SourceResolver, Disposable {
  
  
  
  1.2       +4 -2      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ListOfMapsResolver.java
  
  Index: ListOfMapsResolver.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ListOfMapsResolver.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ListOfMapsResolver.java	2001/11/08 14:39:23	1.1
  +++ ListOfMapsResolver.java	2001/11/12 18:07:43	1.2
  @@ -21,7 +21,7 @@
    * Utility class for handling {...} pattern substitutions from a List of Maps.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public abstract class ListOfMapsResolver extends AbstractLoggable {
  @@ -137,10 +137,12 @@
        * No-op resolver for expressions that don't need to be resolved.
        */
       private static class NullResolver extends ListOfMapsResolver {
  -        private String expression;
  +        private String expression = null;
   
           public NullResolver(String expression) {
  -            this.expression = this.unescape(expression);
  +            if (expression != null) {
  +                this.expression = this.unescape(expression);
  +            }
           }
           
           public String resolve(List listOfMaps) {
  
  
  
  1.2       +4 -0      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNode.java
  
  Index: ProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ProcessingNode.java	2001/11/08 14:39:23	1.1
  +++ ProcessingNode.java	2001/11/12 18:07:43	1.2
  @@ -23,7 +23,7 @@
    * on the root node.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public interface ProcessingNode extends ThreadSafe, Disposable {
  @@ -48,4 +48,8 @@
        */
       void dispose();
       
  +    /**
  +     * Get the location of this node.
  +     */
  +    String getLocation();
   }
  
  
  
  1.2       +0 -0      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNodeBuilder.java
  
  Index: ProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ProcessingNodeBuilder.java	2001/11/08 14:39:23	1.1
  +++ ProcessingNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -34,7 +34,7 @@
    * implementations.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   import java.util.Map;
  
  
  
  1.2       +14 -11    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeBuilder.java
  
  Index: TreeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TreeBuilder.java	2001/11/08 14:39:23	1.1
  +++ TreeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -38,23 +38,19 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class TreeBuilder extends AbstractLoggable implements
     Composable, Configurable, Contextualizable, LogKitManageable {
       
       /**
  -     * The role name to be used by composable <code>ProcessingNodeBuilder</code>s to get
  -     * the <code>Builder</code> for which they operate.
  -     */
  -    public static final String ROLE = "org.apache.cocoon.components.treeprocessor.Builder";
  -    
  -    /**
        * The categories of node Maps.
        */
       private Map categories = new HashMap();
       
  +    private Map attributes = new HashMap();
  +    
       /**
        * The tree processor that we're building.
        */
  @@ -114,7 +110,7 @@
           this.languageName = config.getAttribute("name");
           getLogger().debug("Configuring Builder for language : " + this.languageName);
           
  -        this.namespace = config.getAttribute("namespace");
  +        this.namespace = config.getChild("namespace").getAttribute("uri", "");
           
           try {
               // Create the NodeBuilder selector.
  @@ -184,7 +180,7 @@
        * For example, <code>ResourceNodeBuilder</code> stores here the <code>ProcessingNode</code>
        * it produces for use by sitemap pipelines. This allows to turn the tree into a graph.
        */
  -    public void addNode(ProcessingNode node, String category, String name) {
  +    public void addNode(String category, String name,ProcessingNode node) {
           Map nodes = (Map)categories.get(category);
           if (nodes == null) {
               nodes = new HashMap();
  @@ -207,6 +203,14 @@
           }
       }
       
  +    public void setAttribute(String name, Object value) {
  +        this.attributes.put(name, value);
  +    }
  +    
  +    public Object getAttribute(String name) {
  +        return this.attributes.get(name);
  +    }
  +    
       /**
        * Some NodeBuilders create components to be used by others
        */
  @@ -222,9 +226,8 @@
       public ProcessingNodeBuilder createNodeBuilder(Configuration config) throws Exception {
           //FIXME : check namespace
           String nodeName = config.getName();
  -        int pos;
  -        if ((pos = nodeName.indexOf(':')) != -1)
  -            nodeName = nodeName.substring(pos+1);
  +        
  +        getLogger().debug("Creating node builder for " + nodeName);
   
           ProcessingNodeBuilder builder = (ProcessingNodeBuilder)this.builderSelector.select(nodeName);
           builder.setBuilder(this);
  
  
  
  1.2       +0 -0      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeBuilderComponentManager.java
  
  Index: TreeBuilderComponentManager.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeBuilderComponentManager.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TreeBuilderComponentManager.java	2001/11/08 14:39:23	1.1
  +++ TreeBuilderComponentManager.java	2001/11/12 18:07:43	1.2
  @@ -23,7 +23,7 @@
    * enriched through <code>Builder.addComponent()</code>.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   
  
  
  
  1.2       +0 -0      xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeProcessor.java
  
  Index: TreeProcessor.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/TreeProcessor.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TreeProcessor.java	2001/11/08 14:39:23	1.1
  +++ TreeProcessor.java	2001/11/12 18:07:43	1.2
  @@ -45,7 +45,7 @@
    * Interpreted tree-traversal implementation of the a Processor language.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class TreeProcessor extends AbstractLoggable implements ThreadSafe, Processor,
  
  
  
  1.2       +27 -16    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/treeprocessor.xconf
  
  Index: treeprocessor.xconf
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/treeprocessor.xconf,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- treeprocessor.xconf	2001/11/08 14:39:23	1.1
  +++ treeprocessor.xconf	2001/11/12 18:07:43	1.2
  @@ -9,48 +9,59 @@
    *****************************************************************************
   
    @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:23 $
  + @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
   -->
   
   <tree-processor>
     <!-- The sitemap language -->
  -  <language name="sitemap" namespace="http://apache.org/cocoon/sitemap/1.0">
  +  <language name="sitemap">
     
  -    <!-- Should we allow to specify the builder class ? -->
  -    <!-- builder class="org.apache.cocoon.treeprocessor.Builder"/ -->
  -    
  +    <!-- The namespace for this language -->
  +    <namespace uri="http://apache.org/cocoon/sitemap/1.0"/>
  +  
       <!-- The file name for this language -->
       <file name="sitemap.xmap"/>
       
       <nodes>
  +      <!-- Note : for now, names are prefixed, but they'll be removed with the namespace-aware Configuration-->
         <!-- Sitemap root node -->
  -      <node name="sitemap" builder="org.apache.cocoon.treeprocessor.sitemap.SitemapNodeBuilder">
  -        <allowed-children>components, pipeline, views, resources, action-sets</allowed-children>
  +      <node name="map:sitemap" builder="org.apache.cocoon.treeprocessor.sitemap.SitemapNodeBuilder">
  +        <allowed-children>map:pipelines, map:components</allowed-children>
  +        <!-- the children below will be allowed when implemented :) -->
  +        <ignored-children>map:views, map:resources, map:action-sets</ignored-children>
         </node>
       
         <!-- Components definition : fills selectors on the TreeProcessor -->
  -      <node name="components" builder="org.apache.cocoon.treeprocessor.sitemap.ComponentsNodeBuilder">
  -        <selector section="matchers"     elements="matcher"
  +      <node name="map:components" builder="org.apache.cocoon.treeprocessor.sitemap.ComponentsNodeBuilder">
  +        <selector section="map:matchers"     elements="map:matcher"
                     role="org.apache.cocoon.matching.MatcherSelector"/>
  -        <selector section="selectors"    elements="selector"
  +        <selector section="map:selectors"    elements="map:selector"
                     role="org.apache.cocoon.selection.SelectorSelector"/>
  -        <selector section="actions"      elements="action"
  +        <selector section="map:actions"      elements="map:action"
                     role="org.apache.cocoon.acting.ActionSelector"/>
  -        <selector section="generators"   elements="generator"
  +        <selector section="map:generators"   elements="map:generator"
                     role="org.apache.cocoon.generation.GeneratorSelector"/>
  -        <selector section="transformers" elements="transformer"
  +        <selector section="map:transformers" elements="map:transformer"
                     role="org.apache.cocoon.transformation.TransformerSelector"/>
  -        <selector section="serializers"  elements="serializer"
  +        <selector section="map:serializers"  elements="map:serializer"
                     role="org.apache.cocoon.serialization.SerializerSelector"/>
  -        <selector section="readers"      elements="reader"
  +        <selector section="map:readers"      elements="map:reader"
                     role="org.apache.cocoon.reading.ReaderSelector"/>
         </node>
  +      
  +      <node name="map:pipelines" builder="org.apache.cocoon.treeprocessor.sitemap.PipelinesNodeBuilder">
  +        <allowed-children>map:pipeline</allowed-children>
  +      </node>
  +      
  +      <node name="map:pipeline" builder="org.apache.cocoon.treeprocessor.sitemap.PipelineNodeBuilder">
  +        <forbidden-children>map:sitemap, map:components, map:pipelines</forbidden-children>
  +      </node>
         
  -      <!--node name="action" builder="org.apache.cocoon.treeprocessor.sitemap.ActionNodeBuilder">
  +      <!--node name="map:action" builder="org.apache.cocoon.treeprocessor.sitemap.ActionNodeBuilder">
           <forbidden-children>sitemap, components, pipeline, error-handler</forbidden-children>
         </node-->
         
  -      <node name="generator" builder="org.apache.cocoon.treeprocessor.sitemap.GeneratorNodeBuilder"/>
  +      <node name="map:generate" builder="org.apache.cocoon.treeprocessor.sitemap.GeneratorNodeBuilder"/>
       </nodes>
       
     </language>
  
  
  
  1.1                  xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingLanguageException.java
  
  Index: ProcessingLanguageException.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  package org.apache.cocoon.treeprocessor;
  
  import org.apache.avalon.framework.CascadingException;
  
  import java.io.PrintStream;
  import java.io.PrintWriter;
  
  /**
   * Exception thrown when there's something wrong in the syntax of a
   * processing language (i.e. sitemap).
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/12 18:07:43 $
   */
  public class ProcessingLanguageException extends CascadingException {
  
      /**
       * Create a new <code>ProcessingLanguageException</code> instance.
       */
      public ProcessingLanguageException(String message) {
          super(message, null);
      }
  
      /**
       * Create a new <code>ProcessingLanguageException</code> instance.
       *
       * @param ex the originating <code>Exception</code>
       */
      public ProcessingLanguageException(Exception ex) {
          super(ex.getMessage(), ex);
      }
   
      /**
       * Construct a new <code>ProcessingLanguageException</code> that references
       * a parent Exception.
       */
      public ProcessingLanguageException(String message, Throwable t) {
          super(message, t);
      }
  
      public String toString() {
          StringBuffer s = new StringBuffer();
          s.append(super.toString());
          if(getCause()!=null) {
              s.append(": ");
              s.append(getCause().toString());
          }
          return s.toString();
      }
  
      public void printStackTrace() {
          super.printStackTrace();
          if(getCause()!=null)
              getCause().printStackTrace();
      }
  
      public void printStackTrace( PrintStream s ) {
          super.printStackTrace(s);
          if(getCause()!=null)
              getCause().printStackTrace(s);
      }
  
      public void printStackTrace( PrintWriter s ) {
          super.printStackTrace(s);
          if(getCause()!=null)
              getCause().printStackTrace(s);
      }
  }
  
  
  
  1.2       +40 -18    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionNode.java
  
  Index: ActionNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActionNode.java	2001/11/08 14:39:24	1.1
  +++ ActionNode.java	2001/11/12 18:07:43	1.2
  @@ -21,7 +21,9 @@
   import org.apache.cocoon.components.pipeline.StreamPipeline;
   
   import org.apache.cocoon.sitemap.PatternException;
  +import org.apache.cocoon.sitemap.SitemapRedirector;
   
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
   import org.apache.cocoon.treeprocessor.ListOfMapsResolver;
   
  @@ -30,13 +32,16 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class ActionNode extends AbstractParentProcessingNode {
       
  +    /** The childrens of this action */
  +    protected ProcessingNode[] children;
  +
       /** The action name */
  -    protected String name;
  +    protected String actionName;
       
       /** The 'src' attribute */
       protected ListOfMapsResolver source;
  @@ -48,16 +53,20 @@
       protected Action threadSafeAction;
   
       public ActionNode(String name, String source) throws PatternException {
  -        this.name = name;
  +        this.actionName = name;
           this.source = ListOfMapsResolver.getResolver(source);
       }
       
  +    public void setChildren(ProcessingNode[] children) {
  +        this.children = children;
  +    }
  +    
       public void setSelector(ComponentSelector selector) throws ComponentException {
           
           this.selector = selector;
           
           // Is it a ThreadSafe action ?
  -        Action action = (Action)selector.select(name);
  +        Action action = (Action)selector.select(actionName);
           if (action instanceof ThreadSafe) {
               // Yes : keep it.
               this.threadSafeAction = action;
  @@ -72,39 +81,52 @@
           
           // Extract required data from the object model
           Map objectModel = env.getObjectModel();
  -        
  -        // Execute the action
  -        Action action = this.threadSafeAction;
  -        if (action == null) {
  -            action = (Action)this.selector.select(this.name);
  -        }
  -
  +        SitemapRedirector redirector = SitemapNode.getRedirector(env);
           Map actionResult;
  -        try {
  -            actionResult = action.act(
  -                getRedirector(objectModel),
  +        
  +        if (this.threadSafeAction != null) {
  +            actionResult = this.threadSafeAction.act(
  +                redirector,
                   getSourceResolver(objectModel),
                   objectModel,
                   source.resolve(listOfMaps),
                   ListOfMapsResolver.buildParameters(this.parameters, listOfMaps)
               );
  -        } finally {
  -            if (this.threadSafeAction == null) {
  +            
  +        } else {
  +            Action action = (Action)this.selector.select(this.actionName);
  +            try {
  +                actionResult = action.act(
  +                    redirector,
  +                    getSourceResolver(objectModel),
  +                    objectModel,
  +                    source.resolve(listOfMaps),
  +                    ListOfMapsResolver.buildParameters(this.parameters, listOfMaps)
  +                );
  +            } finally {
                   this.selector.release(action);
               }
           }
           
  +        if (redirector.hasRedirected()) {
  +            return true;
  +        }
  +        
           if (actionResult == null) {
               // Action failed
               return false;
           } else {
  -            // Action succeeded : process children
  -            return this.invokeChildren(env, pipeline, eventPipeline, listOfMaps, actionResult);
  +            // Action succeeded : process children if there are some.
  +            if (this.children != null) {
  +                return this.invokeNodes(this.children, env, pipeline, eventPipeline, listOfMaps, actionResult);
  +            } else {
  +                return true;
  +            }
           }
       }
       
       public void dispose() {
  -        super.dispose();
  +        disposeNodes(children);
           if (this.threadSafeAction != null) {
               this.selector.release(this.threadSafeAction);
           }
  
  
  
  1.2       +43 -17    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ComponentsNodeBuilder.java
  
  Index: ComponentsNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ComponentsNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ComponentsNodeBuilder.java	2001/11/08 14:39:24	1.1
  +++ ComponentsNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -27,6 +27,8 @@
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentSelector;
   
  +import org.apache.cocoon.sitemap.SitemapComponentSelector;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  @@ -40,14 +42,18 @@
    * but creates <code>ComponentSelectors</code> that are made available to other nodes.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class ComponentsNodeBuilder extends AbstractProcessingNodeBuilder implements
     Composable, Configurable, Contextualizable, LogKitManageable {
   
  -    /** The hint name to use to select the default component in a selector */
  -    public static final String DEFAULT_HINT = "!default!";
  +    /**
  +     * The prefix used to store default components as <code>TreeBuilder</code> attributes.
  +     * For example, the default generator (if any) can be obtained using 
  +     * <code>builder.getAttribute(ComponentsNodeBuilder.DEFAULT_PREFIX + "generator")</code>.
  +     */
  +    public static final String DEFAULT_PREFIX = "components:default-";
       
       private Context context;
       
  @@ -97,16 +103,21 @@
       
       /**
        * Build a <code>ComponentSelector</code> for each component section and add it
  -     * each component contained in the section. Selectors are also published on the
  -     * <code>TreeBuilder</code> for use by other nodes.
  +     * each component contained in the section.
  +     * <p>
  +     * Selectors are added to the component manager using <code>TreeBuilder.addComponent()</code>
  +     * for use by other nodes.
  +     * <p>
  +     * For each section for which a default is provided (e.g. <code>&lt;generators default="file"&gt;</code>),
  +     * this default is registred as an attribute on the builder
        */
       public void buildNode(Configuration config, Map buildModel) throws Exception {
           
           // Iterate on all sections
           Configuration[] sections = config.getChildren();
  -        for (int i = 0; i < sections.length; i++) {
  +        for (int sectIdx = 0; sectIdx < sections.length; sectIdx++) {
               
  -            Configuration section = sections[i];
  +            Configuration section = sections[sectIdx];
               checkNamespace(section);
               String sectionName = section.getName();
               
  @@ -122,8 +133,10 @@
               String defaultElement = section.getAttribute("default", null);
               if (defaultElement == null) {
                   getLogger().debug("Component section '" + sectionName + "' has no default");
  +            } else {
  +                this.treeBuilder.setAttribute(DEFAULT_PREFIX + elementName, defaultElement);
               }
  -                   
  +
               // Create the selector for this section
               getLogger().debug("Creating component selector for " + sectionName);
               
  @@ -136,20 +149,19 @@
                   throw new ComponentException("Cannot configure role manager", ce);
               }
               
  -            ExcaliburComponentSelector selector = new ExcaliburComponentSelector();
  +            SitemapComponentSelector selector = new SitemapComponentSelector();
               selector.setLogger(getLogger());
               selector.contextualize(this.context);
               selector.setRoleManager(emptyRoleManager);
               selector.setLogKitManager(this.logKit);
               selector.compose(this.manager);
               // selector.configure( - no configuration - );
  -
  -
  +            
               // Iterate on all components
               Configuration[] elements = section.getChildren();
  -            for (int j = 0; i < elements.length; j++) {
  +            for (int compIdx = 0; compIdx < elements.length; compIdx++) {
                   
  -                Configuration element = elements[i];
  +                Configuration element = elements[compIdx];
                   checkNamespace(element);
                   
                   // Is it the right name ?
  @@ -161,7 +173,7 @@
                   // Get the element name
                   String name = element.getAttribute("name");
                   
  -                // Register the class
  +                // Get the class
                   String className = element.getAttribute("src");
                   Class clazz;
                   try {
  @@ -171,12 +183,13 @@
                           "' for " + elementName + " '" + name + "', at " + element.getLocation(), e);
                   }
                   
  +                // Get the mime-type, if any
  +                String mimeType = element.getAttribute("mime-type", null);
  +                
                   // Register the component
                   selector.addComponent(name, clazz, element);
  +                
                   if (name.equals(defaultElement)) {
  -                    // Also register as default component
  -                    selector.addComponent(DEFAULT_HINT, clazz, element);
  -                    
                       // Clear default to mark it as found
                       defaultElement = null;
                   }
  @@ -188,10 +201,23 @@
                       "' does not exist, at " + section.getLocation());
               }
               
  +            // Chain with parent processor selector, if any
  +            String role = (String)this.sectionRoles.get(sectionName);
  +            try {
  +                SitemapComponentSelector parentSelector =
  +                    (SitemapComponentSelector)this.manager.lookup(role);
  +
  +                // Found.
  +                selector.setParentSelector(parentSelector);
  +                
  +            } catch (ComponentException ce) {
  +                // Ignore : means no parent
  +            }
  +
               selector.initialize();
               
               // Publish the selector
  -            this.builder.addComponentInstance((String)this.sectionRoles.get(sectionName), selector);
  +            this.treeBuilder.addComponentInstance(role , selector);
               
           } // end for sections
       }
  
  
  
  1.2       +11 -4     xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GeneratorNode.java
  
  Index: GeneratorNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GeneratorNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GeneratorNode.java	2001/11/08 14:39:24	1.1
  +++ GeneratorNode.java	2001/11/12 18:07:43	1.2
  @@ -11,6 +11,7 @@
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.sitemap.PatternException;
   import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
   import org.apache.cocoon.treeprocessor.ListOfMapsResolver;
   
  @@ -18,15 +19,20 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class GeneratorNode extends AbstractProcessingNode {
   
  -    protected String generatorName;
  +    private String generatorName;
       
  -    protected ListOfMapsResolver source;
  -
  +    private ListOfMapsResolver source;
  +    
  +    public GeneratorNode(String name, String source) throws PatternException {
  +        this.generatorName = name;
  +        this.source = ListOfMapsResolver.getResolver(source);
  +    }
  +    
       public boolean invoke(Environment env, StreamPipeline pipeline, EventPipeline eventPipeline, List listOfMaps)
         throws Exception {
           
  @@ -36,7 +42,8 @@
               ListOfMapsResolver.buildParameters(this.parameters, listOfMaps)
           );
           
  -        return true;
  +        // Return false to contine sitemap invocation
  +        return false;
       }
       
   }
  
  
  
  1.2       +24 -2     xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GeneratorNodeBuilder.java
  
  Index: GeneratorNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GeneratorNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GeneratorNodeBuilder.java	2001/11/08 14:39:24	1.1
  +++ GeneratorNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -9,6 +9,7 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.configuration.Configuration;
  +import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  @@ -17,14 +18,35 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class GeneratorNodeBuilder extends AbstractProcessingNodeBuilder {
   
  -    public void buildNode(Configuration config, Map buildModel) {
  +    private GeneratorNode node;
  +
  +    public void buildNode(Configuration config, Map buildModel) throws Exception {
  +        
  +        String type = config.getAttribute("type", null);
  +        if (type == null) {
  +            type = (String)this.treeBuilder.getAttribute(ComponentsNodeBuilder.DEFAULT_PREFIX + "generator");
  +        }
  +        
  +        if (type == null) {
  +            throw new ConfigurationException(
  +                "There is no default generator defined. Cannot create generator at " +
  +                config.getLocation());
  +        }
  +        
  +        this.node = new GeneratorNode(type, config.getAttribute("src", null));
  +        this.node.setLogger(getLogger());
  +        this.node.setLocation(config.getLocation());
  +        
  +        this.node.setParameters(getParameters(config));
  +        
       }
  +    
       public ProcessingNode getNode() {
  -        return null;
  +        return this.node;
       }
   }
  
  
  
  1.2       +145 -13   xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNode.java
  
  Index: PipelineNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PipelineNode.java	2001/11/08 14:39:24	1.1
  +++ PipelineNode.java	2001/11/12 18:07:43	1.2
  @@ -9,45 +9,177 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.activity.Disposable;
   
  +import org.apache.cocoon.ResourceNotFoundException;
  +
   import org.apache.cocoon.environment.Environment;
  +import org.apache.cocoon.environment.ObjectModelHelper;
  +import org.apache.cocoon.environment.http.HttpResponse;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
  +import org.apache.cocoon.treeprocessor.ListOfMapsResolver;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  -import java.util.List;
  -import java.util.Map;
  +import java.util.*;
   
   /**
    * 
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class PipelineNode extends AbstractParentProcessingNode {
   
  +    // TODO : handle a 'fail-hard' environment attribute
  +    // can be useful to stop off-line generation when there's an error
  +    
  +    private ProcessingNode[] children;
  +    
  +    private ProcessingNode error404;
  +    
  +    private ProcessingNode error500;
  +
  +    private ComponentManager manager;
  +    
  +    private boolean internalOnly = false;
  +    
  +    /**
  +     * The component manager is used to create error pipelines
  +     */
  +    public void compose(ComponentManager manager) {
  +        this.manager = manager;
  +    }
  +    
  +    public void setChildren(ProcessingNode[] node)
  +    {
  +        this.children = children;
  +    }
  +    
  +    public void set404Handler(ProcessingNode node)
  +    {
  +        this.error404 = node;
  +    }
  +    
  +    public void set500Handler(ProcessingNode node)
  +    {
  +        this.error500 = node;
  +    }
  +    
  +    public void setInternalOnly(boolean internalOnly) {
  +        this.internalOnly = internalOnly;
  +    }
  +
       public boolean invoke(Environment env, StreamPipeline pipeline, EventPipeline eventPipeline, List listOfMaps)
         throws Exception {
           
  -        boolean success = false;
  +        // Always fail on external resquests if internal only.
  +        if (this.internalOnly && !SitemapNode.isInternalRequest(env)) {
  +            return false;
  +        }
           
  -        // Try each of the children until one is successfull.
           try {
               
  -            for (int i = 0; i < childNodes.length; i++) {
  -                if (childNodes[i].invoke(env, pipeline, eventPipeline, listOfMaps)) {
  -                    success = true;
  -                    break;
  -                }
  -            }    
  +            if (invokeNodes(children, env, pipeline, eventPipeline, listOfMaps)) {
  +                return true;
  +            } else {
  +              throw new ResourceNotFoundException("No pipeline matched request: " +
  +                env.getURIPrefix()+'/'+env.getURI());
  +            }
  +            
  +        } catch(ResourceNotFoundException rnfe) {
  +            getLogger().debug("Not found while processing pipeline", rnfe);
  +            
  +            if (error404 != null) {
  +                
  +                invokeErrorHandler(error404, rnfe, env);
  +                return false;
  +                
  +            } else {
  +                throw rnfe;
  +            }
           } catch(Exception e) {
  -            // FIXME Error pipelines.
               getLogger().debug("Error while processing pipeline", e);
  -            throw e;
  +            
  +            // Rethrow exception for internal requests
  +            if (error500 != null || !SitemapNode.isInternalRequest(env)) {
  +                
  +                invokeErrorHandler(error500, e, env);
  +                return false;
  +                
  +            } else {
  +                throw e;
  +            }
           }
  +    }
  +    
  +    private boolean invokeErrorHandler(ProcessingNode node, Exception ex, Environment env)
  +      throws Exception {
  +        EventPipeline eventPipeline = null;
  +        StreamPipeline pipeline = null;
  +        try {
  +            tryResetResponse(env);
  +            eventPipeline = (EventPipeline) this.manager.lookup(EventPipeline.ROLE);
  +            pipeline = (StreamPipeline) this.manager.lookup(StreamPipeline.ROLE);
  +            pipeline.setEventPipeline(eventPipeline);
  +            List listOfMaps = new ArrayList();
  +            
  +            eventPipeline.setGenerator ("!error-notifier!", ex.getMessage(),
  +                ListOfMapsResolver.EMPTY_PARAMETERS, ex);
  +            
  +            return node.invoke(env, pipeline, eventPipeline, listOfMaps);
  +            
  +        } catch (Exception subEx) {
  +            getLogger().error("error notifier barfs", subEx);
  +            throw ex;
  +            
  +        } finally {
  +            this.manager.release(eventPipeline);
  +            this.manager.release(pipeline);
  +        }
  +    }
  +
  +    /**
  +     * Reset the response if possible. This allows error handlers to have
  +     * a higher chance to produce clean output if the pipeline that raised
  +     * the error has already output some data.
  +     *
  +     * @param objectModel the object model
  +     * @return true if the response was successfully reset
  +     */
  +    private void tryResetResponse(Environment env)
  +    {
  +        try {
  +            Object responseObj = ObjectModelHelper.getRequest(env.getObjectModel());
  +            if (responseObj instanceof HttpResponse) {
  +                HttpResponse response = (HttpResponse)responseObj;
  +                if (! response.isCommitted()) {
  +                    response.reset();
  +                    getLogger().debug("Response successfully reset");
  +                }
  +            }
  +        } catch(Exception e) {
  +            // Log the error, but don't transmit it
  +            getLogger().warn("Problem resetting response", e);
  +        }
  +        
  +        getLogger().debug("Response wasn't reset");
  +    }
  +    
  +    
  +    public void dispose() {
  +        
  +        disposeNodes(children);
           
  -        return success;
  +        if (this.error404 != null) {
  +            this.error404.dispose();
  +        }
  +        
  +        if (this.error500 != null) {
  +            this.error500.dispose();
  +        }
       }
   }
  
  
  
  1.2       +30 -16    xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapNode.java
  
  Index: SitemapNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SitemapNode.java	2001/11/08 14:39:24	1.1
  +++ SitemapNode.java	2001/11/12 18:07:43	1.2
  @@ -22,15 +22,15 @@
   
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
   import org.apache.cocoon.treeprocessor.EnvironmentSourceResolver;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  -import java.util.List;
  -import java.util.Map;
  +import java.util.*;
   
   /**
    * The root node of a sitemap.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class SitemapNode extends AbstractParentProcessingNode implements Composable {
  @@ -41,12 +41,16 @@
       
       protected ComponentManager manager;
       
  +    protected PipelinesNode pipelines;
  +    
  +    protected ProcessingNode[] otherNodes;
  +    
       public static boolean isInternalRequest(Environment env) {
           return env.getAttribute(INTERNAL_ATTR) != null;
       }
       
  -    public static Redirector getRedirector(Environment env) {
  -        return (Redirector)env.getAttribute(REDIRECTOR_ATTR);
  +    public static SitemapRedirector getRedirector(Environment env) {
  +        return (SitemapRedirector)env.getAttribute(REDIRECTOR_ATTR);
       }
       
       /**
  @@ -58,6 +62,21 @@
       }
       
       /**
  +     * Set the pipeline nodes that will process the environment.
  +     */
  +    public void setPipelines(PipelinesNode pipelines) {
  +        this.pipelines = pipelines;
  +    }
  +    
  +    /**
  +     * Set the non-pipeline nodes (views & resources), which are held to properly
  +     * <code>dispose()</code> them.
  +     */
  +    public void setOtherNodes(ProcessingNode[] otherNodes) {
  +        this.otherNodes = otherNodes;
  +    }
  +
  +    /**
        * Process the environment. Also adds an <code>EnvironmentSourceResolver</code>
        * and a <code>Redirector</code> in the object model. The previous resolver and
        * redirector, if any, are restored before return.
  @@ -106,6 +125,7 @@
           // component manager used by all other nodes, which may redefine the
           // SourceHandler to use.
           EnvironmentSourceResolver resolver = new EnvironmentSourceResolver(this.manager, env);
  +        SitemapRedirector redirector = new SitemapRedirector(env);
           
           Map objectModel = env.getObjectModel();
           
  @@ -113,23 +133,14 @@
           Object oldRedirector = env.getAttribute(REDIRECTOR_ATTR);
   
           objectModel.put(OBJECT_SOURCE_RESOLVER, resolver);
  -        env.setAttribute(REDIRECTOR_ATTR, new SitemapRedirector(env));
  +        env.setAttribute(REDIRECTOR_ATTR, redirector);
   
  -        boolean success = true;
           try {
               // FIXME : is there any useful information that can be passed as top-level parameters,
               //         such as the URI of the mount point ?
  -            for (int i = 0; i < childNodes.length; i++) {
  -                if (! childNodes[i].invoke(env, pipeline, eventPipeline, listOfMaps)) {
  -                    success = false;
  -                    break;
  -                }
  -            }
               
  -            //TODO : check redirector
  +            return this.pipelines.invoke(env, pipeline, eventPipeline, listOfMaps);
               
  -            return success;
  -            
           } finally {
   
               // Restore old redirector and resolver
  @@ -145,7 +156,10 @@
        * Dispose all children and the component manager.
        */
       public void dispose() {
  -        this.disposeChildren();
  +        
  +        this.pipelines.dispose();
  +        disposeNodes(this.otherNodes);
  +        
           if (this.manager instanceof Disposable) {
               ((Disposable)this.manager).dispose();
           }
  
  
  
  1.2       +42 -4     xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapNodeBuilder.java
  
  Index: SitemapNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SitemapNodeBuilder.java	2001/11/08 14:39:24	1.1
  +++ SitemapNodeBuilder.java	2001/11/12 18:07:43	1.2
  @@ -12,35 +12,73 @@
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.configuration.Configuration;
  +import org.apache.avalon.framework.configuration.ConfigurationException;
   
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNodeBuilder;
   
  -import java.util.Map;
  +import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/08 14:39:24 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/12 18:07:43 $
    */
   
   public class SitemapNodeBuilder extends AbstractParentProcessingNodeBuilder implements Composable {
   
  -    protected ComponentManager manager;
  +    private ComponentManager manager;
       
  -    protected SitemapNode node;
  +    private SitemapNode node;
       
  +    private List childBuilders;
  +    
  +    private String location;
  +    
       public void compose(ComponentManager manager) throws ComponentException {
           this.manager = manager;
       }
       
       public void buildNode(Configuration config, Map buildModel) throws Exception {
  +        this.location = config.getLocation();
           node = new SitemapNode();
  +        node.setLocation(this.location);
  +        node.setLogger(getLogger());
           node.compose(this.manager);
  +        
  +        this.childBuilders = createChildBuilders(config, buildModel);
  +        
       }
       
       public ProcessingNode getNode() throws Exception {
  +        
  +        ProcessingNode[] childNodes = getNodes(childBuilders);
  +        
  +        // Children contain resources, view and pipelines : separate pipelines
  +        PipelinesNode pipelines = null;
  +        List otherNodes = new ArrayList();
  +        
  +        for (int i = 0; i < childNodes.length; i++) {
  +            
  +            if (childNodes[i] instanceof PipelinesNode) {
  +                if (pipelines != null) {
  +                    throw new ConfigurationException("There can only be one 'map:pipelines' at " +
  +                        this.location);
  +                } else {
  +                    pipelines = (PipelinesNode) childNodes[i];
  +                }
  +            } else {
  +                otherNodes.add(childNodes[i]);
  +            }
  +        }
  +        
  +        if (pipelines == null) {
  +            throw new ConfigurationException("There is no 'map:pipelines' in sitemap at " + this.location);
  +        }
  +        
  +        node.setPipelines(pipelines);
  +        node.setOtherNodes(toNodeArray(otherNodes));
  +
           return this.node;
       }
  -
   }
  
  
  
  1.1                  xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNodeBuilder.java
  
  Index: PipelineNodeBuilder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.cocoon.treeprocessor.sitemap;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.cocoon.treeprocessor.AbstractParentProcessingNodeBuilder;
  import org.apache.cocoon.treeprocessor.ProcessingNode;
  import org.apache.cocoon.treeprocessor.ProcessingNodeBuilder;
  
  import java.util.*;
  
  /**
   * Builds a &lt;map:pipeline&gt;
   
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/12 18:07:43 $
   */
  
  public class PipelineNodeBuilder extends AbstractParentProcessingNodeBuilder {
  
      private PipelineNode node;
      private List builders;
      private ProcessingNodeBuilder error404Builder;
      private ProcessingNodeBuilder error500Builder;
      
      public void buildNode(Configuration config, Map buildModel) throws Exception {
          
          this.node = new PipelineNode();
          this.node.setLocation(config.getLocation());
          this.node.setLogger(getLogger());
  
          this.node.setInternalOnly(config.getAttributeAsBoolean("internal-only", false));
          
          // Get all children but the error handlers
          if (this.ignoredChildren == null)
              this.ignoredChildren = new ArrayList();
              
          this.ignoredChildren.add("handle-errors");
          
          this.builders = createChildBuilders(config, buildModel);
          
          Configuration[] handlersConfig = config.getChildren("handle-errors");
          for (int i = 0; i < handlersConfig.length; i++) {
              Configuration handlerConfig = handlersConfig[i];
              
              int type = handlerConfig.getAttributeAsInteger("type", 500);
              
              ProcessingNodeBuilder handlerBuilder = this.treeBuilder.createNodeBuilder(handlerConfig);
              handlerBuilder.buildNode(handlerConfig, buildModel);
              
              if ( (type == 404 && this.error404Builder != null) ||
                   (type == 500 && this.error500Builder != null) ) {
                  throw new ConfigurationException("Duplicate handle-errors at " + handlerConfig.getLocation());
              }
              
              if (type == 404) {
                  this.error404Builder = handlerBuilder;
              } else if (type == 500) {
                  this.error500Builder = handlerBuilder;
              } else {
                  throw new ConfigurationException("Unkown handle-errors type (" + type + ") at " +
                      handlerConfig.getLocation());
              }
          }
      }
      
      public ProcessingNode getNode() throws Exception {
          this.node.setChildren(this.getNodes(builders));
          
          if (this.error404Builder != null) {
              this.node.set404Handler(this.error404Builder.getNode());
          }
          
          if (this.error500Builder != null) {
              this.node.set500Handler(this.error500Builder.getNode());
          }
          
          return this.node;
      }
  }
  
  
  1.1                  xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNode.java
  
  Index: PipelinesNode.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.cocoon.treeprocessor.sitemap;
  
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.activity.Disposable;
  
  import org.apache.cocoon.ResourceNotFoundException;
  
  import org.apache.cocoon.environment.Environment;
  import org.apache.cocoon.components.pipeline.EventPipeline;
  import org.apache.cocoon.components.pipeline.StreamPipeline;
  import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
  import org.apache.cocoon.treeprocessor.ProcessingNode;
  
  import java.util.*;
  
  /**
   * Handles &lt;map:pipelines&gt;
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/12 18:07:43 $
   */
  
  public final class PipelinesNode extends AbstractParentProcessingNode {
  
      private ProcessingNode[] children;
      
      public void setChildren(ProcessingNode[] node)
      {
          this.children = children;
      }
      
      public final boolean invoke(Environment env, StreamPipeline pipeline, EventPipeline eventPipeline, List listOfMaps)
        throws Exception {
          
          return invokeNodes(children, env, pipeline, eventPipeline, listOfMaps);
      }
      
      public final void dispose() {
          
          disposeNodes(children);
      }
      
  }
  
  
  1.1                  xml-cocoon2/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNodeBuilder.java
  
  Index: PipelinesNodeBuilder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.cocoon.treeprocessor.sitemap;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.cocoon.treeprocessor.AbstractParentProcessingNodeBuilder;
  import org.apache.cocoon.treeprocessor.ProcessingNode;
  import org.apache.cocoon.treeprocessor.ProcessingNodeBuilder;
  
  import java.util.*;
  
  /**
   * Buildes a &lt;map:pipelines&gt;
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/12 18:07:43 $
   */
  
  public class PipelinesNodeBuilder extends AbstractParentProcessingNodeBuilder {
  
      private PipelinesNode node;
      private List builders;
  
      public void buildNode(Configuration config, Map buildModel) throws Exception {
          
          this.node = new PipelinesNode();
          this.node.setLocation(config.getLocation());
          this.node.setLogger(getLogger());
  
          
          // Get all children but the error handlers
          this.builders = createChildBuilders(config, buildModel);
          
          if (this.builders.size() == 0) {
              throw new ConfigurationException("There must be at least one pipeline at " +
                  config.getLocation());
          }
      }
      
      public ProcessingNode getNode() throws Exception {
          
          this.node.setChildren(this.getNodes(builders));
                  
          return this.node;
      }
  }
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     webmaster@xml.apache.org
To unsubscribe, e-mail:          cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org