Clover coverage report - Cactus 1.5 for J2EE API 1.2
Coverage timestamp: Wed Feb 18 2004 09:04:33 EST
file stats: LOC: 525   Methods: 13
NCLOC: 268   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
AbstractWebTestCaller.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * ====================================================================
 3   
  *
 4   
  * The Apache Software License, Version 1.1
 5   
  *
 6   
  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 7   
  * reserved.
 8   
  *
 9   
  * Redistribution and use in source and binary forms, with or without
 10   
  * modification, are permitted provided that the following conditions
 11   
  * are met:
 12   
  *
 13   
  * 1. Redistributions of source code must retain the above copyright
 14   
  *    notice, this list of conditions and the following disclaimer.
 15   
  *
 16   
  * 2. Redistributions in binary form must reproduce the above copyright
 17   
  *    notice, this list of conditions and the following disclaimer in
 18   
  *    the documentation and/or other materials provided with the
 19   
  *    distribution.
 20   
  *
 21   
  * 3. The end-user documentation included with the redistribution, if
 22   
  *    any, must include the following acknowlegement:
 23   
  *       "This product includes software developed by the
 24   
  *        Apache Software Foundation (http://www.apache.org/)."
 25   
  *    Alternately, this acknowlegement may appear in the software itself,
 26   
  *    if and wherever such third-party acknowlegements normally appear.
 27   
  *
 28   
  * 4. The names "The Jakarta Project", "Cactus" and "Apache Software
 29   
  *    Foundation" must not be used to endorse or promote products
 30   
  *    derived from this software without prior written permission. For
 31   
  *    written permission, please contact apache@apache.org.
 32   
  *
 33   
  * 5. Products derived from this software may not be called "Apache"
 34   
  *    nor may "Apache" appear in their names without prior written
 35   
  *    permission of the Apache Group.
 36   
  *
 37   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 38   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 39   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 40   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 41   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 42   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 43   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 44   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 45   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 46   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 47   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 48   
  * SUCH DAMAGE.
 49   
  * ====================================================================
 50   
  *
 51   
  * This software consists of voluntary contributions made by many
 52   
  * individuals on behalf of the Apache Software Foundation.  For more
 53   
  * information on the Apache Software Foundation, please see
 54   
  * <http://www.apache.org/>.
 55   
  *
 56   
  */
 57   
 package org.apache.cactus.server;
 58   
 
 59   
 import java.io.IOException;
 60   
 import java.io.Writer;
 61   
 
 62   
 import java.lang.reflect.Constructor;
 63   
 
 64   
 import javax.servlet.ServletException;
 65   
 
 66   
 import junit.framework.Test;
 67   
 import junit.framework.TestCase;
 68   
 
 69   
 import org.apache.cactus.HttpServiceDefinition;
 70   
 import org.apache.cactus.ServiceEnumeration;
 71   
 import org.apache.cactus.WebTestResult;
 72   
 import org.apache.cactus.configuration.Version;
 73   
 import org.apache.cactus.util.ClassLoaderUtils;
 74   
 import org.apache.commons.logging.Log;
 75   
 import org.apache.commons.logging.LogFactory;
 76   
 
 77   
 /**
 78   
  * Responsible for instanciating the <code>TestCase</code> class on the server
 79   
  * side, set up the implicit objects and call the test method. This class
 80   
  * provides a common abstraction for all test web requests.
 81   
  *
 82   
  * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
 83   
  * @author <a href="mailto:ndlesiecki@apache.org">Nicholas Lesiecki</a>
 84   
  *
 85   
  * @version $Id: AbstractWebTestCaller.java,v 1.23 2003/07/12 19:31:41 vmassol Exp $
 86   
  */
 87   
 public abstract class AbstractWebTestCaller
 88   
 {
 89   
     /**
 90   
      * Name of the attribute in the <code>application</code> scope that will
 91   
      * hold the results of the test.
 92   
      */
 93   
     protected static final String TEST_RESULTS = 
 94   
         "ServletTestRedirector_TestResults";
 95   
 
 96   
     /**
 97   
      * The logger.
 98   
      */
 99   
     private static final Log LOGGER = 
 100   
         LogFactory.getLog(AbstractWebTestCaller.class);
 101   
 
 102   
     /**
 103   
      * The implicit objects (which will be used to set the test case fields
 104   
      * in the <code>setTesCaseFields</code> method.
 105   
      */
 106   
     protected WebImplicitObjects webImplicitObjects;
 107   
 
 108   
     /**
 109   
      * @param theObjects the implicit objects coming from the redirector
 110   
      */
 111  0
     public AbstractWebTestCaller(WebImplicitObjects theObjects)
 112   
     {
 113  0
         this.webImplicitObjects = theObjects;
 114   
     }
 115   
 
 116   
     /**
 117   
      * Sets the implicit object in the test case class
 118   
      *
 119   
      * @param theTestCase the instance of the test case class on which the
 120   
      *        class variable (implicit objects) should be set
 121   
      * @exception Exception if an errors occurs when setting the implicit
 122   
      *            objects
 123   
      */
 124   
     protected abstract void setTestCaseFields(TestCase theTestCase) 
 125   
         throws Exception;
 126   
 
 127   
     /**
 128   
      * @return a <code>Writer</code> object that will be used to return the
 129   
      *         test result to the client side.
 130   
      * @exception IOException if an error occurs when retrieving the writer
 131   
      */
 132   
     protected abstract Writer getResponseWriter() throws IOException;
 133   
 
 134   
     /**
 135   
      * Calls a test method. The parameters needed to call this method are found
 136   
      * in the HTTP request. Save the results in the <code>application</code>
 137   
      * scope so that the Get Test Result service can find them.
 138   
      *
 139   
      * @exception ServletException if an unexpected error occurred
 140   
      */
 141  0
     public void doTest() throws ServletException
 142   
     {
 143  0
         WebTestResult result = null;
 144   
 
 145  0
         try
 146   
         {
 147   
             // Create an instance of the test class
 148  0
             TestCase testInstance = getTestClassInstance(
 149   
                 getTestClassName(), getWrappedTestClassName(), 
 150   
                 getTestMethodName());
 151   
 
 152   
             // Set its fields (implicit objects)
 153  0
             setTestCaseFields(testInstance);
 154   
 
 155   
             // Call it's method corresponding to the current test case
 156  0
             testInstance.runBare();
 157   
 
 158   
             // Return an instance of <code>WebTestResult</code> with a
 159   
             // positive result.
 160  0
             result = new WebTestResult();
 161   
         }
 162   
         catch (Throwable e)
 163   
         {
 164   
             // An error occurred, return an instance of
 165   
             // <code>WebTestResult</code> with an exception.
 166  0
             result = new WebTestResult(e);
 167   
         }
 168   
 
 169  0
         LOGGER.debug("Test result : [" + result + "]");
 170   
 
 171   
 
 172   
         // Set the test result.
 173  0
         this.webImplicitObjects.getServletContext()
 174   
             .setAttribute(TEST_RESULTS, result);
 175   
 
 176  0
         LOGGER.debug("Result saved in context scope");
 177   
     }
 178   
 
 179   
     /**
 180   
      * Return the last test results in the HTTP response.
 181   
      *
 182   
      * @exception ServletException if an unexpected error occurred
 183   
      */
 184  0
     public void doGetResults() throws ServletException
 185   
     {
 186   
         // One could think there is a potential risk that the client side of
 187   
         // Cactus will request the result before it has been written to the
 188   
         // context scope as the HTTP request will not block in some containers.
 189   
         // However this will not happen because on the client side, once the
 190   
         // first request is done to execute the test, all the result is read
 191   
         // by the AutoReadHttpURLConnection class, thus ensuring that the
 192   
         // request is fully finished and the result has been committed ...
 193  0
         WebTestResult result = (WebTestResult) (this.webImplicitObjects
 194   
             .getServletContext().getAttribute(TEST_RESULTS));
 195   
 
 196  0
         LOGGER.debug("Test Result = [" + result + "]");
 197   
 
 198   
         // Write back the results to the outgoing stream as an XML string.
 199   
 
 200   
         // Use UTF-8 to transfer the result back
 201  0
         webImplicitObjects.getHttpServletResponse().setContentType(
 202   
             "text/xml; charset=UTF-8");
 203   
 
 204  0
         try
 205   
         {
 206  0
             Writer writer = getResponseWriter();
 207   
 
 208  0
             writer.write(result.toXml());
 209  0
             writer.close();
 210   
         }
 211   
         catch (IOException e)
 212   
         {
 213  0
             String message = "Error writing WebTestResult instance to output "
 214   
                 + "stream";
 215   
 
 216  0
             LOGGER.error(message, e);
 217  0
             throw new ServletException(message, e);
 218   
         }
 219   
     }
 220   
 
 221   
     /**
 222   
      * Run the connection test between client and server. This is just to
 223   
      * ensure that configuration is set up correctly.
 224   
      *
 225   
      * @exception ServletException if an unexpected error occurred
 226   
      */
 227  0
     public void doRunTest() throws ServletException
 228   
     {
 229   
         // Do not return any http response (not needed). It is enough to
 230   
         // know this point has been reached ... it means the connection has
 231   
         // been established !
 232   
     }
 233   
 
 234   
     /**
 235   
      * Return the cactus version. This is to make sure both the client side
 236   
      * and server side are using the same version.
 237   
      *  
 238   
      * @exception ServletException if an unexpected error occurred
 239   
      */    
 240  0
     public void doGetVersion() throws ServletException
 241   
     {
 242  0
         try
 243   
         {
 244  0
             Writer writer = getResponseWriter();
 245  0
             writer.write(Version.VERSION);
 246  0
             writer.close();
 247   
         }
 248   
         catch (IOException e)
 249   
         {
 250  0
             String message = "Error writing HTTP response back to client "
 251   
                 + "for service [" + ServiceEnumeration.GET_VERSION_SERVICE
 252   
                 + "]";
 253   
 
 254  0
             LOGGER.error(message, e);
 255  0
             throw new ServletException(message, e);
 256   
         }        
 257   
     }
 258   
     
 259   
     /**
 260   
      * Create an HTTP Session and returns the response that contains the
 261   
      * HTTP session as a cookie (unless URL rewriting is used in which
 262   
      * case the jsesssionid cookie is not returned).
 263   
      * 
 264   
      * @exception ServletException if an unexpected error occurred
 265   
      */
 266  0
     public void doCreateSession() throws ServletException
 267   
     {
 268   
         // Create an HTTP session
 269  0
         this.webImplicitObjects.getHttpServletRequest().getSession(true);
 270   
 
 271  0
         try
 272   
         {
 273  0
             Writer writer = getResponseWriter();
 274  0
             writer.close();
 275   
         }
 276   
         catch (IOException e)
 277   
         {
 278  0
             String message = "Error writing HTTP response back to client "
 279   
                 + "for service [" + ServiceEnumeration.CREATE_SESSION_SERVICE
 280   
                 + "]";
 281   
 
 282  0
             LOGGER.error(message, e);
 283  0
             throw new ServletException(message, e);
 284   
         }
 285   
     }
 286   
 
 287   
     /**
 288   
      * @return the class to test class name, extracted from the HTTP request
 289   
      * @exception ServletException if the class name of the test case is missing
 290   
      *            from the HTTP request
 291   
      */
 292  0
     protected String getTestClassName() throws ServletException
 293   
     {
 294  0
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 295   
             .getQueryString();
 296  0
         String className = ServletUtil.getQueryStringParameter(queryString, 
 297   
             HttpServiceDefinition.CLASS_NAME_PARAM);
 298   
 
 299  0
         if (className == null)
 300   
         {
 301  0
             String message = "Missing class name parameter ["
 302   
                 + HttpServiceDefinition.CLASS_NAME_PARAM
 303   
                 + "] in HTTP request.";
 304   
 
 305  0
             LOGGER.error(message);
 306  0
             throw new ServletException(message);
 307   
         }
 308   
 
 309  0
         LOGGER.debug("Class to call = [" + className + "]");
 310   
 
 311  0
         return className;
 312   
     }
 313   
 
 314   
     /**
 315   
      * @return the optional test class that is wrapped by a Cactus test case, 
 316   
      *         extracted from the HTTP request
 317   
      * @exception ServletException if the wrapped class name is missing from 
 318   
      *            the HTTP request
 319   
      */
 320  0
     protected String getWrappedTestClassName() throws ServletException
 321   
     {
 322  0
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 323   
             .getQueryString();
 324  0
         String className = ServletUtil.getQueryStringParameter(queryString, 
 325   
             HttpServiceDefinition.WRAPPED_CLASS_NAME_PARAM);
 326   
 
 327  0
         if (className == null)
 328   
         {
 329  0
             LOGGER.debug("No wrapped test class");
 330   
         } 
 331   
         else
 332   
         { 
 333  0
             LOGGER.debug("Wrapped test class = [" + className + "]");
 334   
         }
 335   
 
 336  0
         return className;
 337   
     }
 338   
 
 339   
     /**
 340   
      * @return the class method to call for the current test case, extracted
 341   
      *         from the HTTP request
 342   
      * @exception ServletException if the method name of the test case is
 343   
      *            missing from the HTTP request
 344   
      */
 345  0
     protected String getTestMethodName() throws ServletException
 346   
     {
 347  0
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 348   
             .getQueryString();
 349  0
         String methodName = ServletUtil.getQueryStringParameter(queryString, 
 350   
             HttpServiceDefinition.METHOD_NAME_PARAM);
 351   
 
 352  0
         if (methodName == null)
 353   
         {
 354  0
             String message = "Missing method name parameter ["
 355   
                 + HttpServiceDefinition.METHOD_NAME_PARAM
 356   
                 + "] in HTTP request.";
 357   
 
 358  0
             LOGGER.error(message);
 359  0
             throw new ServletException(message);
 360   
         }
 361   
 
 362  0
         LOGGER.debug("Method to call = " + methodName);
 363   
 
 364  0
         return methodName;
 365   
     }
 366   
 
 367   
     /**
 368   
      * @return true if the auto session flag for the Session can be found in
 369   
      *         the HTTP request
 370   
      */
 371  0
     protected boolean isAutoSession()
 372   
     {
 373  0
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 374   
             .getQueryString();
 375  0
         String autoSession = ServletUtil.getQueryStringParameter(queryString, 
 376   
             HttpServiceDefinition.AUTOSESSION_NAME_PARAM);
 377   
 
 378  0
         boolean isAutomaticSession = 
 379   
             Boolean.valueOf(autoSession).booleanValue();
 380   
 
 381  0
         LOGGER.debug("Auto session is " + isAutomaticSession);
 382   
 
 383  0
         return isAutomaticSession;
 384   
     }
 385   
 
 386   
     /**
 387   
      * @param theClassName the name of the test class
 388   
      * @param theWrappedClassName the name of the wrapped test class. Can be
 389   
      *        null if there is none
 390   
      * @param theTestCaseName the name of the current test case
 391   
      * @return an instance of the test class to call
 392   
      * @exception ServletException if the test case instance for the current
 393   
      *            test fails to be instanciated (for example if some
 394   
      *            information is missing from the HTTP request)
 395   
      */
 396  0
     protected TestCase getTestClassInstance(
 397   
         String theClassName, String theWrappedClassName, 
 398   
         String theTestCaseName) throws ServletException
 399   
     {
 400   
         // Get the class to call and build an instance of it.
 401  0
         Class testClass = getTestClassClass(theClassName);
 402  0
         TestCase testInstance = null;
 403  0
         Constructor constructor;
 404   
         
 405  0
         try
 406   
         {
 407  0
             if (theWrappedClassName == null)
 408   
             {
 409  0
                 constructor = getTestClassConstructor(testClass); 
 410   
 
 411  0
                 if (constructor.getParameterTypes().length == 0)
 412   
                 {
 413  0
                     testInstance = (TestCase) constructor.newInstance(
 414   
                         new Object[0]);
 415  0
                     ((TestCase) testInstance).setName(theTestCaseName);
 416   
                 }
 417   
                 else
 418   
                 {
 419  0
                     testInstance = (TestCase) constructor.newInstance(
 420   
                         new Object[] {theTestCaseName});                
 421   
                 }
 422   
             }
 423   
             else
 424   
             {
 425  0
                 Class wrappedTestClass = 
 426   
                     getTestClassClass(theWrappedClassName);
 427  0
                 Constructor wrappedConstructor =
 428   
                     getTestClassConstructor(wrappedTestClass);
 429   
 
 430  0
                 TestCase wrappedTestInstance;
 431  0
                 if (wrappedConstructor.getParameterTypes().length == 0)
 432   
                 {
 433  0
                     wrappedTestInstance = 
 434   
                         (TestCase) wrappedConstructor.newInstance(
 435   
                         new Object[0]);
 436  0
                     wrappedTestInstance.setName(theTestCaseName);
 437   
                 }
 438   
                 else
 439   
                 {
 440  0
                     wrappedTestInstance = 
 441   
                         (TestCase) wrappedConstructor.newInstance(
 442   
                         new Object[] {theTestCaseName});
 443   
                 }
 444   
 
 445  0
                 constructor = testClass.getConstructor(
 446   
                     new Class[] {String.class, Test.class});
 447   
 
 448  0
                 testInstance = 
 449   
                     (TestCase) constructor.newInstance(
 450   
                     new Object[] {theTestCaseName, wrappedTestInstance});
 451   
             }
 452   
         }
 453   
         catch (Exception e)
 454   
         {
 455  0
             String message = "Error instantiating class [" + theClassName + "(["
 456   
                 + theTestCaseName + "], [" + theWrappedClassName + "])]";
 457   
 
 458  0
             LOGGER.error(message, e);
 459  0
             throw new ServletException(message, e);
 460   
         }
 461   
 
 462  0
         return testInstance;
 463   
     }
 464   
 
 465   
     /**
 466   
      * @param theTestClass the test class for which we want to find the
 467   
      *        constructor
 468   
      * @return the availble constructor for the test class
 469   
      * @throws NoSuchMethodException if no suitable constructor is found
 470   
      */
 471  0
     private Constructor getTestClassConstructor(Class theTestClass)
 472   
         throws NoSuchMethodException
 473   
     {
 474  0
         Constructor constructor;
 475  0
         try 
 476   
         {
 477  0
             constructor = theTestClass.getConstructor(
 478   
                 new Class[] {String.class});         
 479   
         }
 480   
         catch (NoSuchMethodException e)
 481   
         {
 482  0
             constructor = theTestClass.getConstructor(new Class[0]);
 483   
         }
 484  0
         return constructor;        
 485   
     }
 486   
 
 487   
     /**
 488   
      * @param theClassName the name of the test class
 489   
      * @return the class object the test class to call
 490   
      * @exception ServletException if the class of the current test case
 491   
      *            cannot be loaded in memory (i.e. it is not in the
 492   
      *            classpath)
 493   
      */
 494  0
     protected Class getTestClassClass(String theClassName)
 495   
         throws ServletException
 496   
     {
 497   
         // Get the class to call and build an instance of it.
 498  0
         Class testClass = null;
 499   
 
 500  0
         try
 501   
         {
 502  0
             testClass = ClassLoaderUtils.loadClass(theClassName, 
 503   
                 this.getClass());
 504   
         }
 505   
         catch (Exception e)
 506   
         {
 507  0
             String message = "Error finding class [" + theClassName
 508   
                 + "] using both the Context classloader and the webapp "
 509   
                 + "classloader. Possible causes include:\r\n";
 510   
 
 511  0
             message += ("\t- Your webapp does not include your test " 
 512   
                 + "classes,\r\n");
 513  0
             message += ("\t- The cactus.jar is not located in your " 
 514   
                 + "WEB-INF/lib directory and your Container has not set the " 
 515   
                 + "Context classloader to point to the webapp one");
 516   
 
 517  0
             LOGGER.error(message, e);
 518  0
             throw new ServletException(message, e);
 519   
         }
 520   
 
 521  0
         return testClass;
 522   
     }
 523   
 
 524   
 }
 525