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: 478   Methods: 15
NCLOC: 297   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
CactusTask.java 30% 32.7% 46.7% 33.3%
coverage coverage
 1   
 /* 
 2   
  * ========================================================================
 3   
  * 
 4   
  * Copyright 2003-2005 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.integration.ant;
 21   
 
 22   
 import java.io.File;
 23   
 import java.net.MalformedURLException;
 24   
 import java.net.URL;
 25   
 import java.util.ArrayList;
 26   
 import java.util.Enumeration;
 27   
 import java.util.List;
 28   
 import java.util.ResourceBundle;
 29   
 
 30   
 import org.apache.cactus.integration.ant.container.Container;
 31   
 import org.apache.cactus.integration.ant.container.ContainerRunner;
 32   
 import org.apache.cactus.integration.ant.deployment.DeployableFile;
 33   
 import org.apache.cactus.integration.ant.deployment.EarParser;
 34   
 import org.apache.cactus.integration.ant.deployment.WarParser;
 35   
 import org.apache.cactus.integration.ant.util.AntLog;
 36   
 import org.apache.cactus.integration.ant.util.AntTaskFactory;
 37   
 import org.apache.cactus.integration.ant.util.DefaultAntTaskFactory;
 38   
 import org.apache.cactus.integration.ant.util.PropertySet;
 39   
 import org.apache.tools.ant.BuildException;
 40   
 import org.apache.tools.ant.Project;
 41   
 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask;
 42   
 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
 43   
 import org.apache.tools.ant.types.Environment;
 44   
 import org.apache.tools.ant.types.Path;
 45   
 import org.apache.tools.ant.types.Environment.Variable;
 46   
 
 47   
 /**
 48   
  * An Ant task that extends the optional JUnit task to provide support for
 49   
  * in-container testing.
 50   
  * 
 51   
  * @version $Id: CactusTask.java 239202 2005-08-11 18:48:07Z felipeal $
 52   
  */
 53   
 public class CactusTask extends JUnitTask
 54   
 {
 55   
     // Instance Variables ------------------------------------------------------
 56   
 
 57   
     /**
 58   
      * The nested containerset element.
 59   
      */
 60   
     private ContainerSet containerSet;
 61   
 
 62   
     /**
 63   
      * The archive that contains the enterprise application that should be
 64   
      * tested.
 65   
      */
 66   
     private File earFile;
 67   
 
 68   
     /**
 69   
      * The archive that contains the web-app that is ready to be tested.
 70   
      */
 71   
     private File warFile;
 72   
 
 73   
     /**
 74   
      * System properties that will be set in the container JVM.
 75   
      */
 76   
     private List systemProperties = new ArrayList();
 77   
 
 78   
     /**
 79   
      * Additional classpath entries for the classpath that will be used to 
 80   
      * start the containers.
 81   
      */
 82   
     private Path containerClasspath;
 83   
     
 84   
     // Constructors ------------------------------------------------------------
 85   
     
 86   
     /**
 87   
      * Constructor.
 88   
      * 
 89   
      * @throws Exception If the constructor of JUnitTask throws an exception
 90   
      */
 91  7
     public CactusTask() throws Exception
 92   
     {
 93   
         // TODO: Fix comment for this constructor as it doesn't seem quite 
 94   
         // right. Explain why we don't call the super constructor?
 95   
     }
 96   
 
 97   
     // Public Methods ----------------------------------------------------------
 98   
 
 99   
     /**
 100   
      * @see org.apache.tools.ant.Task#init()
 101   
      */
 102  14
     public void init()
 103   
     {
 104  14
         super.init();
 105   
         
 106  14
         addClasspathEntry("/org/aspectj/lang/JoinPoint.class");
 107  14
         addClasspathEntry("/org/apache/cactus/ServletTestCase.class");
 108  14
         addClasspathEntry(
 109   
             "/org/apache/cactus/integration/ant/CactusTask.class");
 110  14
         addClasspathEntry("/org/apache/commons/logging/Log.class");
 111  14
         addClasspathEntry("/org/apache/commons/httpclient/HttpClient.class");
 112   
     }
 113   
 
 114   
     /**
 115   
      * @see org.apache.tools.ant.Task#execute()
 116   
      */
 117  7
     public void execute() throws BuildException
 118   
     {
 119  7
         log("cactus tag is under major change " 
 120   
             + " consider to use cactustest instead" , Project.MSG_INFO);
 121  7
         if ((this.warFile == null) && (this.earFile == null))
 122   
         {
 123  1
             throw new BuildException("You must specify either the [warfile] or "
 124   
                 + "the [earfile] attribute");
 125   
         }
 126   
 
 127  6
         if ((this.warFile != null) && (this.earFile != null))
 128   
         {
 129  0
             throw new BuildException("You must specify either the [warfile] or "
 130   
                 + "the [earfile] attribute but not both");
 131   
         }
 132   
 
 133   
         // Parse deployment descriptors for WAR or EAR files
 134  6
         DeployableFile deployableFile;
 135  6
         if (this.warFile != null)
 136   
         {
 137  3
             deployableFile = WarParser.parse(this.warFile);
 138   
         }
 139   
         else 
 140   
         {
 141  3
             deployableFile = EarParser.parse(this.earFile);
 142   
         } 
 143   
 
 144  3
         addRedirectorNameProperties(deployableFile);
 145   
         
 146  2
         if (this.containerSet == null)
 147   
         {
 148  2
             log("No containers specified, tests will run locally",
 149   
                 Project.MSG_VERBOSE);
 150  2
             super.execute();
 151   
         }
 152   
         else
 153   
         {
 154  0
             Container[] containers = this.containerSet.getContainers();
 155  0
             Variable contextUrl = new Variable();
 156  0
             contextUrl.setKey("cactus.contextURL");
 157  0
             addSysproperty(contextUrl);
 158   
 
 159  0
             AntTaskFactory antTaskFactory = new DefaultAntTaskFactory(
 160   
                 getProject(), getTaskName(), getLocation(), getOwningTarget()); 
 161   
             
 162  0
             for (int i = 0; i < containers.length; i++)
 163   
             {
 164  0
                 containers[i].setAntTaskFactory(antTaskFactory);
 165  0
                 containers[i].setLog(new AntLog(this));
 166   
 
 167   
                 // Clone the DeployableFile instance as each container can
 168   
                 // override default deployment properties (e.g. port, context
 169   
                 // root, etc).
 170  0
                 DeployableFile thisDeployable = null;
 171  0
                 try
 172   
                 {
 173  0
                     thisDeployable = (DeployableFile) deployableFile.clone();
 174   
                 }
 175   
                 catch (CloneNotSupportedException e)
 176   
                 {
 177  0
                     throw new BuildException(e);
 178   
                 }
 179  0
                 containers[i].setDeployableFile(thisDeployable);
 180   
 
 181   
                 // Allow the container to override the default test context. 
 182   
                 // This is to support container extensions to the web.xml file.
 183   
                 // Most containers allow defining the root context in these
 184   
                 // extensions.
 185  0
                 if (containers[i].getTestContext() != null)
 186   
                 {
 187  0
                     thisDeployable.setTestContext(
 188   
                         containers[i].getTestContext());
 189   
                 }               
 190   
                 
 191  0
                 containers[i].setSystemProperties(
 192   
                     (Variable[]) this.systemProperties.toArray(
 193   
                         new Variable[0]));
 194   
 
 195   
                 // Add extra classpath entries
 196  0
                 containers[i].setContainerClasspath(this.containerClasspath);
 197   
                 
 198  0
                 if (containers[i].isEnabled())
 199   
                 {
 200  0
                     containers[i].init();
 201  0
                     log("--------------------------------------------------"
 202   
                         + "---------------", Project.MSG_INFO);
 203  0
                     log("Running tests against " + containers[i].getName()
 204   
                         + " @ " + containers[i].getBaseURL(),
 205   
                         Project.MSG_INFO);
 206  0
                     log("--------------------------------------------------"
 207   
                         + "---------------", Project.MSG_INFO);
 208  0
                     contextUrl.setValue(containers[i].getBaseURL() + "/"
 209   
                         + thisDeployable.getTestContext());
 210  0
                     executeInContainer(containers[i], thisDeployable); 
 211   
                 }
 212   
             }
 213   
         }
 214   
     }
 215   
 
 216   
     /**
 217   
      * Adds the nested containers element (only one is permitted).
 218   
      * 
 219   
      * @param theContainerSet The nested element to add
 220   
      */
 221  0
     public final void addContainerSet(ContainerSet theContainerSet)
 222   
     {
 223  0
         if (this.containerSet != null)
 224   
         {
 225  0
             throw new BuildException(
 226   
                 "Only one nested containerset element supported");
 227   
         }
 228  0
         this.containerSet = theContainerSet;
 229   
     }
 230   
 
 231   
     /**
 232   
      * Sets the enterprise application archive that will be tested. It must
 233   
      * already contain the test-cases and the required libraries as a web
 234   
      * module.
 235   
      * 
 236   
      * @param theEarFile The EAR file to set  
 237   
      */
 238  3
     public final void setEarFile(File theEarFile)
 239   
     {
 240  3
         if (this.warFile != null)
 241   
         {
 242  0
             throw new BuildException(
 243   
                 "You may only specify one of [earfile] and [warfile]");
 244   
         }
 245  3
         this.earFile = theEarFile;
 246   
     }
 247   
 
 248   
     /**
 249   
      * Sets the web application archive that will be tested. It must already 
 250   
      * contain the test-cases and the required libraries.
 251   
      * 
 252   
      * @param theWarFile The WAR file to set  
 253   
      */
 254  3
     public final void setWarFile(File theWarFile)
 255   
     {
 256  3
         if (this.earFile != null)
 257   
         {
 258  0
             throw new BuildException(
 259   
                 "You may only specify one of [earfile] and [warfile]");
 260   
         }
 261  3
         this.warFile = theWarFile;
 262   
     }
 263   
 
 264   
     /**
 265   
      * Adds a system property to both client side and server side JVMs. 
 266   
      * @see JUnitTask#addSysproperty(Environment.Variable) 
 267   
      */
 268  0
     public void addSysproperty(Environment.Variable theProperty)
 269   
     {
 270  0
         addCactusServerProperty(theProperty);
 271  0
         super.addSysproperty(theProperty);
 272   
     }
 273   
 
 274   
     /**
 275   
      * Called by Ant when the Variable object has been properly initialized.
 276   
      * 
 277   
      * @param theProperty the system property to set 
 278   
      */
 279  0
     public void addConfiguredSysproperty(Environment.Variable theProperty)
 280   
     {
 281  0
         addSysproperty(theProperty);
 282   
     }
 283   
 
 284   
     /**
 285   
      * Adds a set of properties that will be used as system properties
 286   
      * either on the client side or on the server side.
 287   
      *
 288   
      * @param thePropertySet the set of properties to be added
 289   
      */
 290  0
     public void addConfiguredCactusproperty(PropertySet thePropertySet)
 291   
     {
 292   
         // Add all properties from the properties file
 293  0
         ResourceBundle bundle = thePropertySet.readProperties();
 294  0
         Enumeration keys = bundle.getKeys();
 295  0
         while (keys.hasMoreElements())
 296   
         {
 297  0
             String key = (String) keys.nextElement();
 298  0
             Variable var = new Variable();
 299  0
             var.setKey(key);
 300  0
             var.setValue(bundle.getString(key));
 301  0
             if (thePropertySet.isServer())
 302   
             {
 303  0
                 addCactusServerProperty(var);
 304   
             }
 305   
             else
 306   
             {
 307  0
                 super.addSysproperty(var);
 308   
             }
 309   
         }
 310   
     }
 311   
 
 312   
     /**
 313   
      * Adds container classpath to the classpath that will be used for starting
 314   
      * the container. 
 315   
      *
 316   
      * @return reference to the classpath
 317   
      * @since Cactus 1.6
 318   
      */
 319  0
     public Path createContainerClasspath()
 320   
     {
 321  0
         if (this.containerClasspath == null)
 322   
         {
 323  0
             this.containerClasspath = new Path(this.project);            
 324   
         }
 325   
         
 326  0
         return this.containerClasspath.createPath();
 327   
     }    
 328   
     
 329   
     // Private Methods ---------------------------------------------------------
 330   
 
 331   
     /**
 332   
      * Adds a Cactus system property for the client side JVM.
 333   
      * 
 334   
      * @param theKey The property name
 335   
      * @param theValue The property value
 336   
      */
 337  2
     private void addCactusClientProperty(String theKey, String theValue)
 338   
     {
 339  2
         log("Adding Cactus client system property [" + theKey 
 340   
             + "] with value [" + theValue + "]", Project.MSG_VERBOSE);
 341  2
         Variable sysProperty = new Variable();
 342  2
         sysProperty.setKey(theKey);
 343  2
         sysProperty.setValue(theValue);
 344  2
         super.addSysproperty(sysProperty);
 345   
     }
 346   
 
 347   
     /**
 348   
      * Adds a Cactus system property for the server side JVM.
 349   
      * 
 350   
      * @param theProperty The system property to set in the container JVM
 351   
      */
 352  0
     private void addCactusServerProperty(Variable theProperty)
 353   
     {
 354  0
         log("Adding Cactus server system property [" 
 355   
             + theProperty.getKey() + "] with value [" 
 356   
             + theProperty.getValue() + "]", Project.MSG_VERBOSE);
 357  0
         this.systemProperties.add(theProperty);
 358   
     }
 359   
 
 360   
     /**
 361   
      * Adds a Cactus system property for the server side JVM.
 362   
      * 
 363   
      * @param theKey The property name
 364   
      * @param theValue The property value
 365   
      */
 366  0
     private void addCactusServerProperty(String theKey, String theValue)
 367   
     {
 368  0
         Variable property = new Variable();
 369  0
         property.setKey(theKey);
 370  0
         property.setValue(theValue);
 371  0
         addCactusServerProperty(property);
 372   
     }
 373   
     
 374   
     /**
 375   
      * Extracts the redirector mappings from the deployment descriptor and sets 
 376   
      * the corresponding system properties.
 377   
      * 
 378   
      * @param theFile The file to deploy in the container
 379   
      */
 380  3
     private void addRedirectorNameProperties(DeployableFile theFile)
 381   
     {
 382  3
         String filterRedirectorMapping = 
 383   
             theFile.getFilterRedirectorMapping();
 384  3
         if (filterRedirectorMapping != null)
 385   
         {
 386  0
             addCactusClientProperty("cactus.filterRedirectorName",
 387   
                 filterRedirectorMapping.substring(1));
 388   
         }
 389   
         else
 390   
         {
 391  3
             log("No mapping of the filter redirector found",
 392   
                 Project.MSG_VERBOSE);
 393   
         }
 394   
 
 395  3
         String jspRedirectorMapping = 
 396   
             theFile.getJspRedirectorMapping();
 397  3
         if (jspRedirectorMapping != null)
 398   
         {
 399  0
             addCactusClientProperty("cactus.jspRedirectorName",
 400   
                 jspRedirectorMapping.substring(1));
 401   
         }
 402   
         else
 403   
         {
 404  3
             log("No mapping of the JSP redirector found",
 405   
                 Project.MSG_VERBOSE);
 406   
         }
 407   
 
 408  3
         String servletRedirectorMapping = 
 409   
             theFile.getServletRedirectorMapping();
 410  3
         if (servletRedirectorMapping != null)
 411   
         {
 412  2
             addCactusClientProperty("cactus.servletRedirectorName",
 413   
                 servletRedirectorMapping.substring(1));
 414   
         }
 415   
         else
 416   
         {
 417  1
             throw new BuildException("The WAR has not been cactified");
 418   
         }
 419   
     }
 420   
 
 421   
     /**
 422   
      * Executes the unit tests in the given container.
 423   
      * 
 424   
      * @param theContainer The container to run the tests against
 425   
      * @param theFile the file to deploy in the container
 426   
      */
 427  0
     private void executeInContainer(Container theContainer, 
 428   
         DeployableFile theFile)
 429   
     {
 430  0
         log("Starting up container", Project.MSG_VERBOSE);
 431  0
         ContainerRunner runner = new ContainerRunner(theContainer);
 432  0
         runner.setLog(new AntLog(this));
 433  0
         try
 434   
         {
 435  0
             URL url = new URL(theContainer.getBaseURL() + "/"
 436   
                 + theFile.getTestContext() 
 437   
                 + theFile.getServletRedirectorMapping()
 438   
                 + "?Cactus_Service=RUN_TEST");
 439  0
             runner.setURL(url);
 440   
          
 441  0
             if (this.containerSet.getTimeout() > 0)
 442   
             {
 443  0
                 runner.setTimeout(this.containerSet.getTimeout());
 444   
             }
 445  0
             runner.startUpContainer();
 446  0
             log("Server name retrieved from 'Server' HTTP header: ["
 447   
                 + runner.getServerName() + "]", Project.MSG_VERBOSE);
 448  0
             try
 449   
             {
 450  0
                 Enumeration tests = getIndividualTests();
 451  0
                 while (tests.hasMoreElements())
 452   
                 {
 453  0
                     JUnitTest test = (JUnitTest) tests.nextElement();
 454  0
                     if (test.shouldRun(getProject())
 455   
                      && !theContainer.isExcluded(test.getName()))
 456   
                     {
 457  0
                         if (theContainer.getToDir() != null)
 458   
                         {
 459  0
                             test.setTodir(theContainer.getToDir());
 460   
                         }
 461  0
                         execute(test);
 462   
                     }
 463   
                 }
 464   
             }
 465   
             finally
 466   
             {
 467  0
                 log("Shutting down container", Project.MSG_VERBOSE);
 468  0
                 runner.shutDownContainer();
 469  0
                 log("Container shut down", Project.MSG_VERBOSE);
 470   
             }
 471   
         }
 472   
         catch (MalformedURLException mue)
 473   
         {
 474  0
             throw new BuildException("Malformed test URL", mue);
 475   
         }
 476   
     }
 477   
 }
 478