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.Constructor;
21  import java.lang.reflect.InvocationTargetException;
22  import java.util.Collection;
23  
24  import org.apache.commons.lang.ArrayUtils;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  import org.springframework.util.StringUtils;
28  
29  /**
30   * This class provides support for assertions and for design by contract.
31   * Methods from this class are used at the beginning of a method, before anyone
32   * is working with the given parameters.
33   *
34   * Parameters which are checked at the end of a method or inside a method should
35   * be checked by using the <code>assert</code> keyword of JDK 1.4. More about
36   * this you can find
37   * <a href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html">here</a>
38   * . <br>
39   *
40   * <b>Example:</b>
41   * <code><pre>
42   *     public class AccountDao {
43   *         public void saveAccount(Account x) {
44   *             Reject.ifNull(x, IllegalArgumentException.class, "My String");
45   *             ...
46   *         }
47   *     }
48   * </pre></code>
49   *
50   * In this example an
51   * <code>IllegalArgumentException</code> is thrown if the given account is null.
52   * This may prevent an ugly <code>NullPointerException</code>.
53   *
54   * <b>Example 2:</b>
55   * <code><pre>
56   *     public class AccountDao {
57   *         public void saveAccount(Account x) {
58   *             Reject.ifNull(x);
59   *             ...
60   *         }
61   *     }
62   * </pre></code> <br> <br>
63   *
64   * In this example, a
65   * <code>ch.elca.el4j.util.codingsupport.PreconditionRTException</code> is
66   * thrown if the given account is null. This prevents that an
67   * ugly <code>NullPointerException</code>.
68   *
69   * <p> It is also possible to add a reason to the reject method, if it is not
70   * absolutely clear what is checked. Alternatively, you can customize the
71   * exception to be thrown in case the condition is violated by providing the
72   * exception class and the arguments to its constructor (the rationale of this
73   * is that it does not require
74   * the (potential expensive) creation of an exception class when its not needed.
75   * The existence and uniqueness of a constructor capable of taking the provided
76   * arguments is not
77   * verified statically and must therefore be ensured by the user.
78   *
79   * @svnLink $Revision: 3883 $;$Date: 2009-08-04 15:35:01 +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/Reject.java $
80   *
81   * @author Martin Zeltner (MZE), Adrian Moos(AMS)
82   */
83  public final class Reject {
84  	/**
85  	 * Private logger of this class.
86  	 */
87  	private static final Logger LOG = LoggerFactory.getLogger(Reject.class);
88  
89  	/**
90  	 * Default constructor.
91  	 */
92  	private Reject() {
93  	}
94  	
95  	///////////////////
96  	// Preconditions //
97  	///////////////////
98  
99  	/**
100 	 * Method to ensure that an object is not null. Used at the beginning of a
101 	 * method before working with parameters.
102 	 *
103 	 * @param object
104 	 *            Is the object to be analyzed.
105 	 */
106 	public static void ifNull(Object object) {
107 		ifNull(object, RuntimeException.class);
108 	}
109 	
110 
111 	/**
112 	 * Method to ensure that an object is not null. Used at the beginning of a
113 	 * method before working with parameters.
114 	 *
115 	 * @param object
116 	 *            Is the object to be analyzed.
117 	 * @param reason
118 	 *            Is the message to explain the reason of the exception.
119 	 */
120 	public static void ifNull(Object object, String reason) {
121 		ifNull(object, RuntimeException.class, reason);
122 	}
123 	
124 	
125 	/**
126 	 * Method to ensure that an object is not null. Used at the beginning of a
127 	 * method before working with parameters.
128 	 *
129 	 * @param object
130 	 *            Is the object to be analyzed.
131 	 * @param exceptionType
132 	 *            the kind of {@link RuntimeException} to be thrown in
133 	 *            case the precondition is violated.
134 	 * @param exceptionArguments
135 	 *            constructor arguments for {@code exceptionType}.
136 	 */
137 	public static
138 	void ifNull(Object object,
139 				Class<? extends RuntimeException> exceptionType,
140 				Object... exceptionArguments) {
141 		
142 		checkCondition(object != null, exceptionType, exceptionArguments);
143 	}
144 	
145 	
146 	
147 	/**
148 	 * Method to ensure that a condition is true. Used at the beginning of a
149 	 * method before working with parameters.
150 	 *
151 	 * @param condition
152 	 *            Is the condition to be analyzed.
153 	 * @deprecated Use {@link #ifCondition(boolean)} instead
154 	 */
155 	public static void ifFalse(boolean condition) {
156 		ifCondition(!condition);
157 	}
158 
159 	/**
160 	 * Method to ensure that a condition is false. Used at the beginning of a
161 	 * method before working with parameters.
162 	 *
163 	 * @param condition
164 	 *            Is the condition to be analyzed.
165 	 */
166 	public static void ifCondition(boolean condition) {
167 		ifCondition(condition, RuntimeException.class);
168 	}
169 
170 	/**
171 	 * Method to ensure that a condition is true. Used at the beginning of a
172 	 * method before working with parameters.
173 	 *
174 	 * @param condition
175 	 *            Is the condition to be analyzed.
176 	 * @param reason
177 	 *            Is the message to explain the reason of the exception.
178 	 * @deprecated Use {@link #ifCondition(boolean,String)} instead
179 	 */
180 	public static void ifFalse(boolean condition, String reason) {
181 		ifCondition(!condition, reason);
182 	}
183 
184 	/**
185 	 * Method to ensure that a condition is false. Used at the beginning of a
186 	 * method before working with parameters.
187 	 *
188 	 * @param condition
189 	 *            Is the condition to be analyzed.
190 	 * @param reason
191 	 *            Is the message to explain the reason of the exception.
192 	 */
193 	public static void ifCondition(boolean condition, String reason) {
194 		ifCondition(condition, RuntimeException.class, reason);
195 	}
196 
197 	/**
198 	 * Method to ensure that a condition is true. Used at the beginning of a
199 	 * method before working with parameters.
200 	 *
201 	 * @param condition
202 	 *            Is the condition to be analyzed.
203 	 * @param exceptionType
204 	 *            the kind of {@link RuntimeException} to be thrown in
205 	 *            case the precondition is violated.
206 	 * @param exceptionArguments
207 	 *            constructor arguments for {@code exceptionType}.
208 	 * @deprecated Use {@link #ifCondition(boolean, Class, Object...)} instead
209 	 */
210 	public static
211 	void ifFalse(boolean condition,
212 		Class<? extends RuntimeException> exceptionType,
213 		Object... exceptionArguments) {
214 		
215 		ifCondition(!condition, exceptionType, exceptionArguments);
216 	}
217 
218 	/**
219 	 * Method to ensure that a condition is false. Used at the beginning of a
220 	 * method before working with parameters.
221 	 *
222 	 * @param condition
223 	 *            Is the condition to be analyzed.
224 	 * @param exceptionType
225 	 *            the kind of {@link RuntimeException} to be thrown in
226 	 *            case the precondition is violated.
227 	 * @param exceptionArguments
228 	 *            constructor arguments for {@code exceptionType}.
229 	 */
230 	public static
231 	void ifCondition(boolean condition,
232 		Class<? extends RuntimeException> exceptionType,
233 		Object... exceptionArguments) {
234 
235 		checkCondition(!condition, exceptionType, exceptionArguments);
236 	}
237 	
238 	
239 	/**
240 	 * Method to ensure that a string is not empty. Used at the beginning of a
241 	 * method before working with parameters.
242 	 *
243 	 * @param s
244 	 *            Is the string to be analyzed.
245 	 */
246 	public static void ifEmpty(String s) {
247 		ifEmpty(s, RuntimeException.class);
248 	}
249 
250 	/**
251 	 * Method to ensure that a string is not empty. Used at the beginning of a
252 	 * method before working with parameters.
253 	 *
254 	 * @param s
255 	 *            Is the string to be analyzed.
256 	 * @param reason
257 	 *            Is the message to explain the reason of the exception.
258 	 */
259 	public static void ifEmpty(String s, String reason) {
260 		ifEmpty(s, RuntimeException.class, reason);
261 	}
262 	
263 	/**
264 	 * Method to ensure that a string is not empty. Used at the beginning of a
265 	 * method before working with parameters.
266 	 *
267 	 * @param s
268 	 *            Is the string to be analyzed.
269 	 * @param exceptionType
270 	 *            the kind of {@link RuntimeException} to be thrown in
271 	 *            case the precondition is violated.
272 	 * @param exceptionArguments
273 	 *            constructor arguments for {@code exceptionType}.
274 	 */
275 	public static
276 	void ifEmpty(String s,
277 		Class<? extends RuntimeException> exceptionType,
278 		Object... exceptionArguments) {
279 		
280 		checkCondition(
281 			StringUtils.hasText(s),
282 			exceptionType,
283 			exceptionArguments
284 		);
285 	}
286 	
287 	
288 	/**
289 	 * Method to ensure that a collection is not empty.
290 	 *
291 	 * @param c
292 	 *            The collection.
293 	 */
294 	public static void ifEmpty(Collection<?> c) {
295 		ifEmpty(c, RuntimeException.class);
296 	}
297 	
298 	/**
299 	 * Method to ensure that a collection is not empty.
300 	 *
301 	 * @param c
302 	 *            The collection.
303 	 * @param reason
304 	 *            Message that explains the reason of the thrown exception.
305 	 */
306 	public static void ifEmpty(Collection<?> c, String reason) {
307 		ifEmpty(c, RuntimeException.class, reason);
308 	}
309 	
310 	/**
311 	 * Method to ensure that a collection is not empty.
312 	 *
313 	 * @param c
314 	 *            The collection.
315 	 * @param exceptionType
316 	 *            the kind of {@link RuntimeException} to be thrown in
317 	 *            case the precondition is violated.
318 	 * @param exceptionArguments
319 	 *            constructor arguments for {@code exceptionType}.
320 	 */
321 	public static
322 	void ifEmpty(Collection<?> c,
323 		Class<? extends RuntimeException> exceptionType,
324 		Object... exceptionArguments) {
325 		
326 		checkCondition(
327 			!CollectionUtils.isEmpty(c),
328 			exceptionType,
329 			exceptionArguments
330 		);
331 	}
332 
333 	/**
334 	 * Method to ensure that an object array is not empty.
335 	 *
336 	 * @param objects The object array.
337 	 */
338 	public static void ifEmpty(Object[] objects) {
339 		ifEmpty(objects, RuntimeException.class);
340 	}
341 	
342 	/**
343 	 * Method to ensure that an object array is not empty.
344 	 *
345 	 * @param objects The object array.
346 	 * @param reason
347 	 *            Message that explains the reason of the thrown exception.
348 	 */
349 	public static void ifEmpty(Object[] objects, String reason) {
350 		ifEmpty(objects, RuntimeException.class, reason);
351 	}
352 	
353 	/**
354 	 * Method to ensure that an object array is not empty.
355 	 *
356 	 * @param objects The object array.
357 	 * @param exceptionType
358 	 *            the kind of {@link RuntimeException} to be thrown in
359 	 *            case the precondition is violated.
360 	 * @param exceptionArguments
361 	 *            constructor arguments for {@code exceptionType}.
362 	 */
363 	public static
364 	void ifEmpty(Object[] objects,
365 		Class<? extends RuntimeException> exceptionType,
366 		Object... exceptionArguments) {
367 		
368 		checkCondition(
369 			!ArrayUtils.isEmpty(objects),
370 			exceptionType,
371 			exceptionArguments
372 		);
373 	}
374 	
375 	/**
376 	 * Ensures that the given object is assignable to the given class.
377 	 *
378 	 * @param o
379 	 *            Is the object that must be assignable to.
380 	 * @param assignableTo
381 	 *            Is the target class.
382 	 */
383 	public static
384 	void ifNotAssignableTo(Object o, Class<?> assignableTo) {
385 		ifNotAssignableTo(o, assignableTo, RuntimeException.class);
386 	}
387 	
388 	/**
389 	 * Ensures that the given object is assignable to the given class.
390 	 *
391 	 * @param o
392 	 *            Is the object that must be assignable to.
393 	 * @param assignableTo
394 	 *            Is the target class.
395 	 * @param reason
396 	 *            Is the message to explain the reason of the exception.
397 	 */
398 	public static
399 	void ifNotAssignableTo(Object o, Class<?> assignableTo, String reason) {
400 		ifNotAssignableTo(o, assignableTo, RuntimeException.class, reason);
401 	}
402 	
403 	/**
404 	 * Ensures that the given object is assignable to the given class.
405 	 *
406 	 * @param o
407 	 *            Is the object that must be assignable to.
408 	 * @param assignableTo
409 	 *            Is the target class.
410 	 * @param exceptionType
411 	 *            Is the type of exception to throw.
412 	 * @param exceptionArguments
413 	 *            constructor arguments for {@code exceptionType}.
414 	 */
415 	public static
416 	void ifNotAssignableTo(Object o, Class<?> assignableTo,
417 		Class<? extends RuntimeException> exceptionType,
418 		Object... exceptionArguments) {
419 		
420 		checkCondition(
421 			assignableTo.isAssignableFrom(o.getClass()),
422 			exceptionType,
423 			exceptionArguments
424 		);
425 	}
426 	
427 	////////////////////
428 	// Common methods //
429 	////////////////////
430 
431 	/**
432 	 * This method throws an exception of give conditionException type, if the
433 	 * condition is false. The given string will be added on created exception.
434 	 *
435 	 * @param condition
436 	 *            Is the condition to check.
437 	 * @param conditionException
438 	 *            Is the exception which will be thrown.
439 	 * @param constructorArgs
440 	 *            Are the arguments to the exception's constructor.
441 	 */
442 	private static void
443 	checkCondition(boolean condition,
444 		Class<? extends RuntimeException> conditionException,
445 		Object... constructorArgs) {
446 		
447 		if (!condition) {
448 			RuntimeException e = instantiateConditionException(
449 				conditionException,
450 				constructorArgs
451 			);
452 			LOG.error(e.getMessage());
453 			throw e;
454 		}
455 	}
456 	
457 	/**
458 	 * Instantiates an RuntimeException of the supplied type
459 	 * using the supplied constructor arguments.
460 	 *
461 	 * @param <T> Is the exception class.
462 	 * @param exceptionClass Is the exception to create.
463 	 * @param constructorArgs Are the constructor arguments of the exception.
464 	 * @return Return the requested exception.
465 	 */
466 	@SuppressWarnings("unchecked")
467 	private static <T extends RuntimeException>
468 	T instantiateConditionException(Class<T> exceptionClass,
469 		Object... constructorArgs) {
470 		
471 		for (Constructor<?> c : exceptionClass.getConstructors()) {
472 			try {
473 				return (T) c.newInstance(constructorArgs);
474 			} catch (IllegalArgumentException e) {
475 				continue;
476 			} catch (InstantiationException e) {
477 				// exceptionClass is abstract
478 				assert false;
479 				throw new RuntimeException(e);
480 			} catch (IllegalAccessException e) {
481 				continue;
482 			} catch (InvocationTargetException e) {
483 				assert false;
484 				throw new RuntimeException(
485 					"error instantiating " + exceptionClass.getName()
486 					+ ": constructor threw ", e
487 				);
488 			}
489 		}
490 		assert false;
491 		throw new IllegalArgumentException(
492 			"error instantiating " + exceptionClass.getName() + ": "
493 			+ "there appears to be no accessible constructor accepting the "
494 			+ "provided arguments."
495 		);
496 	}
497 }