001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.functor.core.composite; 018 019import java.io.Serializable; 020 021import org.apache.commons.functor.UnaryFunction; 022import org.apache.commons.lang3.Validate; 023 024/** 025 * A {@link UnaryFunction UnaryFunction} 026 * representing the composition of 027 * {@link UnaryFunction UnaryFunctions}, 028 * "chaining" the output of one to the input 029 * of another. For example, 030 * <pre>new CompositeUnaryFunction(f).of(g)</pre> 031 * {@link #evaluate evaluates} to 032 * <code>f.evaluate(g.evaluate(obj))</code>, and 033 * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre> 034 * {@link #evaluate evaluates} to 035 * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>. 036 * <p> 037 * When the collection is empty, this function is 038 * an identity function. 039 * </p> 040 * <p> 041 * Note that although this class implements 042 * {@link Serializable}, a given instance will 043 * only be truly <code>Serializable</code> if all the 044 * underlying functors are. Attempts to serialize 045 * an instance whose delegates are not all 046 * <code>Serializable</code> will result in an exception. 047 * </p> 048 * @param <A> the argument type. 049 * @param <T> the returned value type. 050 * @version $Revision: 1365329 $ $Date: 2012-07-24 18:34:23 -0400 (Tue, 24 Jul 2012) $ 051 */ 052public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable { 053 054 /** 055 * serialVersionUID declaration. 056 */ 057 private static final long serialVersionUID = 4945193629275757281L; 058 059 /** Base hash integer used to shift hash. */ 060 private static final int HASH_SHIFT = 4; 061 062 /** 063 * Encapsulates a double function evaluation. 064 * @param <A> argument type 065 * @param <X> intermediate type 066 * @param <T> return type 067 */ 068 private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable { 069 /** 070 * serialVersionUID declaration. 071 */ 072 private static final long serialVersionUID = 8167255331321876718L; 073 /** 074 * The last evaluator function. 075 */ 076 private UnaryFunction<? super X, ? extends T> following; 077 /** 078 * The first evaluator function. 079 */ 080 private UnaryFunction<? super A, ? extends X> preceding; 081 082 /** 083 * Create a new Helper. 084 * @param following UnaryFunction<X, Y> 085 * @param preceding UnaryFunction<Y, Z> 086 */ 087 public Helper(UnaryFunction<? super X, ? extends T> following, 088 UnaryFunction<? super A, ? extends X> preceding) { 089 this.following = Validate.notNull(following, "UnaryFunction argument must not be null"); 090 this.preceding = Validate.notNull(preceding, "UnaryFunction argument must not be null"); 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 public T evaluate(A obj) { 097 return following.evaluate(preceding.evaluate(obj)); 098 } 099 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}