001    /*
002     * Copyright 2002-2004 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.rules.closure.support;
017    
018    import java.util.Arrays;
019    import java.util.Iterator;
020    import java.util.LinkedHashSet;
021    import java.util.Set;
022    
023    import org.springframework.rules.closure.Closure;
024    import org.springframework.core.style.ToStringCreator;
025    
026    /**
027     * A chain of closures that evaluate their results in a ordered sequence.
028     * <p>
029     * For example, declaring
030     * <code>new ClosureChain() { f1, f2, f3 }.call(fooArg)</code> will trigger
031     * the evaluation of <code>f1</code> first, it's result will be passed to
032     * <code>f2</code> for evaluation, and f2's result will be passed to
033     * <code>f3</code> for evaluation. The final f3 result will be returned to the
034     * caller.
035     * </p>
036     *
037     * @author Keith Donald
038     */
039    public class ClosureChain implements Closure {
040    
041            /** Holds the sequence of closures. */
042            private Set closures = new LinkedHashSet();
043    
044            /**
045             * Constructs a function chain with no initial members. It is expected the
046             * client will call "add" to add individual predicates.
047             */
048            public ClosureChain() {
049    
050            }
051    
052            /**
053             * Creates a chain composed of two functions.
054             *
055             * @param function1 the first function
056             * @param function2 the second function
057             */
058            public ClosureChain(Closure function1, Closure function2) {
059                    closures.add(function1);
060                    closures.add(function2);
061            }
062    
063            /**
064             * Creates a chain composed of the ordered array of functions.
065             *
066             * @param functions the aggregated functions
067             */
068            public ClosureChain(Closure[] functions) {
069                    this.closures.addAll(Arrays.asList(functions));
070            }
071    
072            /**
073             * Add the specified function to the set of functions aggregated by this
074             * function chain.
075             *
076             * @param function the function to add
077             * @return A reference to this, to support easy chaining.
078             */
079            public ClosureChain add(Closure function) {
080                    this.closures.add(function);
081                    return this;
082            }
083    
084            /**
085             * Return an iterator over the aggregated predicates.
086             *
087             * @return An iterator
088             */
089            public Iterator iterator() {
090                    return closures.iterator();
091            }
092    
093            /**
094             * {@inheritDoc}
095             */
096            public Object call(Object argument) {
097                    Object result = argument;
098                    Iterator it = iterator();
099                    while (it.hasNext()) {
100                            Closure f = (Closure) it.next();
101                            result = f.call(result);
102                    }
103                    return result;
104            }
105    
106            /**
107             * {@inheritDoc}
108             */
109            public String toString() {
110                    return new ToStringCreator(this).append("closureChain", closures).toString();
111            }
112    }