You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2003/05/16 15:41:10 UTC

cvs commit: jakarta-commons/collections/src/java/org/apache/commons/collections TransformerUtils.java FunctorException.java PredicateUtils.java FactoryUtils.java ClosureUtils.java Closure.java Transformer.java Predicate.java Factory.java

scolebourne    2003/05/16 06:41:10

  Modified:    collections/src/java/org/apache/commons/collections
                        Closure.java Transformer.java Predicate.java
                        Factory.java
  Added:       collections/src/java/org/apache/commons/collections
                        TransformerUtils.java FunctorException.java
                        PredicateUtils.java FactoryUtils.java
                        ClosureUtils.java
  Log:
  Add functor utility implementations
  
  Revision  Changes    Path
  1.6       +21 -12    jakarta-commons/collections/src/java/org/apache/commons/collections/Closure.java
  
  Index: Closure.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/Closure.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Closure.java	11 May 2003 14:15:23 -0000	1.5
  +++ Closure.java	16 May 2003 13:41:10 -0000	1.6
  @@ -57,21 +57,30 @@
    */
   package org.apache.commons.collections;
   
  -/** 
  - * An interface to represent some Closure, a block of code which is executed 
  - * from inside some block, function or iteration which operates on an input 
  - * object.
  - *
  +/**
  + * <code>Closure</code> defines an interface implemented by classes that
  + * do something.
  + * <p>
  + * A Closure represents a block of code which is executed from inside some
  + * block, function or iteration. It operates an input object.
  + *  
    * @since Commons Collections 1.0
    * @version $Revision$ $Date$
  - * 
  - * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  + *
  + * @author James Strachan
  + * @author Nicola Ken Barozzi
  + * @author Stephen Colebourne
    */
   public interface Closure {
  -
  -    /** 
  -     * Performs some operation on the input object.
  +    
  +    /**
  +     * Performs an action on the specified input object.
  +     *
  +     * @param input  the input to execute on
  +     * @throws ClassCastException (runtime) if the input is the wrong class
  +     * @throws IllegalArgumentException (runtime) if the input is invalid
  +     * @throws FunctorException (runtime) if any other error occurs
        */
  -    void execute(Object input);
  +    public void execute(Object input);
       
   }
  
  
  
  1.5       +28 -17    jakarta-commons/collections/src/java/org/apache/commons/collections/Transformer.java
  
  Index: Transformer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/Transformer.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Transformer.java	12 Jun 2002 03:59:15 -0000	1.4
  +++ Transformer.java	16 May 2003 13:41:10 -0000	1.5
  @@ -1,13 +1,10 @@
   /*
    * $Header$
  - * $Revision$
  - * $Date$
  - *
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -23,11 +20,11 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:
  + *    any, must include the following acknowledgment:
    *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
  - *    Alternately, this acknowlegement may appear in the software itself,
  - *    if and wherever such third-party acknowlegements normally appear.
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
    *
    * 4. The names "The Jakarta Project", "Commons", and "Apache Software
    *    Foundation" must not be used to endorse or promote products derived
  @@ -36,7 +33,7 @@
    *
    * 5. Products derived from this software may not be called "Apache"
    *    nor may "Apache" appear in their names without prior written
  - *    permission of the Apache Group.
  + *    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
  @@ -60,15 +57,29 @@
    */
   package org.apache.commons.collections;
   
  -/** An object capable of transforming an input object into some output object.
  -  *
  -  * @since 1.0
  -  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  -  */
  +/**
  + * <code>Transformer</code> defines an interface implemented by classes that
  + * transform one object into another. The original object is left unchanged.
  + * Transformers are typically used for type conversions, or extracting data
  + * from an object.
  + * 
  + * @since Commons Collections 1.0
  + * @version $Revision$ $Date$
  + * 
  + * @author James Strachan
  + * @author Stephen Colebourne
  + */
   public interface Transformer {
   
  -    /** Transforms the input object (leaving it unchanged) into some output object.
  -      * @return the transformation of the input object to the output object
  -      */
  +    /**
  +     * Transforms the input object (leaving it unchanged) into some output object.
  +     *
  +     * @param input  the object to be transformed
  +     * @return a transformed object
  +     * @throws ClassCastException (runtime) if the input is the wrong class
  +     * @throws IllegalArgumentException (runtime) if the input is invalid
  +     * @throws FunctorException (runtime) if the transform cannot be completed
  +     */
       public Object transform(Object input);
  +    
   }
  
  
  
  1.6       +28 -21    jakarta-commons/collections/src/java/org/apache/commons/collections/Predicate.java
  
  Index: Predicate.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/Predicate.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Predicate.java	15 Aug 2002 20:04:31 -0000	1.5
  +++ Predicate.java	16 May 2003 13:41:10 -0000	1.6
  @@ -1,13 +1,10 @@
   /*
    * $Header$
  - * $Revision$
  - * $Date$
  - *
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -23,11 +20,11 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:
  + *    any, must include the following acknowledgment:
    *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
  - *    Alternately, this acknowlegement may appear in the software itself,
  - *    if and wherever such third-party acknowlegements normally appear.
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
    *
    * 4. The names "The Jakarta Project", "Commons", and "Apache Software
    *    Foundation" must not be used to endorse or promote products derived
  @@ -36,7 +33,7 @@
    *
    * 5. Products derived from this software may not be called "Apache"
    *    nor may "Apache" appear in their names without prior written
  - *    permission of the Apache Group.
  + *    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
  @@ -60,18 +57,28 @@
    */
   package org.apache.commons.collections;
   
  -/** Performs some predicate which returns true or false based on the input object.
  -  * Predicate instances can be used to implement queries or to do filtering.
  -  *
  -  * @since 1.0
  -  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  -  */
  +/**
  + * <code>Predicate</code> defines an interface implemented by classes that
  + * perform a predicate test on an object. Predicate instances can be used
  + * to implement queries or to do filtering. 
  + * 
  + * @since Commons Collections 1.0
  + * @version $Revision$ $Date$
  + * 
  + * @author James Strachan
  + * @author Stephen Colebourne
  + */
   public interface Predicate {
  -
  +    
       /**
  -      *  Returns true if the input object matches this predicate. 
  -      *
  -      * @return true if the input object matches this predicate, else returns false
  -      */
  -    public boolean evaluate(Object input);
  +     * Use the specified parameter to perform a test that returns true or false.
  +     *
  +     * @param object  the object to evaluate
  +     * @return true or false
  +     * @throws ClassCastException (runtime) if the input is the wrong class
  +     * @throws IllegalArgumentException (runtime) if the input is invalid
  +     * @throws FunctorException (runtime) if the predicate encounters a problem
  +     */
  +    public boolean evaluate(Object object);
  +    
   }
  
  
  
  1.4       +22 -23    jakarta-commons/collections/src/java/org/apache/commons/collections/Factory.java
  
  Index: Factory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/Factory.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Factory.java	12 Oct 2002 22:15:19 -0000	1.3
  +++ Factory.java	16 May 2003 13:41:10 -0000	1.4
  @@ -1,12 +1,10 @@
   /*
    * $Header$
  - * $Revision$
  - * $Date$
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  + * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -22,20 +20,20 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:
  + *    any, must include the following acknowledgment:
    *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
  - *    Alternately, this acknowlegement may appear in the software itself,
  - *    if and wherever such third-party acknowlegements normally appear.
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
    *
  - * 4. The names "The Jakarta Project", "Struts", and "Apache Software
  + * 4. The names "The Jakarta Project", "Commons", 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 names without prior written
  - *    permission of the Apache Group.
  + *    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
  @@ -59,23 +57,24 @@
    */
   package org.apache.commons.collections;
   
  -
  -
   /**
  - * Factory
  - * A simple interface that describes the most basic means of having the ability
  - * to create an object.
  + * <code>Factory</code> defines an interface implemented by classes that
  + * create objects.
  + * 
  + * @since Commons Collections 2.1
  + * @version $Revision$ $Date$
    *
    * @author Arron Bates
  - * @version $Revision$
  - * @since 2.1
  + * @author Stephen Colebourne
    */
   public interface Factory {
  -
  -  /** Simple method from which will come the new object from the factory.
  -   *
  -   * @return Object reference to the new object.
  -   */
  -  public Object create();
  -  
  +    
  +    /**
  +     * Create a new object.
  +     *
  +     * @return a new object
  +     * @throws FunctorException (runtime) if the factory cannot create an object
  +     */
  +    public Object create();
  +    
   }
  
  
  
  1.1                  jakarta-commons/collections/src/java/org/apache/commons/collections/TransformerUtils.java
  
  Index: TransformerUtils.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/TransformerUtils.java,v 1.1 2003/05/16 13:41:10 scolebourne Exp $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 "The Jakarta Project", "Commons", 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 names 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 (INCLUDING, 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.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  package org.apache.commons.collections;
  
  import java.io.Serializable;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.Collection;
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * <code>TransformerUtils</code> provides reference implementations and 
   * utilities for the Transformer functor interface. The supplied transformers are:
   * <ul>
   * <li>Invoker - returns the result of a method call on the input object
   * <li>Clone - returns a clone of the input object
   * <li>Constant - always returns the same object
   * <li>Closure - performs a Closure and returns the input object
   * <li>Predicate - returns the result of the predicate as a Boolean
   * <li>Factory - returns a new object from a factory
   * <li>Chained - chains two or more transformers together
   * <li>Switch - calls one transformer based on one or more predicates
   * <li>SwitchMap - calls one transformer looked up from a Map
   * <li>Instantiate - the Class input object is instantiated
   * <li>Map - returns an object from a supplied Map
   * <li>Null - always returns null
   * <li>NOP - returns the input object, which should be immutable
   * <li>Exception - always throws an exception
   * </ul>
   * All the supplied transformers are Serializable.
   *
   * @since Commons Collections 3.0
   * @version $Revision: 1.1 $ $Date: 2003/05/16 13:41:10 $
   * 
   * @author Stephen Colebourne
   */
  public class TransformerUtils {
  
      /**
       * A transformer that always throws an exception
       */
      private static final Transformer EXCEPTION_TRANSFORMER = new ExceptionTransformer();
      /**
       * A transformer that always returns null
       */
      private static final Transformer NULL_TRANSFORMER = new ConstantTransformer(null);
      /**
       * A transformer that returns the input object
       */
      private static final Transformer NOP_TRANSFORMER = new NOPTransformer();
      /**
       * A transformer that clones the input object
       */
      private static final Transformer CLONE_TRANSFORMER = new CloneTransformer();
      /**
       * A transformer that creates an object from a Class
       */
      private static final Transformer INSTANTIATE_TRANSFORMER = new InstantiateTransformer(null, null);
  
      /**
       * This class is not normally instantiated.
       */
      public TransformerUtils() {
          super();
      }
  
      /**
       * Gets a transformer that always throws an exception.
       * This could be useful during testing as a placeholder.
       * 
       * @return the transformer
       */
      public static Transformer exceptionTransformer() {
          return EXCEPTION_TRANSFORMER;
      }
  
      /**
       * Gets a transformer that always returns null.
       * 
       * @return the transformer
       */
      public static Transformer nullTransformer() {
          return NULL_TRANSFORMER;
      }
  
      /**
       * Gets a transformer that returns the input object.
       * The input object should be immutable to maintain the
       * contract of Transformer (although this is not checked).
       * 
       * @return the transformer
       */
      public static Transformer nopTransformer() {
          return NOP_TRANSFORMER;
      }
  
      /**
       * Gets a transformer that returns a clone of the input
       * object. The input object will be cloned using one of these
       * techniques (in order):
       * <ul>
       * <li>public clone method
       * <li>public copy constructor
       * <li>serialization clone
       * <ul>
       * 
       * @return the transformer
       */
      public static Transformer cloneTransformer() {
          return CLONE_TRANSFORMER;
      }
  
      /**
       * Creates a Transformer that will return the same object each time the 
       * transformer is used.
       *
       * @param constantToReturn  the constant object to return each time in the transformer
       * @return the transformer.
       */
      public static Transformer constantTransformer(Object constantToReturn) {
          return new ConstantTransformer(constantToReturn);
      }
  
      /**
       * Creates a Transformer that calls a Closure each time the transformer is used.
       * The transformer returns the input object.
       *
       * @param command  the command to run each time in the transformer
       * @return the transformer.
       */
      public static Transformer asTransformer(Closure closure) {
          if (closure == null) {
              throw new IllegalArgumentException("The closure must not be null");
          }
          return new ClosureTransformer(closure);
      }
  
      /**
       * Creates a Transformer that calls a Predicate each time the transformer is used.
       * The transformer will return either Boolean.TRUE or Boolean.FALSE.
       *
       * @param predicate  the predicate to run each time in the transformer
       * @return the transformer.
       */
      public static Transformer asTransformer(Predicate predicate) {
          if (predicate == null) {
              throw new IllegalArgumentException("The predicate must not be null");
          }
          return new PredicateTransformer(predicate);
      }
  
      /**
       * Creates a Transformer that calls a Factory each time the transformer is used.
       * The transformer will return the value returned by the factory.
       *
       * @param factory  the factory to run each time in the transformer
       * @return the transformer.
       */
      public static Transformer asTransformer(Factory factory) {
          if (factory == null) {
              throw new IllegalArgumentException("The factory must not be null");
          }
          return new FactoryTransformer(factory);
      }
  
      /**
       * Create a new Transformer that calls two transformers, passing the result of
       * the first into the second.
       * 
       * @param transformer1  the first transformer
       * @param transformer2  the second transformer
       * @return the transformer
       * @throws IllegalArgumentException if either transformer is null
       */
      public static Transformer chainedTransformer(Transformer transformer1, Transformer transformer2) {
          Transformer[] trs = new Transformer[] {transformer1, transformer2};
          validate(trs);
          return new ChainedTransformer(trs);
      }
  
      /**
       * Create a new Transformer that calls each transformer in turn, passing the 
       * result into the next transformer.
       * 
       * @param transformers  an array of transformers to chain
       * @return the transformer
       * @throws IllegalArgumentException if the transformers array is null
       * @throws IllegalArgumentException if the transformers array has 0 elements
       * @throws IllegalArgumentException if any transformer in the array is null
       */
      public static Transformer chainedTransformer(Transformer[] transformers) {
          Transformer[] trs = copy(transformers);
          validate(trs);
          return new ChainedTransformer(trs);
      }
  
      /**
       * Create a new Transformer that calls each transformer in turn, passing the 
       * result into the next transformer. The ordering is that of the iterator()
       * method on the collection.
       * 
       * @param transformers  a collection of transformers to chain
       * @return the transformer
       * @throws IllegalArgumentException if the transformers collection is null
       * @throws IllegalArgumentException if the transformers collection is empty
       * @throws IllegalArgumentException if any transformer in the collection is null
       */
      public static Transformer chainedTransformer(Collection transformers) {
          Transformer[] trs = null;
          if (transformers == null) {
              throw new IllegalArgumentException("The transformer collection must not be null");
          }
          // convert to array like this to guarantee iterator() ordering
          trs = new Transformer[transformers.size()];
          int i = 0;
          for (Iterator it = transformers.iterator(); it.hasNext();) {
              trs[i++] = (Transformer) it.next();
          }
          validate(trs);
          return new ChainedTransformer(trs);
      }
  
      /**
       * Create a new Transformer that calls one of two transformers depending 
       * on the specified predicate.
       * 
       * @param predicate  the predicate to switch on
       * @param trueTransformer  the transformer called if the predicate is true
       * @param falseTransformer  the transformer called if the predicate is false
       * @return the transformer
       * @throws IllegalArgumentException if the predicate is null
       * @throws IllegalArgumentException if either transformer is null
       */
      public static Transformer switchTransformer(Predicate predicate, Transformer trueTransformer, Transformer falseTransformer) {
          return switchTransformerInternal(new Predicate[] { predicate }, new Transformer[] { trueTransformer }, falseTransformer);
      }
  
      /**
       * Create a new Transformer that calls one of the transformers depending 
       * on the predicates. The transformer at array location 0 is called if the
       * predicate at array location 0 returned true. Each predicate is evaluated
       * until one returns true. If no predicates evaluate to true, null is returned.
       * 
       * @param predicates  an array of predicates to check
       * @param transformers  an array of transformers to call
       * @return the transformer
       * @throws IllegalArgumentException if the either array is null
       * @throws IllegalArgumentException if the either array has 0 elements
       * @throws IllegalArgumentException if any element in the arrays is null
       * @throws IllegalArgumentException if the arrays are different sizes
       */
      public static Transformer switchTransformer(Predicate[] predicates, Transformer[] transformers) {
          return switchTransformerInternal(copy(predicates), copy(transformers), null);
      }
  
      /**
       * Create a new Transformer that calls one of the transformers depending 
       * on the predicates. The transformer at array location 0 is called if the
       * predicate at array location 0 returned true. Each predicate is evaluated
       * until one returns true. If no predicates evaluate to true, the default
       * transformer is called.
       * 
       * @param predicates  an array of predicates to check
       * @param transformers  an array of transformers to call
       * @param defaultTransformer  the default to call if no predicate matches
       * @return the transformer
       * @throws IllegalArgumentException if the either array is null
       * @throws IllegalArgumentException if the either array has 0 elements
       * @throws IllegalArgumentException if any element in the arrays is null
       * @throws IllegalArgumentException if the arrays are different sizes
       */
      public static Transformer switchTransformer(Predicate[] predicates, Transformer[] transformers, Transformer defaultTransformer) {
          return switchTransformerInternal(copy(predicates), copy(transformers), defaultTransformer);
      }
  
      /**
       * Create a new Transformer that calls one of the transformers depending 
       * on the predicates. 
       * <p>
       * The Map consists of Predicate keys and Transformer values. A transformer 
       * is called if its matching predicate returns true. Each predicate is evaluated
       * until one returns true. If no predicates evaluate to true, the default
       * transformer is called. The default transformer is set in the map with a 
       * null key. If no default transformer is set, null will be returned in a default
       * case. The ordering is that of the iterator() method on the entryset collection 
       * of the map.
       * 
       * @param predicatesAndTransformers  a map of predicates to transformers
       * @return the transformer
       * @throws IllegalArgumentException if the map is null
       * @throws IllegalArgumentException if the map is empty
       * @throws IllegalArgumentException if any transformer in the map is null
       * @throws ClassCastException  if the map elements are of the wrong type
       */
      public static Transformer switchTransformer(Map predicatesAndTransformers) {
          Transformer[] trs = null;
          Predicate[] preds = null;
          if (predicatesAndTransformers == null) {
              throw new IllegalArgumentException("The predicate and transformer map must not be null");
          }
          // convert to array like this to guarantee iterator() ordering
          Transformer def = (Transformer) predicatesAndTransformers.remove(null);
          int size = predicatesAndTransformers.size();
          trs = new Transformer[size];
          preds = new Predicate[size];
          int i = 0;
          for (Iterator it = predicatesAndTransformers.entrySet().iterator(); it.hasNext();) {
              Map.Entry entry = (Map.Entry) it.next();
              preds[i] = (Predicate) entry.getKey();
              trs[i] = (Transformer) entry.getValue();
              i++;
          }
          return switchTransformerInternal(preds, trs, def);
      }
  
      /**
       * Validate input and create transformer
       */
      private static Transformer switchTransformerInternal(Predicate[] predicates, Transformer[] transformers, Transformer defaultTransformer) {
          validate(predicates);
          validate(transformers);
          if (predicates.length != transformers.length) {
              throw new IllegalArgumentException("The predicate and transformer arrays must be the same size");
          }
          if (defaultTransformer == null) {
              defaultTransformer = nullTransformer();
          }
          return new SwitchTransformer(predicates, transformers, defaultTransformer);
      }
      
      /**
       * Create a new Transformer that uses the input object as a key to find the
       * transformer to call. 
       * <p>
       * The Map consists of object keys and Transformer values. A transformer 
       * is called if the input object equals the key. If there is no match, the
       * default transformer is called. The default transformer is set in the map
       * using a null key. If no default is set, null will be returned in a default case.
       * 
       * @param objectsAndTransformers  a map of objects to transformers
       * @return the transformer
       * @throws IllegalArgumentException if the map is null
       * @throws IllegalArgumentException if the map is empty
       * @throws IllegalArgumentException if any transformer in the map is null
       */
      public static Transformer switchMapTransformer(Map objectsAndTransformers) {
          Transformer[] trs = null;
          Predicate[] preds = null;
          if (objectsAndTransformers == null) {
              throw new IllegalArgumentException("The obejct and transformer map must not be null");
          }
          Transformer def = (Transformer) objectsAndTransformers.remove(null);
          int size = objectsAndTransformers.size();
          trs = new Transformer[size];
          preds = new Predicate[size];
          int i = 0;
          for (Iterator it = objectsAndTransformers.entrySet().iterator(); it.hasNext();) {
              Map.Entry entry = (Map.Entry) it.next();
              preds[i] = PredicateUtils.equalPredicate(entry.getKey());
              trs[i] = (Transformer) entry.getValue();
              i++;
          }
          return switchTransformer(preds, trs, def);
      }
  
      /**
       * Gets a Transformer that expects an input Class object that it will instantiate.
       * 
       * @return the transformer
       */
      public static Transformer instantiateTransformer() {
          return INSTANTIATE_TRANSFORMER;
      }
  
      /** 
       * Creates a Transformer that expects an input Class object that it will 
       * instantiate. The constructor used is determined by the arguments specified
       * to this method.
       *
       * @param paramTypes  parameter types for the constructor, can be null
       * @param args  the arguments to pass to the constructor, can be null
       * @return the transformer
       * @throws IllegalArgumentException if the paramTypes and args don't match
       */
      public static Transformer instantiateTransformer(Class[] paramTypes, Object[] args) {
          return new InstantiateTransformer(paramTypes, args);
      }
  
      /** 
       * Creates a Transformer that uses the passed in Map to transform the input 
       * object (as a simple lookup).
       *
       * @param map  the map to use to transform the objects
       * @return the transformer
       * @throws IllegalArgumentException if the map is null
       */
      public static Transformer mapTransformer(Map map) {
          if (map == null) {
              throw new IllegalArgumentException("The map must not be null");
          }
          return new MapTransformer(map);
      }
  
      /**
       * Gets a Transformer that invokes a method on the input object.
       * The method must have no parameters. If the input object is null, 
       * null is returned.
       * <p>
       * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
       * will call the <code>getName/code> method on the input object to 
       * determine the transformer result.
       * 
       * @param methodName  the method name to call on the input object, may not be null
       * @return the transformer
       * @throws IllegalArgumentException if the methodName is null.
       */
      public static Transformer invokerTransformer(String methodName){
          return new InvokerTransformer(methodName, null, null);
      }
  
      /**
       * Gets a Transformer that invokes a method on the input object.
       * The method parameters are specified. If the input object is null, 
       * null is returned.
       * 
       * @param methodName  the name of the method
       * @param paramTypes  the parameter types
       * @param args  the arguments
       * @return the transformer
       * @throws IllegalArgumentException if the method name is null
       * @throws IllegalArgumentException if the paramTypes and args don't match
       */
      public static Transformer invokerTransformer(String methodName, Class[] paramTypes, Object[] args){
          return new InvokerTransformer(methodName, paramTypes, args);
      }
  
      /**
       * Copy method
       * 
       * @param predicates  the predicates to copy
       */
      private static Predicate[] copy(Predicate[] predicates) {
          if (predicates == null) {
              return null;
          }
          return (Predicate[]) predicates.clone();
      }
      
      /**
       * Validate method
       * 
       * @param predicates  the predicates to validate
       */
      private static void validate(Predicate[] predicates) {
          if (predicates == null) {
              throw new IllegalArgumentException("The predicate array must not be null");
          }
          if (predicates.length < 1) {
              throw new IllegalArgumentException(
                  "At least 1 predicate must be specified in the predicate array, size was " + predicates.length);
          }
          for (int i = 0; i < predicates.length; i++) {
              if (predicates[i] == null) {
                  throw new IllegalArgumentException(
                      "The predicate array must not contain a null predicate, index " + i + " was null");
              }
          }
      }
  
      /**
       * Copy method
       * 
       * @param transformers  the transformers to copy
       */
      private static Transformer[] copy(Transformer[] transformers) {
          if (transformers == null) {
              return null;
          }
          return (Transformer[]) transformers.clone();
      }
      
      /**
       * Validate method
       * 
       * @param transformers  the transformers to validate
       */
      private static void validate(Transformer[] transformers) {
          if (transformers == null) {
              throw new IllegalArgumentException("The transformer array must not be null");
          }
          if (transformers.length < 1) {
              throw new IllegalArgumentException(
                  "At least 1 transformer must be specified in the transformer array, size was " + transformers.length);
          }
          for (int i = 0; i < transformers.length; i++) {
              if (transformers[i] == null) {
                  throw new IllegalArgumentException(
                      "The transformer array must not contain a null transformer, index " + i + " was null");
              }
          }
      }
  
      // ExceptionTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * ExceptionTransformer always throws an exception.
       */
      private static class ExceptionTransformer implements Transformer, Serializable {
  
          /**
           * Constructor
           */
          private ExceptionTransformer() {
              super();
          }
  
          /**
           * Always throw exception
           */
          public Object transform(Object input) {
              throw new FunctorException("ExceptionTransformer invoked");
          }
      }
  
      // NOPTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * NOPTransformer returns the input object.
       */
      private static class NOPTransformer implements Transformer, Serializable {
  
          /**
           * Constructor
           */
          private NOPTransformer() {
              super();
          }
  
          /**
           * Return the input object
           */
          public Object transform(Object input) {
              return input;
          }
      }
  
      // CloneTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * CloneTransformer returns a clone of the input object.
       */
      private static class CloneTransformer implements Transformer, Serializable {
  
          /**
           * Constructor
           */
          private CloneTransformer() {
              super();
          }
  
          /**
           * Returns a clone of the input object
           */
          public Object transform(Object input) {
              if (input == null) {
                  return null;
              }
              return FactoryUtils.prototypeFactory(input).create();
          }
      }
  
      // ConstantTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * ConstantTransformer returns the same instance each time.
       */
      private static class ConstantTransformer implements Transformer, Serializable {
          /** The constant to return each time */
          private final Object iConstant;
  
          /**
           * Constructor to store constant.
           */
          private ConstantTransformer(Object constant) {
              super();
              iConstant = constant;
          }
  
          /**
           * Always return constant.
           */
          public Object transform(Object input) {
              return iConstant;
          }
      }
  
      // ClosureTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * ClosureTransformer executes a Closure object.
       */
      private static class ClosureTransformer implements Transformer, Serializable {
          /** The closure to call each time */
          private final Closure iClosure;
  
          /**
           * Constructor to store closure.
           */
          private ClosureTransformer(Closure closure) {
              super();
              iClosure = closure;
          }
  
          /**
           * Exceute the closure and return the input.
           */
          public Object transform(Object input) {
              iClosure.execute(input);
              return input;
          }
      }
  
      // PredicateTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * PredicateTransformer evaluates a Predicate object.
       */
      private static class PredicateTransformer implements Transformer, Serializable {
          /** The predicate to call each time */
          private final Predicate iPredicate;
  
          /**
           * Constructor to store predicate.
           */
          private PredicateTransformer(Predicate predicate) {
              super();
              iPredicate = predicate;
          }
  
          /**
           * Evaluate the predicate and return the result as a Boolean.
           */
          public Object transform(Object input) {
              return new Boolean(iPredicate.evaluate(input));
          }
      }
  
      // FactoryTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * FactoryTransformer returns the result of calling a Factory.
       */
      private static class FactoryTransformer implements Transformer, Serializable {
          /** The factory to call each time */
          private final Factory iFactory;
  
          /**
           * Constructor to store factory.
           */
          private FactoryTransformer(Factory factory) {
              super();
              iFactory = factory;
          }
  
          /**
           * Return the result of calling the factory.
           */
          public Object transform(Object input) {
              return iFactory.create();
          }
      }
  
      // ChainedTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * ChainedTransformer returns the result of calling a list of transformers.
       */
      private static class ChainedTransformer implements Transformer, Serializable {
          /** The array of transformers to call */
          private final Transformer[] iTransformers;
  
          /**
           * Constructor to store params.
           */
          private ChainedTransformer(Transformer[] transformers) {
              super();
              iTransformers = transformers;
          }
  
          /**
           * Returns the result of calling a list of transformers.
           */
          public Object transform(Object object) {
              for (int i = 0; i < iTransformers.length; i++) {
                  object = iTransformers[i].transform(object);
              }
              return object;
          }
      }
  
      // SwitchTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * SwitchTransformer returns the result of the transformer whose predicate returns true.
       */
      private static class SwitchTransformer implements Transformer, Serializable {
          /** The array of predicates to switch on */
          private final Predicate[] iPredicates;
          /** The array of transformers to call */
          private final Transformer[] iTransformers;
          /** The default transformer called if no predicate matches */
          private final Transformer iDefault;
  
          /**
           * Constructor to store params.
           */
          private SwitchTransformer(Predicate[] predicates, Transformer[] transformers, Transformer defaultTransformer) {
              super();
              iPredicates = predicates;
              iTransformers = transformers;
              iDefault = defaultTransformer;
          }
  
          /**
           * Returns the result of the transformer whose predicate returns true.
           */
          public Object transform(Object input) {
              for (int i = 0; i < iPredicates.length; i++) {
                  if (iPredicates[i].evaluate(input) == true) {
                      return iTransformers[i].transform(input);
                  }
              }
              return iDefault.transform(input);
          }
      }
  
      // InstantiateTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * InstantiateTransformer returns the result of instantiating the input Class object.
       */
      private static class InstantiateTransformer implements Transformer, Serializable {
          /** The array of reflection parameter types */
          private final Class[] iParamTypes;
          /** The array of reflection arguments */
          private final Object[] iArgs;
  
          /**
           * Constructor to store params.
           */
          private InstantiateTransformer(Class[] paramTypes, Object[] args) {
              super();
              if (((paramTypes == null) && (args != null))
                  || ((paramTypes != null) && (args == null))
                  || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
                  throw new IllegalArgumentException("InstantiateTransformer: The parameter types must match the arguments");
              }
              if ((paramTypes == null) && (args == null)) {
                  iParamTypes = null;
                  iArgs = null;
              } else {
                  iParamTypes = (Class[]) paramTypes.clone();
                  iArgs = (Object[]) args.clone();
              }
          }
  
          /**
           * Return the result of instantiating the input Class object.
           */
          public Object transform(Object input) {
              try {
                  if (input instanceof Class == false) {
                      throw new FunctorException(
                          "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                              + (input == null ? "null object" : input.getClass().getName()));
                  }
                  return FactoryUtils.reflectionFactory((Class) input, iParamTypes, iArgs).create();
  
              } catch (IllegalArgumentException ex) {
                  throw new FunctorException("InstantiateTransformer", ex);
              }
          }
      }
  
      // MapTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * MapTransformer returns the result by looking up in the map.
       */
      private static class MapTransformer implements Transformer, Serializable {
          /** The map of data to lookup in */
          private final Map iMap;
  
          /**
           * Constructor to store map.
           */
          private MapTransformer(Map map) {
              super();
              iMap = map;
          }
  
          /**
           * Returns the result by looking up in the map.
           */
          public Object transform(Object input) {
              return iMap.get(input);
          }
      }
  
      // InvokerTransformer
      //----------------------------------------------------------------------------------
  
      /**
       * InvokerTransformer returns the result of invoking the specified method on 
       * the input object.
       */
      private static class InvokerTransformer implements Transformer, Serializable {
          /** The method name to call */
          private final String iMethodName;
          /** The array of reflection parameter types */
          private final Class[] iParamTypes;
          /** The array of reflection arguments */
          private final Object[] iArgs;
  
          /**
           * Constructor.
           */
          public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
              super();
              if (methodName == null) {
                  throw new IllegalArgumentException("InvokerTransformer: The method to invoke must not be null");
              }
              if (((paramTypes == null) && (args != null))
                  || ((paramTypes != null) && (args == null))
                  || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
                  throw new IllegalArgumentException("InvokerTransformer: The parameter types must match the arguments");
              }
  
              iMethodName = methodName;
              if ((paramTypes == null) && (args == null)) {
                  iParamTypes = null;
                  iArgs = null;
              } else {
                  iParamTypes = (Class[]) paramTypes.clone();
                  iArgs = (Object[]) args.clone();
              }
          }
  
          /**
           * Invoke the specified method on the input object.
           */
          public Object transform(Object input) {
              if (input == null) {
                  return null;
              }
              try {
                  Class cls = input.getClass();
                  Method method = cls.getMethod(iMethodName, iParamTypes);
                  return method.invoke(input, iArgs);
                  
              } catch (NoSuchMethodException ex) {
                  throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
              } catch (IllegalAccessException ex) {
                  throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
              } catch (InvocationTargetException ex) {
                  throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
              }
          }
      }
  
  }
  
  
  
  1.1                  jakarta-commons/collections/src/java/org/apache/commons/collections/FunctorException.java
  
  Index: FunctorException.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/FunctorException.java,v 1.1 2003/05/16 13:41:10 scolebourne Exp $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 "The Jakarta Project", "Commons", 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 names 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 (INCLUDING, 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.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  package org.apache.commons.collections;
  
  import java.io.PrintStream;
  import java.io.PrintWriter;
  
  /**
   * Exception thrown from functors.
   * If required, a root cause error can be wrapped within this one.
   * 
   * @since Commons Collections 3.0
   * @version $Revision: 1.1 $ $Date: 2003/05/16 13:41:10 $
   *
   * @author Stephen Colebourne
   */
  public class FunctorException extends RuntimeException {
      
      /**
       * Does JDK support nested exceptions
       */
      private static final boolean JDK_SUPPORTS_NESTED;
      
      static {
          boolean flag = false;
          try {
              Throwable.class.getDeclaredMethod("getCause", new Class[0]);
              flag = true;
          } catch (NoSuchMethodException ex) {
              flag = false;
          }
          JDK_SUPPORTS_NESTED = flag;
      }
      
      /**
       * Root cause of the exception
       */
      private final Throwable iThrowable;
  
      /**
       * Constructs a new <code>FunctorException</code> without specified
       * detail message.
       */
      public FunctorException() {
          super();
          iThrowable = null;
      }
  
      /**
       * Constructs a new <code>FunctorException</code> with specified
       * detail message.
       *
       * @param msg  the error message.
       */
      public FunctorException(String msg) {
          super(msg);
          iThrowable = null;
      }
  
      /**
       * Constructs a new <code>FunctorException</code> with specified
       * nested <code>Throwable</code> root cause.
       *
       * @param rootCause  the exception or error that caused this exception
       *                   to be thrown.
       */
      public FunctorException(Throwable rootCause) {
          super((rootCause == null ? null : rootCause.getMessage()));
          iThrowable = rootCause;
      }
  
      /**
       * Constructs a new <code>FunctorException</code> with specified
       * detail message and nested <code>Throwable</code> root cause.
       *
       * @param msg        the error message.
       * @param rootCause  the exception or error that caused this exception
       *                   to be thrown.
       */
      public FunctorException(String msg, Throwable rootCause) {
          super(msg);
          iThrowable = rootCause;
      }
  
      /**
       * Gets the cause of this throwable.
       * 
       * @return  the cause of this throwable, or <code>null</code>
       */
      public Throwable getCause() {
          return iThrowable;
      }
  
      /**
       * Prints the stack trace of this exception to the standard error stream.
       */
      public void printStackTrace() {
          printStackTrace(System.err);
      }
  
      /**
       * Prints the stack trace of this exception to the specified stream.
       *
       * @param out  the <code>PrintStream</code> to use for output
       */
      public void printStackTrace(PrintStream out) {
          synchronized (out) {
              PrintWriter pw = new PrintWriter(out, false);
              printStackTrace(pw);
              // Flush the PrintWriter before it's GC'ed.
              pw.flush();
          }
      }
  
      /**
       * Prints the stack trace of this exception to the specified writer.
       *
       * @param out  the <code>PrintWriter</code> to use for output
       */
      public void printStackTrace(PrintWriter out) {
          synchronized (out) {
              super.printStackTrace(out);
              if (iThrowable != null && JDK_SUPPORTS_NESTED == false) {
                  out.print("Caused by: ");
                  iThrowable.printStackTrace(out);
              }
          }
      }
  
  }
  
  
  
  1.7       +982 -279  jakarta-commons/collections/src/java/org/apache/commons/collections/PredicateUtils.java
  
  
  
  
  1.7       +388 -123  jakarta-commons/collections/src/java/org/apache/commons/collections/FactoryUtils.java
  
  
  
  
  1.1                  jakarta-commons/collections/src/java/org/apache/commons/collections/ClosureUtils.java
  
  Index: ClosureUtils.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/ClosureUtils.java,v 1.1 2003/05/16 13:41:10 scolebourne Exp $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 "The Jakarta Project", "Commons", 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 names 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 (INCLUDING, 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.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  package org.apache.commons.collections;
  
  import java.io.Serializable;
  import java.util.Collection;
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * <code>ClosureUtils</code> provides reference implementations and utilities
   * for the Closure functor interface. The supplied closures are:
   * <ul>
   * <li>Invoker - invokes a method on the input object
   * <li>For - repeatedly calls a closure for a fixed number of times
   * <li>While - repeatedly calls a closure while a predicate is true
   * <li>DoWhile - repeatedly calls a closure while a predicate is true
   * <li>Chained - chains two or more closures together
   * <li>Switch - calls one closure based on one or more predicates
   * <li>SwitchMap - calls one closure looked up from a Map
   * <li>Transformer - wraps a Transformer as a Closure
   * <li>NOP - does nothing
   * <li>Exception - always throws an exception
   * </ul>
   * All the supplied closures are Serializable.
   * 
   * @since Commons Collections 3.0
   * @version $Revision: 1.1 $ $Date: 2003/05/16 13:41:10 $
   *
   * @author Stephen Colebourne
   */
  public class ClosureUtils {
  
      /**
       * A Closure that always throws an exception
       */
      private static final Closure EXCEPTION_CLOSURE = new ExceptionClosure();
      /**
       * A Closure that does nothing
       */
      private static final Closure NOP_CLOSURE = new NOPClosure();
  
      /**
       * This class is not normally instantiated.
       */
      public ClosureUtils() {
          super();
      }
  
      /**
       * Gets a Closure that always throws an exception.
       * This could be useful during testing as a placeholder.
       *
       * @return the closure
       */
      public static Closure exceptionClosure() {
          return EXCEPTION_CLOSURE;
      }
  
      /**
       * Gets a Closure that will do nothing.
       * This could be useful during testing as a placeholder.
       *
       * @return the closure
       */
      public static Closure nopClosure() {
          return NOP_CLOSURE;
      }
  
      /**
       * Creates a Closure that calls a Transformer each time it is called.
       * The transformer will be called using the closure's input object.
       * The transformer's result will be ignored.
       *
       * @param transformer  the transformer to run each time in the closure
       * @return the closure.
       */
      public static Closure asClosure(Transformer transformer) {
          if (transformer == null) {
              throw new IllegalArgumentException("The transformer must not be null");
          }
          return new TransformerClosure(transformer);
      }
  
      /**
       * Creates a Closure that will call the closure <code>count</code> times.
       *
       * @param count  the number of times to loop
       * @param closure  the closure to call repeatedly
       * @return the <code>for</code> closure
       * @throws IllegalArgumentException if either argument is null
       */
      public static Closure forClosure(int count, Closure closure) {
          if (count < 0) {
              throw new IllegalArgumentException("The loop count must not be less than zero, it was " + count);
          }
          if (closure == null) {
              throw new IllegalArgumentException("The closure must not be null");
          }
          return new ForClosure(count, closure);
      }
  
      /**
       * Creates a Closure that will call the closure repeatedly until the 
       * predicate returns false.
       *
       * @param predicate  the predicate to use as an end of loop test
       * @param closure  the closure to call repeatedly
       * @return the <code>while</code> closure
       * @throws IllegalArgumentException if either argument is null
       */
      public static Closure whileClosure(Predicate predicate, Closure closure) {
          if (predicate == null) {
              throw new IllegalArgumentException("The predicate must not be null");
          }
          if (closure == null) {
              throw new IllegalArgumentException("The closure must not be null");
          }
          return new WhileClosure(predicate, closure, false);
      }
  
      /**
       * Creates a Closure that will call the closure once and then repeatedly
       * until the predicate returns false.
       *
       * @param closure  the closure to call repeatedly
       * @param predicate  the predicate to use as an end of loop test
       * @return the <code>do-while</code> closure
       * @throws IllegalArgumentException if either argument is null
       */
      public static Closure doWhileClosure(Closure closure, Predicate predicate) {
          if (closure == null) {
              throw new IllegalArgumentException("The closure must not be null");
          }
          if (predicate == null) {
              throw new IllegalArgumentException("The predicate must not be null");
          }
          return new WhileClosure(predicate, closure, true);
      }
  
      /**
       * Creates a Closure that will invoke a specific method on the closure's
       * input object by reflection.
       *
       * @param methodName  the name of the method
       * @return the <code>invoker</code> closure
       * @throws IllegalArgumentException if the method name is null
       */
      public static Closure invokerClosure(String methodName) {
          // reuse transformer as it has caching - this is lazy really, should have inner class here
          return asClosure(TransformerUtils.invokerTransformer(methodName, null, null));
      }
  
      /**
       * Creates a Closure that will invoke a specific method on the closure's
       * input object by reflection.
       *
       * @param methodName  the name of the method
       * @param paramTypes  the parameter types
       * @param args  the arguments
       * @return the <code>invoker</code> closure
       * @throws IllegalArgumentException if the method name is null
       * @throws IllegalArgumentException if the paramTypes and args don't match
       */
      public static Closure invokerClosure(String methodName, Class[] paramTypes, Object[] args) {
          // reuse transformer as it has caching - this is lazy really, should have inner class here
          return asClosure(TransformerUtils.invokerTransformer(methodName, paramTypes, args));
      }
  
      /**
       * Create a new Closure that calls two Closures, passing the result of
       * the first into the second.
       * 
       * @param closure1  the first closure
       * @param closure2  the second closure
       * @return the <code>chained</code> closure
       * @throws IllegalArgumentException if either closure is null
       */
      public static Closure chainedClosure(Closure closure1, Closure closure2) {
          Closure[] closures = new Closure[] { closure1, closure2 };
          validate(closures);
          return new ChainedClosure(closures);
      }
  
      /**
       * Create a new Closure that calls each closure in turn, passing the 
       * result into the next closure.
       * 
       * @param closures  an array of closures to chain
       * @return the <code>chained</code> closure
       * @throws IllegalArgumentException if the closures array is null
       * @throws IllegalArgumentException if the closures array has 0 elements
       * @throws IllegalArgumentException if any closure in the array is null
       */
      public static Closure chainedClosure(Closure[] closures) {
          closures = copy(closures);
          validate(closures);
          return new ChainedClosure(closures);
      }
  
      /**
       * Create a new Closure that calls each closure in turn, passing the 
       * result into the next closure. The ordering is that of the iterator()
       * method on the collection.
       * 
       * @param closures  a collection of closures to chain
       * @return the <code>chained</code> closure
       * @throws IllegalArgumentException if the closures collection is null
       * @throws IllegalArgumentException if the closures collection is empty
       * @throws IllegalArgumentException if any closure in the collection is null
       */
      public static Closure chainedClosure(Collection closures) {
          if (closures == null) {
              throw new IllegalArgumentException("The closure collection must not be null");
          }
          // convert to array like this to guarantee iterator() ordering
          Closure[] cmds = new Closure[closures.size()];
          int i = 0;
          for (Iterator it = closures.iterator(); it.hasNext();) {
              cmds[i++] = (Closure) it.next();
          }
          validate(cmds);
          return new ChainedClosure(cmds);
      }
  
      /**
       * Create a new Closure that calls one of two closures depending 
       * on the specified predicate.
       * 
       * @param predicate  the predicate to switch on
       * @param trueClosure  the closure called if the predicate is true
       * @param falseClosure  the closure called if the predicate is false
       * @return the <code>switch</code> closure
       * @throws IllegalArgumentException if the predicate is null
       * @throws IllegalArgumentException if either closure is null
       */
      public static Closure switchClosure(Predicate predicate, Closure trueClosure, Closure falseClosure) {
          return switchClosureInternal(new Predicate[] { predicate }, new Closure[] { trueClosure }, falseClosure);
      }
  
      /**
       * Create a new Closure that calls one of the closures depending 
       * on the predicates.
       * <p>
       * The closure at array location 0 is called if the predicate at array 
       * location 0 returned true. Each predicate is evaluated
       * until one returns true.
       * 
       * @param predicates  an array of predicates to check
       * @param closures  an array of closures to call
       * @return the <code>switch</code> closure
       * @throws IllegalArgumentException if the either array is null
       * @throws IllegalArgumentException if the either array has 0 elements
       * @throws IllegalArgumentException if any element in the arrays is null
       * @throws IllegalArgumentException if the arrays are different sizes
       */
      public static Closure switchClosure(Predicate[] predicates, Closure[] closures) {
          return switchClosureInternal(copy(predicates), copy(closures), null);
      }
  
      /**
       * Create a new Closure that calls one of the closures depending 
       * on the predicates.
       * <p>
       * The closure at array location 0 is called if the predicate at array
       * location 0 returned true. Each predicate is evaluated
       * until one returns true. If no predicates evaluate to true, the default
       * closure is called.
       * 
       * @param predicates  an array of predicates to check
       * @param closures  an array of closures to call
       * @param defaultClosure  the default to call if no predicate matches
       * @return the <code>switch</code> closure
       * @throws IllegalArgumentException if the either array is null
       * @throws IllegalArgumentException if the either array has 0 elements
       * @throws IllegalArgumentException if any element in the arrays is null
       * @throws IllegalArgumentException if the arrays are different sizes
       */
      public static Closure switchClosure(Predicate[] predicates, Closure[] closures, Closure defaultClosure) {
          return switchClosureInternal(copy(predicates), copy(closures), defaultClosure);
      }
      
      /**
       * Create a new Closure that calls one of the closures depending 
       * on the predicates. 
       * <p>
       * The Map consists of Predicate keys and Closure values. A closure 
       * is called if its matching predicate returns true. Each predicate is evaluated
       * until one returns true. If no predicates evaluate to true, the default
       * closure is called. The default closure is set in the map with a 
       * null key. The ordering is that of the iterator() method on the entryset 
       * collection of the map.
       * 
       * @param predicatesAndClosures  a map of predicates to closures
       * @return the <code>switch</code> closure
       * @throws IllegalArgumentException if the map is null
       * @throws IllegalArgumentException if the map is empty
       * @throws IllegalArgumentException if any closure in the map is null
       * @throws ClassCastException  if the map elements are of the wrong type
       */
      public static Closure switchClosure(Map predicatesAndClosures) {
          Closure[] trs = null;
          Predicate[] preds = null;
          if (predicatesAndClosures == null) {
              throw new IllegalArgumentException("The predicate and closure map must not be null");
          }
          // convert to array like this to guarantee iterator() ordering
          Closure def = (Closure) predicatesAndClosures.remove(null);
          int size = predicatesAndClosures.size();
          trs = new Closure[size];
          preds = new Predicate[size];
          int i = 0;
          for (Iterator it = predicatesAndClosures.entrySet().iterator(); it.hasNext();) {
              Map.Entry entry = (Map.Entry) it.next();
              preds[i] = (Predicate) entry.getKey();
              trs[i] = (Closure) entry.getValue();
              i++;
          }
          return switchClosureInternal(preds, trs, def);
      }
  
      /**
       * Validate input and create closure.
       * 
       * @param predicates  an array of predicates to check
       * @param closures  an array of closures to call
       * @param defaultClosure  the default to call if no predicate matches
       * @return the <code>switch</code> closure
       * @throws IllegalArgumentException if the either array is null
       * @throws IllegalArgumentException if the either array has 0 elements
       * @throws IllegalArgumentException if any element in the arrays is null
       * @throws IllegalArgumentException if the arrays are different sizes
       */
      private static Closure switchClosureInternal(Predicate[] predicates, Closure[] closures, Closure defaultClosure) {
          validate(predicates);
          validate(closures);
          if (predicates.length != closures.length) {
              throw new IllegalArgumentException("The predicate and closure arrays must be the same size");
          }
          if (defaultClosure == null) {
              defaultClosure = nopClosure();
          }
          return new SwitchClosure(predicates, closures, defaultClosure);
      }
  
      /**
       * Create a new Closure that uses the input object as a key to find the
       * closure to call. 
       * <p>
       * The Map consists of object keys and Closure values. A closure 
       * is called if the input object equals the key. If there is no match, the
       * default closure is called. The default closure is set in the map
       * using a null key.
       * 
       * @param objectsAndClosures  a map of objects to closures
       * @return the closure
       * @throws IllegalArgumentException if the map is null
       * @throws IllegalArgumentException if the map is empty
       * @throws IllegalArgumentException if any closure in the map is null
       */
      public static Closure switchMapClosure(Map objectsAndClosures) {
          Closure[] trs = null;
          Predicate[] preds = null;
          if (objectsAndClosures == null) {
              throw new IllegalArgumentException("The obejct and closure map must not be null");
          }
          Closure def = (Closure) objectsAndClosures.remove(null);
          int size = objectsAndClosures.size();
          trs = new Closure[size];
          preds = new Predicate[size];
          int i = 0;
          for (Iterator it = objectsAndClosures.entrySet().iterator(); it.hasNext();) {
              Map.Entry entry = (Map.Entry) it.next();
              preds[i] = PredicateUtils.equalPredicate(entry.getKey());
              trs[i] = (Closure) entry.getValue();
              i++;
          }
          return switchClosure(preds, trs, def);
      }
  
      /**
       * Clone the predicates to ensure that the internal reference can't be messed with.
       * 
       * @param predicates  the predicates to copy
       * @return the cloned predicates
       */
      private static Predicate[] copy(Predicate[] predicates) {
          if (predicates == null) {
              return null;
          }
          return (Predicate[]) predicates.clone();
      }
      
      /**
       * Validate the predicates to ensure that all is well.
       * 
       * @param predicates  the predicates to validate
       * @return the validated predicates
       */
      private static void validate(Predicate[] predicates) {
          if (predicates == null) {
              throw new IllegalArgumentException("The predicate array must not be null");
          }
          if (predicates.length < 1) {
              throw new IllegalArgumentException(
                  "At least 1 predicate must be specified in the predicate array, size was " + predicates.length);
          }
          for (int i = 0; i < predicates.length; i++) {
              if (predicates[i] == null) {
                  throw new IllegalArgumentException("The predicate array must not contain a null predicate, index " + i + " was null");
              }
          }
      }
  
      /**
       * Clone the closures to ensure that the internal reference can't be messed with.
       * 
       * @param closures  the closures to copy
       * @return the cloned closures
       */
      private static Closure[] copy(Closure[] closures) {
          if (closures == null) {
              return null;
          }
          return (Closure[]) closures.clone();
      }
      
      /**
       * Validate the closures to ensure that all is well.
       * 
       * @param closures  the closures to validate
       * @return the validated closures
       */
      private static void validate(Closure[] closures) {
          if (closures == null) {
              throw new IllegalArgumentException("The closure array must not be null");
          }
          if (closures.length < 1) {
              throw new IllegalArgumentException(
                  "At least 1 closure must be specified in the closure array, size was " + closures.length);
          }
          for (int i = 0; i < closures.length; i++) {
              if (closures[i] == null) {
                  throw new IllegalArgumentException("The closure array must not contain a null closure, index " + i + " was null");
              }
          }
      }
  
      // ExceptionClosure
      //----------------------------------------------------------------------------------
  
      /**
       * ExceptionClosure always throws an exception
       */
      private static class ExceptionClosure implements Closure, Serializable {
  
          /**
           * Constructor
           */
          private ExceptionClosure() {
              super();
          }
  
          /**
           * Always throw an exception
           */
          public void execute(Object input) {
              throw new FunctorException("ExceptionClosure invoked");
          }
      }
  
      // NOPClosure
      //----------------------------------------------------------------------------------
  
      /**
       * NOPClosure does nothing
       */
      private static class NOPClosure implements Closure, Serializable {
  
          /**
           * Constructor
           */
          private NOPClosure() {
              super();
          }
  
          /**
           * Do nothing
           */
          public void execute(Object input) {
              // do nothing
          }
      }
  
      // TransformerClosure
      //----------------------------------------------------------------------------------
  
      /**
       * TransformerClosure calls a Transformer using the input object and ignore the result.
       */
      private static class TransformerClosure implements Closure, Serializable {
          /** The transformer to wrap */
          private final Transformer iTransformer;
  
          /**
           * Constructor to store transformer
           */
          private TransformerClosure(Transformer transformer) {
              super();
              iTransformer = transformer;
          }
  
          /**
           * Call the transformer
           */
          public void execute(Object input) {
              iTransformer.transform(input);
          }
      }
  
      // ChainedClosure
      //----------------------------------------------------------------------------------
  
      /**
       * ChainedClosure calls a list of closures.
       */
      private static class ChainedClosure implements Closure, Serializable {
          /** The closures to call in turn */
          private final Closure[] iClosures;
  
          /**
           * Constructor to store params
           */
          private ChainedClosure(Closure[] closures) {
              super();
              iClosures = closures;
          }
  
          /**
           * Execute a list of closures
           */
          public void execute(Object input) {
              for (int i = 0; i < iClosures.length; i++) {
                  iClosures[i].execute(input);
              }
          }
      }
  
      // SwitchClosure
      //----------------------------------------------------------------------------------
  
      /**
       * SwitchClosure calls the closure whose predicate returns true.
       */
      private static class SwitchClosure implements Closure, Serializable {
          /** The tests to consider */
          private final Predicate[] iPredicates;
          /** The matching closures to call */
          private final Closure[] iClosures;
          /** The default closure to call if no tests match */
          private final Closure iDefault;
  
          /**
           * Constructor to store params
           */
          private SwitchClosure(Predicate[] predicates, Closure[] closures, Closure defaultClosure) {
              super();
              iPredicates = predicates;
              iClosures = closures;
              iDefault = defaultClosure;
          }
  
          /**
           * Execute the closure whose predicate returns true
           */
          public void execute(Object input) {
              for (int i = 0; i < iPredicates.length; i++) {
                  if (iPredicates[i].evaluate(input) == true) {
                      iClosures[i].execute(input);
                      return;
                  }
              }
              iDefault.execute(input);
          }
      }
  
      // ForClosure
      //----------------------------------------------------------------------------------
  
      /**
       * ForClosure calls the closure a fixed nunmber of times.
       */
      private static class ForClosure implements Closure, Serializable {
          /** The number of times to loop */
          private final int iCount;
          /** The closure to call */
          private final Closure iClosure;
  
          /**
           * Constructor to store params
           */
          private ForClosure(int count, Closure closure) {
              super();
              iCount = count;
              iClosure = closure;
          }
  
          /**
           * Execute the closure count times
           */
          public void execute(Object input) {
              for (int i = 0; i < iCount; i++) {
                  iClosure.execute(input);
              }
          }
      }
  
      // WhileClosure
      //----------------------------------------------------------------------------------
  
      /**
       * WhileClosure calls the closure until the predicate is false.
       */
      private static class WhileClosure implements Closure, Serializable {
          /** The test condition */
          private final Predicate iPredicate;
          /** The closure to call */
          private final Closure iClosure;
          /** The flag, true is a do loop, false is a while */
          private final boolean iDoLoop;
  
          /**
           * Constructor to store params
           */
          private WhileClosure(Predicate predicate, Closure closure, boolean doLoop) {
              super();
              iPredicate = predicate;
              iClosure = closure;
              iDoLoop = doLoop;
          }
  
          /**
           * Execute the closure until the predicate is false
           */
          public void execute(Object input) {
              if (iDoLoop) {
                  iClosure.execute(input);
              }
              while (iPredicate.evaluate(input)) {
                  iClosure.execute(input);
              }
          }
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org