You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@forrest.apache.org by ni...@apache.org on 2003/10/21 10:33:36 UTC

cvs commit: xml-forrest/src/java/org/apache/cocoon/components/modules/input LocationMapModule.java

nicolaken    2003/10/21 01:33:36

  Added:       src/java/org/apache/cocoon/components/modules/input/lm
                        AbstractNode.java LocationMap.java
                        LocationNode.java LocatorNode.java MatchNode.java
                        SelectNode.java
               src/java/org/apache/cocoon/components/modules/input
                        LocationMapModule.java
  Log:
  Add the LocationMapModule form Unico Hommes.
  He has sent a signed CLA already.
  
  Revision  Changes    Path
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/AbstractNode.java
  
  Index: AbstractNode.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
  import org.apache.cocoon.sitemap.PatternException;
  
  /**
   * Base class for LocationMap nodes.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public abstract class AbstractNode extends AbstractLogEnabled {
      
      
      protected final ComponentManager m_manager;
      
      // optional parameters defined 
      // by the node's configuration
      private Map m_parameters;
      
      
      public AbstractNode(final ComponentManager manager) {
          m_manager = manager;
      }
      
      public void build(final Configuration configuration) throws ConfigurationException {
          m_parameters = getParameters(configuration);
      }
      
      /**
       * Create a Map of resolvable parameters.
       * 
       * @param configuration  the configuration to build parameters from.
       * @return  a Map of parameters wrapped in VariableResolver objects,
       * <code>null</code> if the configuration contained no parameters.
       * @throws ConfigurationException
       */
      protected final Map getParameters(final Configuration configuration) 
          throws ConfigurationException {
          
          final Configuration[] children = configuration.getChildren("parameter");
          if (children.length == 0) {
              return null;
          }
          final Map parameters = new HashMap();
          for (int i = 0; i < children.length; i++) {
              final String name = children[i].getAttribute("name");
              final String value = children[i].getAttribute("value");
              try {
                  parameters.put(
                      VariableResolverFactory.getResolver(name,m_manager),
                      VariableResolverFactory.getResolver(value,m_manager));
              } catch(PatternException pe) {
                  String msg = "Invalid pattern '" + value + "' at " 
                      + children[i].getLocation();
                  throw new ConfigurationException(msg, pe);
              }
          }
  
          return parameters;
      }
      
      /**
       * Resolve the parameters. Also passes the LocationMap special
       * variables into the Parameters object.
       * 
       * @param context  InvokeContext used during resolution.
       * @param om  object model used during resolution.
       * @return  the resolved parameters or null if this node contains no parameters.
       * @throws PatternException
       */
      protected final Parameters resolveParameters(
          final InvokeContext context, 
          final Map om) throws PatternException {
          
          Parameters parameters = null;
          if (m_parameters != null) {
              parameters = VariableResolver.buildParameters(m_parameters,context,om);
          }
          else {
              parameters = new Parameters();
          }
          // also pass the anchor map as parameters
          // for use by components
          Map anchorMap = context.getMapByAnchor("lm");
          Iterator entries = anchorMap.entrySet().iterator();
          while (entries.hasNext()) {
              Map.Entry entry = (Map.Entry) entries.next();
              parameters.setParameter("#lm:"+entry.getKey(),entry.getValue().toString());
          }
          return parameters;
      }
      
      public abstract String locate(Map objectModel, InvokeContext context) throws Exception;
          
  }
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/LocationMap.java
  
  Index: LocationMap.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.DefaultComponentManager;
  import org.apache.avalon.framework.component.DefaultComponentSelector;
  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.container.ContainerUtil;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.matching.Matcher;
  import org.apache.cocoon.matching.WildcardURIMatcher;
  import org.apache.cocoon.selection.ResourceExistsSelector;
  import org.apache.cocoon.selection.Selector;
  
  /**
   * A LocationMap defines a mapping from requests to locations.
   * <p>
   * The syntax of the locationmap is similar to the way a sitemap 
   * maps requests to pipelines. In the locationmap's case 
   * Matchers and Selectors are not used to identify pipelines but
   * location strings.
   * </p>
   * <p>
   * The locationmap was conceived to:
   * <ul>
   *  <li>
   *   Provide a tool for more powerful virtual linking.
   *  </li>
   *  <li>
   *   Enable Forrest with a standard configuration override
   *   mechanism.
   *  </li>
   * </ul>
   * </p>
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public final class LocationMap extends AbstractLogEnabled {
      
      /** 
       * The locationmap namespace: 
       * <code>http://apache.org/cocoon/locationmap/1.0</code>
       */
      public static final String URI = "http://apache.org/cocoon/locationmap/1.0";
      
      private static final String DEFAULT_MATCHER  = "wildcard";
      private static final String DEFAULT_MATCHER_TYPE = WildcardURIMatcher.class.getName();
      private static final Configuration DEFAULT_MATCHER_CONFIGURATION = 
          new DefaultConfiguration("matcher");
      private static final String DEFAULT_SELECTOR = "exists";
      private static final String DEFAULT_SELECTOR_TYPE = ResourceExistsSelector.class.getName();
      private static final Configuration DEFAULT_SELECTOR_CONFIGURATION = 
          new DefaultConfiguration("selector");
      
      
      private final ComponentManager m_manager;
      
      // the global default matcher type as configured in the components section
      private String m_defaultMatcher;
      // the global default selector type as configured in the components section
      private String m_defaultSelector;
      
      // the list of LocatorNodes
      private LocatorNode[] m_locatorNodes;
      
      public LocationMap(final ComponentManager manager) {
          m_manager = manager;
      }
      
      public void build(final Configuration configuration) throws ConfigurationException {
          
          // components
          final Configuration components = configuration.getChild("components",true);
          final DefaultComponentManager manager = new DefaultComponentManager(m_manager);
          
          // matchers
          final DefaultComponentSelector matcherSelector = new DefaultComponentSelector();
          Configuration child = components.getChild("matchers",true);
          m_defaultMatcher = child.getAttribute("default",DEFAULT_MATCHER);
          if (m_defaultMatcher.equals(DEFAULT_MATCHER)) {
              Matcher defaultMatcher = (Matcher) createComponent(
                  DEFAULT_MATCHER_TYPE,DEFAULT_MATCHER_CONFIGURATION);
              matcherSelector.put(m_defaultMatcher,defaultMatcher);
          }
          final Configuration[] matchers = child.getChildren("matcher");
          for (int i = 0; i < matchers.length; i++) {
              String name = matchers[i].getAttribute("name");
              String src  = matchers[i].getAttribute("src");
              Matcher matcher = (Matcher) createComponent(src, matchers[i]);
              matcherSelector.put(name,matcher);
          }
          matcherSelector.makeReadOnly();
          manager.put(Matcher.ROLE+"Selector",matcherSelector);
          
          // selectors
          final DefaultComponentSelector selectorSelector = new DefaultComponentSelector();
          child = configuration.getChild("selectors",true);
          m_defaultSelector = child.getAttribute("default",DEFAULT_SELECTOR);
          if (m_defaultSelector.equals(DEFAULT_SELECTOR)) {
              Selector defaultSelector = (Selector) createComponent(
                  DEFAULT_SELECTOR_TYPE,DEFAULT_SELECTOR_CONFIGURATION);
              selectorSelector.put(m_defaultSelector,defaultSelector);
          }
          final Configuration[] selectors = child.getChildren("selector");
          for (int i = 0; i < selectors.length; i++) {
              String name = selectors[i].getAttribute("name");
              String src  = selectors[i].getAttribute("src");
              Selector selector = (Selector) createComponent(src,selectors[i]);
              selectorSelector.put(name,selector);
          }
          selectorSelector.makeReadOnly();
          manager.put(Selector.ROLE+"Selector",selectorSelector);
          manager.makeReadOnly();
          
          // locators
          final Configuration[] children = configuration.getChildren("locator");
          m_locatorNodes = new LocatorNode[children.length];
          for (int i = 0; i < children.length; i++) {
              m_locatorNodes[i] = new LocatorNode(this,manager);
              m_locatorNodes[i].enableLogging(getLogger());
              m_locatorNodes[i].build(children[i]);
          }
      }
      
      private Object createComponent(String src, Configuration config) throws ConfigurationException {
          Object component = null;
          try {
              component = Class.forName(src).newInstance();
          } catch (Exception e) {
              throw new ConfigurationException("Couldn't create object of type " + src,e);
          }
          ContainerUtil.enableLogging(component,getLogger());
          ContainerUtil.configure(component,config);
          return component;
      }
      
      public String locate(String name, Map om) throws Exception {
          
          String location = null;
          
          final InvokeContext context = new InvokeContext();
          context.enableLogging(getLogger().getChildLogger("ctx"));
          context.compose(m_manager);
          
          final Map anchorMap = new HashMap(2);
          anchorMap.put("name",name);
          context.pushMap("lm",anchorMap);
          
          for (int i = 0; i < m_locatorNodes.length; i++) {
              location = m_locatorNodes[i].locate(om,context);
              if (location != null) {
                  break;
              }
          }
          
          context.popMap();
          return location;
      }
      
      String getDefaultMatcher() {
          return m_defaultMatcher;
      }
      
      String getDefaultSelector() {
          return m_defaultSelector;
      }
      
  }
  
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/LocationNode.java
  
  Index: LocationNode.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.Map;
  
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
  import org.apache.cocoon.sitemap.PatternException;
  import org.apache.excalibur.source.SourceUtil;
  
  /**
   * LocationMap node representing a location.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public class LocationNode extends AbstractNode {
  
      private final LocatorNode m_ln;
      
      // the resolvable location source
      private VariableResolver m_src;
      
      public LocationNode(final LocatorNode ln, final ComponentManager manager) {
          super(manager);
          m_ln = ln;
      }
      
      public void build(final Configuration configuration) throws ConfigurationException {
          try {
              m_src = VariableResolverFactory.getResolver(
                  configuration.getAttribute("src"),super.m_manager);
          } catch (PatternException e) {
              final String message = "Illegal pattern syntax at for location attribute 'src' " +
                "at " + configuration.getLocation();
              throw new ConfigurationException(message,e);
          }
  
      }
      
      public String locate(Map om, InvokeContext context) throws Exception {
          
          String src = m_src.resolve(context,om);
          
          // absolute, don't prefix
          if (src.charAt(0) == '/' || SourceUtil.indexOfSchemeColon(src) != -1) {
              return src;
          }
          else {
              String base = (String) context.getMapByAnchor("lm").get("base");
              return base + (base.charAt(base.length()-1) == '/' ? "" : "/") + src;
          }
          
      }
  
  }
  
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/LocatorNode.java
  
  Index: LocatorNode.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
  import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
  import org.apache.cocoon.sitemap.PatternException;
  
  
  /**
   * LocationMap node for containing a set <code>MatchNode</code>s.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public final class LocatorNode extends AbstractNode {
      
      // the containing LocationMap
      private final LocationMap m_lm;
      
      // location base resolver
      private VariableResolver m_baseLocation;
      
      // the contained MatchNodes
      private AbstractNode[] m_nodes;
      
      public LocatorNode(final LocationMap lm, final ComponentManager manager) {
          super(manager);
          m_lm = lm;
      }
      
      public void build(final Configuration configuration) throws ConfigurationException {
          String base = configuration.getAttribute("base",".");
          try {
              m_baseLocation = VariableResolverFactory.getResolver(base,super.m_manager);
          } catch (PatternException e) {
              final String message = "Illegal pattern syntax for locator attribute 'base' " +
                "at " + configuration.getLocation(); 
              throw new ConfigurationException(message);
          }
          final Configuration[] children = configuration.getChildren();
          final List nodes = new ArrayList(children.length);
          for (int i = 0; i < children.length; i++) {
              AbstractNode node = null;
              if (children[i].getName().equals("match")) {
                  node = new MatchNode(this,super.m_manager);
              }
              else if (children[i].getName().equals("select")) {
                  node = new SelectNode(this,super.m_manager);
              }
              else {
                  final String message = "Illegal locator node child: " 
                      + children[i].getName();
                  throw new ConfigurationException(message);
              }
              node.enableLogging(getLogger());
              node.build(children[i]);
              nodes.add(node);
          }
          m_nodes = (AbstractNode[]) nodes.toArray(new AbstractNode[nodes.size()]);
      }
      
      public String locate(Map om, InvokeContext context) throws Exception {
          
          // resolve the base location and put it in the anchor map
          Map anchorMap = context.getMapByAnchor("lm");
          anchorMap.put("base",m_baseLocation.resolve(context,om));
          
          for (int i = 0; i < m_nodes.length; i++) {
              final String location = m_nodes[i].locate(om,context);
              if (location != null) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("located: " + location);
                  }
                  return location;
              }
          }
          return null;
      }
      
      String getDefaultMatcher() {
          return m_lm.getDefaultMatcher();
      }
      
      String getDefaultSelector() {
          return m_lm.getDefaultSelector();
      }
      
  }
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/MatchNode.java
  
  Index: MatchNode.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  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.parameters.Parameters;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.matching.Matcher;
  
  /**
   * LocationMap node representing a Matcher.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public final class MatchNode extends AbstractNode {
      
      // the containing LocatorNode
      private final LocatorNode m_ln;
      
      // the Matcher that does the work
      private Matcher m_matcher;
      
      // the type of Matcher for this node
      private String m_type;
      
      // the pattern to match
      private String m_pattern;
      
      // the child nodes
      private AbstractNode[] m_nodes;
      
      public MatchNode(final LocatorNode ln, final ComponentManager manager) {
          super(manager);
          m_ln = ln;
      }
      
      public void build(final Configuration configuration) throws ConfigurationException {
          
          super.build(configuration);
          
          // get the matcher
          m_type = configuration.getAttribute("type",m_ln.getDefaultMatcher());
          try {
              ComponentSelector matchers = (ComponentSelector) 
                  super.m_manager.lookup(Matcher.ROLE + "Selector");
              m_matcher = (Matcher) matchers.select(m_type);
          } catch (ComponentException e) {
              final String message = "Unable to get Matcher of type " + m_type;
              throw new ConfigurationException(message,e);
          }
          
          // get the matcher pattern
          m_pattern = configuration.getAttribute("pattern");
          
          // get the child nodes
          final Configuration[] children = configuration.getChildren();
          final List nodes = new ArrayList(children.length);
          for (int i = 0; i < children.length; i++) {
              AbstractNode node = null;
              String name = children[i].getName();
              if (name.equals("location")) {
                  node = new LocationNode(m_ln,super.m_manager);
              }
              else if (name.equals("match")) {
                  node = new MatchNode(m_ln,super.m_manager);
              }
              else if (name.equals("select")) {
                  node = new SelectNode(m_ln,super.m_manager);
              }
              else if (!name.equals("parameter")) {
                  final String message =
                      "Unknown match node child: " + name;
                  throw new ConfigurationException(message);
              }
              if (node != null) {
                  node.enableLogging(getLogger());
                  node.build(children[i]);
                  nodes.add(node);
              }
          }
          m_nodes = (AbstractNode[]) nodes.toArray(new AbstractNode[nodes.size()]);
      }
      
      public String locate(Map om, InvokeContext context) throws Exception {
          
          Parameters parameters = resolveParameters(context,om);
          Map substitutions = m_matcher.match(m_pattern,om,parameters);
          if (substitutions != null) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("matched " + m_pattern);
              }
              context.pushMap(null,substitutions);
              for (int i = 0; i < m_nodes.length; i++) {
                  String location = m_nodes[i].locate(om,context);
                  if (location != null) {
                      return location;
                  }
              }
              context.popMap();
          }
          return null;
      }
      
  }
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/lm/SelectNode.java
  
  Index: SelectNode.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input.lm;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  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.parameters.Parameters;
  import org.apache.cocoon.components.treeprocessor.InvokeContext;
  import org.apache.cocoon.selection.Selector;
  
  
  /**
   * LocationMap node representing a Selector.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public final class SelectNode extends AbstractNode {
      
      // the containing LocatorNode
      private final LocatorNode m_ln;
      
      // the selector that does the work
      private Selector m_selector;
      
      // the type of selector for this node
      private String m_type;
      
      // the locations to test against
      private AbstractNode[] m_nodes;
      
      
      public SelectNode(LocatorNode ln, ComponentManager manager) {
          super(manager);
          m_ln = ln;
      }
      
      public void build(Configuration configuration) throws ConfigurationException {
          
          super.build(configuration);
          
          // get the selector
          m_type = configuration.getAttribute("type",m_ln.getDefaultSelector());
          try {
              final ComponentSelector selectors = (ComponentSelector) 
                  super.m_manager.lookup(Selector.ROLE + "Selector");
              m_selector = (Selector) selectors.select(m_type);
          } catch (ComponentException e) {
              final String message = "Unable to get Selector of type " + m_type;
              throw new ConfigurationException(message,e);
          }
          
          // build the child nodes
          final Configuration[] children = configuration.getChildren();
          final List nodes = new ArrayList(children.length);
          for (int i = 0; i < children.length; i++) {
              AbstractNode node = null;
              String name = children[i].getName();
              if (name.equals("location")) {
                  node = new LocationNode(m_ln,super.m_manager);
              } 
              else if (name.equals("match")) {
                  node = new MatchNode(m_ln,super.m_manager);
              }
              else if (name.equals("select")) {
                  node = new SelectNode(m_ln,super.m_manager);
              }
              else if (!name.equals("parameter")) {
                  final String message = "Unknown select node child:" + name;
                  throw new ConfigurationException(message);
              }
              if (node != null) {
                  node.enableLogging(getLogger());
                  node.build(children[i]);
                  nodes.add(node);
              }
          }
          m_nodes = (AbstractNode[]) nodes.toArray(new AbstractNode[nodes.size()]);
      }
      
      
      public String locate(Map om, InvokeContext context) throws Exception {
          
          Parameters parameters = resolveParameters(context,om);
          for (int i = 0; i < m_nodes.length; i++) {
              String location = m_nodes[i].locate(om,context);
              if (m_selector.select(location,om,parameters)) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("selected: " + location);
                  }
                  return location;
              }
          }
          return null;
      }
  }
  
  
  1.1                  xml-forrest/src/java/org/apache/cocoon/components/modules/input/LocationMapModule.java
  
  Index: LocationMapModule.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.modules.input;
  
  import java.io.IOException;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.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.NamespacedSAXConfigurationHandler;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.components.modules.input.lm.*;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceResolver;
  import org.apache.excalibur.source.SourceValidity;
  import org.apache.excalibur.xml.sax.SAXParser;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  /**
   * Resolves a request against a LocationMap.
   * 
   * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
   */
  public class LocationMapModule extends AbstractLogEnabled 
      implements InputModule, Composable, Configurable, ThreadSafe {
      
      private static final Iterator ATTNAMES = Collections.EMPTY_LIST.iterator();
      
      private ComponentManager m_manager;
      private SourceResolver m_resolver;
      private String m_src;
      private SourceValidity m_srcVal;
      private LocationMap m_lm;
      
      public void compose(ComponentManager manager) throws ComponentException {
          m_manager = manager;
          m_resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
      }
      
      public void configure(Configuration configuration) throws ConfigurationException {
          m_src = configuration.getChild("file").getAttribute("src");
      }
      
      private LocationMap getLocationMap() throws Exception {
          Source source = null;
          try {
              source = m_resolver.resolveURI(m_src);
              if (m_lm == null) {
                  synchronized (this) {
                      if (m_lm == null) {
                          if (getLogger().isDebugEnabled()) {
                              getLogger().debug("loading location map at " + m_src);
                          }
                          m_srcVal = source.getValidity();
                          m_lm = new LocationMap(m_manager);
                          m_lm.enableLogging(getLogger());
                          m_lm.build(loadConfiguration(source));
                      }
                  }
              }
              else {
                  SourceValidity valid = source.getValidity();
                  if (m_srcVal != null && m_srcVal.isValid(valid) != 1) {
                      synchronized (this) {
                          if (m_srcVal != null && m_srcVal.isValid(valid) != 1) {
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("reloading location map at " + m_src);
                              }
                              m_srcVal = valid;
                              m_lm = new LocationMap(m_manager);
                              m_lm.enableLogging(getLogger());
                              m_lm.build(loadConfiguration(source));
                          }
                      }
                  }
              }
          }
          finally {
              if (source != null) {
                  m_resolver.release(source);
              }
          }
          return m_lm;
      }
      
      private Configuration loadConfiguration(Source source) throws ConfigurationException {
          Configuration configuration = null;
          SAXParser parser = null;
          try {
              parser = (SAXParser) m_manager.lookup(SAXParser.ROLE);
              NamespacedSAXConfigurationHandler handler = 
                  new NamespacedSAXConfigurationHandler();
              parser.parse(new InputSource(source.getInputStream()),handler);
              configuration = handler.getConfiguration();
          }
          catch (IOException e) {
              throw new ConfigurationException("Unable to build LocationMap.",e);
          }
          catch (SAXException e) {
              throw new ConfigurationException("Unable to build LocationMap.",e);
          }
          catch (ComponentException e) {
              throw new ConfigurationException("Unable to build LocationMap.",e);
          }
          finally {
              if (parser != null) {
                  m_manager.release((Component) parser);
              }
          }
          return configuration;
      }
      
      public Object getAttribute(
          final String name,
          final Configuration modeConf,
          final Map objectModel)
          throws ConfigurationException {
          
          try {
              return getLocationMap().locate(name,objectModel);
          }
          catch (ConfigurationException e) {
              throw e;
          }
          catch (Exception e) {
              getLogger().error("Failure processing LocationMap.",e);
          }
          return null;
      }
      
      /**
       * The possibilities are endless. No way to enumerate them all.
       * Therefore returns an empty Iterator.
       */
      public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
          throws ConfigurationException {
          
          return null;
      }
      
      /**
       * Always returns only one value. Use getAttribute() instead.
       */
      public Object[] getAttributeValues(
          String name,
          Configuration modeConf,
          Map objectModel)
          throws ConfigurationException {
          
          return new Object[] {getAttribute(name,modeConf,objectModel)};
      }
      
  }