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.BinaryProcedure;
023    import org.apache.commons.functor.core.NoOp;
024    
025    /**
026     * A {@link BinaryProcedure BinaryProcedure}
027     * similiar to Java's "ternary"
028     * or "conditional" operator (<code>&#x3F; &#x3A;</code>).
029     * Given a {@link BinaryPredicate predicate}
030     * <i>p</i> and {@link BinaryProcedure procedures}
031     * <i>q</i> and <i>r</i>, {@link #run runs}
032     * <code>if (p.test(x,y)) { q.run(x,y); } else { r.run(x,y); }</code>.
033     * <p>
034     * Note that although this class implements
035     * {@link Serializable}, a given instance will
036     * only be truly <code>Serializable</code> if all the
037     * underlying functors are.  Attempts to serialize
038     * an instance whose delegates are not all
039     * <code>Serializable</code> will result in an exception.
040     * </p>
041     * @version $Revision: 1166384 $ $Date: 2011-09-07 22:22:00 +0200 (Wed, 07 Sep 2011) $
042     * @author Rodney Waldhoff
043     */
044    public final class ConditionalBinaryProcedure<L, R> implements BinaryProcedure<L, R>, Serializable {
045    
046        /**
047         * serialVersionUID declaration.
048         */
049        private static final long serialVersionUID = -3521992036791188475L;
050    
051        /** Base hash integer used to shift hash */
052        private static final int HASH_SHIFT = 4;
053        // attributes
054        // ------------------------------------------------------------------------
055        private final BinaryPredicate<? super L, ? super R> ifPred;
056        private final BinaryProcedure<? super L, ? super R> thenProc;
057        private final BinaryProcedure<? super L, ? super R> elseProc;
058    
059        // constructor
060        // ------------------------------------------------------------------------
061    
062        /**
063         * Create a new ConditionalBinaryProcedure.
064         * @param ifPred to evaluate
065         * @param thenProc if <code>ifPred</code> yields <code>true</code>
066         */
067        public ConditionalBinaryProcedure(BinaryPredicate<? super L, ? super R> ifPred,
068                BinaryProcedure<? super L, ? super R> thenProc) {
069            this(ifPred, thenProc, NoOp.instance());
070        }
071    
072        /**
073         * Create a new ConditionalBinaryProcedure.
074         * @param ifPred to evaluate
075         * @param thenProc if <code>ifPred</code> yields <code>true</code>
076         * @param elseProc if <code>ifPred</code> yields <code>false</code>
077         */
078        public ConditionalBinaryProcedure(BinaryPredicate<? super L, ? super R> ifPred,
079                BinaryProcedure<? super L, ? super R> thenProc, BinaryProcedure<? super L, ? super R> elseProc) {
080            if (ifPred == null) {
081                throw new IllegalArgumentException("BinaryPredicate argument was null");
082            }
083            this.ifPred = ifPred;
084            if (thenProc == null || elseProc == null) {
085                throw new IllegalArgumentException("One or more BinaryProcedure arguments was null");
086            }
087            this.thenProc = thenProc;
088            this.elseProc = elseProc;
089        }
090    
091        // predicate interface
092        // ------------------------------------------------------------------------
093    
094        /**
095         * {@inheritDoc}
096         */
097        public void run(L left, R right) {
098            if (ifPred.test(left, right)) {
099                thenProc.run(left, right);
100            } else {
101                elseProc.run(left, right);
102            }
103        }
104    
105        /**
106         * {@inheritDoc}
107         */
108        public boolean equals(Object that) {
109            return that == this || (that instanceof ConditionalBinaryProcedure<?, ?>
110                                        && equals((ConditionalBinaryProcedure<?, ?>) that));
111        }
112    
113        /**
114         * Learn whether a given ConditionalBinaryProcedure is equal to this.
115         * @param that compared object
116         * @return boolean
117         */
118        public boolean equals(ConditionalBinaryProcedure<?, ?> that) {
119            return null != that
120                    && (null == ifPred ? null == that.ifPred : ifPred.equals(that.ifPred))
121                    && (null == thenProc ? null == that.thenProc : thenProc.equals(that.thenProc))
122                    && (null == elseProc ? null == that.elseProc : elseProc.equals(that.elseProc));
123        }
124    
125        /**
126         * {@inheritDoc}
127         */
128        public int hashCode() {
129            int hash = "ConditionalBinaryProcedure".hashCode();
130            if (null != ifPred) {
131                hash <<= HASH_SHIFT;
132                hash ^= ifPred.hashCode();
133            }
134            if (null != thenProc) {
135                hash <<= HASH_SHIFT;
136                hash ^= thenProc.hashCode();
137            }
138            if (null != elseProc) {
139                hash <<= HASH_SHIFT;
140                hash ^= elseProc.hashCode();
141            }
142            return hash;
143        }
144    
145        /**
146         * {@inheritDoc}
147         */
148        public String toString() {
149            return "ConditionalBinaryProcedure<" + ifPred + "?" + thenProc + ":" + elseProc + ">";
150        }
151    }