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.BinaryFunction;
22  import org.apache.commons.functor.UnaryFunction;
23  import org.apache.commons.lang3.Validate;
24  
25  /**
26   * A BinaryFunction whose result is then run through a UnaryFunction.
27   *
28   * @param <L> the left argument type.
29   * @param <R> the right argument type.
30   * @param <T> the returned value type.
31   * @version $Revision: 1365329 $ $Date: 2012-07-24 19:34:23 -0300 (Tue, 24 Jul 2012) $
32   */
33  public class TransformedBinaryFunction<L, R, T> implements BinaryFunction<L, R, T>, Serializable {
34      /**
35       * serialVersionUID declaration.
36       */
37      private static final long serialVersionUID = 3312781645741807814L;
38  
39      /**
40       * Type-remembering helper.
41       *
42       * @param <X> the following function left argument.
43       */
44      private static final class Helper<X, L, R, T> implements BinaryFunction<L, R, T>, Serializable {
45          /**
46           * serialVersionUID declaration.
47           */
48          private static final long serialVersionUID = 8141488776884860650L;
49          /**
50           * The preceding function.
51           */
52          private BinaryFunction<? super L, ? super R, ? extends X> preceding;
53          /**
54           * The following function.
55           */
56          private UnaryFunction<? super X, ? extends T> following;
57  
58          /**
59           * Create a new Helper.
60           * @param preceding BinaryFunction
61           * @param following UnaryFunction
62           */
63          private Helper(BinaryFunction<? super L, ? super R, ? extends X> preceding,
64                  UnaryFunction<? super X, ? extends T> following) {
65              this.preceding = Validate.notNull(preceding, "BinaryFunction argument was null");
66              this.following = Validate.notNull(following, "UnaryFunction argument was null");
67          }
68  
69          /**
70           * {@inheritDoc}
71           */
72          public T evaluate(L left, R right) {
73              return following.evaluate(preceding.evaluate(left, right));
74          }
75      }
76  
77      /**
78       * The adapted helper.
79       */
80      private final Helper<?, L, R, T> helper;
81  
82      /**
83       * Create a new TransformedBinaryFunction.
84       * @param <X> the following function left argument.
85       * @param preceding BinaryFunction
86       * @param following UnaryFunction
87       */
88      public <X> TransformedBinaryFunction(BinaryFunction<? super L, ? super R, ? extends X> preceding,
89              UnaryFunction<? super X, ? extends T> following) {
90          this.helper = new Helper<X, L, R, T>(preceding, following);
91      }
92  
93      /**
94       * {@inheritDoc}
95       */
96      public final T evaluate(L left, R right) {
97          return helper.evaluate(left, right);
98      }
99  
100     /**
101      * {@inheritDoc}
102      */
103     @Override
104     public final boolean equals(Object obj) {
105         return obj == this || obj instanceof TransformedBinaryFunction<?, ?, ?>
106                 && equals((TransformedBinaryFunction<?, ?, ?>) obj);
107     }
108 
109     /**
110      * Learn whether another TransformedBinaryFunction is equal to <code>this</code>.
111      * @param that instance to test
112      * @return whether equal
113      */
114     public final boolean equals(TransformedBinaryFunction<?, ?, ?> that) {
115         return that != null && that.helper.preceding.equals(this.helper.preceding)
116                 && that.helper.following.equals(this.helper.following);
117     }
118 
119     /**
120      * {@inheritDoc}
121      */
122     @Override
123     public int hashCode() {
124         int result = "TransformedBinaryFunction".hashCode();
125         result <<= 2;
126         result |= helper.following.hashCode();
127         result <<= 2;
128         result |= helper.preceding.hashCode();
129         return result;
130     }
131 
132     /**
133      * {@inheritDoc}
134      */
135     @Override
136     public String toString() {
137         return "TransformedBinaryFunction<" + helper.preceding + "; " + helper.following + ">";
138     }
139 }