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.BinaryPredicate;
022    import org.apache.commons.functor.UnaryFunction;
023    
024    /**
025     * A {@link BinaryPredicate BinaryPredicate} composed of
026     * one binary predicate, <i>p</i>, and two unary
027     * functions, <i>f</i> and <i>g</i>,
028     * evaluating the ordered parameters <i>x</i>, <i>y</i>
029     * to <code><i>p</i>(<i>f</i>(<i>x</i>),<i>g</i>(<i>y</i>))</code>.
030     * <p>
031     * Note that although this class implements
032     * {@link Serializable}, a given instance will
033     * only be truly <code>Serializable</code> if all the
034     * underlying functors are.  Attempts to serialize
035     * an instance whose delegates are not all
036     * <code>Serializable</code> will result in an exception.
037     * </p>
038     * @version $Revision: 1156337 $ $Date: 2011-08-10 21:44:54 +0200 (Wed, 10 Aug 2011) $
039     * @author Rodney Waldhoff
040     */
041    public class UnaryCompositeBinaryPredicate<L, R> implements BinaryPredicate<L, R>, Serializable {
042        /**
043         * serialVersionUID declaration.
044         */
045        private static final long serialVersionUID = 3841123079006929493L;
046    
047        private static class Helper<G, H, L, R> implements BinaryPredicate<L, R>, Serializable {
048            /**
049             * serialVersionUID declaration.
050             */
051            private static final long serialVersionUID = -3463108273324567825L;
052            private BinaryPredicate<? super G, ? super H> f;
053            private UnaryFunction<? super L, ? extends G> g;
054            private UnaryFunction<? super R, ? extends H> h;
055    
056            /**
057             * Create a new Helper.
058             * @param f BinaryPredicate to test <i>output(</i><code>f</code><i>), output(</i><code>g</code><i>)</i>
059             * @param g left UnaryFunction
060             * @param h right UnaryFunction
061             */
062            public Helper(BinaryPredicate<? super G, ? super H> f, UnaryFunction<? super L, ? extends G> g,
063                    UnaryFunction<? super R, ? extends H> h) {
064                this.f = f;
065                this.g = g;
066                this.h = h;
067            }
068    
069            /**
070             * {@inheritDoc}
071             */
072            public boolean test(L left, R right) {
073                return f.test(g.evaluate(left), h.evaluate(right));
074            }
075        }
076    
077        // attributes
078        // ------------------------------------------------------------------------
079        private final Helper<?, ?, L, R> helper;
080    
081        // constructor
082        // ------------------------------------------------------------------------
083        /**
084         * Create a new UnaryCompositeBinaryPredicate.
085         * @param f BinaryPredicate to test <i>output(</i><code>f</code><i>), output(</i><code>g</code><i>)</i>
086         * @param g left UnaryFunction
087         * @param h right UnaryFunction
088         */
089        public <G, H> UnaryCompositeBinaryPredicate(final BinaryPredicate<? super G, ? super H> f,
090                final UnaryFunction<? super L, ? extends G> g, final UnaryFunction<? super R, ? extends H> h) {
091            if (f == null) {
092                throw new IllegalArgumentException("BinaryPredicate must not be null");
093            }
094            if (g == null || h == null) {
095                throw new IllegalArgumentException("Left and right UnaryFunctions may not be null");
096            }
097            helper = new Helper<G, H, L, R>(f, g, h);
098        }
099    
100        // function interface
101        // ------------------------------------------------------------------------
102        /**
103         * {@inheritDoc}
104         */
105        public boolean test(L left, R right) {
106            return helper.test(left, right);
107        }
108    
109        /**
110         * {@inheritDoc}
111         */
112        public boolean equals(Object that) {
113            return that == this || (that instanceof UnaryCompositeBinaryPredicate<?, ?>
114                                        && equals((UnaryCompositeBinaryPredicate<?, ?>) that));
115        }
116    
117        /**
118         * Learn whether another UnaryCompositeBinaryPredicate is equal to this.
119         * @param that UnaryCompositeBinaryPredicate to test
120         * @return boolean
121         */
122        public boolean equals(UnaryCompositeBinaryPredicate<?, ?> that) {
123            return null != that && helper.f.equals(that.helper.f) && helper.g.equals(that.helper.g)
124                    && helper.h.equals(that.helper.h);
125        }
126    
127        /**
128         * {@inheritDoc}
129         */
130        public int hashCode() {
131            int hash = "UnaryCompositeBinaryPredicate".hashCode();
132            hash <<= 4;
133            hash ^= helper.f.hashCode();
134            hash <<= 4;
135            hash ^= helper.g.hashCode();
136            hash <<= 4;
137            hash ^= helper.h.hashCode();
138            return hash;
139        }
140    
141        /**
142         * {@inheritDoc}
143         */
144        public String toString() {
145            return "UnaryCompositeBinaryPredicate<" + helper.f + ";" + helper.g + ";" + helper.h + ">";
146        }
147    
148    }