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.collection;
018
019import java.lang.reflect.Array;
020import java.util.Collection;
021
022import org.apache.commons.functor.BinaryPredicate;
023import org.apache.commons.functor.Predicate;
024import org.apache.commons.functor.adapter.RightBoundPredicate;
025import org.apache.commons.lang3.Validate;
026
027/**
028 * A {@link BinaryPredicate} that checks to see if the
029 * specified object is an element of the specified
030 * Collection.
031 *
032 * @param <L> the left argument type.
033 * @param <R> the right argument type.
034 * @since 1.0
035 * @version $Revision: 1537909 $ $Date: 2013-11-01 13:24:41 +0100 (Fr, 01 Nov 2013) $
036 */
037public final class IsElementOf<L, R> implements BinaryPredicate<L, R> {
038    // static members
039    //---------------------------------------------------------------
040
041    /**
042     * A static {@link IsElementOf} instance reference.
043     */
044    private static final IsElementOf<Object, Object> INSTANCE = new IsElementOf<Object, Object>();
045
046    // constructors
047    //---------------------------------------------------------------
048    /**
049     * Create a new IsElementOf.
050     */
051    public IsElementOf() {
052    }
053
054    // instance methods
055    //---------------------------------------------------------------
056    /**
057     * {@inheritDoc}
058     */
059    public boolean test(L obj, R col) {
060        Validate.notNull(col, "Right side argument must not be null.");
061        if (col instanceof Collection<?>) {
062            return testCollection(obj, (Collection<?>) col);
063        }
064        if (col.getClass().isArray()) {
065            return testArray(obj, col);
066        }
067        throw new IllegalArgumentException("Expected Collection or Array, found " + col.getClass());
068    }
069
070    /**
071     * {@inheritDoc}
072     */
073    @Override
074    public boolean equals(Object obj) {
075        return (obj instanceof IsElementOf<?, ?>);
076    }
077
078    /**
079     * {@inheritDoc}
080     */
081    @Override
082    public int hashCode() {
083        return "IsElementOf".hashCode();
084    }
085
086    /**
087     * {@inheritDoc}
088     */
089    @Override
090    public String toString() {
091        return "IsElementOf";
092    }
093
094    /**
095     * Test a collection.
096     * @param obj to find
097     * @param col to search
098     * @return boolean
099     */
100    private boolean testCollection(Object obj, Collection<?> col) {
101        return col.contains(obj);
102    }
103
104    /**
105     * Test an array.
106     * @param obj to find
107     * @param array to search
108     * @return boolean
109     */
110    private boolean testArray(Object obj, Object array) {
111        for (int i = 0, m = Array.getLength(array); i < m; i++) {
112            Object value = Array.get(array, i);
113            if (obj == value) {
114                return true;
115            }
116            if (obj != null && obj.equals(value)) {
117                return true;
118            }
119        }
120        return false;
121    }
122
123    // static methods
124    //---------------------------------------------------------------
125    /**
126     * Get an IsElementOf instance.
127     * @return IsElementOf
128     */
129    public static IsElementOf<Object, Object> instance() {
130        return INSTANCE;
131    }
132
133    /**
134     * Get an IsElementOf(collection|array) Predicate.
135     *
136     * @param <A> the Predicate argument generic type
137     * @param obj collection/array to search
138     * @return Predicate
139     */
140    public static <A> Predicate<A> instance(Object obj) {
141        if (null == obj) {
142            throw new NullPointerException("Argument must not be null");
143        } else if (obj instanceof Collection<?>) {
144            return new RightBoundPredicate<A>(new IsElementOf<A, Object>(), obj);
145        } else if (obj.getClass().isArray()) {
146            return new RightBoundPredicate<A>(new IsElementOf<A, Object>(), obj);
147        } else {
148            throw new IllegalArgumentException("Expected Collection or Array, found " + obj.getClass());
149        }
150    }
151
152}