    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;
    018
    019import org.apache.commons.collections4.bag.CollectionBag;
    020import org.apache.commons.collections4.bag.HashBag;
    021import org.apache.commons.collections4.bag.PredicatedBag;
    022import org.apache.commons.collections4.bag.PredicatedSortedBag;
    023import org.apache.commons.collections4.bag.SynchronizedBag;
    024import org.apache.commons.collections4.bag.SynchronizedSortedBag;
    025import org.apache.commons.collections4.bag.TransformedBag;
    026import org.apache.commons.collections4.bag.TransformedSortedBag;
    027import org.apache.commons.collections4.bag.TreeBag;
    028import org.apache.commons.collections4.bag.UnmodifiableBag;
    029import org.apache.commons.collections4.bag.UnmodifiableSortedBag;
    030
    031/**
    032 * Provides utility methods and decorators for {@link Bag} and {@link SortedBag} instances.
    033 *
    034 * @since 2.1
    035 */
    036public class BagUtils {
    037
    038    /**
    039     * An empty unmodifiable bag.
    040     */
    041    @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
    042    public static final Bag EMPTY_BAG = UnmodifiableBag.unmodifiableBag(new HashBag<>());
    043
    044    /**
    045     * An empty unmodifiable sorted bag.
    046     */
    047    @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
    048    public static final Bag EMPTY_SORTED_BAG =
    049            UnmodifiableSortedBag.unmodifiableSortedBag(new TreeBag<>());
    050
    051    /**
    052     * Instantiation of BagUtils is not intended or required.
    053     */
    054    private BagUtils() {}
    055
    056    //-----------------------------------------------------------------------
    057    /**
    058     * Returns a synchronized (thread-safe) bag backed by the given bag. In
    059     * order to guarantee serial access, it is critical that all access to the
    060     * backing bag is accomplished through the returned bag.
    061     * <p>
    062     * It is imperative that the user manually synchronize on the returned bag
    063     * when iterating over it:
    064     *
    065     * <pre>
    066     * Bag bag = BagUtils.synchronizedBag(new HashBag());
    067     * ...
    068     * synchronized(bag) {
    069     *     Iterator i = bag.iterator(); // Must be in synchronized block
    070     *     while (i.hasNext())
    071     *         foo(i.next());
    072     *     }
    073     * }
    074     * </pre>
    075     *
    076     * Failure to follow this advice may result in non-deterministic behavior.
    077     *
    078     * @param <E> the element type
    079     * @param bag the bag to synchronize, must not be null
    080     * @return a synchronized bag backed by that bag
    081     * @throws NullPointerException if the Bag is null
    082     */
    083    public static <E> Bag<E> synchronizedBag(final Bag<E> bag) {
    084        return SynchronizedBag.synchronizedBag(bag);
    085    }
    086
    087    /**
    088     * Returns an unmodifiable view of the given bag. Any modification attempts
    089     * to the returned bag will raise an {@link UnsupportedOperationException}.
    090     *
    091     * @param <E> the element type
    092     * @param bag the bag whose unmodifiable view is to be returned, must not be null
    093     * @return an unmodifiable view of that bag
    094     * @throws NullPointerException if the Bag is null
    095     */
    096    public static <E> Bag<E> unmodifiableBag(final Bag<? extends E> bag) {
    097        return UnmodifiableBag.unmodifiableBag(bag);
    098    }
    099
    100    /**
    101     * Returns a predicated (validating) bag backed by the given bag.
    102     * <p>
    103     * Only objects that pass the test in the given predicate can be added to
    104     * the bag. Trying to add an invalid object results in an
    105     * IllegalArgumentException. It is important not to use the original bag
    106     * after invoking this method, as it is a backdoor for adding invalid
    107     * objects.
    108     *
    109     * @param <E> the element type
    110     * @param bag the bag to predicate, must not be null
    111     * @param predicate the predicate for the bag, must not be null
    112     * @return a predicated bag backed by the given bag
    113     * @throws NullPointerException if the Bag or Predicate is null
    114     */
    115    public static <E> Bag<E> predicatedBag(final Bag<E> bag, final Predicate<? super E> predicate) {
    116        return PredicatedBag.predicatedBag(bag, predicate);
    117    }
    118
    119    /**
    120     * Returns a transformed bag backed by the given bag.
    121     * <p>
    122     * Each object is passed through the transformer as it is added to the Bag.
    123     * It is important not to use the original bag after invoking this method,
    124     * as it is a backdoor for adding untransformed objects.
    125     * <p>
    126     * Existing entries in the specified bag will not be transformed.
    127     * If you want that behaviour, see {@link TransformedBag#transformedBag(Bag, Transformer)}.
    128     *
    129     * @param <E> the element type
    130     * @param bag the bag to predicate, must not be null
    131     * @param transformer the transformer for the bag, must not be null
    132     * @return a transformed bag backed by the given bag
    133     * @throws NullPointerException if the Bag or Transformer is null
    134     */
    135    public static <E> Bag<E> transformingBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) {
    136        return TransformedBag.transformingBag(bag, transformer);
    137    }
    138
    139    /**
    140     * Returns a bag that complies to the Collection contract, backed by the given bag.
    141     *
    142     * @param <E> the element type
    143     * @param bag the bag to decorate, must not be null
    144     * @return a Bag that complies to the Collection contract
    145     * @throws NullPointerException if bag is null
    146     * @since 4.0
    147     */
    148    public static <E> Bag<E> collectionBag(final Bag<E> bag) {
    149        return CollectionBag.collectionBag(bag);
    150    }
    151
    152    //-----------------------------------------------------------------------
    153    /**
    154     * Returns a synchronized (thread-safe) sorted bag backed by the given
    155     * sorted bag. In order to guarantee serial access, it is critical that all
    156     * access to the backing bag is accomplished through the returned bag.
    157     * <p>
    158     * It is imperative that the user manually synchronize on the returned bag
    159     * when iterating over it:
    160     *
    161     * <pre>
    162     * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
    163     * ...
    164     * synchronized(bag) {
    165     *     Iterator i = bag.iterator(); // Must be in synchronized block
    166     *     while (i.hasNext())
    167     *         foo(i.next());
    168     *     }
    169     * }
    170     * </pre>
    171     *
    172     * Failure to follow this advice may result in non-deterministic behavior.
    173     *
    174     * @param <E> the element type
    175     * @param bag the bag to synchronize, must not be null
    176     * @return a synchronized bag backed by that bag
    177     * @throws NullPointerException if the SortedBag is null
    178     */
    179    public static <E> SortedBag<E> synchronizedSortedBag(final SortedBag<E> bag) {
    180        return SynchronizedSortedBag.synchronizedSortedBag(bag);
    181    }
    182
    183    /**
    184     * Returns an unmodifiable view of the given sorted bag. Any modification
    185     * attempts to the returned bag will raise an
    186     * {@link UnsupportedOperationException}.
    187     *
    188     * @param <E> the element type
    189     * @param bag the bag whose unmodifiable view is to be returned, must not be null
    190     * @return an unmodifiable view of that bag
    191     * @throws NullPointerException if the SortedBag is null
    192     */
    193    public static <E> SortedBag<E> unmodifiableSortedBag(final SortedBag<E> bag) {
    194        return UnmodifiableSortedBag.unmodifiableSortedBag(bag);
    195    }
    196
    197    /**
    198     * Returns a predicated (validating) sorted bag backed by the given sorted
    199     * bag.
    200     * <p>
    201     * Only objects that pass the test in the given predicate can be added to
    202     * the bag. Trying to add an invalid object results in an
    203     * IllegalArgumentException. It is important not to use the original bag
    204     * after invoking this method, as it is a backdoor for adding invalid
    205     * objects.
    206     *
    207     * @param <E> the element type
    208     * @param bag the sorted bag to predicate, must not be null
    209     * @param predicate the predicate for the bag, must not be null
    210     * @return a predicated bag backed by the given bag
    211     * @throws NullPointerException if the SortedBag or Predicate is null
    212     */
    213    public static <E> SortedBag<E> predicatedSortedBag(final SortedBag<E> bag,
    214            final Predicate<? super E> predicate) {
    215        return PredicatedSortedBag.predicatedSortedBag(bag, predicate);
    216    }
    217
    218    /**
    219     * Returns a transformed sorted bag backed by the given bag.
    220     * <p>
    221     * Each object is passed through the transformer as it is added to the Bag.
    222     * It is important not to use the original bag after invoking this method,
    223     * as it is a backdoor for adding untransformed objects.
    224     * <p>
    225     * Existing entries in the specified bag will not be transformed.
    226     * If you want that behaviour, see
    227     * {@link TransformedSortedBag#transformedSortedBag(SortedBag, Transformer)}.
    228     *
    229     * @param <E> the element type
    230     * @param bag the bag to predicate, must not be null
    231     * @param transformer the transformer for the bag, must not be null
    232     * @return a transformed bag backed by the given bag
    233     * @throws NullPointerException if the Bag or Transformer is null
    234     */
    235    public static <E> SortedBag<E> transformingSortedBag(final SortedBag<E> bag,
    236                                                         final Transformer<? super E, ? extends E> transformer) {
    237        return TransformedSortedBag.transformingSortedBag(bag, transformer);
    238    }
    239
    240    /**
    241     * Get an empty <code>Bag</code>.
    242     *
    243     * @param <E> the element type
    244     * @return an empty Bag
    245     */
    246    @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
    247    public static <E> Bag<E> emptyBag() {
    248        return EMPTY_BAG;
    249    }
    250
    251    /**
    252     * Get an empty <code>SortedBag</code>.
    253     *
    254     * @param <E> the element type
    255     * @return an empty sorted Bag
    256     */
    257    @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
    258    public static <E> SortedBag<E> emptySortedBag() {
    259        return (SortedBag<E>) EMPTY_SORTED_BAG;
    260    }
    261}