1 /*
2 * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3 * the spring framework, http://el4j.sf.net
4 * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5 * 1000 Lausanne, Switzerland, http://www.elca.ch
6 *
7 * EL4J is published under the GNU Lesser General Public License (LGPL)
8 * Version 2.1. See http://www.gnu.org/licenses/
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * For alternative licensing, please contact info@elca.ch
16 */
17
18 package ch.elca.el4j.util.codingsupport;
19
20 import java.lang.reflect.Array;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.util.Assert;
34
35 import ch.elca.el4j.util.collections.ExtendedReorderableList;
36 import ch.elca.el4j.util.collections.FilteredList;
37 import ch.elca.el4j.util.collections.TransformedList;
38 import ch.elca.el4j.util.collections.helpers.Filter;
39 import ch.elca.el4j.util.collections.helpers.Function;
40 import ch.elca.el4j.util.collections.impl.DefaultFilteredList;
41 import ch.elca.el4j.util.collections.impl.DefaultTransformedList;
42
43 /**
44 * This class supports methods to handle with collections. It covers only gaps
45 * of class <code>org.springframework.util.CollectionUtils</code>.
46 *
47 *
48 *
49 * @svnLink $Revision: 3873 $;$Date: 2009-08-04 13:59:45 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/core/src/main/java/ch/elca/el4j/util/codingsupport/CollectionUtils.java $
50 *
51 * @author Martin Zeltner (MZE), Adrian Moos (AMS)
52 */
53 public class CollectionUtils {
54 /**
55 * Private logger of this class.
56 */
57 private static Logger s_logger
58 = LoggerFactory.getLogger(CollectionUtils.class);
59
60 /**
61 * Hidden constructor.
62 */
63 protected CollectionUtils() { }
64
65 /**
66 * Null save check if a collection is empty.
67 *
68 * @param c Is the given collection
69 * @return Returns true if the given collection is null or empty.
70 */
71 public static boolean isEmpty(Collection<?> c) {
72 return c == null || c.isEmpty();
73 }
74
75 /**
76 * Method to always return a list object.
77 *
78 * @param list
79 * Is the list which should not be null.
80 * @return Returns the given list if it is not null. Otherwise it returns an
81 * empty list.
82 */
83 public static <T> List<T> asList(List<T> list) {
84 return list == null ? new LinkedList<T>() : list;
85 }
86
87 /**
88 * Method to always return a set object.
89 *
90 * @param set
91 * Is the set which should not be null.
92 * @return Returns the given set if it is not null. Otherwise it returns an
93 * empty set.
94 */
95 public static <T> Set<T> asSet(Set<T> set) {
96 return set == null ? new HashSet<T>() : set;
97 }
98
99 /**
100 * Method to always return a map object.
101 *
102 * @param map
103 * Is the map which should not be null.
104 * @return Returns the given map if it is not null. Otherwise it returns an
105 * empty map.
106 */
107 public static <K,V> Map<K,V> asMap(Map<K,V> map) {
108 return map == null ? new HashMap<K,V>() : map;
109 }
110
111 /**
112 * Method to check if a collection contains only objects which are equals, a
113 * subclass or implements one of the given classes. If the given collection
114 * is empty, <code>true</code> will be returned.
115 *
116 * @param c
117 * Is the collection to check.
118 * @param containingClassTypes
119 * Are the class types which are expected.
120 * @return Returns <code>true</code> if the given collection contains only
121 * objects which are equals, a subclass or implements one of the
122 * given classes
123 */
124 public static boolean containsOnlyObjectsOfType(
125 Collection<?> c, Class<?>[] containingClassTypes) {
126 Reject.ifNull(c);
127 Reject.ifEmpty(containingClassTypes);
128 Iterator<?> it = c.iterator();
129 while (it.hasNext()) {
130 Class<?> elementClass = it.next().getClass();
131 boolean noClassMatches = true;
132 for (int i = 0; noClassMatches && i < containingClassTypes.length;
133 i++) {
134 Class<?> containingClassType = containingClassTypes[i];
135 noClassMatches
136 = !containingClassType.isAssignableFrom(elementClass);
137 }
138 if (noClassMatches) {
139 if (s_logger.isDebugEnabled()) {
140 StringBuffer sb = new StringBuffer();
141 sb.append("Found object of type '");
142 sb.append(elementClass.getName());
143 sb.append("' which is not in assignable form for one of ");
144 sb.append("the following types: ");
145 for (int i = 0; i < containingClassTypes.length; i++) {
146 Class<?> containingClassType = containingClassTypes[i];
147 if (i > 0) { sb.append(", "); }
148 sb.append(containingClassType.getName());
149 }
150 s_logger.debug(sb.toString());
151 }
152 return false;
153 }
154 }
155 return true;
156 }
157
158 /**
159 * Method to check if a collection contains only objects which are equals, a
160 * subclass or implements the given class. If the given collection is empty,
161 * <code>true</code> will be returned.
162 *
163 * @param c
164 * Is the collection to check.
165 * @param containingClassType
166 * Is the class type which is expected.
167 * @return Returns <code>true</code> if the given collection contains only
168 * objects which are equals, a subclass or implements the given
169 * class.
170 */
171 public static boolean containsOnlyObjectsOfType(
172 Collection<?> c, Class<?> containingClassType) {
173 Reject.ifNull(c);
174 Reject.ifNull(containingClassType);
175 return containsOnlyObjectsOfType(c, new Class[] {containingClassType});
176 }
177
178
179 /**
180 * Finds the first element with index at least
181 * {@code startAt} that equals {@code o}. This method may take linear time.
182 *
183 * @param list the list to search
184 * @param <T> the list's element type (duh!)
185 * @param t the element to look for
186 * @param startAt the index to start the search at
187 * @return the index of the first matching element
188 * @throws NoSuchElementException if no such element exists.
189 */
190 public static <T> int find(List<T> list, T t, int startAt)
191 throws NoSuchElementException {
192 for (int id = startAt; id < list.size(); id++) {
193 if (list.get(id).equals(t)) {
194 return id;
195 }
196 }
197 throw new NoSuchElementException(t.toString());
198 }
199
200
201
202 /**
203 * See {@link ExtendedReorderableList#orderLike(List)}.
204 * @param <T> see there
205 * @param list see there
206 * @param example see there
207 */
208 public static <T> void orderLike(ExtendedReorderableList<T> list,
209 List<? extends T> example) {
210
211 for (int i = 0; i < example.size(); i++) {
212 list.swap(i, find(list, example.get(i), i));
213 }
214 }
215
216 /** swaps the elements at locations {@code i} and {@code j}.
217 * If this list is a {@link ExtendedReorderableList}, its swap method
218 * is invoked, otherwise, set/get is used.
219 *
220 * This behaves like Lists always declared a convenience swap method,
221 * that is overridden if ReordableRandomAccessList is implemented.
222 * @param list see above
223 * @param i see above
224 * @param j see above
225 * @param <T> .
226 */
227 public static <T> void swap(List<T> list, int i, int j) {
228 if (list instanceof ExtendedReorderableList) {
229 ((ExtendedReorderableList<T>) list).swap(i, j);
230 } else {
231 defaultSwap(list, i, j);
232 }
233 }
234
235 /**
236 * swaps the elements at locations {@code i} and {@code j} by set/get.
237 * @param list .
238 * @param i .
239 * @param j .
240 * @param <T> .
241 */
242 private static <T> void defaultSwap(List<T> list, int i, int j) {
243 T t = list.get(i);
244 list.set(i, list.get(j));
245 list.set(j, t);
246 }
247
248 /**
249 * Copies the list's contents to an array.
250 * @param <T> the arrays element type
251 * @param list the list to copy
252 * @param c the element type for the new array
253 * @return an new array containing this list's contents
254 */
255 @SuppressWarnings("unchecked")
256 public static <T> T[] toArray(List<? extends T> list, Class<T> c) {
257 return list.toArray((T[]) Array.newInstance(c, list.size()));
258 }
259
260 /**
261 * returns a filtered view on {@code list}.
262 * @param <T> .
263 * @param list see above
264 * @param filter the filter deciding which elements to include
265 * @return the filtered view
266 */
267 public static <T> FilteredList<T> filtered(List<? extends T> list,
268 Filter<? super T> filter) {
269
270 return new DefaultFilteredList<T>(list, filter);
271 }
272
273 /**
274 * Convenience method returning a {@link TransformedList} view to the
275 * supplied list.
276 *
277 * @param <T> the backing list's element type
278 * @param <O> this list's element type
279 * @param list Is the list to transform.
280 * @param function the transformation function to apply to each element
281 * @return see above
282 */
283 public static <T, O> TransformedList<T, O> mapped(List<T> list,
284 Function<? super T, O> function) {
285 return new DefaultTransformedList<T, O>(list, function);
286 }
287
288 /**
289 * @param base
290 * Is the collection to enrich.
291 * @param annex
292 * Is the collection with the items to enrich the base
293 * collection.
294 * @return Return the complemented base collection.
295 */
296 @SuppressWarnings("unchecked")
297 public static Collection nullSaveAddAll(Collection base, Collection annex) {
298 Assert.notNull(base);
299 if (annex != null) {
300 base.addAll(annex);
301 }
302 return base;
303 }
304 }