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.map;
018
019import java.util.Comparator;
020import java.util.SortedMap;
021
022import org.apache.commons.collections4.Predicate;
023
024/**
025 * Decorates another <code>SortedMap </code> to validate that additions
026 * match a specified predicate.
027 * <p>
028 * This map exists to provide validation for the decorated map.
029 * It is normally created to decorate an empty map.
030 * If an object cannot be added to the map, an IllegalArgumentException is thrown.
031 * <p>
032 * One usage would be to ensure that no null keys are added to the map.
033 * <pre>SortedMap map = PredicatedSortedSet.decorate(new TreeMap(), NotNullPredicate.INSTANCE, null);</pre>
034 * <p>
035 * <strong>Note that PredicatedSortedMap is not synchronized and is not thread-safe.</strong>
036 * If you wish to use this map from multiple threads concurrently, you must use
037 * appropriate synchronization. The simplest approach is to wrap this map
038 * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw
039 * exceptions when accessed by concurrent threads without synchronization.
040 * <p>
041 * This class is Serializable from Commons Collections 3.1.
042 *
043 * @since 3.0
044 * @version $Id: PredicatedSortedMap.html 972421 2015-11-14 20:00:04Z tn $
045 */
046public class PredicatedSortedMap<K, V> extends PredicatedMap<K, V> implements SortedMap<K, V> {
047
048    /** Serialization version */
049    private static final long serialVersionUID = 3359846175935304332L;
050
051    /**
052     * Factory method to create a predicated (validating) sorted map.
053     * <p>
054     * If there are any elements already in the list being decorated, they
055     * are validated.
056     *
057     * @param <K>  the key type
058     * @param <V>  the value type
059     * @param map  the map to decorate, must not be null
060     * @param keyPredicate  the predicate to validate the keys, null means no check
061     * @param valuePredicate  the predicate to validate to values, null means no check
062     * @return a new predicated sorted map
063     * @throws IllegalArgumentException if the map is null
064     * @since 4.0
065     */
066    public static <K, V> PredicatedSortedMap<K, V> predicatedSortedMap(final SortedMap<K, V> map,
067            final Predicate<? super K> keyPredicate, final Predicate<? super V> valuePredicate) {
068        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
069    }
070
071    //-----------------------------------------------------------------------
072    /**
073     * Constructor that wraps (not copies).
074     *
075     * @param map  the map to decorate, must not be null
076     * @param keyPredicate  the predicate to validate the keys, null means no check
077     * @param valuePredicate  the predicate to validate to values, null means no check
078     * @throws IllegalArgumentException if the map is null
079     */
080    protected PredicatedSortedMap(final SortedMap<K, V> map, final Predicate<? super K> keyPredicate,
081            final Predicate<? super V> valuePredicate) {
082        super(map, keyPredicate, valuePredicate);
083    }
084
085    //-----------------------------------------------------------------------
086    /**
087     * Gets the map being decorated.
088     *
089     * @return the decorated map
090     */
091    protected SortedMap<K, V> getSortedMap() {
092        return (SortedMap<K, V>) map;
093    }
094
095    //-----------------------------------------------------------------------
096    public K firstKey() {
097        return getSortedMap().firstKey();
098    }
099
100    public K lastKey() {
101        return getSortedMap().lastKey();
102    }
103
104    public Comparator<? super K> comparator() {
105        return getSortedMap().comparator();
106    }
107
108    public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
109        final SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
110        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
111    }
112
113    public SortedMap<K, V> headMap(final K toKey) {
114        final SortedMap<K, V> map = getSortedMap().headMap(toKey);
115        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
116    }
117
118    public SortedMap<K, V> tailMap(final K fromKey) {
119        final SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
120        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
121    }
122
123}