2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

Clover coverage report - Cactus 1.8dev for J2EE API 1.3
Coverage timestamp: Sun Mar 26 2006 18:50:18 BRT
file stats: LOC: 508   Methods: 13
NCLOC: 284   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
AbstractWebTestCaller.java 43.8% 55.2% 76.9% 56%
coverage coverage
 1   
 /* 
 2   
  * ========================================================================
 3   
  * 
 4   
  * Copyright 2001-2004 The Apache Software Foundation.
 5   
  *
 6   
  * Licensed under the Apache License, Version 2.0 (the "License");
 7   
  * you may not use this file except in compliance with the License.
 8   
  * You may obtain a copy of the License at
 9   
  * 
 10   
  *   http://www.apache.org/licenses/LICENSE-2.0
 11   
  * 
 12   
  * Unless required by applicable law or agreed to in writing, software
 13   
  * distributed under the License is distributed on an "AS IS" BASIS,
 14   
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15   
  * See the License for the specific language governing permissions and
 16   
  * limitations under the License.
 17   
  * 
 18   
  * ========================================================================
 19   
  */
 20   
 package org.apache.cactus.internal.server;
 21   
 
 22   
 import java.io.IOException;
 23   
 import java.io.Writer;
 24   
 
 25   
 import java.lang.reflect.Constructor;
 26   
 
 27   
 import javax.servlet.ServletException;
 28   
 
 29   
 import junit.framework.Test;
 30   
 import junit.framework.TestCase;
 31   
 
 32   
 import org.apache.cactus.internal.CactusTestCase;
 33   
 import org.apache.cactus.internal.HttpServiceDefinition;
 34   
 import org.apache.cactus.internal.ServiceEnumeration;
 35   
 import org.apache.cactus.internal.WebTestResult;
 36   
 import org.apache.cactus.internal.configuration.Version;
 37   
 import org.apache.cactus.internal.util.ClassLoaderUtils;
 38   
 import org.apache.commons.logging.Log;
 39   
 import org.apache.commons.logging.LogFactory;
 40   
 
 41   
 /**
 42   
  * Responsible for instanciating the <code>TestCase</code> class on the server
 43   
  * side, set up the implicit objects and call the test method. This class
 44   
  * provides a common abstraction for all test web requests.
 45   
  *
 46   
  * @version $Id: AbstractWebTestCaller.java 238991 2004-05-22 11:34:50Z vmassol $
 47   
  */
 48   
 public abstract class AbstractWebTestCaller
 49   
 {
 50   
     /**
 51   
      * Name of the attribute in the <code>application</code> scope that will
 52   
      * hold the results of the test.
 53   
      */
 54   
     protected static final String TEST_RESULTS = 
 55   
         "ServletTestRedirector_TestResults";
 56   
 
 57   
     /**
 58   
      * The logger.
 59   
      */
 60   
     private static final Log LOGGER = 
 61   
         LogFactory.getLog(AbstractWebTestCaller.class);
 62   
 
 63   
     /**
 64   
      * The implicit objects (which will be used to set the test case fields
 65   
      * in the <code>setTesCaseFields</code> method.
 66   
      */
 67   
     protected WebImplicitObjects webImplicitObjects;
 68   
 
 69   
     /**
 70   
      * @param theObjects the implicit objects coming from the redirector
 71   
      */
 72  48
     public AbstractWebTestCaller(WebImplicitObjects theObjects)
 73   
     {
 74  48
         this.webImplicitObjects = theObjects;
 75   
     }
 76   
 
 77   
     /**
 78   
      * Sets the implicit object in the test case class
 79   
      *
 80   
      * @param theTestCase the instance of the test case class on which the
 81   
      *        class variable (implicit objects) should be set
 82   
      * @exception Exception if an errors occurs when setting the implicit
 83   
      *            objects
 84   
      */
 85   
     protected abstract void setTestCaseFields(TestCase theTestCase) 
 86   
         throws Exception;
 87   
 
 88   
     /**
 89   
      * @return a <code>Writer</code> object that will be used to return the
 90   
      *         test result to the client side.
 91   
      * @exception IOException if an error occurs when retrieving the writer
 92   
      */
 93   
     protected abstract Writer getResponseWriter() throws IOException;
 94   
 
 95   
     /**
 96   
      * Calls a test method. The parameters needed to call this method are found
 97   
      * in the HTTP request. Save the results in the <code>application</code>
 98   
      * scope so that the Get Test Result service can find them.
 99   
      *
 100   
      * @exception ServletException if an unexpected error occurred
 101   
      */
 102  24
     public void doTest() throws ServletException
 103   
     {
 104  24
         WebTestResult result = null;
 105   
 
 106  24
         try
 107   
         {
 108   
             // Create an instance of the test class
 109  24
             TestCase testInstance = getTestClassInstance(
 110   
                 getTestClassName(), getWrappedTestClassName(), 
 111   
                 getTestMethodName());
 112   
 
 113   
             // Set its fields (implicit objects)
 114  24
             setTestCaseFields(testInstance);
 115   
 
 116   
             // Call it's method corresponding to the current test case
 117  24
             if (testInstance instanceof CactusTestCase)
 118   
             {
 119  24
                 ((CactusTestCase) testInstance).runBareServer();                
 120   
                 
 121   
             }
 122   
             else
 123   
             {
 124  0
                 testInstance.runBare();                
 125   
             }
 126   
 
 127   
             // Return an instance of <code>WebTestResult</code> with a
 128   
             // positive result.
 129  24
             result = new WebTestResult();
 130   
         }
 131   
         catch (Throwable e)
 132   
         {
 133   
             // An error occurred, return an instance of
 134   
             // <code>WebTestResult</code> with an exception.
 135  0
             result = new WebTestResult(e);
 136   
         }
 137   
 
 138  24
         LOGGER.debug("Test result : [" + result + "]");
 139   
 
 140   
 
 141   
         // Set the test result.
 142  24
         this.webImplicitObjects.getServletContext()
 143   
             .setAttribute(TEST_RESULTS, result);
 144   
 
 145  24
         LOGGER.debug("Result saved in context scope");
 146   
     }
 147   
 
 148   
     /**
 149   
      * Return the last test results in the HTTP response.
 150   
      *
 151   
      * @exception ServletException if an unexpected error occurred
 152   
      */
 153  24
     public void doGetResults() throws ServletException
 154   
     {
 155   
         // One could think there is a potential risk that the client side of
 156   
         // Cactus will request the result before it has been written to the
 157   
         // context scope as the HTTP request will not block in some containers.
 158   
         // However this will not happen because on the client side, once the
 159   
         // first request is done to execute the test, all the result is read
 160   
         // by the AutoReadHttpURLConnection class, thus ensuring that the
 161   
         // request is fully finished and the result has been committed ...
 162  24
         WebTestResult result = (WebTestResult) (this.webImplicitObjects
 163   
             .getServletContext().getAttribute(TEST_RESULTS));
 164   
 
 165   
         // It can happen that the result has not been written in the Servlet
 166   
         // context. This could happen for example when using a load-balancer
 167   
         // which would direct the second Cactus HTTP connection to another
 168   
         // instance. In that case, we throw an error.
 169  24
         if (result == null)
 170   
         {
 171  0
             String message = "Error getting test result. This could happen "
 172   
                 + "for example if you're using a load-balancer. Please disable "
 173   
                 + "it before running Cactus tests.";
 174   
 
 175  0
             LOGGER.error(message);
 176  0
             throw new ServletException(message);
 177   
         }       
 178   
 
 179  24
         LOGGER.debug("Test Result = [" + result + "]");
 180   
 
 181   
         // Write back the results to the outgoing stream as an XML string.
 182   
 
 183   
         // Use UTF-8 to transfer the result back
 184  24
         webImplicitObjects.getHttpServletResponse().setContentType(
 185   
             "text/xml; charset=UTF-8");
 186   
 
 187  24
         try
 188   
         {
 189  24
             Writer writer = getResponseWriter();
 190   
 
 191  24
             writer.write(result.toXml());
 192  24
             writer.close();
 193   
         }
 194   
         catch (IOException e)
 195   
         {
 196  0
             String message = "Error writing WebTestResult instance to output "
 197   
                 + "stream";
 198   
 
 199  0
             LOGGER.error(message, e);
 200  0
             throw new ServletException(message, e);
 201   
         }
 202   
     }
 203   
 
 204   
     /**
 205   
      * Run the connection test between client and server. This is just to
 206   
      * ensure that configuration is set up correctly.
 207   
      *
 208   
      * @exception ServletException if an unexpected error occurred
 209   
      */
 210  0
     public void doRunTest() throws ServletException
 211   
     {
 212   
         // Do not return any http response (not needed). It is enough to
 213   
         // know this point has been reached ... it means the connection has
 214   
         // been established !
 215   
     }
 216   
 
 217   
     /**
 218   
      * Return the cactus version. This is to make sure both the client side
 219   
      * and server side are using the same version.
 220   
      *  
 221   
      * @exception ServletException if an unexpected error occurred
 222   
      */    
 223  0
     public void doGetVersion() throws ServletException
 224   
     {
 225  0
         try
 226   
         {
 227  0
             Writer writer = getResponseWriter();
 228  0
             writer.write(Version.VERSION);
 229  0
             writer.close();
 230   
         }
 231   
         catch (IOException e)
 232   
         {
 233  0
             String message = "Error writing HTTP response back to client "
 234   
                 + "for service [" + ServiceEnumeration.GET_VERSION_SERVICE
 235   
                 + "]";
 236   
 
 237  0
             LOGGER.error(message, e);
 238  0
             throw new ServletException(message, e);
 239   
         }        
 240   
     }
 241   
     
 242   
     /**
 243   
      * Create an HTTP Session and returns the response that contains the
 244   
      * HTTP session as a cookie (unless URL rewriting is used in which
 245   
      * case the jsesssionid cookie is not returned).
 246   
      * 
 247   
      * @exception ServletException if an unexpected error occurred
 248   
      */
 249  0
     public void doCreateSession() throws ServletException
 250   
     {
 251   
         // Create an HTTP session
 252  0
         this.webImplicitObjects.getHttpServletRequest().getSession(true);
 253   
 
 254  0
         try
 255   
         {
 256  0
             Writer writer = getResponseWriter();
 257  0
             writer.close();
 258   
         }
 259   
         catch (IOException e)
 260   
         {
 261  0
             String message = "Error writing HTTP response back to client "
 262   
                 + "for service [" + ServiceEnumeration.CREATE_SESSION_SERVICE
 263   
                 + "]";
 264   
 
 265  0
             LOGGER.error(message, e);
 266  0
             throw new ServletException(message, e);
 267   
         }
 268   
     }
 269   
 
 270   
     /**
 271   
      * @return the class to test class name, extracted from the HTTP request
 272   
      * @exception ServletException if the class name of the test case is missing
 273   
      *            from the HTTP request
 274   
      */
 275  24
     protected String getTestClassName() throws ServletException
 276   
     {
 277  24
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 278   
             .getQueryString();
 279  24
         String className = ServletUtil.getQueryStringParameter(queryString, 
 280   
             HttpServiceDefinition.CLASS_NAME_PARAM);
 281   
 
 282  24
         if (className == null)
 283   
         {
 284  0
             String message = "Missing class name parameter ["
 285   
                 + HttpServiceDefinition.CLASS_NAME_PARAM
 286   
                 + "] in HTTP request.";
 287   
 
 288  0
             LOGGER.error(message);
 289  0
             throw new ServletException(message);
 290   
         }
 291   
 
 292  24
         LOGGER.debug("Class to call = [" + className + "]");
 293   
 
 294  24
         return className;
 295   
     }
 296   
 
 297   
     /**
 298   
      * @return the optional test class that is wrapped by a Cactus test case, 
 299   
      *         extracted from the HTTP request
 300   
      * @exception ServletException if the wrapped class name is missing from 
 301   
      *            the HTTP request
 302   
      */
 303  24
     protected String getWrappedTestClassName() throws ServletException
 304   
     {
 305  24
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 306   
             .getQueryString();
 307  24
         String className = ServletUtil.getQueryStringParameter(queryString, 
 308   
             HttpServiceDefinition.WRAPPED_CLASS_NAME_PARAM);
 309   
 
 310  24
         if (className == null)
 311   
         {
 312  24
             LOGGER.debug("No wrapped test class");
 313   
         } 
 314   
         else
 315   
         { 
 316  0
             LOGGER.debug("Wrapped test class = [" + className + "]");
 317   
         }
 318   
 
 319  24
         return className;
 320   
     }
 321   
 
 322   
     /**
 323   
      * @return the class method to call for the current test case, extracted
 324   
      *         from the HTTP request
 325   
      * @exception ServletException if the method name of the test case is
 326   
      *            missing from the HTTP request
 327   
      */
 328  24
     protected String getTestMethodName() throws ServletException
 329   
     {
 330  24
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 331   
             .getQueryString();
 332  24
         String methodName = ServletUtil.getQueryStringParameter(queryString, 
 333   
             HttpServiceDefinition.METHOD_NAME_PARAM);
 334   
 
 335  24
         if (methodName == null)
 336   
         {
 337  0
             String message = "Missing method name parameter ["
 338   
                 + HttpServiceDefinition.METHOD_NAME_PARAM
 339   
                 + "] in HTTP request.";
 340   
 
 341  0
             LOGGER.error(message);
 342  0
             throw new ServletException(message);
 343   
         }
 344   
 
 345  24
         LOGGER.debug("Method to call = " + methodName);
 346   
 
 347  24
         return methodName;
 348   
     }
 349   
 
 350   
     /**
 351   
      * @return true if the auto session flag for the Session can be found in
 352   
      *         the HTTP request
 353   
      */
 354  19
     protected boolean isAutoSession()
 355   
     {
 356  19
         String queryString = this.webImplicitObjects.getHttpServletRequest()
 357   
             .getQueryString();
 358  19
         String autoSession = ServletUtil.getQueryStringParameter(queryString, 
 359   
             HttpServiceDefinition.AUTOSESSION_NAME_PARAM);
 360   
 
 361  19
         boolean isAutomaticSession = 
 362   
             Boolean.valueOf(autoSession).booleanValue();
 363   
 
 364  19
         LOGGER.debug("Auto session is " + isAutomaticSession);
 365   
 
 366  19
         return isAutomaticSession;
 367   
     }
 368   
 
 369   
     /**
 370   
      * @param theClassName the name of the test class
 371   
      * @param theWrappedClassName the name of the wrapped test class. Can be
 372   
      *        null if there is none
 373   
      * @param theTestCaseName the name of the current test case
 374   
      * @return an instance of the test class to call
 375   
      * @exception ServletException if the test case instance for the current
 376   
      *            test fails to be instanciated (for example if some
 377   
      *            information is missing from the HTTP request)
 378   
      */
 379  24
     protected TestCase getTestClassInstance(
 380   
         String theClassName, String theWrappedClassName, 
 381   
         String theTestCaseName) throws ServletException
 382   
     {
 383   
         // Get the class to call and build an instance of it.
 384  24
         Class testClass = getTestClassClass(theClassName);
 385  24
         TestCase testInstance = null;
 386  24
         Constructor constructor;
 387   
         
 388  24
         try
 389   
         {
 390  24
             if (theWrappedClassName == null)
 391   
             {
 392  24
                 constructor = getTestClassConstructor(testClass); 
 393   
 
 394  24
                 if (constructor.getParameterTypes().length == 0)
 395   
                 {
 396  24
                     testInstance = (TestCase) constructor.newInstance(
 397   
                         new Object[0]);
 398  24
                     ((TestCase) testInstance).setName(theTestCaseName);
 399   
                 }
 400   
                 else
 401   
                 {
 402  0
                     testInstance = (TestCase) constructor.newInstance(
 403   
                         new Object[] {theTestCaseName});                
 404   
                 }
 405   
             }
 406   
             else
 407   
             {
 408  0
                 Class wrappedTestClass = 
 409   
                     getTestClassClass(theWrappedClassName);
 410  0
                 Constructor wrappedConstructor =
 411   
                     getTestClassConstructor(wrappedTestClass);
 412   
 
 413  0
                 TestCase wrappedTestInstance;
 414  0
                 if (wrappedConstructor.getParameterTypes().length == 0)
 415   
                 {
 416  0
                     wrappedTestInstance = 
 417   
                         (TestCase) wrappedConstructor.newInstance(
 418   
                         new Object[0]);
 419  0
                     wrappedTestInstance.setName(theTestCaseName);
 420   
                 }
 421   
                 else
 422   
                 {
 423  0
                     wrappedTestInstance = 
 424   
                         (TestCase) wrappedConstructor.newInstance(
 425   
                         new Object[] {theTestCaseName});
 426   
                 }
 427   
 
 428  0
                 constructor = testClass.getConstructor(
 429   
                     new Class[] {String.class, Test.class});
 430   
 
 431  0
                 testInstance = 
 432   
                     (TestCase) constructor.newInstance(
 433   
                     new Object[] {theTestCaseName, wrappedTestInstance});
 434   
             }
 435   
         }
 436   
         catch (Exception e)
 437   
         {
 438  0
             String message = "Error instantiating class [" + theClassName + "(["
 439   
                 + theTestCaseName + "], [" + theWrappedClassName + "])]";
 440   
 
 441  0
             LOGGER.error(message, e);
 442  0
             throw new ServletException(message, e);
 443   
         }
 444   
 
 445  24
         return testInstance;
 446   
     }
 447   
 
 448   
     /**
 449   
      * @param theTestClass the test class for which we want to find the
 450   
      *        constructor
 451   
      * @return the availble constructor for the test class
 452   
      * @throws NoSuchMethodException if no suitable constructor is found
 453   
      */
 454  24
     private Constructor getTestClassConstructor(Class theTestClass)
 455   
         throws NoSuchMethodException
 456   
     {
 457  24
         Constructor constructor;
 458  24
         try 
 459   
         {
 460  24
             constructor = theTestClass.getConstructor(
 461   
                 new Class[] {String.class});         
 462   
         }
 463   
         catch (NoSuchMethodException e)
 464   
         {
 465  24
             constructor = theTestClass.getConstructor(new Class[0]);
 466   
         }
 467  24
         return constructor;        
 468   
     }
 469   
 
 470   
     /**
 471   
      * @param theClassName the name of the test class
 472   
      * @return the class object the test class to call
 473   
      * @exception ServletException if the class of the current test case
 474   
      *            cannot be loaded in memory (i.e. it is not in the
 475   
      *            classpath)
 476   
      */
 477  24
     protected Class getTestClassClass(String theClassName)
 478   
         throws ServletException
 479   
     {
 480   
         // Get the class to call and build an instance of it.
 481  24
         Class testClass = null;
 482   
 
 483  24
         try
 484   
         {
 485  24
             testClass = ClassLoaderUtils.loadClass(theClassName, 
 486   
                 this.getClass());
 487   
         }
 488   
         catch (Exception e)
 489   
         {
 490  0
             String message = "Error finding class [" + theClassName
 491   
                 + "] using both the Context classloader and the webapp "
 492   
                 + "classloader. Possible causes include:\r\n";
 493   
 
 494  0
             message += ("\t- Your webapp does not include your test " 
 495   
                 + "classes,\r\n");
 496  0
             message += ("\t- The cactus.jar is not located in your " 
 497   
                 + "WEB-INF/lib directory and your Container has not set the " 
 498   
                 + "Context classloader to point to the webapp one");
 499   
 
 500  0
             LOGGER.error(message, e);
 501  0
             throw new ServletException(message, e);
 502   
         }
 503   
 
 504  24
         return testClass;
 505   
     }
 506   
 
 507   
 }
 508