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