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}