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