1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.functor.core.composite;
18
19 import java.io.Serializable;
20
21 import org.apache.commons.functor.UnaryFunction;
22 import org.apache.commons.lang3.Validate;
23
24 /**
25 * A {@link UnaryFunction UnaryFunction}
26 * representing the composition of
27 * {@link UnaryFunction UnaryFunctions},
28 * "chaining" the output of one to the input
29 * of another. For example,
30 * <pre>new CompositeUnaryFunction(f).of(g)</pre>
31 * {@link #evaluate evaluates} to
32 * <code>f.evaluate(g.evaluate(obj))</code>, and
33 * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre>
34 * {@link #evaluate evaluates} to
35 * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>.
36 * <p>
37 * When the collection is empty, this function is
38 * an identity function.
39 * </p>
40 * <p>
41 * Note that although this class implements
42 * {@link Serializable}, a given instance will
43 * only be truly <code>Serializable</code> if all the
44 * underlying functors are. Attempts to serialize
45 * an instance whose delegates are not all
46 * <code>Serializable</code> will result in an exception.
47 * </p>
48 * @param <A> the argument type.
49 * @param <T> the returned value type.
50 * @version $Revision: 1365329 $ $Date: 2012-07-24 19:34:23 -0300 (Tue, 24 Jul 2012) $
51 */
52 public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable {
53
54 /**
55 * serialVersionUID declaration.
56 */
57 private static final long serialVersionUID = 4945193629275757281L;
58
59 /** Base hash integer used to shift hash. */
60 private static final int HASH_SHIFT = 4;
61
62 /**
63 * Encapsulates a double function evaluation.
64 * @param <A> argument type
65 * @param <X> intermediate type
66 * @param <T> return type
67 */
68 private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable {
69 /**
70 * serialVersionUID declaration.
71 */
72 private static final long serialVersionUID = 8167255331321876718L;
73 /**
74 * The last evaluator function.
75 */
76 private UnaryFunction<? super X, ? extends T> following;
77 /**
78 * The first evaluator function.
79 */
80 private UnaryFunction<? super A, ? extends X> preceding;
81
82 /**
83 * Create a new Helper.
84 * @param following UnaryFunction<X, Y>
85 * @param preceding UnaryFunction<Y, Z>
86 */
87 public Helper(UnaryFunction<? super X, ? extends T> following,
88 UnaryFunction<? super A, ? extends X> preceding) {
89 this.following = Validate.notNull(following, "UnaryFunction argument must not be null");
90 this.preceding = Validate.notNull(preceding, "UnaryFunction argument must not be null");
91 }
92
93 /**
94 * {@inheritDoc}
95 */
96 public T evaluate(A obj) {
97 return following.evaluate(preceding.evaluate(obj));
98 }
99
100 /**
101 * {@inheritDoc}
102 */
103 @Override
104 public boolean equals(Object obj) {
105 return obj == this || obj instanceof Helper<?, ?, ?> && equals((Helper<?, ?, ?>) obj);
106 }
107
108 /**
109 * Checks if input helper is equals to this instance.
110 *
111 * @param helper the helper to check
112 * @return true, if helpers are equals, false otherwise
113 */
114 private boolean equals(Helper<?, ?, ?> helper) {
115 return helper.following.equals(following) && helper.preceding.equals(preceding);
116 }
117
118 /**
119 * {@inheritDoc}
120 */
121 @Override
122 public int hashCode() {
123 int result = "CompositeUnaryFunction$Helper".hashCode();
124 result <<= 2;
125 result |= following.hashCode();
126 result <<= 2;
127 result |= preceding.hashCode();
128 return result;
129 }
130
131 /**
132 * {@inheritDoc}
133 */
134 @Override
135 public String toString() {
136 return following.toString() + " of " + preceding.toString();
137 }
138 }
139
140 /**
141 * The adapted function.
142 */
143 private final UnaryFunction<? super A, ? extends T> function;
144
145 /**
146 * Create a new CompositeUnaryFunction.
147 * @param function UnaryFunction to call
148 */
149 public CompositeUnaryFunction(UnaryFunction<? super A, ? extends T> function) {
150 this.function = Validate.notNull(function, "function must not be null");
151 }
152
153 /**
154 * Creates a new {@link CompositeUnaryFunction} instance given the input functions.
155 *
156 * @param <X> the argument type.
157 * @param following The first evaluator function.
158 * @param preceding The last evaluator function.
159 */
160 private <X> CompositeUnaryFunction(UnaryFunction<? super X, ? extends T> following,
161 UnaryFunction<? super A, ? extends X> preceding) {
162 this.function = new Helper<X, A, T>(following, preceding);
163 }
164
165 /**
166 * {@inheritDoc}
167 */
168 public final T evaluate(A obj) {
169 return function.evaluate(obj);
170 }
171
172 /**
173 * Fluently obtain a CompositeUnaryFunction that is "this function" applied to the specified preceding function.
174 * @param <P> argument type of the resulting function.
175 * @param preceding UnaryFunction
176 * @return CompositeUnaryFunction<P, T>
177 */
178 public final <P> CompositeUnaryFunction<P, T> of(UnaryFunction<? super P, ? extends A> preceding) {
179 Validate.notNull(preceding, "preceding function was null");
180 return new CompositeUnaryFunction<P, T>(function, preceding);
181 }
182
183 /**
184 * {@inheritDoc}
185 */
186 @Override
187 public final boolean equals(Object that) {
188 return that == this
189 || (that instanceof CompositeUnaryFunction<?, ?> && equals((CompositeUnaryFunction<?, ?>) that));
190 }
191
192 /**
193 * Learn whether another CompositeUnaryFunction is equal to this.
194 * @param that CompositeUnaryFunction to test
195 * @return boolean
196 */
197 public final boolean equals(CompositeUnaryFunction<?, ?> that) {
198 // by construction, list is never null
199 return null != that && function.equals(that.function);
200 }
201
202 /**
203 * {@inheritDoc}
204 */
205 @Override
206 public int hashCode() {
207 // by construction, list is never null
208 return ("CompositeUnaryFunction".hashCode() << HASH_SHIFT) ^ function.hashCode();
209 }
210
211 /**
212 * {@inheritDoc}
213 */
214 @Override
215 public String toString() {
216 return "CompositeUnaryFunction<" + function + ">";
217 }
218
219 }