View Javadoc

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  
23  /**
24   * A {@link UnaryFunction UnaryFunction}
25   * representing the composition of
26   * {@link UnaryFunction UnaryFunctions},
27   * "chaining" the output of one to the input
28   * of another.  For example,
29   * <pre>new CompositeUnaryFunction(f).of(g)</pre>
30   * {@link #evaluate evaluates} to
31   * <code>f.evaluate(g.evaluate(obj))</code>, and
32   * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre>
33   * {@link #evaluate evaluates} to
34   * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>.
35   * <p>
36   * When the collection is empty, this function is
37   * an identity function.
38   * </p>
39   * <p>
40   * Note that although this class implements
41   * {@link Serializable}, a given instance will
42   * only be truly <code>Serializable</code> if all the
43   * underlying functors are.  Attempts to serialize
44   * an instance whose delegates are not all
45   * <code>Serializable</code> will result in an exception.
46   * </p>
47   * @version $Revision: 1171157 $ $Date: 2011-09-15 18:04:31 +0200 (Thu, 15 Sep 2011) $
48   * @author Rodney Waldhoff
49   * @author Matt Benson
50   */
51  public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable {
52  
53      /**
54       * serialVersionUID declaration.
55       */
56      private static final long serialVersionUID = 4945193629275757281L;
57  
58      /** Base hash integer used to shift hash */
59      private static final int HASH_SHIFT = 4;
60  
61      /**
62       * Encapsulates a double function evaluation.
63       * @param <A> argument type
64       * @param <X> intermediate type
65       * @param <T> return type
66       */
67      private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable {
68          /**
69           * serialVersionUID declaration.
70           */
71          private static final long serialVersionUID = 8167255331321876718L;
72          private UnaryFunction<? super X, ? extends T> following;
73          private UnaryFunction<? super A, ? extends X> preceding;
74  
75          /**
76           * Create a new Helper.
77           * @param following UnaryFunction<X, Y>
78           * @param preceding UnaryFunction<Y, Z>
79           */
80          public Helper(UnaryFunction<? super X, ? extends T> following,
81                  UnaryFunction<? super A, ? extends X> preceding) {
82              this.following = following;
83              this.preceding = preceding;
84          }
85  
86          /**
87           * {@inheritDoc}
88           */
89          public T evaluate(A obj) {
90              return following.evaluate(preceding.evaluate(obj));
91          }
92  
93          /**
94           * {@inheritDoc}
95           */
96          @Override
97          public boolean equals(Object obj) {
98              return obj == this || obj instanceof Helper<?, ?, ?> && equals((Helper<?, ?, ?>) obj);
99          }
100 
101         private boolean equals(Helper<?, ?, ?> helper) {
102             return helper.following.equals(following) && helper.preceding.equals(preceding);
103         }
104 
105         /**
106          * {@inheritDoc}
107          */
108         @Override
109         public int hashCode() {
110             int result = "CompositeUnaryFunction$Helper".hashCode();
111             result <<= 2;
112             result |= following.hashCode();
113             result <<= 2;
114             result |= preceding.hashCode();
115             return result;
116         }
117 
118         /**
119          * {@inheritDoc}
120          */
121         @Override
122         public String toString() {
123             return following.toString() + " of " + preceding.toString();
124         }
125     }
126 
127     private final UnaryFunction<? super A, ? extends T> function;
128 
129     /**
130      * Create a new CompositeUnaryFunction.
131      * @param function UnaryFunction to call
132      */
133     public CompositeUnaryFunction(UnaryFunction<? super A, ? extends T> function) {
134         if (function == null) {
135             throw new IllegalArgumentException("function must not be null");
136         }
137         this.function = function;
138     }
139 
140     private <X> CompositeUnaryFunction(UnaryFunction<? super X, ? extends T> following,
141             UnaryFunction<? super A, ? extends X> preceding) {
142         this.function = new Helper<X, A, T>(following, preceding);
143     }
144 
145     /**
146      * {@inheritDoc}
147      */
148     public final T evaluate(A obj) {
149         return function.evaluate(obj);
150     }
151 
152     /**
153      * Fluently obtain a CompositeUnaryFunction that is "this function" applied to the specified preceding function.
154      * @param <P> argument type of the resulting function.
155      * @param preceding UnaryFunction
156      * @return CompositeUnaryFunction<P, T>
157      */
158     public final <P> CompositeUnaryFunction<P, T> of(UnaryFunction<? super P, ? extends A> preceding) {
159         if (preceding == null) {
160             throw new IllegalArgumentException("preceding function was null");
161         }
162         return new CompositeUnaryFunction<P, T>(function, preceding);
163     }
164 
165     /**
166      * {@inheritDoc}
167      */
168     public final boolean equals(Object that) {
169         return that == this
170                 || (that instanceof CompositeUnaryFunction<?, ?> && equals((CompositeUnaryFunction<?, ?>) that));
171     }
172 
173     /**
174      * Learn whether another CompositeUnaryFunction is equal to this.
175      * @param that CompositeUnaryFunction to test
176      * @return boolean
177      */
178     public final boolean equals(CompositeUnaryFunction<?, ?> that) {
179         // by construction, list is never null
180         return null != that && function.equals(that.function);
181     }
182 
183     /**
184      * {@inheritDoc}
185      */
186     public int hashCode() {
187         // by construction, list is never null
188         return ("CompositeUnaryFunction".hashCode() << HASH_SHIFT) ^ function.hashCode();
189     }
190 
191     /**
192      * {@inheritDoc}
193      */
194     public String toString() {
195         return "CompositeUnaryFunction<" + function + ">";
196     }
197 
198 }