1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections;
18
19 import org.apache.commons.collections.bag.HashBag;
20 import org.apache.commons.collections.bag.PredicatedBag;
21 import org.apache.commons.collections.bag.PredicatedSortedBag;
22 import org.apache.commons.collections.bag.SynchronizedBag;
23 import org.apache.commons.collections.bag.SynchronizedSortedBag;
24 import org.apache.commons.collections.bag.TransformedBag;
25 import org.apache.commons.collections.bag.TransformedSortedBag;
26 import org.apache.commons.collections.bag.TreeBag;
27 import org.apache.commons.collections.bag.UnmodifiableBag;
28 import org.apache.commons.collections.bag.UnmodifiableSortedBag;
29
30 /**
31 * Provides utility methods and decorators for {@link Bag} and {@link SortedBag} instances.
32 *
33 * @since 2.1
34 * @version $Id: BagUtils.java 1436066 2013-01-21 01:28:08Z sebb $
35 */
36 public class BagUtils {
37
38 /**
39 * An empty unmodifiable bag.
40 */
41 public static final Bag<Object> EMPTY_BAG = UnmodifiableBag.unmodifiableBag(new HashBag<Object>());
42
43 /**
44 * An empty unmodifiable sorted bag.
45 */
46 public static final Bag<Object> EMPTY_SORTED_BAG =
47 UnmodifiableSortedBag.unmodifiableSortedBag(new TreeBag<Object>());
48
49 /**
50 * Instantiation of BagUtils is not intended or required. However, some
51 * tools require an instance to operate.
52 */
53 public BagUtils() {
54 }
55
56 //-----------------------------------------------------------------------
57 /**
58 * Returns a synchronized (thread-safe) bag backed by the given bag. In
59 * order to guarantee serial access, it is critical that all access to the
60 * backing bag is accomplished through the returned bag.
61 * <p>
62 * It is imperative that the user manually synchronize on the returned bag
63 * when iterating over it:
64 *
65 * <pre>
66 * Bag bag = BagUtils.synchronizedBag(new HashBag());
67 * ...
68 * synchronized(bag) {
69 * Iterator i = bag.iterator(); // Must be in synchronized block
70 * while (i.hasNext())
71 * foo(i.next());
72 * }
73 * }
74 * </pre>
75 *
76 * Failure to follow this advice may result in non-deterministic behavior.
77 *
78 * @param <E> the element type
79 * @param bag the bag to synchronize, must not be null
80 * @return a synchronized bag backed by that bag
81 * @throws IllegalArgumentException if the Bag is null
82 */
83 public static <E> Bag<E> synchronizedBag(final Bag<E> bag) {
84 return SynchronizedBag.synchronizedBag(bag);
85 }
86
87 /**
88 * Returns an unmodifiable view of the given bag. Any modification attempts
89 * to the returned bag will raise an {@link UnsupportedOperationException}.
90 *
91 * @param <E> the element type
92 * @param bag the bag whose unmodifiable view is to be returned, must not be null
93 * @return an unmodifiable view of that bag
94 * @throws IllegalArgumentException if the Bag is null
95 */
96 public static <E> Bag<E> unmodifiableBag(final Bag<E> bag) {
97 return UnmodifiableBag.unmodifiableBag(bag);
98 }
99
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 IllegalArgumentException 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 IllegalArgumentException 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 /**
141 * Returns a synchronized (thread-safe) sorted bag backed by the given
142 * sorted bag. In order to guarantee serial access, it is critical that all
143 * access to the backing bag is accomplished through the returned bag.
144 * <p>
145 * It is imperative that the user manually synchronize on the returned bag
146 * when iterating over it:
147 *
148 * <pre>
149 * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
150 * ...
151 * synchronized(bag) {
152 * Iterator i = bag.iterator(); // Must be in synchronized block
153 * while (i.hasNext())
154 * foo(i.next());
155 * }
156 * }
157 * </pre>
158 *
159 * Failure to follow this advice may result in non-deterministic behavior.
160 *
161 * @param <E> the element type
162 * @param bag the bag to synchronize, must not be null
163 * @return a synchronized bag backed by that bag
164 * @throws IllegalArgumentException if the SortedBag is null
165 */
166 public static <E> SortedBag<E> synchronizedSortedBag(final SortedBag<E> bag) {
167 return SynchronizedSortedBag.synchronizedSortedBag(bag);
168 }
169
170 /**
171 * Returns an unmodifiable view of the given sorted bag. Any modification
172 * attempts to the returned bag will raise an
173 * {@link UnsupportedOperationException}.
174 *
175 * @param <E> the element type
176 * @param bag the bag whose unmodifiable view is to be returned, must not be null
177 * @return an unmodifiable view of that bag
178 * @throws IllegalArgumentException if the SortedBag is null
179 */
180 public static <E> SortedBag<E> unmodifiableSortedBag(final SortedBag<E> bag) {
181 return UnmodifiableSortedBag.unmodifiableSortedBag(bag);
182 }
183
184 /**
185 * Returns a predicated (validating) sorted bag backed by the given sorted
186 * bag.
187 * <p>
188 * Only objects that pass the test in the given predicate can be added to
189 * the bag. Trying to add an invalid object results in an
190 * IllegalArgumentException. It is important not to use the original bag
191 * after invoking this method, as it is a backdoor for adding invalid
192 * objects.
193 *
194 * @param <E> the element type
195 * @param bag the sorted bag to predicate, must not be null
196 * @param predicate the predicate for the bag, must not be null
197 * @return a predicated bag backed by the given bag
198 * @throws IllegalArgumentException if the SortedBag or Predicate is null
199 */
200 public static <E> SortedBag<E> predicatedSortedBag(final SortedBag<E> bag,
201 final Predicate<? super E> predicate) {
202 return PredicatedSortedBag.predicatedSortedBag(bag, predicate);
203 }
204
205 /**
206 * Returns a transformed sorted bag backed by the given bag.
207 * <p>
208 * Each object is passed through the transformer as it is added to the Bag.
209 * It is important not to use the original bag after invoking this method,
210 * as it is a backdoor for adding untransformed objects.
211 * <p>
212 * Existing entries in the specified bag will not be transformed.
213 * If you want that behaviour, see
214 * {@link TransformedSortedBag#transformedSortedBag(SortedBag, Transformer)}.
215 *
216 * @param <E> the element type
217 * @param bag the bag to predicate, must not be null
218 * @param transformer the transformer for the bag, must not be null
219 * @return a transformed bag backed by the given bag
220 * @throws IllegalArgumentException if the Bag or Transformer is null
221 */
222 public static <E> SortedBag<E> transformingSortedBag(final SortedBag<E> bag,
223 final Transformer<? super E, ? extends E> transformer) {
224 return TransformedSortedBag.transformingSortedBag(bag, transformer);
225 }
226
227 /**
228 * Get an empty <code>Bag</code>.
229 *
230 * @param <E> the element type
231 * @return an empty Bag
232 */
233 @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
234 public static <E> Bag<E> emptyBag() {
235 return (Bag<E>) EMPTY_BAG;
236 }
237
238 /**
239 * Get an empty <code>SortedBag</code>.
240 *
241 * @param <E> the element type
242 * @return an empty sorted Bag
243 */
244 @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
245 public static <E> SortedBag<E> emptySortedBag() {
246 return (SortedBag<E>) EMPTY_SORTED_BAG;
247 }
248 }