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