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 }