cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sylv...@apache.org
Subject cvs commit: xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap ComponentsSelector.java SitemapLanguage.java ViewNodeBuilder.java ActNodeBuilder.java ActSetNode.java ActTypeNode.java ActionSetNode.java ActionSetNodeBuilder.java AggregateNode.java AggregateNodeBuilder.java CallNode.java CallNodeBuilder.java ComponentsNodeBuilder.java GenerateNode.java GenerateNodeBuilder.java HandleErrorsNode.java HandleErrorsNodeBuilder.java MatchNode.java MatchNodeBuilder.java MountNodeBuilder.java PipelineNode.java PipelineNodeBuilder.java PipelinesNode.java PipelinesNodeBuilder.java PreparableMatchNode.java ReadNode.java ReadNodeBuilder.java RedirectToNodeBuilder.java RedirectToURINode.java SelectNode.java SelectNodeBuilder.java SerializeNode.java SerializeNodeBuilder.java SitemapNodeBuilder.java TransformNode.java TransformNodeBuilder.java
Date Tue, 15 Jan 2002 11:10:55 GMT
sylvain     02/01/15 03:10:55

  Modified:    src/java/org/apache/cocoon/components/pipeline
                        AbstractStreamPipeline.java
               src/java/org/apache/cocoon/components/source
                        AbstractSAXSource.java SitemapSource.java
                        XMLDBSource.java
               src/java/org/apache/cocoon/sitemap
                        SitemapComponentSelector.java
               src/scratchpad/src/org/apache/cocoon/treeprocessor
                        AbstractParentProcessingNode.java
                        AbstractParentProcessingNodeBuilder.java
                        AbstractProcessingNode.java
                        AbstractProcessingNodeBuilder.java
                        CategoryNode.java CategoryNodeBuilder.java
                        ContainerNode.java ContainerNodeBuilder.java
                        EnvironmentSourceResolver.java InvokeContext.java
                        LinkedProcessingNodeBuilder.java
                        MapStackResolver.java NamedContainerNode.java
                        NamedContainerNodeBuilder.java
                        NamedProcessingNode.java NullNode.java
                        NullNodeBuilder.java ProcessingNode.java
                        ProcessingNodeBuilder.java
                        SimpleParentProcessingNode.java
                        SimpleSelectorProcessingNode.java TreeBuilder.java
                        TreeProcessor.java treeprocessor.xconf
               src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap
                        ActNodeBuilder.java ActSetNode.java
                        ActTypeNode.java ActionSetNode.java
                        ActionSetNodeBuilder.java AggregateNode.java
                        AggregateNodeBuilder.java CallNode.java
                        CallNodeBuilder.java ComponentsNodeBuilder.java
                        GenerateNode.java GenerateNodeBuilder.java
                        HandleErrorsNode.java HandleErrorsNodeBuilder.java
                        MatchNode.java MatchNodeBuilder.java
                        MountNodeBuilder.java PipelineNode.java
                        PipelineNodeBuilder.java PipelinesNode.java
                        PipelinesNodeBuilder.java PreparableMatchNode.java
                        ReadNode.java ReadNodeBuilder.java
                        RedirectToNodeBuilder.java RedirectToURINode.java
                        SelectNode.java SelectNodeBuilder.java
                        SerializeNode.java SerializeNodeBuilder.java
                        SitemapNodeBuilder.java TransformNode.java
                        TransformNodeBuilder.java
  Added:       src/java/org/apache/cocoon/components/pipeline
                        OutputComponentSelector.java
               src/scratchpad/src/org/apache/cocoon/components
                        ExtendedComponentSelector.java LifecycleHelper.java
               src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap
                        ComponentsSelector.java SitemapLanguage.java
                        ViewNodeBuilder.java
  Removed:     src/scratchpad/src/org/apache/cocoon treeprocessor.txt
               src/scratchpad/src/org/apache/cocoon/treeprocessor
                        LifecycleHelper.java
                        TreeBuilderComponentManager.java
  Log:
  Full featured (views are implemented),
  major refactoring of component management
  
  Revision  Changes    Path
  1.2       +7 -8      xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/AbstractStreamPipeline.java
  
  Index: AbstractStreamPipeline.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/AbstractStreamPipeline.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractStreamPipeline.java	3 Jan 2002 12:31:12 -0000	1.1
  +++ AbstractStreamPipeline.java	15 Jan 2002 11:10:51 -0000	1.2
  @@ -16,7 +16,6 @@
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.reading.Reader;
   import org.apache.cocoon.serialization.Serializer;
  -import org.apache.cocoon.sitemap.SitemapComponentSelector;
   import org.apache.cocoon.xml.XMLProducer;
   
   import java.io.ByteArrayOutputStream;
  @@ -31,7 +30,7 @@
    * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
    * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:12 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:51 $
    */
   public abstract class AbstractStreamPipeline extends AbstractLoggable implements StreamPipeline, Disposable {
       protected EventPipeline eventPipeline;
  @@ -45,8 +44,8 @@
       protected String serializerSource;
       protected String serializerMimeType;
       protected String sitemapSerializerMimeType;
  -    protected SitemapComponentSelector readerSelector;
  -    protected SitemapComponentSelector serializerSelector;
  +    protected OutputComponentSelector readerSelector;
  +    protected OutputComponentSelector serializerSelector;
   
       /** the component manager set with compose() */
       protected ComponentManager manager;
  @@ -94,12 +93,12 @@
           if (this.reader != null) {
               throw new ProcessingException ("Reader already set. You can only select one Reader (" + role + ")");
           }
  -        this.readerSelector = (SitemapComponentSelector) this.newManager.lookup(Reader.ROLE + "Selector");
  +        this.readerSelector = (OutputComponentSelector) this.newManager.lookup(Reader.ROLE + "Selector");
           this.reader = (Reader)readerSelector.select(role);
           this.readerSource = source;
           this.readerParam = param;
           this.readerMimeType = mimeType;
  -        this.sitemapReaderMimeType = readerSelector.getMimeTypeForRole(role);
  +        this.sitemapReaderMimeType = readerSelector.getMimeTypeForHint(role);
       }
   
       public void setSerializer (String role, String source, Parameters param)
  @@ -112,12 +111,12 @@
           if (this.serializer != null) {
               throw new ProcessingException ("Serializer already set. You can only select one Serializer (" + role + ")");
           }
  -        this.serializerSelector = (SitemapComponentSelector) this.newManager.lookup(Serializer.ROLE + "Selector");
  +        this.serializerSelector = (OutputComponentSelector) this.newManager.lookup(Serializer.ROLE + "Selector");
           this.serializer = (Serializer)serializerSelector.select(role);
           this.serializerSource = source;
           this.serializerParam = param;
           this.serializerMimeType = mimeType;
  -        this.sitemapSerializerMimeType = serializerSelector.getMimeTypeForRole(role);
  +        this.sitemapSerializerMimeType = serializerSelector.getMimeTypeForHint(role);
       }
   
       public boolean process(Environment environment)
  
  
  
  1.1                  xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/OutputComponentSelector.java
  
  Index: OutputComponentSelector.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.components.pipeline;
  
  import org.apache.avalon.framework.component.ComponentSelector;
  
  /**
   * A <code>ComponentSelector</code> for output components used by a {@link StreamPipeline}.
   * This selector is able to associate a MIME type to a hint.
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:51 $
   */
  
  public interface OutputComponentSelector extends ComponentSelector {
  
      /**
       * Get the MIME type for a given hint.
       *
       * @param hint the component hint
       * @return the MIME type for this hint, or <code>null</code>.
       */
      String getMimeTypeForHint(Object hint);
  }
  
  
  1.2       +4 -4      xml-cocoon2/src/java/org/apache/cocoon/components/source/AbstractSAXSource.java
  
  Index: AbstractSAXSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/source/AbstractSAXSource.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractSAXSource.java	3 Jan 2002 12:31:14 -0000	1.1
  +++ AbstractSAXSource.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -11,13 +11,13 @@
   
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.cocoon.ProcessingException;
   import org.apache.cocoon.ResourceNotFoundException;
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.environment.Source;
   import org.apache.cocoon.environment.ModifiableSource;
   import org.apache.cocoon.serialization.Serializer;
  -import org.apache.cocoon.sitemap.SitemapComponentSelector;
   import org.apache.log.Logger;
   
   import org.xml.sax.InputSource;
  @@ -39,7 +39,7 @@
    * obtain a valid Source implementation.
    *
    * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
  - * @version $Id: AbstractSAXSource.java,v 1.1 2002/01/03 12:31:14 giacomo Exp $
  + * @version $Id: AbstractSAXSource.java,v 1.2 2002/01/15 11:10:52 sylvain Exp $
    */
   
   public abstract class AbstractSAXSource
  @@ -76,11 +76,11 @@
       public InputStream getInputStream() 
         throws ProcessingException, IOException {
   
  -        SitemapComponentSelector serializerSelector = null;
  +        ComponentSelector serializerSelector = null;
           Serializer serializer = null;
           try {
   
  -            serializerSelector = (SitemapComponentSelector) this.manager.lookup(Serializer.ROLE + "Selector");
  +            serializerSelector = (ComponentSelector) this.manager.lookup(Serializer.ROLE + "Selector");
               serializer = (Serializer)serializerSelector.select("xml");
               ByteArrayOutputStream os = new ByteArrayOutputStream();
               serializer.setOutputStream(os);
  
  
  
  1.2       +4 -4      xml-cocoon2/src/java/org/apache/cocoon/components/source/SitemapSource.java
  
  Index: SitemapSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/source/SitemapSource.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SitemapSource.java	3 Jan 2002 12:31:14 -0000	1.1
  +++ SitemapSource.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -10,6 +10,7 @@
   
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.cocoon.Constants;
   import org.apache.cocoon.ProcessingException;
   import org.apache.cocoon.Processor;
  @@ -23,7 +24,6 @@
   import org.apache.cocoon.environment.Source;
   import org.apache.cocoon.environment.wrapper.EnvironmentWrapper;
   import org.apache.cocoon.serialization.Serializer;
  -import org.apache.cocoon.sitemap.SitemapComponentSelector;
   import org.apache.cocoon.util.HashUtil;
   import org.apache.cocoon.xml.AbstractXMLConsumer;
   import org.apache.cocoon.xml.ContentHandlerWrapper;
  @@ -45,7 +45,7 @@
    * Description of a source which is defined by a pipeline.
    *
    * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:14 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public final class SitemapSource
  @@ -183,11 +183,11 @@
           if (this.exception != null) {
               throw this.exception;
           }
  -        SitemapComponentSelector serializerSelector = null;
  +        ComponentSelector serializerSelector = null;
           Serializer serializer = null;
           try {
   
  -            serializerSelector = (SitemapComponentSelector) this.manager.lookup(Serializer.ROLE + "Selector");
  +            serializerSelector = (ComponentSelector) this.manager.lookup(Serializer.ROLE + "Selector");
               serializer = (Serializer)serializerSelector.select("xml");
               ByteArrayOutputStream os = new ByteArrayOutputStream();
               serializer.setOutputStream(os);
  
  
  
  1.4       +1 -2      xml-cocoon2/src/java/org/apache/cocoon/components/source/XMLDBSource.java
  
  Index: XMLDBSource.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/source/XMLDBSource.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- XMLDBSource.java	10 Jan 2002 15:56:32 -0000	1.3
  +++ XMLDBSource.java	15 Jan 2002 11:10:52 -0000	1.4
  @@ -16,7 +16,6 @@
   import org.apache.cocoon.environment.Source;
   import org.apache.cocoon.environment.ModifiableSource;
   import org.apache.cocoon.serialization.Serializer;
  -import org.apache.cocoon.sitemap.SitemapComponentSelector;
   import org.apache.log.Logger;
   
   import org.xmldb.api.DatabaseManager;
  @@ -49,7 +48,7 @@
    *
    * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
    * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
  - * @version $Id: XMLDBSource.java,v 1.3 2002/01/10 15:56:32 vgritsenko Exp $
  + * @version $Id: XMLDBSource.java,v 1.4 2002/01/15 11:10:52 sylvain Exp $
    */
   public class XMLDBSource extends AbstractSAXSource {
   
  
  
  
  1.2       +11 -8     xml-cocoon2/src/java/org/apache/cocoon/sitemap/SitemapComponentSelector.java
  
  Index: SitemapComponentSelector.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/sitemap/SitemapComponentSelector.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SitemapComponentSelector.java	3 Jan 2002 12:31:20 -0000	1.1
  +++ SitemapComponentSelector.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -14,6 +14,8 @@
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   
  +import org.apache.cocoon.components.pipeline.OutputComponentSelector;
  +
   import java.util.Collections;
   import java.util.HashMap;
   import java.util.Map;
  @@ -21,9 +23,10 @@
   /** Default component manager for Cocoon's sitemap components.
    * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
    * @author <a href="mailto:giacomo@apache.org">Giacomo Pati</a>
  - * @version CVS $Id: SitemapComponentSelector.java,v 1.1 2002/01/03 12:31:20 giacomo Exp $
  + * @version CVS $Id: SitemapComponentSelector.java,v 1.2 2002/01/15 11:10:52 sylvain Exp $
    */
  -public class SitemapComponentSelector extends ExcaliburComponentSelector {
  +public class SitemapComponentSelector extends ExcaliburComponentSelector
  +  implements OutputComponentSelector {
       private Map mime_types;
       private SitemapComponentSelector parentSelector;
   
  @@ -75,13 +78,13 @@
           super.initialize();
           this.mime_types = Collections.unmodifiableMap(this.mime_types);
       }
  -
  -    public String getMimeTypeForRole(String role) {
  -        if (this.mime_types.containsKey(role) == true) {
  -            return (String)this.mime_types.get(role);
  +        
  +    public String getMimeTypeForHint(Object hint) {
  +        if (this.mime_types.containsKey(hint) == true) {
  +            return (String)this.mime_types.get(hint);
           }
           if (this.parentSelector != null) {
  -            return this.parentSelector.getMimeTypeForRole(role);
  +            return this.parentSelector.getMimeTypeForHint(hint);
           }
           return null;
       }
  @@ -91,4 +94,4 @@
               super.addComponent(hint, component, conf);
               this.mime_types.put(hint, mime_type);
       }
  -}
  +}
  \ No newline at end of file
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/ExtendedComponentSelector.java
  
  Index: ExtendedComponentSelector.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.components;
  
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentSelector;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  
  import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
  import org.apache.avalon.excalibur.component.RoleManager;
  
  import java.util.*;
  
  /**
   * An extension of <code>ExcaliburComponentSelector</code> that can have a parent
   * and accepts a wider variety of configurations.
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:52 $
   */
  
  public class ExtendedComponentSelector extends ExcaliburComponentSelector {
      
      /** The role manager */
      protected RoleManager roles;
      
      /** The parent selector, if any */
      protected ComponentSelector parentSelector;
      
      /** The class loader to use */
      protected ClassLoader classLoader;
      
      /** The components selected in the parent selector */
      protected Set parentComponents;
      
      /** The role of this selector. Set in <code>configure()</code>. */
      protected String roleName;
      
      /** The default hint */
      protected String defaultHint;
      
      public ExtendedComponentSelector()
      {
          super();
          this.classLoader = Thread.currentThread().getContextClassLoader();
      }
  
      /** Create the ComponentSelector with a Classloader */
      public ExtendedComponentSelector(ClassLoader loader)
      {
          super(loader);
          
          if (loader == null) {
              this.classLoader = Thread.currentThread().getContextClassLoader();
              
          } else {
              this.classLoader = loader;
          }
      }
      
      /**
       * Get the name for component-instance elements (i.e. components not defined
       * by their role shortcut. If <code>null</code>, any element having a 'class'
       * attribute will be considered as a component instance.
       * <p>
       * The default here is to return <code>null</code>, and subclasses can redefine
       * this method to return particular values.
       *
       * @return <code>null</code>, but can be changed by subclasses
       */
      protected String getComponentInstanceName() {
          return null;
      }
      
      /**
       * Get the name of the attribute giving the class name of a component.
       * The default here is "class", but this can be overriden in subclasses.
       *
       * @return "<code>class</code>", but can be changed by subclasses
       */
      protected String getClassAttributeName() {
          return "class";
      }
      
      /**
       * Get the name of the attribute giving the default hint to use if
       * none is given. The default here is "default", but this can be
       * overriden in subclasses. If this method returns <code>null</code>,
       * no default hint can be specified.
       *
       * @return "<code>default</code>", but can be changed by subclasses
       */
      protected String getDefaultHintAttributeName() {
          return "default";
      }
      
      /**
       * Configure the RoleManager. Redeclared only because parent member is private.
       */
      public void setRoleManager(RoleManager roles) {
          super.setRoleManager(roles);
          this.roles = roles;
      }
  
      /**
       * Set the parent of this selector. This can be done after the selector is
       * initialized, but <em>only once</em>. This allows this selector to be
       * created by a component manager while still being able to have a parent.
       *
       * @param parent the parent selector
       * @throws IllegalStateException if parent is already set
       */
      public void setParentSelector(ComponentSelector parent) {
          if (this.parentSelector != null) {
              throw new IllegalStateException("Parent selector is already set");
          }
          this.parentSelector = parent;
          this.parentComponents = new HashSet();
      }
      
      /**
       * Get the role name for this selector. This is called by <code>configure()</code>
       * to set the value of <code>this.roleName</code>.
       *
       * @return the role name, or <code>null<code> if it couldn't be determined.
       */
      protected String getRoleName(Configuration config) {
          // Get the role for this selector
          String roleName = config.getAttribute("role", null);
          if (roleName == null && this.roles != null) {
              roleName = this.roles.getRoleForName(config.getName());
          }
          
          return roleName;
      }
  
      /**
       * Configure this selector. This is the main difference with the parent class :
       * <ul>
       * <li>if {@link #getComponentInstanceName()} returns <code>null</code>,
       *     any child configurations having a attribute named as the result of
       *     {@link "getClassAttributeName()}, is considered as a component instance.
       * </li>
       * <li>if {@link #getComponentInstanceName()} returns a non-null value,
       *     only child configurations having this name are considered as a
       *     component instance.
       * </li>
       * <li>if other cases, it's name is considered to be a hint in the role manager.
       *     The behaviour is then the same as <code>ExcaliburComponentSelector</code>.
       * </li>
       *
       * @param config the configuration
       * @throws ConfigurationException if some hints aren't defined
       */
      public void configure(Configuration config) throws ConfigurationException {
  
          this.roleName = getRoleName(config);
          
          // Pass a copy of the top-level object to superclass so that
          // our name is properly initialized
          // FIXME : could be avoided if parent m_role was protected or had protected accessors
          DefaultConfiguration temp = new DefaultConfiguration(config.getName(), config.getLocation());
          if (config.getAttribute("role", null) != null) {
              temp.setAttribute("role", this.roleName);
          }
          super.configure(temp);
          
          // Get default hint
          this.defaultHint = config.getAttribute(this.getDefaultHintAttributeName(), null);
          
          // Add components
          String compInstanceName = getComponentInstanceName();
  
          Configuration[] instances = config.getChildren();
          
          for (int i = 0; i < instances.length; i++) {
              
              Configuration instance = instances[i];
              
              Object hint = instance.getAttribute("name").trim();
              
              String classAttr = instance.getAttribute(getClassAttributeName(), null);
              String className;
              
              if (compInstanceName == null) {
                  // component-instance implicitly defined by the presence of the 'class' attribute
                  if (classAttr == null) {
                      className = this.roles.getDefaultClassNameForHint(roleName, instance.getName());
                  } else {
                      className = classAttr.trim();
                  }
                  
              } else {
                  // component-instances names explicitly defined
                  if (compInstanceName.equals(instance.getName())) {
                      className = (classAttr == null) ? null : classAttr.trim();
                  } else {
                      className = this.roles.getDefaultClassNameForHint(roleName, instance.getName());
                  }
              }
              
              if (className == null) {
                  String message = "Unable to determine class name for component named '" + hint +
                      "' at " + instance.getLocation();
                  
                  getLogger().error(message);
                  throw new ConfigurationException(message);
              }
                          
              try
              {
                  Class clazz = this.classLoader.loadClass(className);
                  addComponent(hint, clazz, instance);
                  
              } catch(Exception e) {
                  
                  String message = "Could not load class " + className + " for component named '" +
                      hint + "' at " + instance.getLocation();
  
                  getLogger().error(message, e);
                  throw new ConfigurationException(message, e);
              }
          }
      }
      
      /**
       * Get the default hint, if any for this selector.
       */
      public String getDefaultHint() {
          return this.defaultHint;
      }
      
      public Component select(Object hint) throws ComponentException {
          
          if (hint == null) {
              hint = this.defaultHint;
          }
          
          if (parentSelector == null) {
              // No parent : default behaviour
              return super.select(hint);
              
          } else {
              
              // Try here first
              try {
                  return super.select(hint);
                  
              } catch(ComponentException ce) {
                  // Doesn't exist here : try in parent selector
                  Component component = this.parentSelector.select(hint);
                  this.parentComponents.add(component);
                  return component;
              }
          }
      }
      
      public void release(Component component) {
          // Was it selected on the parent ?
          if (this.parentComponents != null && this.parentComponents.remove(component)) {
              this.parentSelector.release(component);
              
          } else {
              super.release(component);
          }
      }
  }
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/LifecycleHelper.java
  
  Index: LifecycleHelper.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.components;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  import org.apache.avalon.framework.logger.Loggable;
  import org.apache.avalon.framework.parameters.Parameterizable;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  import org.apache.avalon.excalibur.component.RoleManageable;
  import org.apache.avalon.excalibur.component.RoleManager;
  import org.apache.avalon.excalibur.logger.LogKitManager;
  import org.apache.avalon.excalibur.logger.LogKitManageable;
  
  import org.apache.log.Logger;
  
  /**
   * Utility class for setting up Avalon components. Similar to Excalibur's
   * <code>DefaultComponentFactory</code>, but on existing objects.
   * <p>
   * To be moved to Avalon ?
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:52 $
   */
   
  // FIXME : need to handle also LogEnabled.
  
  public class LifecycleHelper
  {
      /** The Logger for the component
       */
      private Logger                  m_logger;
  
      /** The Context for the component
       */
      private Context                 m_context;
  
      /** The component manager for this component.
       */
      private ComponentManager        m_componentManager;
  
      /** The configuration for this component.
       */
      private Configuration           m_configuration;
  
      /** The RoleManager for child ComponentSelectors
       */
      private RoleManager             m_roles;
  
      /** The LogKitManager for child ComponentSelectors
       */
      private LogKitManager           m_logkit;
  
      /**
       * Construct a new <code>LifecycleHelper</code> that can be used repeatedly to
       * setup several components. <b>Note</b> : if a parameter is <code>null</code>,
       * the corresponding method isn't called (e.g. if <code>configuration</code> is
       * <code>null</code>, <code>configure()</code> isn't called).
       *
       * @param logger the <code>Logger</code> to pass to <code>Loggable</code>s, unless there is
       *        a <code>LogKitManager</code> and the configuration specifies a logger name.
       * @param context the <code>Context</code> to pass to <code>Contexutalizable</code>s.
       * @param componentManager the component manager to pass to <code>Composable</code>s.
       * @param roles the <code>RoleManager</code> to pass to <code>DefaultComponentSelector</code>s.
       * @param configuration the <code>Configuration</code> object to pass to new instances.
       */
      public LifecycleHelper( final Logger logger,
              final Context context,
              final ComponentManager componentManager,
              final RoleManager roles,
              final LogKitManager logkit,
              final Configuration configuration )
      {
          m_logger = logger;
          m_context = context;
          m_componentManager = componentManager;
          m_roles = roles;
          m_logkit = logkit;
          m_configuration = configuration;
      }
  
      /**
       * Setup a component, including initialization and start.
       *
       * @param component the component to setup.
       * @return the component passed in, to allow function chaining.
       * @throws Exception if something went wrong.
       */
      public Object setupComponent(Object component)
          throws Exception
      {
          return setupComponent(component, true);
      }
  
      /**
       * Setup a component, and optionnaly initializes (if it's <code>Initializable</code>)
       * and starts it (if it's <code>Startable</code>).
       *
       * @param component the component to setup.
       * @param initializeAndStart if true, <code>intialize()</code> and <code>start()</code>
       *        will be called.
       * @return the component passed in, to allow function chaining.
       * @throws Exception if something went wrong.
       */
      public Object setupComponent( Object component, boolean initializeAndStart )
          throws Exception
      {
          return setupComponent( component,
                  m_logger,
                  m_context,
                  m_componentManager,
                  m_roles,
                  m_logkit,
                  m_configuration,
                  initializeAndStart );
      }
  
      /**
       * Static equivalent to {@link #setupComponent(Object)}, to be used when there's only one
       * component to setup.
       */
      public static Object setupComponent( final Object component,
              final Logger logger,
              final Context context,
              final ComponentManager componentManager,
              final RoleManager roles,
              final LogKitManager logkit,
              final Configuration configuration )
          throws Exception
      {
          return setupComponent( component,
                  logger,
                  context,
                  componentManager,
                  roles,
                  logkit,
                  configuration,
                  true );
      }
  
      /**
       * Static equivalent to {@link #setupComponent(Object, boolean)}, to be used when there's only one
       * component to setup.
       */
      public static Object setupComponent( final Object component,
              final Logger logger,
              final Context context,
              final ComponentManager componentManager,
              final RoleManager roles,
              final LogKitManager logkit,
              final Configuration configuration,
              final boolean initializeAndStart )
          throws Exception
      {
          if( component instanceof Loggable )
          {
              Logger usedLogger;
              if( null == logkit )
              {
                  usedLogger = logger;
              }
              else if( configuration == null )
              {
                  usedLogger = logger;
              }
              else
              {
                  final String loggerName = configuration.getAttribute( "logger", null );
                  if( null == loggerName )
                  {
                      // No logger attribute available, using standard logger
                      usedLogger = logger;
                  }
                  else
                  {
                      usedLogger = logkit.getLogger( loggerName );
                  }
              }
              
              ((Loggable)component).setLogger( usedLogger );
          }
  
          if( null != context && component instanceof Contextualizable )
          {
              ((Contextualizable)component).contextualize( context );
          }
  
          if( null != componentManager && component instanceof Composable )
          {
              ((Composable)component).compose( componentManager );
          }
  
          if( null != roles && component instanceof RoleManageable )
          {
              ((RoleManageable)component).setRoleManager( roles );
          }
  
          if( null != logkit && component instanceof LogKitManageable )
          {
              ((LogKitManageable)component).setLogKitManager( logkit );
          }
  
          if( null != configuration && component instanceof Configurable )
          {
              ((Configurable)component).configure( configuration );
          }
  
          if( null != configuration && component instanceof Parameterizable )
          {
              ((Parameterizable)component).
                  parameterize( Parameters.fromConfiguration( configuration ) );
          }
  
          if( initializeAndStart && component instanceof Initializable )
          {
              ((Initializable)component).initialize();
          }
  
          if( initializeAndStart && component instanceof Startable )
          {
              ((Startable)component).start();
          }
  
          return component;
      }
  
      /**
       * Decomission a component, by stopping (if it's <code>Startable</code>) and
       * disposing (if it's <code>Disposable</code>) a component.
       */
      public static final void decommission( final Object component )
          throws Exception
      {
          if( component instanceof Startable )
          {
              ((Startable)component).stop();
          }
  
          dispose( component );
      }
      
      /**
       * Dispose a component if it's <code>Disposable</code>. Otherwhise, do nothing.
       */
      public static final void dispose( final Object component )
      {
          if ( component instanceof Disposable )
          {
              ((Disposable)component).dispose();
          }
      }
  }
  
  
  
  1.2       +6 -14     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNode.java
  
  Index: AbstractParentProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ AbstractParentProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,8 +8,6 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -
  -import org.apache.log.Logger;
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  @@ -20,24 +18,18 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public abstract class AbstractParentProcessingNode extends AbstractProcessingNode {
   
  -    private static Logger logger;
  -    
  -    public static void setStaticLogger(Logger log) {
  -        logger = log;
  -    }
  -
       /**
        * 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>.
        */
  -    protected static final boolean invokeNodes(
  +    protected final boolean invokeNodes(
           ProcessingNode[] nodes,
           Environment env,
           InvokeContext context,
  @@ -54,21 +46,21 @@
       /**
        * Invoke all nodes of a node array in order, until one succeeds.
        */
  -    protected static final boolean invokeNodes (
  +    protected final boolean invokeNodes (
           ProcessingNode[] nodes,
           Environment env,
           InvokeContext context)
         throws Exception {
           
  -        boolean debug = logger.isDebugEnabled();
  +        boolean debug = getLogger().isDebugEnabled();
           for (int i = 0; i < nodes.length; i++) {
               if (nodes[i].invoke(env, context)) {
                   if (debug)
  -                    logger.debug("Node " + nodes[i] + " at " + nodes[i].getLocation() + " succeeded");
  +                    getLogger().debug("Node " + nodes[i] + " at " + nodes[i].getLocation() + " succeeded");
                   return true;
               }
           }
           
           return false;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +15 -13    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractParentProcessingNodeBuilder.java
  
  Index: AbstractParentProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ AbstractParentProcessingNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,24 +8,24 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -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.avalon.framework.logger.AbstractLoggable;
  +
   import org.apache.cocoon.util.StringUtils;
   
  +import java.util.*;
  +
   /**
    * 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: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
  -
   public abstract class AbstractParentProcessingNodeBuilder extends AbstractProcessingNodeBuilder implements Configurable {
       
       protected Collection allowedChildren;
  @@ -73,8 +73,9 @@
           // 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());
  +            String msg = "Element '" + name + "' is not allowed at " + child.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
           
           return true;
  @@ -86,8 +87,9 @@
               if (this.hasParameters()) {
                   return true;
               } else {
  -                throw new ConfigurationException("Element '" + name + "' has no parameters at " +
  -                    config.getLocation());
  +                String msg = "Element '" + name + "' has no parameters at " + config.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
               }
           }
           return false;
  @@ -115,8 +117,9 @@
               } catch(ConfigurationException ce) {
                   throw ce;
               } catch(Exception e) {
  -                throw new ConfigurationException("Error while creating node '" + child.getName() +
  -                    "' at " + child.getLocation(), e);
  +                String msg = "Error while creating node '" + child.getName() + "' at " + child.getLocation();
  +                getLogger().error(msg, e);
  +                throw new ConfigurationException(msg, e);
               }
           }
           
  @@ -146,5 +149,4 @@
           
           return (s == null) ? null : Arrays.asList(StringUtils.split(s, ", \t\n\r"));
       }
  -
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNode.java
  
  Index: AbstractProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ AbstractProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -17,7 +17,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public abstract class AbstractProcessingNode extends AbstractLoggable implements ProcessingNode {
  @@ -44,4 +44,4 @@
       public void setLocation(String location) {
           this.location = location;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +10 -6     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/AbstractProcessingNodeBuilder.java
  
  Index: AbstractProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ AbstractProcessingNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -9,9 +9,11 @@
   package org.apache.cocoon.treeprocessor;
   
   import org.apache.avalon.framework.logger.AbstractLoggable;
  +
   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.component.Composable;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentException;
  @@ -24,7 +26,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   
  @@ -67,8 +69,9 @@
                   try {
                       params.put(child.getAttribute("name"), MapStackResolver.getResolver(value));
                   } catch(PatternException pe) {
  -                    throw new ConfigurationException("Invalid pattern '" + value +
  -                        " at " + child.getLocation());
  +                    String msg = "Invalid pattern '" + value + " at " + child.getLocation();
  +                    getLogger().error(msg, pe);
  +                    throw new ConfigurationException(msg, pe);
                   }
               }
           }
  @@ -83,8 +86,9 @@
       protected void checkNamespace(Configuration config) throws ConfigurationException {
           if (!this.treeBuilder.getNamespace().equals(config.getNamespace()))
           {
  -            throw new ConfigurationException("Invalid namespace '" + config.getNamespace() +
  -                "' at " + config.getLocation());
  +            String msg = "Invalid namespace '" + config.getNamespace() + "' at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +10 -8     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/CategoryNode.java
  
  Index: CategoryNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/CategoryNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CategoryNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ CategoryNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,10 +8,10 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.cocoon.ProcessingException;
  -import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
  +import org.apache.cocoon.ProcessingException;
   
   import java.util.*;
   
  @@ -19,7 +19,7 @@
    * A generic container node that just invokes its children.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public final class CategoryNode extends AbstractParentProcessingNode {
  @@ -36,15 +36,17 @@
       }
       
       public final boolean invoke(Environment env, InvokeContext context) throws Exception {
  -        throw new ProcessingException("Cannot invoke " + this.categoryName + " at " + getLocation());
  +        String msg = "Cannot invoke " + this.categoryName + " at " + getLocation();
  +        getLogger().error(msg);
  +        throw new ProcessingException(msg);
       }
       
       public final ProcessingNode getNodeByName(String name) throws Exception {
           ProcessingNode node = (ProcessingNode)nodes.get(name);
           if (node == null) {
  -            String message = "Unknown " + this.categoryName + " named '" + name + "' at " + getLocation();
  -            getLogger().error(message);
  -            throw new ProcessingException(message);
  +            String msg = "Unknown " + this.categoryName + " named '" + name + "' at " + getLocation();
  +            getLogger().error(msg);
  +            throw new ProcessingException(msg);
           }
           
           return node;
  @@ -55,4 +57,4 @@
           
           return getNodeByName(name).invoke(env, context);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +8 -3      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/CategoryNodeBuilder.java
  
  Index: CategoryNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/CategoryNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CategoryNodeBuilder.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ CategoryNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -11,6 +11,7 @@
   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.thread.ThreadSafe;
   
   import java.util.*;
  @@ -19,7 +20,7 @@
    * Builds a generic container node.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class CategoryNodeBuilder extends AbstractParentProcessingNodeBuilder
  @@ -30,9 +31,13 @@
       
       protected String name;
       
  +    /**
  +     * The category name is the value of the "category-name" child, or if not
  +     * present, the name of the configuration element.
  +     */
       public void configure(Configuration config) throws ConfigurationException {
           super.configure(config);
  -        this.name = config.getChild("category-name").getValue();
  +        this.name = config.getChild("category-name").getValue(config.getAttribute("name"));
       }
   
       /** This builder has no parameters -- return <code>false</code> */
  @@ -73,4 +78,4 @@
           
           return category.getNodeByName(nodeName);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +4 -11     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ContainerNode.java
  
  Index: ContainerNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ContainerNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ContainerNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ ContainerNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,9 +8,9 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
   
   import java.util.*;
   
  @@ -18,20 +18,13 @@
    * A generic container node that just invokes its children.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
  -public class ContainerNode extends AbstractParentProcessingNode {
  +public class ContainerNode extends SimpleParentProcessingNode {
   
  -    /** The childrens of this matcher */
  -    protected ProcessingNode[] children;
  -    
  -    public void setChildren(ProcessingNode[] children) {
  -        this.children = children;
  -    }
  -    
       public final boolean invoke(Environment env, InvokeContext context) throws Exception {
           
           return invokeNodes(this.children, env, context);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +6 -5      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ContainerNodeBuilder.java
  
  Index: ContainerNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ContainerNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ContainerNodeBuilder.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ ContainerNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,9 +8,9 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.avalon.framework.thread.ThreadSafe;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import java.util.*;
   
  @@ -18,7 +18,7 @@
    * Builds a generic container node.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class ContainerNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
  @@ -42,10 +42,11 @@
           
           ProcessingNode[] children = buildChildNodes(config);
           if (children.length == 0) {
  -            throw new ConfigurationException("There must be at least one child at " +
  -                config.getLocation());
  +            String msg = "There must be at least one child at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
               
           node.setChildren(children);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +3 -3      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/EnvironmentSourceResolver.java
  
  Index: EnvironmentSourceResolver.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ EnvironmentSourceResolver.java	15 Jan 2002 11:10:52 -0000	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: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class EnvironmentSourceResolver implements SourceResolver, Disposable {
  @@ -47,7 +47,7 @@
        * Resolve an entity.
        */
       public Source resolve(String systemId) throws ProcessingException, SAXException, IOException {
  -        if (systemId == null) throw new SAXException("Invalid System ID");
  +        if (systemId == null) throw new SAXException("Cannot resolve a null system ID !");
   
           URL context = new URL(this.contextSource.getSystemId());
   
  @@ -67,4 +67,4 @@
           }
           manager.release(sourceHandler);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +4 -3      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/InvokeContext.java
  
  Index: InvokeContext.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/InvokeContext.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- InvokeContext.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ InvokeContext.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,16 +8,17 @@
   
   package org.apache.cocoon.treeprocessor;
   
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.Recomposable;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.thread.ThreadSafe;
  -import org.apache.cocoon.environment.Environment;
  +
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
   
   import java.util.*;
  -import org.apache.avalon.framework.activity.Disposable;
   
   /**
    * The invocation context of <code>ProcessingNode</code>s.
  @@ -30,7 +31,7 @@
    * </ul>
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class InvokeContext implements Recomposable, Disposable {
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/LinkedProcessingNodeBuilder.java
  
  Index: LinkedProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/LinkedProcessingNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LinkedProcessingNodeBuilder.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ LinkedProcessingNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -14,7 +14,7 @@
    * into a directed graph.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public interface LinkedProcessingNodeBuilder extends ProcessingNodeBuilder {
  @@ -23,4 +23,4 @@
        * Resolve the links needed by the node built by this builder.
        */
       void linkNode() throws Exception;
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/MapStackResolver.java
  
  Index: MapStackResolver.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/MapStackResolver.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MapStackResolver.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ MapStackResolver.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -18,7 +18,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: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public abstract class MapStackResolver {
  @@ -249,4 +249,4 @@
               }
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +3 -5      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedContainerNode.java
  
  Index: NamedContainerNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedContainerNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- NamedContainerNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ NamedContainerNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,17 +8,15 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  -
  -import java.util.*;
  +import org.apache.cocoon.environment.Environment;
   
   /**
    * A named container node that just invokes its children.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class NamedContainerNode extends ContainerNode implements NamedProcessingNode {
  @@ -32,4 +30,4 @@
       public String getName() {
           return this.name;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedContainerNodeBuilder.java
  
  Index: NamedContainerNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedContainerNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- NamedContainerNodeBuilder.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ NamedContainerNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -16,7 +16,7 @@
    * Builds a generic named container node.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class NamedContainerNodeBuilder extends ContainerNodeBuilder implements Configurable {
  @@ -34,4 +34,4 @@
           this.setupNode(node, config);
           return node;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +1 -3      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedProcessingNode.java
  
  Index: NamedProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NamedProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- NamedProcessingNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ NamedProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,14 +8,12 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import java.util.Map;
  -
   /**
    * A <code>ProcessingNode</code> that has a name. This is primarily used by
    * <code>CategoryNode</code> to access its children.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public interface NamedProcessingNode extends ProcessingNode {
  
  
  
  1.2       +1 -5      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NullNode.java
  
  Index: NullNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NullNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- NullNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ NullNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,17 +8,13 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.cocoon.components.pipeline.StreamPipeline;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.environment.Environment;
   
  -import java.util.*;
  -
   /**
    * A no-op node to stub not yet implemented features.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class NullNode extends AbstractProcessingNode {
  
  
  
  1.2       +2 -4      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NullNodeBuilder.java
  
  Index: NullNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/NullNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- NullNodeBuilder.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ NullNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -10,12 +10,10 @@
   
   import org.apache.avalon.framework.configuration.Configuration;
   
  -import java.util.*;
  -
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class NullNodeBuilder extends AbstractProcessingNodeBuilder {
  @@ -23,4 +21,4 @@
       public ProcessingNode buildNode(Configuration config) throws Exception {
           return this.treeBuilder.setupNode(new NullNode(), config);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -5      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNode.java
  
  Index: ProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ ProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -9,16 +9,13 @@
   package org.apache.cocoon.treeprocessor;
   
   import org.apache.avalon.framework.thread.ThreadSafe;
  -import org.apache.cocoon.environment.Environment;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
  -import org.apache.cocoon.components.pipeline.StreamPipeline;
   
  -import java.util.List;
  +import org.apache.cocoon.environment.Environment;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public interface ProcessingNode extends ThreadSafe {
  
  
  
  1.2       +4 -4      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/ProcessingNodeBuilder.java
  
  Index: ProcessingNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ ProcessingNodeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -12,15 +12,15 @@
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   
  +import java.util.Map;
  +
   /**
    * A <code>ProcessingNode</code> builder.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
  -import java.util.Map;
  -
   public interface ProcessingNodeBuilder extends Component {
   
       /**
  @@ -34,4 +34,4 @@
        * for lookup by other <code>LinkedProcessingNodeBuilder</code>s.
        */
       ProcessingNode buildNode(Configuration config) throws Exception;
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/SimpleParentProcessingNode.java
  
  Index: SimpleParentProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/SimpleParentProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleParentProcessingNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ SimpleParentProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -14,7 +14,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public abstract class SimpleParentProcessingNode extends AbstractParentProcessingNode {
  @@ -25,4 +25,4 @@
       public void setChildren(ProcessingNode[] children) {
           this.children = children;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +4 -3      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/SimpleSelectorProcessingNode.java
  
  Index: SimpleSelectorProcessingNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/SimpleSelectorProcessingNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleSelectorProcessingNode.java	3 Jan 2002 12:31:36 -0000	1.1
  +++ SimpleSelectorProcessingNode.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -12,13 +12,14 @@
   import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.thread.ThreadSafe;
  +
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public abstract class SimpleSelectorProcessingNode extends SimpleParentProcessingNode {
  @@ -33,7 +34,7 @@
           this.componentName = componentName;
       }
       
  -    public void setSelector(ComponentSelector selector) throws Exception {
  +    public void setSelector(ComponentSelector selector) throws ComponentException {
           this.selector = selector;
       }
           
  @@ -62,4 +63,4 @@
               return null;
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +215 -126  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/TreeBuilder.java
  
  Index: TreeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ TreeBuilder.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -8,7 +8,6 @@
   
   package org.apache.cocoon.treeprocessor;
   
  -import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.excalibur.component.DefaultRoleManager;
   import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
   import org.apache.avalon.excalibur.component.RoleManageable;
  @@ -16,23 +15,29 @@
   import org.apache.avalon.excalibur.logger.LogKitManageable;
   import org.apache.avalon.excalibur.logger.LogKitManager;
   
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
  +
   import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.component.Component;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentException;
  +import org.apache.avalon.framework.component.ComponentSelector;
   
  -import org.apache.avalon.framework.configuration.Configuration;
   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.configuration.DefaultConfiguration;
   
  -import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.context.Context;
  +import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.context.ContextException;
   
   import org.apache.avalon.framework.logger.AbstractLoggable;
   
  +import org.apache.cocoon.components.ExtendedComponentSelector;
  +import org.apache.cocoon.components.LifecycleHelper;
  +
   import org.apache.cocoon.sitemap.PatternException;
   import org.apache.cocoon.util.ClassUtils;
   
  @@ -41,51 +46,61 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class TreeBuilder extends AbstractLoggable implements
     Composable, Configurable, Contextualizable, LogKitManageable, RoleManageable, Disposable {
       
  -    private Map registeredNodes = new HashMap();
  -    
  -    private Map registeredBuilders = new HashMap();
  -    
  -    private Map attributes = new HashMap();
  -    
       /**
        * The tree processor that we're building.
        */
  -    private TreeProcessor processor;
  +    protected TreeProcessor processor;
       
  -    private Context context;
  +    //----- lifecycle-related objects ------
  +    protected Context context;
       
  -    private LogKitManager logKit;
  +    protected LogKitManager logKit;
   
  -    private ComponentManager parentManager;
  +    protected ComponentManager parentManager;
  +    
  +    protected RoleManager roleManager;
       
  -    private RoleManager roleManager;
  +    protected Configuration configuration;
  +    // -------------------------------------
       
  -    private TreeBuilderComponentManager manager;
  +    protected ComponentManager manager;
       
  -    private ExcaliburComponentSelector builderSelector;
  +    /** Selector for ProcessingNodeBuilders */
  +    protected ComponentSelector builderSelector;
       
  -    private LifecycleHelper lifecycle;
  +    protected LifecycleHelper lifecycle;
       
  -    private String namespace;
  +    protected String namespace;
       
  -    private String parameterElement;
  +    protected String parameterElement;
       
  -    private String languageName;
  +    protected String languageName;
       
  +    /** Nodes gone through setupNode() that implement Initializable */
       private List initializableNodes = new ArrayList();
       
  +    /** Nodes gone through setupNode() that implement Disposable */
       private List disposableNodes = new ArrayList();
       
  +    /** NodeBuilders created by createNodeBuilder() that implement LinkedProcessingNodeBuilder */
       private List linkedBuilders = new ArrayList();
       
  +    /** Are we in a state that allows to get registered nodes ? */
       private boolean canGetNode = false;
  +
  +    /** Nodes registered using registerNode() */
  +    private Map registeredNodes = new HashMap();
       
  +    /** Attributes set using setAttribute() */
  +    private Map attributes = new HashMap();
  +
  +
       public void contextualize(Context context) throws ContextException {
           this.context = context;
       }
  @@ -103,83 +118,89 @@
       }
   
       public void configure(Configuration config) throws ConfigurationException {
  +        this.configuration = config;
           
  -        // Create the new component manager
  -        this.manager = new TreeBuilderComponentManager(this.parentManager);
  -        try {
  -            LifecycleHelper.setupComponent(this.manager,
  -                getLogger(),
  -                this.context,
  -                null, // component manager
  -                this.roleManager,
  -                this.logKit,
  -                null // configuration
  -            );
  -        } catch(Exception e) {
  -            throw new ConfigurationException("Couldn't setup internal component manager", e);
  -        }
  -
  -        // makeVisible() is called later. In the meantime, only parent components will be visible.
  -            
  -        try {
  -            // Create a helper object to setup components
  -            this.lifecycle = new LifecycleHelper(getLogger(),
  -                this.context,
  -                this.manager,
  -                this.roleManager,
  -                this.logKit,
  -                null // configuration
  -            );
  +        this.languageName = config.getAttribute("name");
  +        getLogger().debug("Configuring Builder for language : " + this.languageName);
  +        
  +        this.namespace = config.getChild("namespace").getAttribute("uri", "");
  +        
  +        this.parameterElement = config.getChild("parameter").getAttribute("element", "parameter");
  +    }
       
  -            this.languageName = config.getAttribute("name");
  -            getLogger().debug("Configuring Builder for language : " + this.languageName);
  -            
  -            this.namespace = config.getChild("namespace").getAttribute("uri", "");
  -            
  -            this.parameterElement = config.getChild("parameter").getAttribute("element", "parameter");
  +    /**
  +     * Create a role manager that will be used by all <code>RoleManageable</code>
  +     * components. The default here is to create a role manager with the contents of
  +     * the &lt;roles&gt; element of the configuration.
  +     * <p>
  +     * Subclasses can redefine this method to create roles from other sources than
  +     * the one used here.
  +     *
  +     * @return the role manager
  +     */
  +    protected RoleManager createRoleManager() throws Exception
  +    {
  +        RoleManager roles = new DefaultRoleManager();
  +
  +        LifecycleHelper.setupComponent(roles,
  +            getLogger(),
  +            this.context,
  +            this.manager,
  +            null, // role manager,
  +            this.logKit,
  +            this.configuration.getChild("roles")
  +        );
           
  -            // Create the NodeBuilder selector.
  -            ExcaliburComponentSelector selector = new ExcaliburComponentSelector();
  -            this.lifecycle.setupComponent(selector, false);
  -            
  -            this.builderSelector = selector;
  -            
  -            // Add components in the selector for all nodes in the configuration
  -            Configuration nodesConfig = config.getChild("nodes", false);
  -            if (nodesConfig == null) {
  -                throw new ConfigurationException("Missing 'nodes' element, at " + config.getLocation());
  +        return roles;
  +    }
  +    
  +    /**
  +     * Create a component manager that will be used for all <code>Composable</code>
  +     * <code>ProcessingNodeBuilder</code>s and <code>ProcessingNode</code>s.
  +     * <p>
  +     * The default here is to simply return the manager set by <code>compose()</code>,
  +     * i.e. the component manager set by the calling <code>TreeProcessor</code>.
  +     * <p>
  +     * Subclasses can redefine this method to create a component manager local to a tree,
  +     * such as for sitemap's &lt;map:components&gt;.
  +     *
  +     * @return a component manager
  +     */
  +    protected ComponentManager createComponentManager(Configuration tree) throws Exception
  +    {
  +        return this.parentManager;
  +    }
  +
  +    /**
  +     * Create a <code>ComponentSelector</code> for <code>ProcessingNodeBuilder</code>s.
  +     * It creates a selector with the contents of the "node" element of the configuration.
  +     *
  +     * @return a selector for node builders
  +     */
  +    protected ComponentSelector createBuilderSelector() throws Exception {
  +        
  +        // Create the NodeBuilder selector.
  +        ExcaliburComponentSelector selector = new ExtendedComponentSelector() {
  +            protected String getComponentInstanceName() {
  +                return "node";
               }
               
  -            Configuration[] nodes = nodesConfig.getChildren("node");
  -            for (int i = 0; i < nodes.length; i++) {
  -                Configuration node = nodes[i];
  -                String name = node.getAttribute("name");
  -                String className = node.getAttribute("builder");
  -                Class clazz;
  -                try {
  -                    clazz = ClassUtils.loadClass(className);
  -                } catch(Exception e) {
  -                    throw new ConfigurationException("Cannot load class '" + className +
  -                        "', at " + node.getLocation());
  -                }
  -                
  -                if (! ProcessingNodeBuilder.class.isAssignableFrom(clazz)) {
  -                    throw new ConfigurationException("Class '" + className +
  -                        "' does not implement ProcessingNodeBuilder, at " + node.getLocation());
  -                }
  -                
  -                // Add it to the builder selector
  -                getLogger().debug("Adding ProcessingNodeBuilder '" + name + "' : class = " + className);
  -                selector.addComponent(name, clazz, node);
  +            protected String getClassAttributeName() {
  +                return "builder";
               }
  -            
  -            selector.initialize();
  -            
  -        } catch(ConfigurationException ce) {
  -            throw ce;
  -        } catch(Exception ex) {
  -            throw new ConfigurationException("Cannot setup selector for node builders", ex);
  -        }
  +        };
  +
  +        // Automagically initialize the selector
  +        LifecycleHelper.setupComponent(selector,
  +            getLogger(),
  +            this.context,
  +            this.manager,
  +            this.roleManager,
  +            this.logKit,
  +            this.configuration.getChild("nodes")
  +        );
  +        
  +        return selector;            
       }
   
       public void setProcessor(TreeProcessor processor) {
  @@ -229,18 +250,6 @@
           return this.attributes.get(name);
       }
       
  -    /**
  -     * Some NodeBuilders create components to be used by others
  -     */
  -    public void addComponent(String role, Class component, Configuration configuration)
  -      throws ComponentException {
  -        this.manager.addComponent(role, component, configuration);
  -    }
  -    
  -    public void addComponentInstance(String role, Component instance) {
  -        this.manager.addComponentInstance(role, instance);
  -    }
  -    
       public ProcessingNodeBuilder createNodeBuilder(Configuration config) throws Exception {
           //FIXME : check namespace
           String nodeName = config.getName();
  @@ -258,7 +267,9 @@
                   throw ce;
               } else {
                   // Throw a more meaningfull exception
  -                throw new ConfigurationException("Unkown element '" + nodeName + "' at " + config.getLocation());
  +                String msg = "Unkown element '" + nodeName + "' at " + config.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
               }
           }
           
  @@ -272,6 +283,31 @@
       }
       
       /**
  +     * Create the tree once component manager and node builders have been set up.
  +     * Can be overriden by subclasses to perform pre/post tree creation operations.
  +     */
  +    protected ProcessingNode createTree(Configuration tree) throws Exception {
  +        // Create a node builder from the top-level element
  +        ProcessingNodeBuilder rootBuilder = createNodeBuilder(tree);
  +        
  +        // Build the whole tree (with an empty buildModel)
  +        return rootBuilder.buildNode(tree);
  +    }
  +    
  +    /**
  +     * Resolve links : call <code>linkNode()</code> on all
  +     * <code>LinkedProcessingNodeBuilder</code>s.
  +     * Can be overriden by subclasses to perform pre/post resolution operations.
  +     */
  +    protected void linkNodes() throws Exception {
  +        // Resolve links
  +        Iterator iter = this.linkedBuilders.iterator();
  +        while(iter.hasNext()) {
  +            ((LinkedProcessingNodeBuilder)iter.next()).linkNode();
  +        }
  +    }
  +    
  +    /**
        * Get the namespace URI that builders should use to find their nodes.
        */
       public String getNamespace() {
  @@ -281,31 +317,35 @@
       /**
        * Build a processing tree from a <code>Configuration</code>.
        */
  -    public ProcessingNode build(Configuration config) throws Exception {
  +    public ProcessingNode build(Configuration tree) throws Exception {
           
  -        // Calls to getRegisteredNode() are forbidden
  -        this.canGetNode = false;
  +        this.roleManager = createRoleManager();
  +        
  +        this.manager = createComponentManager(tree);
  +        
  +        // Create a helper object to setup components
  +        this.lifecycle = new LifecycleHelper(getLogger(),
  +            this.context,
  +            this.manager,
  +            this.roleManager,
  +            this.logKit,
  +            null // configuration
  +        );
   
  -        // Create a node builder from the top-level element
  -        ProcessingNodeBuilder rootBuilder = createNodeBuilder(config);
  +        this.builderSelector = createBuilderSelector();
           
  -        // Build the whole tree (with an empty buildModel)
  -        ProcessingNode result = rootBuilder.buildNode(config);
  +        // Calls to getRegisteredNode() are forbidden
  +        this.canGetNode = false;
           
  -        // Expose newly added components
  -        this.manager.makeVisible();
  +        ProcessingNode result = createTree(tree);
           
           // Calls to getRegisteredNode() are now allowed
           this.canGetNode = true;
  -
  -        // Resolve links
  -        Iterator iter = this.linkedBuilders.iterator();
  -        while(iter.hasNext()) {
  -            ((LinkedProcessingNodeBuilder)iter.next()).linkNode();
  -        }
           
  +        linkNodes();
  +
           // Initialize all Initializable nodes
  -        iter = this.initializableNodes.iterator();
  +        Iterator iter = this.initializableNodes.iterator();
           while(iter.hasNext()) {
               ((Initializable)iter.next()).initialize();
           }
  @@ -313,7 +353,7 @@
           // And that's all !
           return result;
       }
  -    
  +        
       /**
        * Return the list of <code>ProcessingNodes</code> part of this tree that are
        * <code>Disposable</code>. Care should be taken to properly dispose them before
  @@ -377,8 +417,9 @@
                   try {
                       params.put(child.getAttribute("name"), MapStackResolver.getResolver(value));
                   } catch(PatternException pe) {
  -                    throw new ConfigurationException("Invalid pattern '" + value +
  -                        " at " + child.getLocation());
  +                    String msg = "Invalid pattern '" + value + "' at " + child.getLocation();
  +                    getLogger().error(msg, pe);
  +                    throw new ConfigurationException(msg, pe);
                   }
               }
           }
  @@ -386,7 +427,55 @@
           return params;
       }
   
  +    /**
  +     * Get the type for a statement : it returns the 'type' attribute if present,
  +     * and otherwhise the default hint of the <code>ExtendedSelector</code> designated by
  +     * role <code>role</code>.
  +     *
  +     * @throws ConfigurationException if the default type could not be found.
  +     */
  +    public String getTypeForStatement(Configuration statement, String role) throws ConfigurationException {
  +        
  +        String type = statement.getAttribute("type", null);
  +        
  +        ComponentSelector selector;
  +        
  +        try {
  +            selector = (ComponentSelector)this.manager.lookup(role);
  +        } catch(ComponentException ce) {
  +            String msg = "Cannot get component selector for '" + statement.getName() + "' at " +
  +                statement.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
  +        }
  +        
  +        if (type == null && selector instanceof ExtendedComponentSelector) {
  +            type = ((ExtendedComponentSelector)selector).getDefaultHint();
  +        }
  +
  +        if (type == null) {
  +            String msg = "No default type exists for '" + statement.getName() + "' at " +
  +                statement.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
  +        }
  +        
  +        if (!selector.hasComponent(type)) {
  +            String msg = "Type '" + type + "' is not defined for '" + statement.getName() + "' at " +
  +                statement.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
  +        }
  +        
  +        this.manager.release(selector);
  +        
  +        return type;
  +    }
  +
       public void dispose() {
  -        this.builderSelector.dispose();
  +        LifecycleHelper.dispose(this.builderSelector);
  +        
  +        // Don't dispose manager or roles : they are used by the built tree
  +        // and thus must live longer than the builder.
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +63 -35    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/TreeProcessor.java
  
  Index: TreeProcessor.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ TreeProcessor.java	15 Jan 2002 11:10:52 -0000	1.2
  @@ -15,23 +15,28 @@
   
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
  +
   import org.apache.avalon.framework.component.Component;
  -import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentSelector;
  +import org.apache.avalon.framework.component.Composable;
  +
   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.configuration.SAXConfigurationHandler;
   import org.apache.avalon.framework.configuration.NamespacedSAXConfigurationHandler;
  +import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
  +
   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.logger.AbstractLoggable;
   import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.Processor;
  +import org.apache.cocoon.components.LifecycleHelper;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
   import org.apache.cocoon.components.source.CocoonSourceFactory;
  @@ -49,14 +54,14 @@
    * Interpreted tree-traversal implementation of a pipeline assembly language.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
    */
   
   public class TreeProcessor extends AbstractLoggable implements ThreadSafe, Processor,
     Composable, Configurable, LogKitManageable, Initializable, Contextualizable, Disposable {
       
       private static final String XCONF_URL = "resource://org/apache/cocoon/treeprocessor/treeprocessor.xconf";
  -    private static final String ROLES_URL = "resource://org/apache/cocoon/sitemap/sitemap.roles";
  +//    private static final String ROLES_URL = "resource://org/apache/cocoon/treeprocessor/treeprocessor.roles";
       
       /** The parent TreeProcessor, if any */
       protected TreeProcessor parent;
  @@ -98,6 +103,9 @@
       protected Configuration currentLanguage;
       
       protected SourceHandler sourceHandler;
  +    
  +    protected Class treeBuilderClass;
  +    
       /**
        * Create a TreeProcessor.
        */
  @@ -160,8 +168,6 @@
   */
       public void configure(Configuration config) throws ConfigurationException {
           
  -        AbstractParentProcessingNode.setStaticLogger(getLogger());
  -
           Configuration rootLangConfig = config.getChild("root-language", false);
           if (rootLangConfig != null) {
               this.language = rootLangConfig.getAttribute("name");
  @@ -227,8 +233,8 @@
           
           Configuration fileConfig = this.currentLanguage.getChild("file", false);
           if (fileConfig == null) {
  -            throw new ConfigurationException("Missing 'file' configuration for language '" +
  -                this.language + "', at " + this.currentLanguage.getLocation());
  +            throw new ConfigurationException("Missing 'file' configuration for language '" + this.language + "', at " +
  +                this.currentLanguage.getLocation());
           }
           
           this.sourceName = fileConfig.getAttribute("name");
  @@ -238,6 +244,19 @@
           
           // and add the special "cocoon:" source factory
           this.sourceHandler.addFactory("cocoon", new CocoonSourceFactory(this, this.manager));
  +        
  +        // Get the TreeBuider class
  +        String builderClassName =
  +            this.currentLanguage.getAttribute("class", TreeBuilder.class.getName());
  +
  +        try {
  +            this.treeBuilderClass = Thread.currentThread().getContextClassLoader().loadClass(builderClassName);
  +        } catch(Exception e) {
  +            String msg = "Cannot create class '" + builderClassName + "' at " +
  +                this.currentLanguage.getLocation();
  +            getLogger().error(msg, e);
  +            throw new ConfigurationException(msg, e);
  +        }
       }
       
       public boolean process(Environment environment) throws Exception {
  @@ -304,19 +323,25 @@
           source.toSAX(handler);
           Configuration treeConfig = handler.getConfiguration();
           
  -        TreeBuilder treeBuilder = new TreeBuilder();
  +        TreeBuilder treeBuilder = (TreeBuilder)this.treeBuilderClass.newInstance();
           LifecycleHelper.setupComponent(treeBuilder,
               getLogger(),
               this.context,
               this.manager,
  -            getRoleManager(),
  +            null, //getRoleManager(),
               this.logKit,
               this.currentLanguage);
   
           treeBuilder.setProcessor(this);
           
           // Build the tree
  -        ProcessingNode root = treeBuilder.build(treeConfig);
  +        ProcessingNode root;
  +        try {
  +            root = treeBuilder.build(treeConfig);
  +        } catch(Exception e) {
  +            getLogger().debug("Failed to build processing tree from " + source.getSystemId(), e);
  +            throw e;
  +        }
           
           LifecycleHelper.decommission(treeBuilder);
               
  @@ -332,29 +357,32 @@
           this.rootNode = root;
       }
   
  -    private RoleManager getRoleManager() throws Exception {
  -
  -        Configuration rolesConfig;
  -        
  -        URLFactory factory = (URLFactory)this.manager.lookup(URLFactory.ROLE);
  -        URLSource source = new URLSource(factory.getURL(ROLES_URL), this.manager);
  -        try {
  -            SAXConfigurationHandler handler = new SAXConfigurationHandler();
  -            source.toSAX(handler);
  -            rolesConfig = handler.getConfiguration();
  -        } finally {
  -            this.manager.release((Component)factory);
  -            if (source != null) {
  -                source.recycle();
  -            }
  -        }
  -    
  -        DefaultRoleManager sitemapRoleManager = new DefaultRoleManager();
  -        sitemapRoleManager.setLogger(getLogger());
  -        sitemapRoleManager.configure(rolesConfig);
  -        
  -        return sitemapRoleManager;
  -    }
  +//
  +// Of no use, since the TreeBuilder has to work with the role manager of the target language.
  +//
  +//    private RoleManager getRoleManager() throws Exception {
  +//
  +//        Configuration rolesConfig;
  +//        
  +//        URLFactory factory = (URLFactory)this.manager.lookup(URLFactory.ROLE);
  +//        URLSource source = new URLSource(factory.getURL(ROLES_URL), this.manager);
  +//        try {
  +//            SAXConfigurationHandler handler = new SAXConfigurationHandler();
  +//            source.toSAX(handler);
  +//            rolesConfig = handler.getConfiguration();
  +//        } finally {
  +//            this.manager.release((Component)factory);
  +//            if (source != null) {
  +//                source.recycle();
  +//            }
  +//        }
  +//    
  +//        DefaultRoleManager sitemapRoleManager = new DefaultRoleManager();
  +//        sitemapRoleManager.setLogger(getLogger());
  +//        sitemapRoleManager.configure(rolesConfig);
  +//        
  +//        return sitemapRoleManager;
  +//    }
   
       public void dispose() {
           disposeTree();        
  @@ -372,4 +400,4 @@
               }
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +71 -27    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/treeprocessor.xconf
  
  Index: treeprocessor.xconf
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:36 -0000	1.1
  +++ treeprocessor.xconf	15 Jan 2002 11:10:52 -0000	1.2
  @@ -9,12 +9,12 @@
    *****************************************************************************
   
    @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:36 $
  + @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:52 $
   -->
   
   <tree-processor>
     <!-- The sitemap language -->
  -  <language name="sitemap">
  +  <language name="sitemap" class="org.apache.cocoon.treeprocessor.sitemap.SitemapLanguage">
     
       <!-- Namespace for this language -->
       <namespace uri="http://apache.org/cocoon/sitemap/1.0"/>
  @@ -25,6 +25,66 @@
       <!-- Description of the element for nodes parameters -->
       <parameter element="parameter"/>
       
  +    <!-- roles for the sitemap language -->
  +    <roles>
  +      <role name="org.apache.cocoon.acting.ActionSelector"
  +            shorthand="actions"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector"/>
  +      
  +      <role name="org.apache.cocoon.selection.SelectorSelector"
  +            shorthand="selectors"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector"/>
  +      
  +      <role name="org.apache.cocoon.matching.MatcherSelector"
  +            shorthand="matchers"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector">
  +
  +        <hint shorthand="regexp-uri-matcher"
  +              class="org.apache.cocoon.matching.RegexpURIMatcher"/>
  +
  +        <hint shorthand="wildcard-uri-matcher"
  +              class="org.apache.cocoon.matching.WildcardURIMatcher"/>
  +
  +      </role>
  +      
  +      <role name="org.apache.cocoon.generation.GeneratorSelector"
  +            shorthand="generators"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector">
  +
  +        <hint shorthand="file-generator"
  +              class="org.apache.cocoon.generation.FileGenerator"/>
  +
  +        <hint shorthand="XSP-generator"
  +              class="org.apache.cocoon.generation.ServerPagesGenerator"/>
  +      </role>
  +      
  +      <role name="org.apache.cocoon.transformation.TransformerSelector"
  +            shorthand="transformers"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector">
  +
  +        <hint shorthand="XSLT-transformer"
  +              class="org.apache.cocoon.transformation.TraxTransformer"/>
  +
  +        <hint shorthand="cinclude-transformer"
  +              class="org.apache.cocoon.transformation.CIncludeTransformer"/>
  +
  +      </role>
  +      
  +      <role name="org.apache.cocoon.serialization.SerializerSelector"
  +            shorthand="serializers"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector"/>
  +      
  +      <role name="org.apache.cocoon.reading.ReaderSelector"
  +            shorthand="readers"
  +            default-class="org.apache.cocoon.treeprocessor.sitemap.ComponentsSelector"/>
  +          
  +      <role name="org.apache.cocoon.components.notification.NotifyingBuilder"
  +            shorthand="notifying-builder"
  +            default-class="org.apache.cocoon.components.notification.DefaultNotifyingBuilder"/>  
  +
  +    </roles>
  +    
  +    <!-- node definitions for the sitemap language -->
       <nodes>
         <!-- All node names are given as local names in the above namespace (no prefix) -->
         
  @@ -33,39 +93,23 @@
           <allowed-children>components, views, action-sets, resources, pipelines</allowed-children>
         </node>
       
  -      <!-- Components definition : fills selectors on the TreeProcessor -->
  -      <node name="components" builder="org.apache.cocoon.treeprocessor.sitemap.ComponentsNodeBuilder">
  -        <selector section="matchers"     elements="matcher"
  -                  role="org.apache.cocoon.matching.MatcherSelector"/>
  -        <selector section="selectors"    elements="selector"
  -                  role="org.apache.cocoon.selection.SelectorSelector"/>
  -        <selector section="actions"      elements="action"
  -                  role="org.apache.cocoon.acting.ActionSelector"/>
  -        <selector section="generators"   elements="generator"
  -                  role="org.apache.cocoon.generation.GeneratorSelector"/>
  -        <selector section="transformers" elements="transformer"
  -                  role="org.apache.cocoon.transformation.TransformerSelector"/>
  -        <selector section="serializers"  elements="serializer"
  -                  role="org.apache.cocoon.serialization.SerializerSelector"/>
  -        <selector section="readers"      elements="reader"
  -                  role="org.apache.cocoon.reading.ReaderSelector"/>
  -      </node>
  +      <!-- Components definition : parse view info associated to components
  +           (actual components creation is done by SitemapLanguage) -->
  +      <node name="components" builder="org.apache.cocoon.treeprocessor.sitemap.ComponentsNodeBuilder"/>
         
         <node name="pipelines" builder="org.apache.cocoon.treeprocessor.sitemap.PipelinesNodeBuilder">
           <allowed-children>pipeline</allowed-children>
         </node>
         
  -      <node name="views" builder="org.apache.cocoon.treeprocessor.NullNodeBuilder"/>
  +      <node name="views" builder="org.apache.cocoon.treeprocessor.CategoryNodeBuilder"/>
         
  -      <node name="resources" builder="org.apache.cocoon.treeprocessor.CategoryNodeBuilder">
  -        <category-name>resources</category-name>
  -      </node>
  +      <node name="view" builder="org.apache.cocoon.treeprocessor.sitemap.ViewNodeBuilder"/>
  +      
  +      <node name="resources" builder="org.apache.cocoon.treeprocessor.CategoryNodeBuilder"/>
         
         <node name="resource" builder="org.apache.cocoon.treeprocessor.NamedContainerNodeBuilder"/>
         
  -      <node name="action-sets" builder="org.apache.cocoon.treeprocessor.CategoryNodeBuilder">
  -        <category-name>action-sets</category-name>
  -      </node>
  +      <node name="action-sets" builder="org.apache.cocoon.treeprocessor.CategoryNodeBuilder"/>
         
         <node name="action-set" builder="org.apache.cocoon.treeprocessor.sitemap.ActionSetNodeBuilder"/>
   
  @@ -77,7 +121,7 @@
           <forbidden-children>sitemap, components, pipeline, handle-errors</forbidden-children>
         </node>
   
  -      <node name="select" builder="org.apache.cocoon.treeprocessor.NullNodeBuilder"/>
  +      <node name="select" builder="org.apache.cocoon.treeprocessor.sitemap.SelectNodeBuilder"/>
   
         <node name="act" builder="org.apache.cocoon.treeprocessor.sitemap.ActNodeBuilder">
           <forbidden-children>sitemap, components, pipeline, handle-errors</forbidden-children>
  @@ -105,4 +149,4 @@
       
     </language>
   
  -</tree-processor>
  \ No newline at end of file
  +</tree-processor>
  
  
  
  1.2       +16 -28    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActNodeBuilder.java
  
  Index: ActNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ActNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -15,52 +15,46 @@
   import org.apache.avalon.framework.configuration.ConfigurationException;
   
   import org.apache.cocoon.acting.Action;
  +
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNodeBuilder;
  -import org.apache.cocoon.treeprocessor.MapStackResolver;
  -import org.apache.cocoon.treeprocessor.ProcessingNode;
   import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
  -import org.apache.cocoon.treeprocessor.NullNode;
  -import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.CategoryNodeBuilder;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ActNodeBuilder extends AbstractParentProcessingNodeBuilder
  -  implements Composable, LinkedProcessingNodeBuilder {
  +  implements LinkedProcessingNodeBuilder {
   
       private ComponentManager manager;
       
  -    private ActTypeNode actTypeNode;
  -    
       private ActSetNode  actSetNode;
       private String      actSetName;
   
  -    public void compose(ComponentManager manager) {
  -        this.manager = manager;
  -    }
  -    
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
           String source = config.getAttribute("src", null);
           
           // Is it an action-set call ?
           this.actSetName = config.getAttribute("set", null);
  -        if (this.actSetName == null) {
  +        if (actSetName == null) {
               
  -            String type = ComponentsNodeBuilder.getComponentType(Action.ROLE + "Selector", config, this.treeBuilder);
  -            this.actTypeNode = new ActTypeNode(type, source);
  -            this.treeBuilder.setupNode(this.actTypeNode, config);
  -            // Selector is set in linkNode() since it isn't visible now
  +            String type = this.treeBuilder.getTypeForStatement(config, Action.ROLE + "Selector");
               
  -            this.actTypeNode.setChildren(buildChildNodes(config));
  +            ActTypeNode actTypeNode = new ActTypeNode(type, source);
  +            this.treeBuilder.setupNode(actTypeNode, config);
               
  -            return this.actTypeNode;
  +            actTypeNode.setChildren(buildChildNodes(config));
  +            
  +            return actTypeNode;
               
           } else {
               
  @@ -76,18 +70,12 @@
   
       public void linkNode() throws Exception {
   
  -        if (this.actTypeNode != null) {
  -
  -            // Get the selector (it's now visible in the manager)
  -            ComponentSelector selector = (ComponentSelector)manager.lookup(Action.ROLE + "Selector");
  -            this.actTypeNode.setSelector(selector);
  -
  -        } else {
  -            
  +        if (this.actSetNode != null) {
  +            // Link action-set call to the action set
               this.actSetNode.setActionSet(
                   (ActionSetNode)CategoryNodeBuilder.getNamedNode(
                       this.treeBuilder, "action-sets", this.actSetName)
               );
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +6 -6      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActSetNode.java
  
  Index: ActSetNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActSetNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActSetNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ActSetNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,8 +9,8 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.component.Component;
  -import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
  +import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.thread.ThreadSafe;
   
  @@ -24,11 +24,11 @@
   import org.apache.cocoon.sitemap.PatternException;
   import org.apache.cocoon.sitemap.SitemapRedirector;
   
  -import org.apache.cocoon.treeprocessor.ProcessingNode;
  -import org.apache.cocoon.treeprocessor.SimpleParentProcessingNode;
   import org.apache.cocoon.treeprocessor.InvokeContext;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
  +import org.apache.cocoon.treeprocessor.SimpleParentProcessingNode;
   
   import java.util.List;
   import java.util.Map;
  @@ -37,7 +37,7 @@
    * Handles &lt;map:act type="..."&gt; (action-sets calls are handled by {@link ActSetNode}).
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ActSetNode extends SimpleParentProcessingNode
  @@ -73,7 +73,7 @@
   
           Map result = this.actionSet.call(env, context, resolvedSource, resolvedParams);
           
  -        if (SitemapNode.getRedirector(env).hasRedirected()) {
  +        if (PipelinesNode.getRedirector(env).hasRedirected()) {
               return true;
               
           } else if (result == null) {
  @@ -86,4 +86,4 @@
               return this.invokeNodes(this.children, env, context, result);
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +12 -7     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActTypeNode.java
  
  Index: ActTypeNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActTypeNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActTypeNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ActTypeNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -26,16 +26,18 @@
   import org.apache.cocoon.treeprocessor.SimpleSelectorProcessingNode;
   
   import java.util.*;
  +import org.apache.avalon.framework.component.Composable;
  +import org.apache.avalon.framework.component.ComponentManager;
   
   /**
    * Handles &lt;map:act type="..."&gt; (action-sets calls are handled by {@link ActSetNode}).
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ActTypeNode extends SimpleSelectorProcessingNode
  -  implements ParameterizableProcessingNode, Disposable {
  +  implements ParameterizableProcessingNode, Disposable, Composable {
       
       /** The parameters of this node */
       private Map parameters;
  @@ -55,8 +57,9 @@
           this.parameters = parameterMap;
       }
   
  -    public void setSelector(ComponentSelector selector) throws Exception {
  -        super.setSelector(selector);
  +    public void compose(ComponentManager manager) throws ComponentException {
  +        
  +        setSelector((ComponentSelector)manager.lookup(Action.ROLE + "Selector"));
   
           // Get the action, if it's thread safe
           this.threadSafeAction = (Action)this.getThreadSafeComponent();
  @@ -67,7 +70,7 @@
           
           // Prepare data needed by the action
           Map               objectModel    = env.getObjectModel();
  -        SitemapRedirector redirector     = SitemapNode.getRedirector(env);
  +        SitemapRedirector redirector     = PipelinesNode.getRedirector(env);
           SourceResolver    resolver       = getSourceResolver(objectModel);
           List              mapStack       = context.getMapStack();
           String            resolvedSource = source.resolve(mapStack);
  @@ -103,8 +106,10 @@
               // Action succeeded : process children if there are some, with the action result
               if (this.children != null) {
                   return this.invokeNodes(this.children, env, context, actionResult);
  +
               } else {
  -                return true;
  +                // Return false to continue sitemap invocation
  +                return false;
               }
           }
       }
  @@ -114,4 +119,4 @@
               this.selector.release(this.threadSafeAction);
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +13 -8     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionSetNode.java
  
  Index: ActionSetNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionSetNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActionSetNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ActionSetNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,6 +9,8 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.activity.Disposable;
  +import org.apache.avalon.framework.component.Composable;
  +import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.parameters.Parameters;
  @@ -30,11 +32,11 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ActionSetNode extends SimpleSelectorProcessingNode
  -  implements Disposable, NamedProcessingNode {
  +  implements Disposable, NamedProcessingNode, Composable {
       
       /** The action types */
       private String[] types;
  @@ -50,9 +52,10 @@
           this.types = types;
           this.actionNames = actionNames;
       }
  -    
  -    public void setSelector(ComponentSelector selector) throws Exception {
  -        super.setSelector(selector);
  +
  +    public void compose(ComponentManager manager) throws ComponentException {
  +        
  +        setSelector((ComponentSelector)manager.lookup(Action.ROLE + "Selector"));
   
           // Get all actions that are thread safe
           this.threadSafeActions = new Action[types.length];
  @@ -64,7 +67,9 @@
       
       public final boolean invoke(Environment env, InvokeContext context)
         throws Exception {
  -        throw new UnsupportedOperationException("An action-set cannot be invoked");
  +        String msg = "An action-set cannot be invoked, at " + this.getLocation();
  +        getLogger().error(msg);
  +        throw new UnsupportedOperationException(msg);
       }
       
       /**
  @@ -75,7 +80,7 @@
           
           // Prepare data needed by the actions
           Map               objectModel    = env.getObjectModel();
  -        SitemapRedirector redirector     = SitemapNode.getRedirector(env);
  +        SitemapRedirector redirector     = PipelinesNode.getRedirector(env);
           SourceResolver    resolver       = getSourceResolver(objectModel);
           
           String cocoonAction = env.getAction();
  @@ -138,4 +143,4 @@
       public String getName() {
           return this.componentName;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +13 -26    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionSetNodeBuilder.java
  
  Index: ActionSetNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ActionSetNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActionSetNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ActionSetNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -13,32 +13,26 @@
   import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.acting.Action;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
  -import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
  -import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
   
   import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class ActionSetNodeBuilder extends AbstractProcessingNodeBuilder
  -  implements Composable, LinkedProcessingNodeBuilder {
  +public class ActionSetNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
   
       private ComponentManager manager;
  -    private ActionSetNode node;
   
  -    public void compose(ComponentManager manager) {
  -        this.manager = manager;
  -    }
  -    
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
           String actionSetName = config.getAttribute("name");
  @@ -56,32 +50,25 @@
               if ("act".equals(name)) {
   
                   checkNamespace(childConfig);
  -                String type = ComponentsNodeBuilder.getComponentType(
  -                    Action.ROLE + "Selector", childConfig, this.treeBuilder);
  +                String type = this.treeBuilder.getTypeForStatement(childConfig, Action.ROLE + "Selector");
                   
                   actionTypes.add(type);
                   actionNames.add(childConfig.getAttribute("action", null));
                   
               } else {
                   // Unknown element
  -                throw new ConfigurationException("Unknown element " + name + " at " + childConfig.getLocation());
  +                String msg = "Unknown element " + name + " in action-set at " + childConfig.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
               }
           }
           
           String[] types   = (String[])actionTypes.toArray(new String[actionTypes.size()]);
           String[] actions = (String[])actionNames.toArray(new String[actionNames.size()]);
           
  -        this.node = new ActionSetNode(actionSetName, types, actions);
  -        this.treeBuilder.setupNode(this.node, config);
  -        // Selector is set in linkNode() since it isn't visible now
  -        
  -        return this.node;
  -    }
  -    
  -    public void linkNode() throws Exception {
  -        
  -        // Get the selector (it's now visible in the manager)
  -        ComponentSelector selector = (ComponentSelector)manager.lookup(Action.ROLE + "Selector");
  -        this.node.setSelector(selector);
  +        ActionSetNode node = new ActionSetNode(actionSetName, types, actions);
  +        this.treeBuilder.setupNode(node, config);
  +
  +        return node;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +75 -14    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/AggregateNode.java
  
  Index: AggregateNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/AggregateNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AggregateNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ AggregateNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,9 +8,9 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
   
   import org.apache.cocoon.sitemap.PatternException;
   import org.apache.cocoon.sitemap.ContentAggregator;
  @@ -24,16 +24,35 @@
   
   /**
    *
  + * View-handling in aggregation :
  + * <ul>
  + * <li>map:aggregate can have a label, but doesn't match view from-position="first" like generators
  + * </li>
  + * <li>each map:part can have a label
  + * </li>
  + * <li>parts labels are checked first for a matching view, then the aggregate label is checked
  + * </li>
  + * </ul>
  + * For more info on aggregation and view, see the mail archive
  + * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100525751417953">here</a> or 
  + * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100517130418424">here</a>.
  + *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class AggregateNode extends AbstractProcessingNode {
       
  -    Part[] parts;
  -    String element;
  -    String nsURI;
  -    String nsPrefix;
  +    private Part[] parts;
  +    private String element;
  +    private String nsURI;
  +    private String nsPrefix;
  +    
  +    /** Views for each part */
  +    private Map[]partViews;
  +    
  +    /** View for map:aggregate */
  +    private Map views;
       
       public AggregateNode(String element, String nsURI, String nsPrefix) {
           this.element = element;
  @@ -45,9 +64,16 @@
           this.parts = parts;
       }
       
  +    public void setViews(Map views, Map[]partViews) {
  +        this.views = views;
  +        this.partViews = partViews;
  +    }
  +    
       public boolean invoke(Environment env, InvokeContext context)
         throws Exception {
           
  +        boolean infoEnabled = getLogger().isInfoEnabled();
  +        
           List mapStack = context.getMapStack();
   
           // Setup aggregator
  @@ -57,14 +83,50 @@
   
           ContentAggregator aggregator = (ContentAggregator)eventPipeline.getGenerator();
           aggregator.setRootElement(this.element, this.nsURI, this.nsPrefix);
  +        
  +        // Get actual parts, potentially filtered by the view
  +        Part[] actualParts;
  +        String cocoonView = env.getView();
  +        if (cocoonView == null) {
  +            // Keep all parts
  +            actualParts = this.parts;
  +
  +        } else {
  +            // Keep only those parts that are in the view
  +            actualParts = new Part[this.parts.length];
  +            for (int i = 0; i < actualParts.length; i++) {
  +                if (this.partViews[i] != null && this.partViews[i].containsKey(cocoonView)) {
  +                    // this part is in the view
  +                    actualParts[i] = this.parts[i];
  +                } else {
  +                    if (infoEnabled) {
  +                        getLogger().info("Aggregate part " + (i+1) + " is not in the '" +
  +                            cocoonView + "' view, at " + this.getLocation());
  +                    }
  +                }
  +            }
  +        }
   
           // Add parts
  -        for (int i = 0; i < parts.length; i++) {
  -            Part part = parts[i];
  -            // FIXME : update ContentAggregator to accept boolean for stripRoot
  -            aggregator.addPart(part.source.resolve(mapStack),
  -                part.element, part.nsURI, String.valueOf(part.stripRoot), part.nsPrefix
  -            );
  +        for (int i = 0; i < actualParts.length; i++) {
  +            Part part = actualParts[i];
  +            if (part != null) {
  +                // FIXME : update ContentAggregator to accept boolean for stripRoot
  +                aggregator.addPart(part.source.resolve(mapStack),
  +                    part.element, part.nsURI, String.valueOf(part.stripRoot), part.nsPrefix
  +                );
  +            }
  +        }
  +        
  +        // Check aggregate-level view
  +        if (cocoonView != null && this.views != null) {
  +            ProcessingNode viewNode = (ProcessingNode)this.views.get(cocoonView);
  +            if (viewNode != null) {
  +                if (infoEnabled) {
  +                    getLogger().info("Jumping to view '" + cocoonView + "' from aggregate at " + this.getLocation());
  +                }
  +                return viewNode.invoke(env, context);
  +            }
           }
           
           // Return false to continue sitemap invocation
  @@ -87,5 +149,4 @@
           private String nsPrefix;
           private boolean stripRoot;
       }
  -    
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +43 -9     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/AggregateNodeBuilder.java
  
  Index: AggregateNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/AggregateNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AggregateNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ AggregateNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -15,36 +15,53 @@
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  +import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
  +
   import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class AggregateNodeBuilder extends AbstractProcessingNodeBuilder {
  +public class AggregateNodeBuilder extends AbstractProcessingNodeBuilder
  +  implements LinkedProcessingNodeBuilder {
  +    
  +    /** The collection of views for each part */
  +    private List partViews;
  +    
  +    /** The views for the whole aggregate element */
  +    private Collection views;
  +    
  +    private AggregateNode node;
   
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
           // Get root node data
  -        AggregateNode node = new AggregateNode(
  +        this.node = new AggregateNode(
               config.getAttribute("element"),
               config.getAttribute("ns", ""),
               config.getAttribute("prefix", "")
           );
  -        this.treeBuilder.setupNode(node, config);
  +        this.treeBuilder.setupNode(this.node, config);
  +        
  +        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement("", "", config);
           
           // Build parts
           List parts = new ArrayList();
           
  +        this.partViews = new ArrayList();
  +        
           Configuration[] childConfigs = config.getChildren();
           for (int i = 0; i < childConfigs.length; i++) {
               Configuration childConfig = childConfigs[i];
               
               if (!"part".equals(childConfig.getName())) {
  -                throw new ConfigurationException("Unknown element '" + childConfig.getName() +
  -                    "' at " + childConfig.getLocation());
  +                String msg = "Unknown element '" + childConfig.getName() + " in aggregate ' at " +
  +                    childConfig.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
               }
               
               checkNamespace(childConfig);
  @@ -56,11 +73,14 @@
                   childConfig.getAttribute("prefix", ""),
                   childConfig.getAttributeAsBoolean("strip-root", false)
               ));
  +            
  +            this.partViews.add(((SitemapLanguage)this.treeBuilder).getViewsForStatement("", "", childConfig));
           }
           
           if (parts.size() == 0) {
  -            throw new ConfigurationException("There must be at least one part in map:aggregate at " +
  -                config.getLocation());
  +            String msg = "There must be at least one part in map:aggregate at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
           
           AggregateNode.Part[] partArray = (AggregateNode.Part[])parts.toArray(
  @@ -71,4 +91,18 @@
           return node;
           
       }
  -}
  \ No newline at end of file
  +
  +    public void linkNode() throws Exception {
  +        
  +        SitemapLanguage sitemap = (SitemapLanguage)this.treeBuilder;
  +        
  +        // Replace all contents of partViews by the map of views.
  +        Map[] partViewNodes = new Map[this.partViews.size()];
  +        
  +        for (int i = 0; i < partViewNodes.length; i++) {
  +            partViewNodes[i] = sitemap.getViewNodes((Collection)this.partViews.get(i));
  +        }
  +        
  +        this.node.setViews(sitemap.getViewNodes(this.views), partViewNodes);
  +    }
  +}
  
  
  
  1.2       +8 -18     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/CallNode.java
  
  Index: CallNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/CallNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CallNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ CallNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,36 +8,26 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.avalon.framework.component.Component;
  -import org.apache.avalon.framework.component.ComponentSelector;
  -import org.apache.avalon.framework.component.ComponentException;
  -import org.apache.avalon.framework.parameters.Parameters;
  -import org.apache.avalon.framework.thread.ThreadSafe;
  +import org.apache.avalon.framework.activity.Initializable;
   
  -import org.apache.cocoon.acting.Action;
   import org.apache.cocoon.environment.Environment;
  -import org.apache.cocoon.environment.Redirector;
  -import org.apache.cocoon.environment.SourceResolver;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
  -import org.apache.cocoon.components.pipeline.StreamPipeline;
   
   import org.apache.cocoon.sitemap.PatternException;
  -import org.apache.cocoon.sitemap.SitemapRedirector;
   
  +import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
   import org.apache.cocoon.treeprocessor.CategoryNode;
  -import org.apache.cocoon.treeprocessor.ProcessingNode;
   import org.apache.cocoon.treeprocessor.InvokeContext;
  -import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.List;
   import java.util.Map;
  -import org.apache.avalon.framework.activity.Initializable;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class CallNode extends AbstractProcessingNode
  @@ -96,8 +86,8 @@
               // Resolved resource name
               String name = this.resourceResolver.resolve(context.getMapStack());
               
  -            if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Calling resource " + name);
  +            if (getLogger().isInfoEnabled()) {
  +                getLogger().info("Calling resource " + name);
               }
               
               result = this.resources.invokeByName(name, env, context);
  @@ -108,4 +98,4 @@
           }
           return result;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +13 -3     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/CallNodeBuilder.java
  
  Index: CallNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/CallNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CallNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ CallNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,8 +9,10 @@
   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.CategoryNode;
   import org.apache.cocoon.treeprocessor.CategoryNodeBuilder;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
  @@ -21,7 +23,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class CallNodeBuilder extends AbstractProcessingNodeBuilder
  @@ -40,9 +42,17 @@
       }
       
       public void linkNode() throws Exception {
  +        CategoryNode resources = CategoryNodeBuilder.getCategoryNode(this.treeBuilder, "resources");
  +        
  +        if (resources == null) {
  +            String msg = "This sitemap contains no resources. Cannot call at " + this.node.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
  +        }
  +        
           this.node.setResource(
  -            CategoryNodeBuilder.getCategoryNode(this.treeBuilder, "resources"),
  +            resources,
               this.resourceName
           );
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +5 -367    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ComponentsNodeBuilder.java
  
  Index: ComponentsNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:37 -0000	1.1
  +++ ComponentsNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,390 +8,28 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
  -import org.apache.avalon.excalibur.component.DefaultRoleManager;
  -
  -import org.apache.avalon.excalibur.logger.LogKitManager;
  -import org.apache.avalon.excalibur.logger.LogKitManageable;
  -
  -import org.apache.avalon.framework.component.Component;
  -
  -import org.apache.avalon.framework.context.Context;
  -import org.apache.avalon.framework.context.Contextualizable;
  -
  -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.configuration.DefaultConfiguration;
  -
  -import org.apache.avalon.framework.component.Composable;
  -import org.apache.avalon.framework.component.ComponentException;
  -import org.apache.avalon.framework.component.ComponentManager;
  -import org.apache.avalon.framework.component.ComponentSelector;
  -
  -import org.apache.cocoon.generation.Generator;
  -import org.apache.cocoon.transformation.Transformer;
  -
  -import org.apache.cocoon.sitemap.SitemapComponentSelector;
   
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
  -import org.apache.cocoon.treeprocessor.LifecycleHelper;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
  -import org.apache.cocoon.treeprocessor.TreeBuilder;
  -
  -import org.apache.cocoon.util.ClassUtils;
  -
  -import java.util.*;
   
   /**
  - * Handles &lt;map:components&gt;. It doesn't actually create a <code>ProcessingNode</code>,
  - * but creates <code>ComponentSelectors</code> that are made available to other nodes.
  + * 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 $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class ComponentsNodeBuilder extends AbstractProcessingNodeBuilder implements
  -  Composable, Configurable, Contextualizable, LogKitManageable {
  -
  -    private static final String COMPONENTS_ATTRIBUTE = ComponentsNodeBuilder.class.getName();
  -    
  -    private Context context;
  -    
  -    private LogKitManager logKit;
  -
  -    private ComponentManager parentManager;
  -    
  -    protected ComponentManager manager;
  -    
  -    /** The selector for each role */
  -    private HashMap selectors = new HashMap();
  -    
  -    /** The element name for each section name */
  -    protected Map sectionElements = new HashMap();
  -    
  -    /** The role name for each section name */
  -    protected Map sectionRoles = new HashMap();
  -    
  -    /** The default type for each role name (used for static lookup methods) */
  -    protected Map defaultTypes = new HashMap();
  -        
  -    public void contextualize(Context context) {
  -        this.context = context;
  -    }
  -    
  -    public void setLogKitManager(LogKitManager logKit) {
  -        this.logKit = logKit;
  -    }
  -
  -    public void compose(ComponentManager manager) throws ComponentException {
  -        this.manager = manager;
  -    }
  +public class ComponentsNodeBuilder extends AbstractProcessingNodeBuilder {
   
  -    public void configure(Configuration config) throws ConfigurationException {
  -        
  -        // Iterate on all "section" children
  -        Configuration[] sectionsConfig = config.getChildren("selector");
  -        for (int i = 0; i < sectionsConfig.length; i++) {
  -            
  -            Configuration sectionConfig = sectionsConfig[i];
  -            
  -            // "section" : name of the section
  -            String name = sectionConfig.getAttribute("section");
  -            
  -            // "elements" : name of elements in the section
  -            sectionElements.put(name, sectionConfig.getAttribute("elements"));
  -            
  -            // "role" : role of the Selector in the component manager
  -            sectionRoles.put(name, sectionConfig.getAttribute("role"));
  -            
  -        }
  -    }
  -    
       /** This builder has no parameters -- return <code>false</code> */
       protected boolean hasParameters() {
  -        return true;
  +        return false;
       }
   
  -    /**
  -     * Build a <code>ComponentSelector</code> for each component section and add it
  -     * 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
  -     *
  -     * @return null (nothing to do at runtime).
  -     */
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        // Iterate on all sections
  -        Configuration[] sections = config.getChildren();
  -        for (int sectIdx = 0; sectIdx < sections.length; sectIdx++) {
  -            
  -            Configuration section = sections[sectIdx];
  -            checkNamespace(section);
  -            String sectionName = section.getName();
  -            
  -            // Is it a known section ?
  -            String elementName = (String)this.sectionElements.get(sectionName);
  -            if (elementName == null) {
  -                // Unknown section
  -                throw new ConfigurationException("Unknown section named '" + sectionName +
  -                    "', at " + section.getLocation());
  -            }
  -            
  -            String role = (String)this.sectionRoles.get(sectionName);
  -            
  -            // default component
  -            String defaultElement = section.getAttribute("default", null);
  -            if (defaultElement == null) {
  -                getLogger().debug("Component section '" + sectionName + "' has no default");
  -            } else {
  -                getLogger().debug("Setting default " + elementName + " type to " + defaultElement);
  -                this.defaultTypes.put(role, defaultElement);
  -            }
  -
  -            // Create the selector for this section
  -            getLogger().debug("Creating component selector for " + sectionName);
  -            
  -            SitemapComponentSelector selector = getSelector(role);
  -            SitemapComponentSelector parentSelector = getParentSelector(role);
  -
  -            // Iterate on all components
  -            Configuration[] elements = section.getChildren();
  -            for (int compIdx = 0; compIdx < elements.length; compIdx++) {
  -                
  -                Configuration element = elements[compIdx];
  -                checkNamespace(element);
  -                
  -                // Is it the right name ?
  -                if (! element.getName().equals(elementName)) {
  -                    throw new ConfigurationException("Unknown element named '" + element.getName() +
  -                        ", at " + element.getLocation());
  -                }
  -                
  -                // Get the element name
  -                String name = element.getAttribute("name");
  -                
  -                // Get the class
  -                String className = element.getAttribute("src");
  -                Class clazz;
  -                try {
  -                    clazz = ClassUtils.loadClass(className);
  -                } catch(Exception e) {
  -                    throw new ConfigurationException("Cannot load class '" + className +
  -                        "' for " + elementName + " '" + name + "', at " + element.getLocation(), e);
  -                }
  -                
  -                // Get the mime-type, if any
  -                String mimeType = element.getAttribute("mime-type", null);
  -                
  -                // Register the component
  -                getLogger().debug("Adding " + elementName + " '" + name + "' class=" + clazz.getName());
  -                if (mimeType == null) {                
  -                    selector.addComponent(name, clazz, element);
  -                } else {
  -                    selector.addSitemapComponent(name, clazz, element, mimeType);
  -                }
  -                
  -                if (name.equals(defaultElement)) {
  -                    // Clear default to mark it as found
  -                    defaultElement = null;
  -                }
  -            } // end for elements
  -            
  -            if (defaultElement != null && parentSelector != null) {
  -                // Default not found : does it exist in parent ?
  -                try {
  -                    Component comp = parentSelector.select(defaultElement);
  -                    parentSelector.release(comp);
  -                    // Found in parent
  -                    defaultElement = null;
  -                } catch(Exception e) {
  -                    // Not found in parent
  -                }
  -            }
  -            
  -            if (defaultElement != null) {
  -                // Really not found
  -                throw new ConfigurationException("Default element '" + defaultElement +
  -                    "' does not exist, at " + section.getLocation());
  -            }
  -            
  -        } // end for sections
  -        
  -        // Add any additional components
  -        addAdditionalComponents();
  -        
  -        // Initialize selectors and publish them in the builder's component manager
  -        Iterator iter = this.selectors.entrySet().iterator();
  -        while(iter.hasNext()) {
  -            Map.Entry entry = (Map.Entry)iter.next();
  -            
  -            String role = (String)entry.getKey();
  -            SitemapComponentSelector selector = (SitemapComponentSelector)entry.getValue();
  -            
  -            selector.initialize();
  -            
  -            this.treeBuilder.addComponentInstance(role, selector);
  -            
  -        }
  -        
  -        // Register ourself in the treebuilder for use in static lookup methods below.
  -        this.treeBuilder.setAttribute(COMPONENTS_ATTRIBUTE, this);
  -        
  +        // Nothing more here. To be removed ;)
           return null;
       }
  -    
  -    protected SitemapComponentSelector getParentSelector(String role) {
  -        try {
  -            return (SitemapComponentSelector)this.manager.lookup(role);
  -        } catch (ComponentException ce) {
  -            return null;
  -        }
  -    }
  -
  -    /**
  -     * Get a selector for a role, and create one if none already exist.
  -     */
  -    protected SitemapComponentSelector getSelector(String role) throws Exception {
  -        
  -        SitemapComponentSelector result = (SitemapComponentSelector)this.selectors.get(role);
  -        
  -        if (result == null) {
  -
  -            getLogger().debug("Creating selector for role " + role);
  -
  -            // Prepare an empty role manager
  -            DefaultRoleManager emptyRoleManager = new DefaultRoleManager();
  -            emptyRoleManager.setLogger(getLogger());
  -            emptyRoleManager.configure(new DefaultConfiguration("role-list", "-"));
  -            
  -            DefaultConfiguration selectorConfig = new DefaultConfiguration("component", "-");
  -            selectorConfig.setAttribute("role", role);
  -            
  -            result = new SitemapComponentSelector();
  -            LifecycleHelper.setupComponent(
  -                result,
  -                getLogger(),
  -                this.context,
  -                this.manager,
  -                emptyRoleManager,
  -                this.logKit,
  -                selectorConfig,
  -                false // don't initialize
  -            );
  -
  -            // Chain with parent processor selector, if any
  -            SitemapComponentSelector parentSelector = getParentSelector(role);
  -            if (parentSelector != null) {
  -                result.setParentSelector(parentSelector);
  -            }
  -            
  -            // Add in selector map
  -            this.selectors.put(role, result);
  -        }
  -            
  -        return result;
  -    }
  -    
  -    /**
  -     * Add additional components not described in the configuration file.
  -     */
  -    protected void addAdditionalComponents() throws Exception {
  -        
  -        DefaultConfiguration emptyConfig = new DefaultConfiguration("", "");
  -        
  -        SitemapComponentSelector generators = getSelector(Generator.ROLE + "Selector");
  -        
  -        generators.addComponent("!error-notifier!", org.apache.cocoon.sitemap.ErrorNotifier.class, emptyConfig);
  -        generators.addComponent("!content-aggregator!", org.apache.cocoon.sitemap.ContentAggregator.class, emptyConfig);
  -        
  -        SitemapComponentSelector transformers = getSelector(Transformer.ROLE + "Selector");
  -        transformers.addComponent("!link-translator!", org.apache.cocoon.sitemap.LinkTranslator.class, emptyConfig);
  -    }
  -
  -    //----- lookup methods for other builders
  -    
  -    /**
  -     * Get the actual type for an element defined by <code>config</code>. If there is
  -     * no 'type' attribute, the default type for this role is returned.
  -     *
  -     * @throws ConfigurationException if no type is given and there is no default type
  -     *         defined for this role, or if there is no definition for the given type.
  -     */
  -    public static final String getComponentType(String role, Configuration config, TreeBuilder treeBuilder)
  -      throws ConfigurationException {
  -        
  -        ComponentsNodeBuilder components =
  -            (ComponentsNodeBuilder)treeBuilder.getAttribute(COMPONENTS_ATTRIBUTE);
  -
  -        if (components == null) {
  -            throw new ConfigurationException("Cannot find components definition to handle " +
  -                config.getName() + " at " + config.getLocation());
  -        }
  -        
  -        return components.doGetComponentType(role, config);
  -    }
  -    
  -    /**
  -     * Get the class for a type and role.
  -     */
  -    public static final Class getComponentClass(String role, String type, TreeBuilder treeBuilder)
  -      throws Exception {
  -        
  -        ComponentsNodeBuilder components =
  -            (ComponentsNodeBuilder)treeBuilder.getAttribute(COMPONENTS_ATTRIBUTE);
  -
  -        if (components == null) {
  -            // Cannot give location information here, but this is unlikely
  -            // to happen since users of this method generally call getComponentType()
  -            // before this one.
  -            throw new ConfigurationException("Cannot find components definition");
  -        }
  -        
  -        return components.doGetComponentClass(role, type);
  -    }
  -    
  -    private String doGetComponentType(String role, Configuration config) throws ConfigurationException {
  -        
  -        String type = config.getAttribute("type", null);
  -        if (type == null) {
  -            type = (String)this.defaultTypes.get(role);
  -        }
  -        
  -        if (type == null) {
  -            throw new ConfigurationException(
  -                "There is no default type defined for " +
  -                config.getName() + " at " + config.getLocation());
  -        }
  -        
  -        return type;
  -    }
  -    
  -    private Class doGetComponentClass(String role, String type) throws Exception {
  -
  -        Class result = null;
  -
  -        // Is there a selector explicitly defined for this role ?
  -        // (cannot directly lookup manager since locally-defined selectors aren't yet visible)
  -        ComponentSelector selector = getSelector(role);
  -        if (selector == null) {
  -            // Try parent
  -            selector = getParentSelector(role);
  -        }
  -        
  -        if (selector == null) {
  -            throw new IllegalArgumentException("Cannot find a selector for role " + role);
  -        }
  -        
  -        Component object = selector.select(type);
  -        result = object.getClass();
  -        selector.release(object);
  -        
  -        return result;
  -    }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +34 -8     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GenerateNode.java
  
  Index: GenerateNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GenerateNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GenerateNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ GenerateNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,21 +8,23 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.components.pipeline.EventPipeline;
  -import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.sitemap.PatternException;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
  +import org.apache.cocoon.treeprocessor.CategoryNode;
  +import org.apache.cocoon.treeprocessor.InvokeContext;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
  -
  -import java.util.List;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
  -import org.apache.cocoon.treeprocessor.InvokeContext;
  -import java.util.Map;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
  +
  +import java.util.*;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class GenerateNode extends AbstractProcessingNode implements ParameterizableProcessingNode {
  @@ -32,6 +34,11 @@
       private MapStackResolver source;
       
       private Map parameters;
  +    
  +    private Map views;
  +    
  +    /** The category node */
  +    private CategoryNode viewsNode;
   
       public GenerateNode(String name, String source) throws PatternException {
           this.generatorName = name;
  @@ -42,6 +49,10 @@
           this.parameters = parameterMap;
       }
       
  +    public void setViews(Map views) {
  +        this.views = views;
  +    }
  +    
       public final boolean invoke(Environment env, InvokeContext context)
         throws Exception {
           
  @@ -53,7 +64,22 @@
               MapStackResolver.buildParameters(this.parameters, mapStack)
           );
           
  +        // Check view
  +        String cocoonView = env.getView();
  +        if (cocoonView != null && this.views != null) {
  +            
  +            // Get view node
  +            ProcessingNode viewNode = (ProcessingNode)this.views.get(cocoonView);
  +            
  +            if (viewNode != null) {
  +                if (getLogger().isInfoEnabled()) {
  +                    getLogger().info("Jumping to view " + cocoonView + " from generator at " + this.getLocation());
  +                }
  +                return viewNode.invoke(env, context);
  +            }
  +        }
  +        
           // Return false to contine sitemap invocation
           return false;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +23 -10    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GenerateNodeBuilder.java
  
  Index: GenerateNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/GenerateNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- GenerateNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ GenerateNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,28 +9,41 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.configuration.Configuration;
  -import org.apache.avalon.framework.configuration.ConfigurationException;
  -import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.generation.Generator;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  +import java.util.*;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class GenerateNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
  +public class GenerateNodeBuilder extends AbstractProcessingNodeBuilder
  +  implements LinkedProcessingNodeBuilder {
   
  +    private GenerateNode node;
  +    
  +    private Collection views;
  +    
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        String type = ComponentsNodeBuilder.getComponentType(
  -            Generator.ROLE + "Selector", config, this.treeBuilder);
  -
  -        String src  = config.getAttribute("src", null);
  +        String type = this.treeBuilder.getTypeForStatement(config, Generator.ROLE + "Selector");
           
  -        return this.treeBuilder.setupNode(new GenerateNode(type, src), config);
  +        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement(Generator.ROLE, type, config);
  +        
  +        this.node = new GenerateNode(type, config.getAttribute("src", null));        
  +        return this.treeBuilder.setupNode(this.node, config);
  +    }
  +    
  +    public void linkNode() throws Exception {
  +        this.node.setViews(
  +            ((SitemapLanguage)this.treeBuilder).getViewNodes(this.views)
  +        );
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +10 -8     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/HandleErrorsNode.java
  
  Index: HandleErrorsNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/HandleErrorsNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HandleErrorsNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ HandleErrorsNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,18 +8,17 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.Composable;
  -import org.apache.avalon.framework.activity.Disposable;
  +import org.apache.avalon.framework.parameters.Parameters;
   
   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 org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.*;
   
  @@ -27,7 +26,7 @@
    * Handles &lt;map:handle-errors&gt;
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public final class HandleErrorsNode extends AbstractParentProcessingNode {
  @@ -51,9 +50,12 @@
       public final boolean invoke(Environment env, InvokeContext context)
         throws Exception {
           
  -        if (getLogger().isDebugEnabled()) {
  -            getLogger().debug("Processing handle-errors at " + getLocation());
  +        if (getLogger().isInfoEnabled()) {
  +            getLogger().info("Processing handle-errors at " + getLocation());
           }
  +        
  +        context.getEventPipeline().setGenerator("!notifying-generator!", "", Parameters.EMPTY_PARAMETERS);
  +            
           return invokeNodes(this.children, env, context);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/HandleErrorsNodeBuilder.java
  
  Index: HandleErrorsNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/HandleErrorsNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HandleErrorsNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ HandleErrorsNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -18,7 +18,7 @@
    * Builds a &lt;map:handle-errors&gt;
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class HandleErrorsNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
  @@ -38,4 +38,4 @@
           
           return node;  
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +12 -6     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MatchNode.java
  
  Index: MatchNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MatchNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MatchNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ MatchNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -23,14 +23,16 @@
   import java.util.*;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
   import java.util.Map;
  +import org.apache.avalon.framework.component.Composable;
  +import org.apache.avalon.framework.component.ComponentManager;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class MatchNode extends SimpleSelectorProcessingNode implements ParameterizableProcessingNode {
  +public class MatchNode extends SimpleSelectorProcessingNode implements ParameterizableProcessingNode, Composable {
       
       /** The 'pattern' attribute */
       private MapStackResolver pattern;
  @@ -49,8 +51,11 @@
           this.parameters = parameterMap;
       }
   
  -    public void setSelector(ComponentSelector selector) throws Exception {
  -        super.setSelector(selector);
  +    public void compose(ComponentManager manager) throws ComponentException {
  +        
  +        super.setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + "Selector"));
  +        
  +        // Get matcher if it's ThreadSafe
           this.threadSafeMatcher = (Matcher)this.getThreadSafeComponent();
       }
       
  @@ -81,8 +86,9 @@
           }
           
           if (result != null) {
  -            if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Matcher '" + this.componentName + "' matched pattern '" + this.pattern + "'");
  +            if (getLogger().isInfoEnabled()) {
  +                getLogger().info("Matcher '" + this.componentName + "' matched pattern '" + this.pattern +
  +                    "' at " + this.getLocation());
               }
               
               // Invoke children with the matcher results
  
  
  
  1.2       +21 -20    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MatchNodeBuilder.java
  
  Index: MatchNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MatchNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MatchNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ MatchNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -27,16 +27,15 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class MatchNodeBuilder extends AbstractParentProcessingNodeBuilder
  -  implements Composable, LinkedProcessingNodeBuilder {
  +  implements Composable {
   
       private static final String SELECTOR_ROLE = Matcher.ROLE + "Selector";
   
       private ComponentManager manager;
  -    private SimpleSelectorProcessingNode node;
   
       public void compose(ComponentManager manager) {
           this.manager = manager;
  @@ -46,9 +45,15 @@
           
           String pattern = config.getAttribute("pattern", null);
           
  +        String type = this.treeBuilder.getTypeForStatement(config, SELECTOR_ROLE);
  +
           // Get the type and class for this matcher
  -        String type = ComponentsNodeBuilder.getComponentType(SELECTOR_ROLE, config, this.treeBuilder);
  -        Class clazz = ComponentsNodeBuilder.getComponentClass(SELECTOR_ROLE, type, this.treeBuilder);
  +        ComponentsSelector selector = (ComponentsSelector)this.manager.lookup(SELECTOR_ROLE);
  +        
  +        // Find matcher class
  +        Matcher matcher = (Matcher)selector.select(type);
  +        Class clazz = matcher.getClass();
  +        selector.release(matcher);
       
           // PreparableMatcher are only prepared if pattern doesn't need request-time resolution.
           boolean preparable =
  @@ -56,31 +61,27 @@
               !MapStackResolver.needsResolve(pattern);
           
           // Instanciate appropriate node
  +        SimpleSelectorProcessingNode node;
  +        
           if (preparable) {
  -            this.node = new PreparableMatchNode(type, pattern);
  +            node = new PreparableMatchNode(type, pattern);
           } else {
  -            this.node = new MatchNode(type, pattern);
  +            node = new MatchNode(type, pattern);
           }
           
  -        this.treeBuilder.setupNode(this.node, config);
  +        this.treeBuilder.setupNode(node, config);
           
           // Get all children
           ProcessingNode[] children = buildChildNodes(config);
           
           if (children.length == 0) {
  -            throw new ConfigurationException("There must be at least one child in match at " +
  -                config.getLocation());
  +            String msg = "There must be at least one child in match at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
          
  -        this.node.setChildren(children);
  -        
  -        return this.node;
  -    }
  -
  -    public void linkNode() throws Exception {
  +        node.setChildren(children);
           
  -        // Get the selector (it's now visible in the manager)
  -        ComponentSelector selector = (ComponentSelector)manager.lookup(SELECTOR_ROLE);
  -        this.node.setSelector(selector);
  +        return node;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +2 -2      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MountNodeBuilder.java
  
  Index: MountNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/MountNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MountNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ MountNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -17,7 +17,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class MountNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
  @@ -37,4 +37,4 @@
           );
           return (this.treeBuilder.setupNode(node, config));
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.3       +49 -49    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNode.java
  
  Index: PipelineNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNode.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PipelineNode.java	15 Jan 2002 07:42:02 -0000	1.2
  +++ PipelineNode.java	15 Jan 2002 11:10:54 -0000	1.3
  @@ -8,15 +8,19 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.Composable;
  -import org.apache.avalon.framework.activity.Disposable;
  +import org.apache.avalon.framework.parameters.Parameters;
   
   import org.apache.cocoon.ConnectionResetException;
  +import org.apache.cocoon.Constants;
   import org.apache.cocoon.ResourceNotFoundException;
   
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.environment.ObjectModelHelper;
  +import org.apache.cocoon.components.notification.Notifying;
  +import org.apache.cocoon.components.notification.NotifyingBuilder;
   import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
  @@ -27,151 +31,147 @@
   import java.util.*;
   
   /**
  - *
  + * 
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 07:42:02 $
  + * @version CVS $Revision: 1.3 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class PipelineNode extends AbstractParentProcessingNode implements Composable {
   
       // 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;
  -
  +    
       /** Is it the last <pipeline> in the enclosing <pipelines> ? */
       private boolean isLast = false;
  -
  +    
       /**
        * The component manager is used to create error pipelines
        */
       public void compose(ComponentManager manager) {
           this.manager = manager;
       }
  -
  +    
       public void setChildren(ProcessingNode[] nodes)
       {
           this.children = nodes;
       }
  -
  +    
       public void setLast(boolean isLast) {
           this.isLast = isLast;
       }
  -
  +    
       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 final boolean invoke(Environment env, InvokeContext context)
         throws Exception {
  -
  +        
           // Always fail on external resquests if internal only.
           if (this.internalOnly && !context.isInternalRequest()) {
               return false;
           }
  -
  +        
           try {
  -
  +            
               if (invokeNodes(children, env, context)) {
                   return true;
               } else if (this.isLast) {
  -                throw new ResourceNotFoundException("No pipeline matched request: " +
  -                    env.getURIPrefix() + '/' + env.getURI());
  +                String msg = "No pipeline matched request: " + env.getURIPrefix() + '/' + env.getURI();
  +                getLogger().info(msg);
  +                throw new ResourceNotFoundException(msg);
               } else {
                   return false;
               }
  -
  +            
           } catch (ConnectionResetException cre) {
               // Will be reported by CocoonServlet, rethrowing
               throw cre;
   
           } catch(ResourceNotFoundException rnfe) {
               getLogger().warn("Resource not found in pipeline at " + getLocation(), rnfe);
  -
  +            
               if (error404 != null) {
                   // There's a handler
                   return invokeErrorHandler(error404, rnfe, env);
  -
  +                
               } else {
                   // No handler : propagate
                   throw rnfe;
               }
   
           } catch(Exception e) {
  -
  +            
               // Rethrow exception for internal requests
               if (error500 != null && !context.isInternalRequest()) {
  -
  +                
                   getLogger().warn("Error while processing pipeline at " + getLocation(), e);
  -
  +                
                   return invokeErrorHandler(error500, e, env);
  -
  +                
               } else {
                   // No handler : propagate
  -
  +                
                   getLogger().error("Error while processing pipeline at " + getLocation(), e);
                   throw e;
               }
           }
       }
  -
  +    
       private boolean invokeErrorHandler(ProcessingNode node, Exception ex, Environment env)
         throws Exception {
   
           InvokeContext errorContext = null;
  -
  +        
           try {
  -            tryResetResponse(env);
  -
  +            // Try to reset the response to avoid mixing already produced output
  +            // and error page.
  +            env.tryResetResponse();
  +            
               // Build a new context
               errorContext = new InvokeContext();
               errorContext.compose(this.manager);
  +            
  +            // Create a Notifying
  +            NotifyingBuilder notifyingBuilder= (NotifyingBuilder)this.manager.lookup(NotifyingBuilder.ROLE);
  +            Notifying currentNotifying = notifyingBuilder.build(this, ex);
  +            this.manager.release(notifyingBuilder);
  +            
  +            // Add it to the object model
  +            env.getObjectModel().put(Constants.NOTIFYING_OBJECT, currentNotifying );
   
  -            errorContext.getEventPipeline().setGenerator("!error-notifier!", ex.getMessage(),
  -                MapStackResolver.EMPTY_PARAMETERS, ex);
  -
  +            // notifying-generator is added in HandleErrorsNode
               return node.invoke(env, errorContext);
  -
  +            
           } catch (Exception subEx) {
               getLogger().error("error notifier barfs", subEx);
               return false;
  -
  +            
           } finally {
               if (errorContext != null) {
                   errorContext.dispose();
               }
           }
       }
  -
  -    /**
  -     * 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)
  -    {
  -        env.tryResetResponse();
  -    }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +8 -5      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNodeBuilder.java
  
  Index: PipelineNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelineNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PipelineNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ PipelineNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -22,7 +22,7 @@
    * Builds a &lt;map:pipeline&gt;
    
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class PipelineNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
  @@ -60,7 +60,9 @@
                   
                   if ( (type == 404 && error404Handler != null) ||
                        (type == 500 && error500Handler != null) ) {
  -                    throw new ConfigurationException("Duplicate handle-errors at " + handler.getLocation());
  +                    String msg = "Duplicate handle-errors at " + handler.getLocation();
  +                    getLogger().error(msg);
  +                    throw new ConfigurationException(msg);
                   }
                   
                   if (type == 404) {
  @@ -68,8 +70,9 @@
                   } else if (type == 500) {
                       error500Handler = handler;
                   } else {
  -                    throw new ConfigurationException("Unkown handle-errors type (" + type + ") at " +
  -                        handler.getLocation());
  +                    String msg = "Unkown handle-errors type (" + type + ") at " + handler.getLocation();
  +                    getLogger().error(msg);
  +                    throw new ConfigurationException(msg);
                   }
   
               } else {
  @@ -85,4 +88,4 @@
           return node;
       }
   
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +78 -4     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNode.java
  
  Index: PipelinesNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PipelinesNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ PipelinesNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -14,23 +14,40 @@
   
   import org.apache.cocoon.ResourceNotFoundException;
   
  +import org.apache.cocoon.sitemap.SitemapRedirector;
  +
   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.ContainerNode;
  +import org.apache.cocoon.treeprocessor.EnvironmentSourceResolver;
  +import org.apache.cocoon.treeprocessor.SimpleParentProcessingNode;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   import org.apache.cocoon.treeprocessor.InvokeContext;
   
   import java.util.*;
  +import org.apache.avalon.framework.component.ComponentException;
   
   /**
    * Handles &lt;map:pipelines&gt;
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public final class PipelinesNode extends ContainerNode {
  +public final class PipelinesNode extends SimpleParentProcessingNode
  +  implements Composable, Disposable {
  +
  +    private static final String REDIRECTOR_ATTR = "sitemap:redirector";
  +    
  +    private ComponentManager manager;
  +    
  +    /**
  +     * Keep the component manager used everywhere in the tree so that we can
  +     * cleanly dispose it.
  +     */
  +    public void compose(ComponentManager manager) {
  +        this.manager = manager;
  +    }
   
       public void setChildren(ProcessingNode[] nodes)
       {
  @@ -39,4 +56,61 @@
           
           super.setChildren(nodes);
       }
  -}
  \ No newline at end of file
  +
  +    public static SitemapRedirector getRedirector(Environment env) {
  +        return (SitemapRedirector)env.getAttribute(REDIRECTOR_ATTR);
  +    }
  +    
  +    /**
  +     * 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.
  +     */
  +    public boolean invoke(Environment env, InvokeContext context)
  +      throws Exception {
  +        
  +        // Recompose context (and pipelines) to the local component manager
  +        context.recompose(this.manager);
  +
  +        // Create the source resolver relative to the environment.
  +        
  +        // Design note : creating the SourceResolver could also have been done
  +        // in TreeProcessor.invoke(), but doing it here ensures we use the local
  +        // component manager used by all other nodes.
  +        EnvironmentSourceResolver resolver = new EnvironmentSourceResolver(this.manager, env);
  +        SitemapRedirector redirector = new SitemapRedirector(env);
  +        
  +        Map objectModel = env.getObjectModel();
  +        
  +        Object oldResolver = objectModel.get(OBJECT_SOURCE_RESOLVER);
  +        Object oldRedirector = env.getAttribute(REDIRECTOR_ATTR);
  +
  +        objectModel.put(OBJECT_SOURCE_RESOLVER, resolver);
  +        env.setAttribute(REDIRECTOR_ATTR, redirector);
  +
  +        try {
  +            // FIXME : is there any useful information that can be passed as top-level parameters,
  +            //         such as the URI of the mount point ?
  +            
  +            return invokeNodes(this.children, env, context);
  +            
  +        } finally {
  +
  +            // Restore old redirector and resolver
  +            env.setAttribute(REDIRECTOR_ATTR, oldRedirector);
  +            objectModel.put(OBJECT_SOURCE_RESOLVER, oldResolver);
  +            
  +            // Dispose the resolver
  +            resolver.dispose();
  +        }
  +    }
  +    
  +    /**
  +     * Dispose the component manager.
  +     */
  +    public void dispose() {
  +        if (this.manager instanceof Disposable) {
  +            ((Disposable)this.manager).dispose();
  +        }
  +    }    
  +}
  
  
  
  1.2       +14 -3     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNodeBuilder.java
  
  Index: PipelinesNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PipelinesNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PipelinesNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ PipelinesNodeBuilder.java	15 Jan 2002 11:10:54 -0000	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.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.treeprocessor.ContainerNodeBuilder;
  @@ -18,14 +19,24 @@
    * Builds a &lt;map:pipelines&gt;
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class PipelinesNodeBuilder extends ContainerNodeBuilder implements ThreadSafe {
   
       public ProcessingNode buildNode(Configuration config) throws Exception {
           PipelinesNode node = new PipelinesNode();
  -        this.setupNode(node, config);
  +        this.treeBuilder.setupNode(node, config);
  +        
  +        ProcessingNode[] children = buildChildNodes(config);
  +        if (children.length == 0) {
  +            String msg = "There must be at least one pipeline at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
  +        }
  +            
  +        node.setChildren(children);
  +        
           return node;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +16 -7     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PreparableMatchNode.java
  
  Index: PreparableMatchNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/PreparableMatchNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PreparableMatchNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ PreparableMatchNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -14,24 +14,26 @@
   import org.apache.cocoon.sitemap.PatternException;
   import org.apache.cocoon.treeprocessor.SimpleSelectorProcessingNode;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.matching.Matcher;
   import org.apache.cocoon.matching.PreparableMatcher;
   import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
  +import org.apache.avalon.framework.component.Composable;
  +import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.thread.ThreadSafe;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
   import org.apache.cocoon.treeprocessor.InvokeContext;
   
   import java.util.*;
  -import java.util.Map;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class PreparableMatchNode extends SimpleSelectorProcessingNode implements ParameterizableProcessingNode {
  +public class PreparableMatchNode extends SimpleSelectorProcessingNode implements ParameterizableProcessingNode, Composable {
       
       /** The 'pattern' attribute */
       private String pattern;
  @@ -52,8 +54,10 @@
           this.parameters = parameterMap;
       }
   
  -    public void setSelector(ComponentSelector selector) throws Exception {
  -        super.setSelector(selector);
  +
  +    public void compose(ComponentManager manager) throws ComponentException {
  +
  +        setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + "Selector"));
           
           // Prepare the pattern, and keep matcher if ThreadSafe
           PreparableMatcher matcher = (PreparableMatcher)selector.select(componentName);
  @@ -64,6 +68,11 @@
           
           try {
               this.preparedPattern = matcher.preparePattern(MapStackResolver.unescape(this.pattern));
  +            
  +        } catch(PatternException pe) {
  +            String msg = "Invalid pattern '" + this.pattern + "' for matcher at " + this.getLocation();
  +            getLogger().error(msg, pe);
  +            throw new ComponentException(msg, pe);
   
           } finally {
               if (this.threadSafeMatcher == null) {
  @@ -96,8 +105,8 @@
           }
           
           if (result != null) {
  -            if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Matcher '" + this.componentName + "' matched prepared pattern '" +
  +            if (getLogger().isInfoEnabled()) {
  +                getLogger().info("Matcher '" + this.componentName + "' matched prepared pattern '" +
                       this.pattern + "' at " + this.getLocation());
               }
               
  
  
  
  1.2       +7 -6      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ReadNode.java
  
  Index: ReadNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ReadNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ReadNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ReadNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,21 +8,22 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.cocoon.environment.Environment;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
   import org.apache.cocoon.components.pipeline.StreamPipeline;
  +import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.sitemap.PatternException;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
  -import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
   
   import java.util.List;
  -import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
   import java.util.Map;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ReadNode extends AbstractProcessingNode implements ParameterizableProcessingNode {
  @@ -94,4 +95,4 @@
               return true;
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +4 -4      xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ReadNodeBuilder.java
  
  Index: ReadNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ReadNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ReadNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ ReadNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -13,21 +13,21 @@
   import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.reading.Reader;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class ReadNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
   
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        String type = ComponentsNodeBuilder.getComponentType(
  -            Reader.ROLE + "Selector", config, this.treeBuilder);
  +        String type = this.treeBuilder.getTypeForStatement(config, Reader.ROLE + "Selector");
           
           ReadNode node = new ReadNode(
               type,
  @@ -38,4 +38,4 @@
   
           return this.treeBuilder.setupNode(node, config);
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +16 -4     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/RedirectToNodeBuilder.java
  
  Index: RedirectToNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/RedirectToNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RedirectToNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ RedirectToNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,11 +9,13 @@
   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.CategoryNode;
   import org.apache.cocoon.treeprocessor.CategoryNodeBuilder;
  -import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.*;
  @@ -21,7 +23,7 @@
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class RedirectToNodeBuilder extends AbstractProcessingNodeBuilder
  @@ -59,11 +61,21 @@
       }
       
       public void linkNode() throws Exception {
  +        
           if (this.callNode != null) {
  +            CategoryNode resources = CategoryNodeBuilder.getCategoryNode(this.treeBuilder, "resources");
  +            
  +            if (resources == null) {
  +                String msg = "This sitemap contains no resources. Cannot redirect at " +
  +                    this.callNode.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
  +            }
  +            
               this.callNode.setResource(
  -                CategoryNodeBuilder.getCategoryNode(this.treeBuilder, "resources"),
  +                resources,
                   this.resourceName
               );
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +7 -17     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/RedirectToURINode.java
  
  Index: RedirectToURINode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/RedirectToURINode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RedirectToURINode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ RedirectToURINode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -8,33 +8,23 @@
   
   package org.apache.cocoon.treeprocessor.sitemap;
   
  -import org.apache.avalon.framework.component.Component;
  -import org.apache.avalon.framework.component.ComponentSelector;
  -import org.apache.avalon.framework.component.ComponentException;
  -import org.apache.avalon.framework.parameters.Parameters;
  -import org.apache.avalon.framework.thread.ThreadSafe;
  -
  -import org.apache.cocoon.acting.Action;
   import org.apache.cocoon.environment.Environment;
   import org.apache.cocoon.environment.Redirector;
  -import org.apache.cocoon.environment.SourceResolver;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
  -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.AbstractProcessingNode;
  -import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.List;
   import java.util.Map;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class RedirectToURINode extends AbstractProcessingNode {
  @@ -52,12 +42,12 @@
         throws Exception {
           String resolvedURI = uri.resolve(context.getMapStack());
           
  -        if (getLogger().isDebugEnabled()) {
  -            getLogger().debug("Sitemap: session='" + this.keepSession + "', redirecting to " + resolvedURI);
  +        if (getLogger().isInfoEnabled()) {
  +            getLogger().info("Redirecting to '" + resolvedURI + "' at " + this.getLocation());
           }
   
           env.redirect (this.keepSession, resolvedURI);
   
           return true;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +19 -27    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SelectNode.java
  
  Index: SelectNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SelectNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SelectNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ SelectNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -10,41 +10,40 @@
   
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.Component;
  -import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
  +import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.ComponentSelector;
  +import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.environment.Environment;
  -import org.apache.cocoon.components.pipeline.EventPipeline;
  -import org.apache.cocoon.components.pipeline.StreamPipeline;
  +
   import org.apache.cocoon.selection.Selector;
   
   import org.apache.cocoon.sitemap.PatternException;
   
  -import org.apache.cocoon.treeprocessor.ProcessingNode;
  -import org.apache.cocoon.treeprocessor.AbstractParentProcessingNode;
  +import org.apache.cocoon.treeprocessor.InvokeContext;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
   import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
  -import org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
  +import org.apache.cocoon.treeprocessor.SimpleSelectorProcessingNode;
   
   import java.util.List;
   import java.util.Map;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class SelectNode extends AbstractParentProcessingNode
  -  implements ParameterizableProcessingNode, Disposable {
  +public class SelectNode extends SimpleSelectorProcessingNode
  +  implements ParameterizableProcessingNode, Composable, Disposable {
       
       /** The parameters of this node */
       private Map parameters;
   
  -    /** The action name */
  -    protected String name;
  -    
       /** Selector where to get Actions from */
       protected ComponentSelector componentSelector;
       
  @@ -58,7 +57,7 @@
       private ProcessingNode[] otherwhiseNodes;
   
       public SelectNode(String name) throws PatternException {
  -        this.name = name;
  +        super(name);
       }
       
       public void setParameters(Map parameterMap) {
  @@ -70,20 +69,13 @@
           this.whenTests = whenTests;
           this.otherwhiseNodes = otherwhiseNodes;
       }
  -    
  -    public void setSelector(ComponentSelector componentSelector) throws ComponentException {
  +
  +    public void compose(ComponentManager manager) throws ComponentException {
           
  -        this.componentSelector = componentSelector;
  +        setSelector((ComponentSelector)manager.lookup(Selector.ROLE));
           
  -        // Is it a ThreadSafe selector ?
  -        Selector selector = (Selector)componentSelector.select(name);
  -        if (selector instanceof ThreadSafe) {
  -            // Yes : keep it.
  -            this.threadSafeSelector = selector;
  -        } else {
  -            this.threadSafeSelector = null;
  -            this.componentSelector.release(selector);
  -        }
  +        // Get the selector, if it's ThreadSafe
  +        this.threadSafeSelector = (Selector)this.getThreadSafeComponent();
       }
       
       public final boolean invoke(Environment env, InvokeContext context)
  @@ -113,7 +105,7 @@
               return false;
               
           } else {
  -            Selector selector = (Selector)this.componentSelector.select(this.name);
  +            Selector selector = (Selector)this.componentSelector.select(this.componentName);
               try {
   
                   for (int i = 0; i < this.whenTests.length; i++) {
  @@ -141,4 +133,4 @@
               this.componentSelector.release(this.threadSafeSelector);
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +14 -21    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SelectNodeBuilder.java
  
  Index: SelectNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SelectNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SelectNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ SelectNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -13,35 +13,32 @@
   import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.selection.Selector;
  +
   import org.apache.cocoon.treeprocessor.AbstractParentProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.MapStackResolver;
  -import org.apache.cocoon.treeprocessor.ProcessingNode;
  -import org.apache.cocoon.treeprocessor.AbstractProcessingNode;
   import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class SelectNodeBuilder extends AbstractParentProcessingNodeBuilder
  -  implements Composable, LinkedProcessingNodeBuilder {
  +public class SelectNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
   
       private ComponentManager manager;
       private SelectNode node;
   
  -    public void compose(ComponentManager manager) {
  -        this.manager = manager;
  -    }
  -    
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        String type = ComponentsNodeBuilder.getComponentType(Selector.ROLE + "Selector", config, this.treeBuilder);
  +        String type = this.treeBuilder.getTypeForStatement(config, Selector.ROLE + "Selector");
  +        
           this.node = new SelectNode(type);
           this.treeBuilder.setupNode(this.node, config);
           // Selector is set in linkNode() since it isn't visible now
  @@ -69,8 +66,9 @@
                   
                   checkNamespace(childConfig);
                   if (otherwhiseNodes != null) {
  -                    throw new ConfigurationException("Duplicate " + name + " (only one is allowed) at " +
  -                        childConfig.getLocation());
  +                    String msg = "Duplicate " + name + " (only one is allowed) at " + childConfig.getLocation();
  +                    getLogger().error(msg);
  +                    throw new ConfigurationException(msg);
                   }
                   
                   otherwhiseNodes = buildChildNodes(childConfig);
  @@ -80,7 +78,9 @@
                   
               } else {
                   // Unknown element
  -                throw new ConfigurationException("Unknown element " + name + " at " + childConfig.getLocation());
  +                String msg = "Unknown element '" + name + "' in select at " + childConfig.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
               }
           }
           
  @@ -92,11 +92,4 @@
           
           return this.node;
       }
  -    
  -    public void linkNode() throws Exception {
  -        
  -        // Get the selector (it's now visible in the manager)
  -        ComponentSelector selector = (ComponentSelector)manager.lookup(Selector.ROLE + "Selector");
  -        this.node.setSelector(selector);
  -    }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +28 -5     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SerializeNode.java
  
  Index: SerializeNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SerializeNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SerializeNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ SerializeNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -10,18 +10,20 @@
   
   import org.apache.cocoon.Constants;
   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.MapStackResolver;
   import org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  -import java.util.List;
  +import java.util.*;
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class SerializeNode extends AbstractProcessingNode {
  @@ -32,6 +34,8 @@
       
       private int statusCode;
       
  +    private Map views;
  +    
       /**
        * Build a <code>SerializerNode</code> having a name, a mime-type and a status code (HTTP codes).
        *
  @@ -45,9 +49,28 @@
           this.statusCode = statusCode;
       }
       
  +    public void setViews(Map views) {
  +        this.views = views;
  +    }
  +    
       public final boolean invoke(Environment env, InvokeContext context)
         throws Exception {
           
  +        // Check view
  +        String cocoonView = env.getView();
  +        if (cocoonView != null && this.views != null) {
  +            
  +            // Get view node
  +            ProcessingNode viewNode = (ProcessingNode)this.views.get(cocoonView);
  +            
  +            if (viewNode != null) {
  +                if (getLogger().isInfoEnabled()) {
  +                    getLogger().info("Jumping to view " + cocoonView + " from serializer at " + this.getLocation());
  +                }
  +                return viewNode.invoke(env, context);
  +            }
  +        }
  +
           // Perform link translation if requested
           if (env.getObjectModel().containsKey(Constants.LINK_OBJECT)) {
               context.getEventPipeline().addTransformer(
  @@ -89,4 +112,4 @@
               return true;
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +21 -7     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SerializeNodeBuilder.java
  
  Index: SerializeNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SerializeNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SerializeNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ SerializeNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -13,19 +13,26 @@
   import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.serialization.Serializer;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  -import java.util.Map;
  +import java.util.*;
   
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class SerializeNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
  +public class SerializeNodeBuilder extends AbstractProcessingNodeBuilder
  +  implements LinkedProcessingNodeBuilder {
   
  +    private SerializeNode node;
  +    
  +    private Collection views;
  +    
       /** This builder has no parameters -- return <code>false</code> */
       protected boolean hasParameters() {
           return false;
  @@ -33,14 +40,21 @@
   
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        String type = ComponentsNodeBuilder.getComponentType(
  -            Serializer.ROLE + "Selector", config, this.treeBuilder);
  +        String type = this.treeBuilder.getTypeForStatement(config, Serializer.ROLE + "Selector");
  +        
  +        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement(Serializer.ROLE, type, config);
           
  -        SerializeNode node = new SerializeNode(
  +        this.node = new SerializeNode(
               type,
               config.getAttribute("mime-type", null),
               config.getAttributeAsInteger("status-code", -1)
           );
           return this.treeBuilder.setupNode(node, config);
       }
  -}
  \ No newline at end of file
  +    
  +    public void linkNode() throws Exception {
  +        this.node.setViews(
  +            ((SitemapLanguage)this.treeBuilder).getViewNodes(this.views)
  +        );
  +    }
  +}
  
  
  
  1.2       +19 -57    xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapNodeBuilder.java
  
  Index: SitemapNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/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	3 Jan 2002 12:31:37 -0000	1.1
  +++ SitemapNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -19,77 +19,39 @@
   import java.util.*;
   
   /**
  + * Builds all nodes below the top-level &lt;sitemap&gt; element, and returns the
  + * &lt;pipelines&gt; node. There is no node for &gt;sitemap&lt; since no processing
  + * occurs at this level.
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class SitemapNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
   
       public ProcessingNode buildNode(Configuration config) throws Exception {
  -        SitemapNode node = new SitemapNode();
  -        this.treeBuilder.setupNode(node, config);
           
  -        // We need to separate the various sorts of builders before building
  -        // the nodes because Components must be created first, otherwhise other
  -        // builders won't know the default type (generators, matchers, etc.)
  -        ProcessingNodeBuilder componentsBuilder = null;
  -        Configuration componentsConfig = null;
  +        ProcessingNode[] children = this.buildChildNodes(config);
           
  -        List otherBuildersAndConfig = new ArrayList();
  +        ProcessingNode pipelines = null;
           
  -        ProcessingNodeBuilder pipelinesBuilder = null;
  -        Configuration pipelinesConfig = null;
  -        
  -        Configuration[] childConfigs = config.getChildren();
  -        buildChildren : for (int i = 0; i < childConfigs.length; i++) {
  -            Configuration childConfig = childConfigs[i];
  -            
  -            if (!isChild(childConfig)) {
  -                continue buildChildren;
  -            }
  -
  -            ProcessingNodeBuilder builder = this.treeBuilder.createNodeBuilder(childConfig);
  -            
  -            if (builder instanceof ComponentsNodeBuilder) {
  -                if (componentsBuilder != null) {
  -                    throw new ConfigurationException("Only one map:components is allowed, at " +
  -                        config.getLocation());
  -                }
  -                componentsBuilder = builder;
  -                componentsConfig = childConfig;
  -                
  -            } else if (builder instanceof PipelinesNodeBuilder) {
  -                if (pipelinesBuilder != null) {
  -                    throw new ConfigurationException("Only one map:pipelines is allowed, at " +
  -                        config.getLocation());
  +        for (int i = 0; i < children.length; i++) {
  +            if (children[i] instanceof PipelinesNode) {
  +                if (pipelines != null) {
  +                    String msg = "Only one 'pipelines' is allowed, at " + config.getLocation();
  +                    getLogger().error(msg);
  +                    throw new ConfigurationException(msg);
                   }
  -                pipelinesBuilder = builder;
  -                pipelinesConfig = childConfig;
  -                
  -            } else {
  -                otherBuildersAndConfig.add(builder);
  -                otherBuildersAndConfig.add(childConfig);
  +                pipelines = children[i];
               }
           }
           
  -        // Now build nodes
  -        if (componentsBuilder != null) {
  -            // Doesn't actually build a node
  -            componentsBuilder.buildNode(componentsConfig);
  +        if (pipelines == null) {
  +            String msg = "Invalid sitemap : there must be a 'pipelines' at " + config.getLocation();
  +            getLogger().error(msg);
  +            throw new ConfigurationException(msg);
           }
  -        
  -        List otherNodes = new ArrayList(otherBuildersAndConfig.size() / 2);
  -        Iterator iter = otherBuildersAndConfig.iterator();
  -        while(iter.hasNext()) {
  -            ProcessingNodeBuilder builder = (ProcessingNodeBuilder)iter.next();
  -            Configuration builderConfig = (Configuration)iter.next();
  -            otherNodes.add(builder.buildNode(builderConfig));
  -        }
  -        
  -        node.setOtherNodes(toNodeArray(otherNodes));
  -        node.setPipelines(pipelinesBuilder.buildNode(pipelinesConfig));
   
  -        return node;
  +        return pipelines;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +28 -6     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/TransformNode.java
  
  Index: TransformNode.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/TransformNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TransformNode.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ TransformNode.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,20 +9,21 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   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.MapStackResolver;
   import org.apache.cocoon.treeprocessor.InvokeContext;
  +import org.apache.cocoon.treeprocessor.MapStackResolver;
  +import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
  +import org.apache.cocoon.treeprocessor.ProcessingNode;
   
   import java.util.List;
  -import org.apache.cocoon.treeprocessor.ParameterizableProcessingNode;
   import java.util.Map;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
   public class TransformNode extends AbstractProcessingNode implements ParameterizableProcessingNode {
  @@ -33,6 +34,8 @@
       
       private Map parameters;
       
  +    private Map views;
  +    
       public TransformNode(String name, String source) throws PatternException {
           this.transformerName = name;
           this.source = MapStackResolver.getResolver(source);
  @@ -42,6 +45,10 @@
           this.parameters = parameterMap;
       }
   
  +    public void setViews(Map views) {
  +        this.views = views;
  +    }
  +    
       public boolean invoke(Environment env, InvokeContext context)
         throws Exception {
           
  @@ -53,7 +60,22 @@
               MapStackResolver.buildParameters(this.parameters, mapStack)
           );
           
  +        // Check view
  +        String cocoonView = env.getView();
  +        if (cocoonView != null && this.views != null) {
  +            
  +            // Get view node
  +            ProcessingNode viewNode = (ProcessingNode)this.views.get(cocoonView);
  +            
  +            if (viewNode != null) {
  +                if (getLogger().isInfoEnabled()) {
  +                    getLogger().info("Jumping to view " + cocoonView + " from transformer at " + this.getLocation());
  +                }
  +                return viewNode.invoke(env, context);
  +            }
  +        }
  +        
           // Return false to contine sitemap invocation
           return false;
       }    
  -}
  \ No newline at end of file
  +}
  
  
  
  1.2       +23 -8     xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/TransformNodeBuilder.java
  
  Index: TransformNodeBuilder.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/TransformNodeBuilder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TransformNodeBuilder.java	3 Jan 2002 12:31:37 -0000	1.1
  +++ TransformNodeBuilder.java	15 Jan 2002 11:10:54 -0000	1.2
  @@ -9,26 +9,41 @@
   package org.apache.cocoon.treeprocessor.sitemap;
   
   import org.apache.avalon.framework.configuration.Configuration;
  -import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.cocoon.transformation.Transformer;
  +
   import org.apache.cocoon.treeprocessor.AbstractProcessingNodeBuilder;
  +import org.apache.cocoon.treeprocessor.LinkedProcessingNodeBuilder;
   import org.apache.cocoon.treeprocessor.ProcessingNode;
   
  +import java.util.*;
  +
   /**
    *
    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:37 $
  + * @version CVS $Revision: 1.2 $ $Date: 2002/01/15 11:10:54 $
    */
   
  -public class TransformNodeBuilder extends AbstractProcessingNodeBuilder implements ThreadSafe {
  +public class TransformNodeBuilder extends AbstractProcessingNodeBuilder
  +  implements LinkedProcessingNodeBuilder {
   
  +    private TransformNode node;
  +    
  +    private Collection views;
  +    
       public ProcessingNode buildNode(Configuration config) throws Exception {
           
  -        String type = ComponentsNodeBuilder.getComponentType(
  -            Transformer.ROLE + "Selector", config, this.treeBuilder);
  +        String type = this.treeBuilder.getTypeForStatement(config, Transformer.ROLE + "Selector");
           
  -        TransformNode node = new TransformNode(type, config.getAttribute("src", null));
  -        return this.treeBuilder.setupNode(node, config);   
  +        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement(Transformer.ROLE, type, config);
  +        
  +        this.node = new TransformNode(type, config.getAttribute("src", null));
  +        return this.treeBuilder.setupNode(node, config);
  +    }
  +    
  +    public void linkNode() throws Exception {
  +        this.node.setViews(
  +            ((SitemapLanguage)this.treeBuilder).getViewNodes(this.views)
  +        );
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ComponentsSelector.java
  
  Index: ComponentsSelector.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.CascadingRuntimeException;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  
  import org.apache.cocoon.components.pipeline.OutputComponentSelector;
  import org.apache.cocoon.components.ExtendedComponentSelector;
  
  import org.apache.cocoon.acting.Action;
  import org.apache.cocoon.generation.Generator;
  import org.apache.cocoon.matching.Matcher;
  import org.apache.cocoon.reading.Reader;
  import org.apache.cocoon.selection.Selector;
  import org.apache.cocoon.serialization.Serializer;
  import org.apache.cocoon.transformation.Transformer;
  
  import java.util.*;
  
  /**
   * Component selector for sitemap components.
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:54 $
   */
  
  public class ComponentsSelector extends ExtendedComponentSelector implements OutputComponentSelector {
      
      public static final int UNKNOWN     = -1;
      public static final int GENERATOR   = 0;
      public static final int TRANSFORMER = 1;
      public static final int SERIALIZER  = 2;
      public static final int READER      = 3;
      public static final int MATCHER     = 4;
      public static final int SELECTOR    = 5;
      public static final int ACTION      = 6;
      
      public static final String[] SELECTOR_ROLES = {
          Generator.ROLE   + "Selector",
          Transformer.ROLE + "Selector",
          Serializer.ROLE  + "Selector",
          Reader.ROLE      + "Selector",
          Matcher.ROLE     + "Selector",
          Selector.ROLE    + "Selector",
          Action.ROLE      + "Selector"
      };
      
      public static final String[] COMPONENT_NAMES = {
          "generator",
          "transformer",
          "serializer",
          "reader",
          "matcher",
          "selector",
          "action"
      };
  
      /** The role as an integer */
      private int roleId;
      
      /** The mime-type for hints */
      private Map mimeTypes;
      
      /** The set of known hints, used to add standard components (see ensureExists) */
      private Set knownHints = new HashSet();
      
      /** The parent selector, if it's of the current class */
      private ComponentsSelector parentComponentsSelector;
      
      public void setParentSelector(ComponentSelector selector) {
          super.setParentSelector(selector);
          
          if (selector instanceof ComponentsSelector) {
              this.parentComponentsSelector = (ComponentsSelector)selector;
          }
      }
      
      /**
       * Return the component instance name according to the selector role
       * (e.g. "action" for "org.apache.cocoon.acting.Action").
       */
      protected String getComponentInstanceName() {
          return (this.roleId == UNKNOWN) ? null : COMPONENT_NAMES[this.roleId];
      }
  
      /**
       * Get the attribute for class names. This is "src" for known roles, and
       * "class" (the default) for other roles.
       */
      protected String getClassAttributeName() {
          return (this.roleId == UNKNOWN) ? "class" : "src";
      }
      
  
      public void configure(Configuration config) throws ConfigurationException {
          
          // How are we ?
          String role = getRoleName(config);
          this.roleId = UNKNOWN; // unknown
          for (int i = 0; i < SELECTOR_ROLES.length; i++) {
              if (SELECTOR_ROLES[i].equals(role)) {
                  this.roleId = i;
                  break;
              }
          }
          
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Setting up sitemap component selector for " +
                  role + " (role id = " + this.roleId + ")");
          }
          
          // Only matchers and serializers can have a MIME type
          if (this.roleId == SERIALIZER || this.roleId == READER) {
              this.mimeTypes = new HashMap();
          }
          
          super.configure(config);
      }
  
      /**
       * Add a component in this selector. If needed, also register it's MIME type.
       */
      public void addComponent(Object hint, Class clazz, Configuration config) throws ComponentException {
          
          super.addComponent(hint, clazz, config);
  
          // Add to known hints
          this.knownHints.add(hint);
          
          if (this.roleId == SERIALIZER || this.roleId == READER) {
              // Get mime-type
              String mimeType = config.getAttribute("mime-type", null);
              if (mimeType != null) {
                  this.mimeTypes.put(hint, mimeType);
              }
          }
      }
      
      /**
       * Ensure system-defined components exist (e.g. !content-aggregator!) and initialize
       * the selector.
       */
      public void initialize() /*throws Exception*/ {
      
      // FIXME : need to catch exceptions since ECS doesn't propagate the throws clause of Initializable
      try {
          
          Configuration emptyConfig = new DefaultConfiguration("", "");
          
          // Ensure all system-defined hints exist.
          // NOTE : checking this here means they can be user-defined in the sitemap
          switch(this.roleId) {
              case GENERATOR :
                  ensureExists("!notifying-generator!",
                      org.apache.cocoon.sitemap.NotifyingGenerator.class, emptyConfig);
  
                  ensureExists("!content-aggregator!",
                      org.apache.cocoon.sitemap.ContentAggregator.class, emptyConfig);
              break;
              
              case TRANSFORMER :
                  ensureExists("!link-translator!",
                      org.apache.cocoon.sitemap.LinkTranslator.class, emptyConfig);
              break;
          }
          
          super.initialize();
          
          // Don't keep known hints (they're no more needed)
          this.knownHints = null;
          
      } catch(Exception e) {
          throw new CascadingRuntimeException("Cannot setup default components", e);
      }
      
      }
      
      /**
       * Ensure a component exists or add it otherwhise. We cannot simply call hasComponent()
       * since it requires to be initialized, and we want to add components, and this must
       * be done before initialization.
       */
      private void ensureExists(Object hint, Class clazz, Configuration config) throws ComponentException {
          
          if (! this.knownHints.contains(hint)) {
              this.addComponent(hint, clazz, config);
          }
      }
  
      /**
       * Get the MIME type for a given hint.
       */
      public String getMimeTypeForHint(Object hint) {
          
          if (this.mimeTypes == null) {
              return null;
              
          } else {
              String mimeType = (String)this.mimeTypes.get(hint);
              
              if (mimeType != null) {
                  return mimeType;
                  
              } else if (this.parentComponentsSelector != null) {
                  return this.parentComponentsSelector.getMimeTypeForHint(hint);
                  
              } else {
                  return null;
              }
          }
      }
  }
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/SitemapLanguage.java
  
  Index: SitemapLanguage.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.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentSelector;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  
  import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
  import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
  import org.apache.avalon.excalibur.component.RoleManager;
  
  import org.apache.cocoon.components.ExtendedComponentSelector;
  import org.apache.cocoon.components.LifecycleHelper;
  
  import org.apache.cocoon.generation.Generator;
  import org.apache.cocoon.transformation.Transformer;
  import org.apache.cocoon.serialization.Serializer;
  
  import org.apache.cocoon.treeprocessor.CategoryNode;
  import org.apache.cocoon.treeprocessor.CategoryNodeBuilder;
  import org.apache.cocoon.treeprocessor.TreeBuilder;
  
  import org.apache.cocoon.util.StringUtils;
  
  import java.util.*;
  
  /**
   * The tree builder for the sitemap language.
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:54 $
   */
  
  public class SitemapLanguage extends TreeBuilder {
  
      private static final String ATTR_PREFIX = "org.apache.cocoon.treeprocessor.ViewNodeBuilder";
  
      /**
       * Build a component manager with the contents of the &lt;map:components&gt; element of
       * the tree.
       */
      protected ComponentManager createComponentManager(Configuration tree) throws Exception {
          
          // Get the map:component node
          // Don't check namespace here : this will be done by node builders
          Configuration config = tree.getChild("components", false);
          
          if (config == null) {
              getLogger().debug("Sitemap has no components definition at " + tree.getLocation());
              config = new DefaultConfiguration("", "");
          }
          
          ComponentManager manager = new ExcaliburComponentManager(this.parentManager) {
              public void setRoleManager(RoleManager rm) {
                  super.setRoleManager(rm);
              }
          };
          
          LifecycleHelper.setupComponent(manager,
              getLogger(),
              this.context,
              this.parentManager,
              this.roleManager,
              this.logKit,
              config
          );
          
          // Set parent of all selectors.
          if (this.parentManager != null) {
              
              for (int i = 0; i < ComponentsSelector.SELECTOR_ROLES.length; i++) {
                  
                  String role = ComponentsSelector.SELECTOR_ROLES[i];
                  
                  ComponentSelector parentSelector = null;
                  try {
                      parentSelector = (ComponentSelector)this.parentManager.lookup(role);
                  } catch(Exception e) {
                      // ignore and keep it null
                  }
                  
                  if (parentSelector != null) {
                  
                      ExtendedComponentSelector localSelector = null;
                      try {
                          localSelector = (ExtendedComponentSelector)manager.lookup(role);
                          
                          if (localSelector != parentSelector) {
                              // local selector wasn't given by chaining to the parent manager
                              localSelector.setParentSelector(parentSelector);
                          }
                          manager.release(localSelector);
  
                      } catch(Exception e) {
                          // ignore
                      }
                      
                      parentManager.release(parentSelector);
                  }
              }
          }
          
          // Parse generators and transformers labels
          
          Configuration[] generators = config.getChild("generators").getChildren();
          // Note : we don't getChildren("generator") because there can be some
          // shortcut declarations that have other names
          
          for (int i = 0; i < generators.length; i++) {
              this.setComponentLabels(
                  Generator.ROLE,
                  generators[i].getAttribute("name"),
                  generators[i].getAttribute("label", null)
              );
          }
          
          Configuration[] transformers = config.getChild("transformers").getChildren();
          for (int i = 0; i < transformers.length; i++) {
              this.setComponentLabels(
                  Transformer.ROLE,
                  transformers[i].getAttribute("name"),
                  transformers[i].getAttribute("label", null)
              );
          }
  
          return manager;
      }
      
      //---- Views management
      
      /** Collection of view names for each label */
      private Map labelViews = new HashMap();
      
      /** Collection of labels for each component, represented by a 'role':'hint' key */
      private Map componentLabels = new HashMap();
      
      /** The views CategoryNode */
      private CategoryNode viewsNode;
      
      /** Are we currently building a view ? */
      private boolean isBuildingView = false;
      
      /**
       * Pseudo-label for views <code>from-position="first"</code> (i.e. generator).
       */
      public static final String FIRST_POS_LABEL = "!first!";
      
      /**
       * Pseudo-label for views <code>from-position="last"</code> (i.e. serializer).
       */
      public static final String LAST_POS_LABEL = "!last!";
      
      /**
       * Set to <code>true</code> while building the internals of a &lt;map:view&gt;
       */
      public void setBuildingView(boolean building) {
          this.isBuildingView = building;
      }
      
      /**
       * Are we currently building a view ?
       */
      public boolean isBuildingView() {
          return this.isBuildingView;
      }
      
      /**
       * Registers the view labels for a component. They're merged later on with the
       * ones defined on each statement.
       */
      private void setComponentLabels(String role, String hint, String labels) {
          getLogger().debug("views:setComponentLabels(" + role + ", " + hint + ", " + labels + ")");
          Collection labelColl = splitLabels(labels);
          this.componentLabels.put(role + ":" + hint, labelColl);
      }
  
      /**
       * Add a view for a label. This is used to register all views that start from
       * a given label.
       *
       * @parameter label the label (or pseudo-label) for the view
       * @parameter view the view name
       */
      public void addViewForLabel(String label, String view) {
          getLogger().debug("views:addViewForLabel(" + label + ", " + view + ")");
          Set views = (Set)this.labelViews.get(label);
          if (views == null) {
              views = new HashSet();
              this.labelViews.put(label, views);
          }
          
          views.add(view);
      }
      
      /**
       * Get the names of views for a given statement. If the cocoon view exists in the returned
       * collection, the statement can directly branch to the view-handling node.
       *
       * @param role the component role (e.g. <code>Generator.ROLE</code>)
       * @param hint the component hint, i.e. the 'type' attribute
       * @param statement the sitemap statement
       * @return the view names for this statement
       */
      public Collection getViewsForStatement(String role, String hint, Configuration statement) throws Exception {
  
          String statementLabels = statement.getAttribute("label", null);
          
          if (this.isBuildingView) {
              // Labels are forbidden inside view definition
              if (statementLabels != null) {
                  String msg = "Cannot put a 'label' attribute inside view definition at " + statement.getLocation();
                  getLogger().error(msg);
                  throw new ConfigurationException(msg);
              }
              
              // We are currently building a view. Don't recurse !
              return null;
          }
          
          // Compute the views attached to this component
          Set views = null;
          
          // Build the set for all labels for this statement
          Set labels = new HashSet();
          
          // 1 - labels defined on the component
          Collection coll = (Collection)this.componentLabels.get(role + ":" + hint);
          if (coll != null) {
              labels.addAll(coll);
          }
  
          // 2 - labels defined on this statement
          if (statementLabels != null) {
              coll = splitLabels(statementLabels);
              labels.addAll(coll);
          }
          
          // 3 - pseudo-label depending on the role
          if (role.equals(Generator.ROLE)) {
              labels.add("!first!");
          } else if (role.equals(Serializer.ROLE)) {
              labels.add("!last!");
          }
          
          // Build the set of views attached to these labels
          views = new HashSet();
          
          // Iterate on all labels for this statement
          Iterator labelIter = labels.iterator();
          while(labelIter.hasNext()) {
              
              // Iterate on all views for this labek
              coll = (Collection)this.labelViews.get(labelIter.next());
              if (coll != null) {
                  Iterator viewIter = coll.iterator();
                  while(viewIter.hasNext()) {
                      String viewName = (String)viewIter.next();
                      
                      views.add(viewName);
                  }
              }
          }
          
          // Don't keep empty result
          if (views.size() == 0) {
              views = null;
              
              getLogger().debug(statement.getName() + " has no views at " + statement.getLocation());
          } else {
              if (getLogger().isDebugEnabled()) {
                  // Dump matching views
                  StringBuffer buf = new StringBuffer(statement.getName() + " will match views [");
                  Iterator iter = views.iterator();
                  while(iter.hasNext()) {
                      buf.append(iter.next()).append(" ");
                  }
                  buf.append("] at ").append(statement.getLocation());
                  
                  getLogger().debug(buf.toString());
              }
          }
          
          return views;
      }
      
      /**
       * Before linking nodes, lookup the view category node used in {@link #getViewNodes(Collection)}.
       */
      protected void linkNodes() throws Exception {
          // Get the views category node
          this.viewsNode = CategoryNodeBuilder.getCategoryNode(this, "views");
          
          super.linkNodes();
      }
  
      /**
       * Get the {view name, view node} map for a collection of view names.
       * This allows to resolve view nodes at build time, thus avoiding runtime lookup.
       *
       * @param viewNames the view names
       * @return association of names to views
       */
      public Map getViewNodes(Collection viewNames) throws Exception {
          if (viewNames == null) {
              return null;
          }
          
          if (this.viewsNode == null) {
              return null;
          }
          
          Map result = new HashMap();
          
          Iterator iter = viewNames.iterator();
          while(iter.hasNext()) {
              String viewName = (String)iter.next();
              result.put(viewName, viewsNode.getNodeByName(viewName));
          }
          
          return result;
      }
  
      /**
       * Split a list of space/comma separated labels into a Collection
       *
       * @return the collection of labels (may be empty, nut never null)
       */
      private static final Collection splitLabels(String labels) {
          if (labels == null) {
              return Collections.EMPTY_SET;
          } else {
              return Arrays.asList(StringUtils.split(labels, ", \t\n\r"));
          }
      }
      
  }
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/treeprocessor/sitemap/ViewNodeBuilder.java
  
  Index: ViewNodeBuilder.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.avalon.framework.thread.ThreadSafe;
  
  import org.apache.cocoon.treeprocessor.NamedContainerNodeBuilder;
  import org.apache.cocoon.treeprocessor.NamedProcessingNode;
  import org.apache.cocoon.treeprocessor.ProcessingNode;
  import org.apache.cocoon.treeprocessor.TreeBuilder;
  
  import org.apache.cocoon.util.StringUtils;
  
  import java.util.*;
  
  /**
   * Builds a &lt;map:view&gt;
   *
   * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/01/15 11:10:54 $
   */
  
  public class ViewNodeBuilder extends NamedContainerNodeBuilder implements ThreadSafe {
      
      public ProcessingNode buildNode(Configuration config) throws Exception {
          
          // Get the label or position (pseudo-label) of this view.
          String label = config.getAttribute("from-label", null);
          
          if (label == null) {
              String position = config.getAttribute("from-position");
              if ("first".equals(position)) {
                  label = SitemapLanguage.FIRST_POS_LABEL;
              } else if ("last".equals(position)) {
                  label = SitemapLanguage.LAST_POS_LABEL;
              } else {
                  String msg = "Bad value for 'from-position' at " + config.getLocation();
                  getLogger().error(msg);
                  throw new ConfigurationException(msg);
              }
          }
          
          SitemapLanguage sitemapBuilder = (SitemapLanguage)this.treeBuilder;
  
          // Indicate to child builders that we're in a view (they won't perform view branching)        
          sitemapBuilder.setBuildingView(true);
          
          // Build children
          NamedProcessingNode result = (NamedProcessingNode)super.buildNode(config);
          
          sitemapBuilder.addViewForLabel(label, result.getName());
  
          // Clear the flag
          sitemapBuilder.setBuildingView(false);
          
          return result;
      }
  }
  
  
  

----------------------------------------------------------------------
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


Mime
View raw message