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.collections4.list;
018
019import java.util.Collection;
020import java.util.List;
021import java.util.ListIterator;
022
023import org.apache.commons.collections4.Predicate;
024import org.apache.commons.collections4.collection.PredicatedCollection;
025import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator;
026
027/**
028 * Decorates another <code>List</code> to validate that all additions
029 * match a specified predicate.
030 * <p>
031 * This list exists to provide validation for the decorated list.
032 * It is normally created to decorate an empty list.
033 * If an object cannot be added to the list, an IllegalArgumentException is thrown.
034 * <p>
035 * One usage would be to ensure that no null entries are added to the list.
036 * <pre>
037 * {@code
038 * List<String> list =
039 *   PredicatedList.predicatedList(new ArrayList<String>(), PredicateUtils.notNullPredicate());
040 * }
041 * </pre>
042 * <p>
043 * This class is Serializable from Commons Collections 3.1.
044 *
045 * @since 3.0
046 */
047public class PredicatedList<E> extends PredicatedCollection<E> implements List<E> {
048
049    /** Serialization version */
050    private static final long serialVersionUID = -5722039223898659102L;
051
052    /**
053     * Factory method to create a predicated (validating) list.
054     * <p>
055     * If there are any elements already in the list being decorated, they
056     * are validated.
057     *
058     * @param <T> the type of the elements in the list
059     * @param list  the list to decorate, must not be null
060     * @param predicate  the predicate to use for validation, must not be null
061     * @return a new predicated list
062     * @throws NullPointerException if list or predicate is null
063     * @throws IllegalArgumentException if the list contains invalid elements
064     * @since 4.0
065     */
066    public static <T> PredicatedList<T> predicatedList(final List<T> list, final Predicate<? super T> predicate) {
067        return new PredicatedList<>(list, predicate);
068    }
069
070    //-----------------------------------------------------------------------
071    /**
072     * Constructor that wraps (not copies).
073     * <p>
074     * If there are any elements already in the list being decorated, they
075     * are validated.
076     *
077     * @param list  the list to decorate, must not be null
078     * @param predicate  the predicate to use for validation, must not be null
079     * @throws NullPointerException if list or predicate is null
080     * @throws IllegalArgumentException if the list contains invalid elements
081     */
082    protected PredicatedList(final List<E> list, final Predicate<? super E> predicate) {
083        super(list, predicate);
084    }
085
086    /**
087     * Gets the list being decorated.
088     *
089     * @return the decorated list
090     */
091    @Override
092    protected List<E> decorated() {
093        return (List<E>) super.decorated();
094    }
095
096    @Override
097    public boolean equals(final Object object) {
098        return object == this || decorated().equals(object);
099    }
100
101    @Override
102    public int hashCode() {
103        return decorated().hashCode();
104    }
105
106    //-----------------------------------------------------------------------
107
108    @Override
109    public E get(final int index) {
110        return decorated().get(index);
111    }
112
113    @Override
114    public int indexOf(final Object object) {
115        return decorated().indexOf(object);
116    }
117
118    @Override
119    public int lastIndexOf(final Object object) {
120        return decorated().lastIndexOf(object);
121    }
122
123    @Override
124    public E remove(final int index) {
125        return decorated().remove(index);
126    }
127
128    //-----------------------------------------------------------------------
129
130    @Override
131    public void add(final int index, final E object) {
132        validate(object);
133        decorated().add(index, object);
134    }
135
136    @Override
137    public boolean addAll(final int index, final Collection<? extends E> coll) {
138        for (final E aColl : coll) {
139            validate(aColl);
140        }
141        return decorated().addAll(index, coll);
142    }
143
144    @Override
145    public ListIterator<E> listIterator() {
146        return listIterator(0);
147    }
148
149    @Override
150    public ListIterator<E> listIterator(final int i) {
151        return new PredicatedListIterator(decorated().listIterator(i));
152    }
153
154    @Override
155    public E set(final int index, final E object) {
156        validate(object);
157        return decorated().set(index, object);
158    }
159
160    @Override
161    public List<E> subList(final int fromIndex, final int toIndex) {
162        final List<E> sub = decorated().subList(fromIndex, toIndex);
163        return new PredicatedList<>(sub, predicate);
164    }
165
166    /**
167     * Inner class Iterator for the PredicatedList
168     */
169    protected class PredicatedListIterator extends AbstractListIteratorDecorator<E> {
170
171        /**
172         * Create a new predicated list iterator.
173         *
174         * @param iterator  the list iterator to decorate
175         */
176        protected PredicatedListIterator(final ListIterator<E> iterator) {
177            super(iterator);
178        }
179
180        @Override
181        public void add(final E object) {
182            validate(object);
183            getListIterator().add(object);
184        }
185
186        @Override
187        public void set(final E object) {
188            validate(object);
189            getListIterator().set(object);
190        }
191    }
192
193}