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 }