View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jelly.tags.junit;
17  
18  import org.apache.commons.jelly.JellyException;
19  import org.apache.commons.jelly.JellyTagException;
20  import org.apache.commons.jelly.XMLOutput;
21  import org.apache.commons.jelly.util.ClassLoaderUtils;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /***
26   * Runs its body and asserts that an exception is thrown by it.  If no
27   * exception is thrown the tag fails.  By default all exceptions are caught.
28   * If however <code>expected</code> was specified the body must throw
29   * an exception of the given class, otherwise the assertion fails.  The
30   * exception thrown by the body can also be of any subtype of the specified
31   * exception class.  The optional <code>var</code> attribute can be specified if
32   * the caught exception is to be exported to a variable.
33   */
34  public class AssertThrowsTag extends AssertTagSupport {
35  
36      /*** The Log to which logging calls will be made. */
37      private static final Log log = LogFactory.getLog(AssertThrowsTag.class);
38  
39      /***
40       * The variable name to export the caught exception to.
41       */
42      private String var;
43  
44      /***
45       * The class name (fully qualified) of the exception expected to be thrown
46       * by the body.  Also a superclass of the expected exception can be given.
47       */
48      private String expected;
49  
50      /***
51       * Sets the ClassLoader to be used when loading an exception class
52       */
53      private ClassLoader classLoader;
54  
55      // Tag interface
56      //-------------------------------------------------------------------------
57      public void doTag(XMLOutput output) throws JellyTagException {
58          Class throwableClass = null;
59          try {
60               throwableClass = getThrowableClass();
61          } catch (ClassNotFoundException e) {
62              throw new JellyTagException(e);
63          }
64  
65          try {
66              invokeBody(output);
67          }
68          catch (Throwable t) {
69              if (t instanceof JellyException) {
70                  // unwrap Jelly exceptions which wrap other exceptions
71                  JellyException je = (JellyException) t;
72                  if (je.getCause() != null) {
73                      t = je.getCause();
74                  }
75              }
76              if (var != null) {
77                  context.setVariable(var, t);
78              }
79              if (throwableClass != null && !throwableClass.isAssignableFrom(t.getClass())) {
80                  fail("Unexpected exception: " + t);
81              }
82              else {
83                  return;
84              }
85          }
86          fail("No exception was thrown.");
87      }
88  
89      // Properties
90      //-------------------------------------------------------------------------
91      /***
92       * Sets the class name of exception expected to be thrown by the body.  The
93       * class name must be fully qualified and can either be the expected
94       * exception class itself or any supertype of it, but must be a subtype of
95       * <code>java.lang.Throwable</code>.
96       */
97      public void setExpected(String expected) {
98          this.expected = expected;
99      }
100 
101     /***
102      * Sets the variable name to define for this expression.
103      */
104     public void setVar(String var) {
105         this.var = var;
106     }
107 
108     /***
109      * Sets the class loader to be used to load the exception type
110      */
111     public void setClassLoader(ClassLoader classLoader) {
112         this.classLoader = classLoader;
113     }
114 
115     public ClassLoader getClassLoader() {
116         return ClassLoaderUtils.getClassLoader(classLoader, getContext().getUseContextClassLoader(), getClass());
117     }
118 
119     // Implementation methods
120     //-------------------------------------------------------------------------
121 
122     /***
123      * Returns the <code>Class</code> corresponding to the class
124      * specified by <code>expected</code>. If
125      * <code>expected</code> was either not specified then <code>java. lang.
126      * Throwable</code> is returned.
127      * Otherwise if the class couldn't be
128      * found or doesn't denote an exception class then an exception is thrown.
129      *
130      * @return Class The class of the exception to expect
131      */
132     protected Class getThrowableClass() throws ClassNotFoundException {
133         if (expected == null) {
134             return Throwable.class;
135         }
136 
137         Class throwableClass = null;
138         try {
139             throwableClass = getClassLoader().loadClass(expected);
140         }
141         catch (ClassNotFoundException e) {
142             try {
143                 throwableClass = Thread.currentThread().getContextClassLoader().loadClass(expected);
144             }
145             catch (ClassNotFoundException e2) {
146                 log.warn( "Could not find exception class: " + expected );
147                 throw e;
148             }
149         }
150 
151         if (!Throwable.class.isAssignableFrom(throwableClass)) {
152             log.warn( "The class: " + expected + " is not an Exception class.");
153             return null;
154         }
155         return throwableClass;
156     }
157 }