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     */
017    package org.apache.commons.collections;
018    
019    import org.apache.commons.collections.bag.HashBag;
020    import org.apache.commons.collections.bag.PredicatedBag;
021    import org.apache.commons.collections.bag.PredicatedSortedBag;
022    import org.apache.commons.collections.bag.SynchronizedBag;
023    import org.apache.commons.collections.bag.SynchronizedSortedBag;
024    import org.apache.commons.collections.bag.TransformedBag;
025    import org.apache.commons.collections.bag.TransformedSortedBag;
026    import org.apache.commons.collections.bag.TreeBag;
027    import org.apache.commons.collections.bag.TypedBag;
028    import org.apache.commons.collections.bag.TypedSortedBag;
029    import org.apache.commons.collections.bag.UnmodifiableBag;
030    import org.apache.commons.collections.bag.UnmodifiableSortedBag;
031    
032    /**
033     * Provides utility methods and decorators for
034     * {@link Bag} and {@link SortedBag} instances.
035     *
036     * @since Commons Collections 2.1
037     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
038     * 
039     * @author Paul Jack
040     * @author Stephen Colebourne
041     * @author Andrew Freeman
042     * @author Matthew Hawthorne
043     */
044    public class BagUtils {
045    
046        /**
047         * An empty unmodifiable bag.
048         */
049        public static final Bag EMPTY_BAG = UnmodifiableBag.decorate(new HashBag());
050    
051        /**
052         * An empty unmodifiable sorted bag.
053         */
054        public static final Bag EMPTY_SORTED_BAG = UnmodifiableSortedBag.decorate(new TreeBag());
055    
056        /**
057         * Instantiation of BagUtils is not intended or required.
058         * However, some tools require an instance to operate.
059         */
060        public BagUtils() {
061        }
062    
063        //-----------------------------------------------------------------------
064        /**
065         * Returns a synchronized (thread-safe) bag backed by the given bag.
066         * In order to guarantee serial access, it is critical that all 
067         * access to the backing bag is accomplished through the returned bag.
068         * <p>
069         * It is imperative that the user manually synchronize on the returned
070         * bag when iterating over it:
071         *
072         * <pre>
073         * Bag bag = BagUtils.synchronizedBag(new HashBag());
074         * ...
075         * synchronized(bag) {
076         *     Iterator i = bag.iterator(); // Must be in synchronized block
077         *     while (i.hasNext())
078         *         foo(i.next());
079         *     }
080         * }
081         * </pre>
082         *
083         * Failure to follow this advice may result in non-deterministic 
084         * behavior.
085         *
086         * @param bag  the bag to synchronize, must not be null
087         * @return a synchronized bag backed by that bag
088         * @throws IllegalArgumentException  if the Bag is null
089         */
090        public static Bag synchronizedBag(Bag bag) {
091            return SynchronizedBag.decorate(bag);
092        }
093    
094        /**
095         * Returns an unmodifiable view of the given bag.  Any modification
096         * attempts to the returned bag will raise an 
097         * {@link UnsupportedOperationException}.
098         *
099         * @param bag  the bag whose unmodifiable view is to be returned, must not be null
100         * @return an unmodifiable view of that bag
101         * @throws IllegalArgumentException  if the Bag is null
102         */
103        public static Bag unmodifiableBag(Bag bag) {
104            return UnmodifiableBag.decorate(bag);
105        }
106        
107        /**
108         * Returns a predicated (validating) bag backed by the given bag.
109         * <p>
110         * Only objects that pass the test in the given predicate can be added to the bag.
111         * Trying to add an invalid object results in an IllegalArgumentException.
112         * It is important not to use the original bag after invoking this method,
113         * as it is a backdoor for adding invalid objects.
114         *
115         * @param bag  the bag to predicate, must not be null
116         * @param predicate  the predicate for the bag, must not be null
117         * @return a predicated bag backed by the given bag
118         * @throws IllegalArgumentException  if the Bag or Predicate is null
119         */
120        public static Bag predicatedBag(Bag bag, Predicate predicate) {
121            return PredicatedBag.decorate(bag, predicate);
122        }
123        
124        /**
125         * Returns a typed bag backed by the given bag.
126         * <p>
127         * Only objects of the specified type can be added to the bag.
128         * 
129         * @param bag  the bag to limit to a specific type, must not be null
130         * @param type  the type of objects which may be added to the bag
131         * @return a typed bag backed by the specified bag
132         */
133        public static Bag typedBag(Bag bag, Class type) {
134            return TypedBag.decorate(bag, type);
135        }
136        
137        /**
138         * Returns a transformed bag backed by the given bag.
139         * <p>
140         * Each object is passed through the transformer as it is added to the
141         * Bag. It is important not to use the original bag after invoking this 
142         * method, as it is a backdoor for adding untransformed objects.
143         *
144         * @param bag  the bag to predicate, must not be null
145         * @param transformer  the transformer for the bag, must not be null
146         * @return a transformed bag backed by the given bag
147         * @throws IllegalArgumentException  if the Bag or Transformer is null
148         */
149        public static Bag transformedBag(Bag bag, Transformer transformer) {
150            return TransformedBag.decorate(bag, transformer);
151        }
152        
153        //-----------------------------------------------------------------------
154        /**
155         * Returns a synchronized (thread-safe) sorted bag backed by the given 
156         * sorted bag.
157         * In order to guarantee serial access, it is critical that all 
158         * access to the backing bag is accomplished through the returned bag.
159         * <p>
160         * It is imperative that the user manually synchronize on the returned
161         * bag when iterating over it:
162         *
163         * <pre>
164         * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
165         * ...
166         * synchronized(bag) {
167         *     Iterator i = bag.iterator(); // Must be in synchronized block
168         *     while (i.hasNext())
169         *         foo(i.next());
170         *     }
171         * }
172         * </pre>
173         *
174         * Failure to follow this advice may result in non-deterministic 
175         * behavior.
176         *
177         * @param bag  the bag to synchronize, must not be null
178         * @return a synchronized bag backed by that bag
179         * @throws IllegalArgumentException  if the SortedBag is null
180         */
181        public static SortedBag synchronizedSortedBag(SortedBag bag) {
182            return SynchronizedSortedBag.decorate(bag);
183        }
184        
185        /**
186         * Returns an unmodifiable view of the given sorted bag.  Any modification
187         * attempts to the returned bag will raise an 
188         * {@link UnsupportedOperationException}.
189         *
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 SortedBag unmodifiableSortedBag(SortedBag bag) {
195            return UnmodifiableSortedBag.decorate(bag);
196        }
197        
198        /**
199         * Returns a predicated (validating) sorted bag backed by the given sorted bag.
200         * <p>
201         * Only objects that pass the test in the given predicate can be added to the bag.
202         * Trying to add an invalid object results in an IllegalArgumentException.
203         * It is important not to use the original bag after invoking this method,
204         * as it is a backdoor for adding invalid objects.
205         *
206         * @param bag  the sorted bag to predicate, must not be null
207         * @param predicate  the predicate for the bag, must not be null
208         * @return a predicated bag backed by the given bag
209         * @throws IllegalArgumentException  if the SortedBag or Predicate is null
210         */
211        public static SortedBag predicatedSortedBag(SortedBag bag, Predicate predicate) {
212            return PredicatedSortedBag.decorate(bag, predicate);
213        }
214        
215        /**
216         * Returns a typed sorted bag backed by the given bag.
217         * <p>
218         * Only objects of the specified type can be added to the bag.
219         * 
220         * @param bag  the bag to limit to a specific type, must not be null
221         * @param type  the type of objects which may be added to the bag
222         * @return a typed bag backed by the specified bag
223         */
224        public static SortedBag typedSortedBag(SortedBag bag, Class type) {
225            return TypedSortedBag.decorate(bag, type);
226        }
227        
228        /**
229         * Returns a transformed sorted bag backed by the given bag.
230         * <p>
231         * Each object is passed through the transformer as it is added to the
232         * Bag. It is important not to use the original bag after invoking this 
233         * method, as it is a backdoor for adding untransformed objects.
234         *
235         * @param bag  the bag to predicate, must not be null
236         * @param transformer  the transformer for the bag, must not be null
237         * @return a transformed bag backed by the given bag
238         * @throws IllegalArgumentException  if the Bag or Transformer is null
239         */
240        public static SortedBag transformedSortedBag(SortedBag bag, Transformer transformer) {
241            return TransformedSortedBag.decorate(bag, transformer);
242        }
243        
244    }