View Javadoc

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 }