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