    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              invokeBody(output);
    62          }
    63          catch (Throwable t) {
    64              if (t instanceof JellyException) {
    65                  // unwrap Jelly exceptions which wrap other exceptions
    66                  JellyException je = (JellyException) t;
    67                  if (je.getCause() != null) {
    68                      t = je.getCause();
    69                  }
    70              }
    71              if (var != null) {
    72                  context.setVariable(var, t);
    73              }
    74              if (throwableClass != null && !throwableClass.isAssignableFrom(t.getClass())) {
    75                  fail("Unexpected exception: " + t);
    76              }
    77              else {
    78                  return;
    79              }
    80          }
    81          fail("No exception was thrown.");
    82      }
    83
    84      // Properties
    85      //-------------------------------------------------------------------------
    86      /***
    87       * Sets the class name of exception expected to be thrown by the body.  The
    88       * class name must be fully qualified and can either be the expected
    89       * exception class itself or any supertype of it, but must be a subtype of
    90       * <code>java.lang.Throwable</code>.
    91       */
    92      public void setExpected(String expected) {
    93          this.expected = expected;
    94      }
    95
    96      /***
    97       * Sets the variable name to define for this expression.
    98       */
    99      public void setVar(String var) {
    100         this.var = var;
    101     }
    102
    103     /***
    104      * Sets the class loader to be used to load the exception type
    105      */
    106     public void setClassLoader(ClassLoader classLoader) {
    107         this.classLoader = classLoader;
    108     }
    109
    110     public ClassLoader getClassLoader() {
    111         return ClassLoaderUtils.getClassLoader(classLoader, getClass());
    112     }
    113
    114     // Implementation methods
    115     //-------------------------------------------------------------------------
    116
    117     /***
    118      * Returns the <code>Class</code> corresponding to the class
    119      * specified by <code>expected</code>. If
    120      * <code>expected</code> was either not specified then <code>java. lang.
    121      * Throwable</code> is returned.
    122      * Otherwise if the class couldn't be
    123      * found or doesn't denote an exception class then an exception is thrown.
    124      *
    125      * @return Class The class of the exception to expect
    126      */
    127     protected Class getThrowableClass() throws ClassNotFoundException {
    128         if (expected == null) {
    129             return Throwable.class;
    130         }
    131
    132         Class throwableClass = null;
    133         try {
    134             throwableClass = getClassLoader().loadClass(expected);
    135         }
    136         catch (ClassNotFoundException e) {
    137             try {
    138                 throwableClass = Thread.currentThread().getContextClassLoader().loadClass(expected);
    139             }
    140             catch (ClassNotFoundException e2) {
    141                 log.warn( "Could not find exception class: " + expected );
    142                 throw e;
    143             }
    144         }
    145
    146         if (!Throwable.class.isAssignableFrom(throwableClass)) {
    147             log.warn( "The class: " + expected + " is not an Exception class.");
    148             return null;
    149         }
    150         return throwableClass;
    151     }
    152 }