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.Function;
022import org.apache.commons.functor.UnaryFunction;
023import org.apache.commons.lang3.Validate;
024
025/**
026 * A Function whose result is then run through a UnaryFunction.
027 *
028 * @param <T> the returned value type.
029 * @version $Revision: 1365329 $ $Date: 2012-07-24 18:34:23 -0400 (Tue, 24 Jul 2012) $
030 */
031public class TransformedFunction<T> implements Function<T>, Serializable {
032    /**
033     * serialVersionUID declaration.
034     */
035    private static final long serialVersionUID = 1201423110871342081L;
036
037    /**
038     * Type-remembering helper.
039     *
040     * @param <X> the adapted function argument type
041     */
042    private static final class Helper<X, T> implements Function<T>, Serializable {
043        /**
044         * serialVersionUID declaration.
045         */
046        private static final long serialVersionUID = -7177784125292465809L;
047        /**
048         * The preceding function.
049         */
050        private Function<? extends X> preceding;
051        /**
052         * The following function.
053         */
054        private UnaryFunction<? super X, ? extends T> following;
055
056        /**
057         * Create a new Helper.
058         * @param preceding Function
059         * @param following UnaryFunction
060         */
061        private Helper(Function<? extends X> preceding, UnaryFunction<? super X, ? extends T> following) {
062            this.preceding = Validate.notNull(preceding, "Function argument was null");
063            this.following = Validate.notNull(following, "UnaryFunction argument was null");
064        }
065
066        /**
067         * {@inheritDoc}
068         */
069        public T evaluate() {
070            return following.evaluate(preceding.evaluate());
071        }
072    }
073
074    /**
075     * The adapted helper.
076     */
077    private final Helper<?, T> helper;
078
079    /**
080     * Create a new TransformedFunction.
081     * @param <X> the preceding function argument type.
082     * @param preceding Function
083     * @param following UnaryFunction
084     */
085    public <X> TransformedFunction(Function<? extends X> preceding,
086            UnaryFunction<? super X, ? extends T> following) {
087        this.helper = new Helper<X, T>(preceding, following);
088    }
089
090    /**
091     * {@inheritDoc}
092     */
093    public final T evaluate() {
094        return helper.evaluate();
095    }
096
097    /**
098     * {@inheritDoc}
099     */
100    @Override
101    public final boolean equals(Object obj) {
102        return obj == this || obj instanceof TransformedFunction<?> && equals((TransformedFunction<?>) obj);
103    }
104
105    /**
106     * Learn whether another TransformedFunction is equal to <code>this</code>.
107     * @param that instance to test
108     * @return whether equal
109     */
110    public final boolean equals(TransformedFunction<?> that) {
111        return that != null && that.helper.preceding.equals(this.helper.preceding)
112                && that.helper.following.equals(this.helper.following);
113    }
114
115    /**
116     * {@inheritDoc}
117     */
118    @Override
119    public int hashCode() {
120        int result = "TransformedFunction".hashCode();
121        result <<= 2;
122        result |= helper.following.hashCode();
123        result <<= 2;
124        result |= helper.preceding.hashCode();
125        return result;
126    }
127
128    /**
129     * {@inheritDoc}
130     */
131    @Override
132    public String toString() {
133        return "TransformedFunction<" + helper.preceding + "; " + helper.following + ">";
134    }
135}