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 }