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     */
017    package org.apache.commons.functor.core.composite;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.functor.UnaryFunction;
022    
023    /**
024     * A {@link UnaryFunction UnaryFunction}
025     * representing the composition of
026     * {@link UnaryFunction UnaryFunctions},
027     * "chaining" the output of one to the input
028     * of another.  For example,
029     * <pre>new CompositeUnaryFunction(f).of(g)</pre>
030     * {@link #evaluate evaluates} to
031     * <code>f.evaluate(g.evaluate(obj))</code>, and
032     * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre>
033     * {@link #evaluate evaluates} to
034     * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>.
035     * <p>
036     * When the collection is empty, this function is
037     * an identity function.
038     * </p>
039     * <p>
040     * Note that although this class implements
041     * {@link Serializable}, a given instance will
042     * only be truly <code>Serializable</code> if all the
043     * underlying functors are.  Attempts to serialize
044     * an instance whose delegates are not all
045     * <code>Serializable</code> will result in an exception.
046     * </p>
047     * @version $Revision: 1171157 $ $Date: 2011-09-15 18:04:31 +0200 (Thu, 15 Sep 2011) $
048     * @author Rodney Waldhoff
049     * @author Matt Benson
050     */
051    public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable {
052    
053        /**
054         * serialVersionUID declaration.
055         */
056        private static final long serialVersionUID = 4945193629275757281L;
057    
058        /** Base hash integer used to shift hash */
059        private static final int HASH_SHIFT = 4;
060    
061        /**
062         * Encapsulates a double function evaluation.
063         * @param <A> argument type
064         * @param <X> intermediate type
065         * @param <T> return type
066         */
067        private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable {
068            /**
069             * serialVersionUID declaration.
070             */
071            private static final long serialVersionUID = 8167255331321876718L;
072            private UnaryFunction<? super X, ? extends T> following;
073            private UnaryFunction<? super A, ? extends X> preceding;
074    
075            /**
076             * Create a new Helper.
077             * @param following UnaryFunction<X, Y>
078             * @param preceding UnaryFunction<Y, Z>
079             */
080            public Helper(UnaryFunction<? super X, ? extends T> following,
081                    UnaryFunction<? super A, ? extends X> preceding) {
082                this.following = following;
083                this.preceding = preceding;
084            }
085    
086            /**
087             * {@inheritDoc}
088             */
089            public T evaluate(A obj) {
090                return following.evaluate(preceding.evaluate(obj));
091            }
092    
093            /**
094             * {@inheritDoc}
095             */
096            @Override
097            public boolean equals(Object obj) {
098                return obj == this || obj instanceof Helper<?, ?, ?> && equals((Helper<?, ?, ?>) obj);
099            }
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    }