KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > integration > ant > CactusTask


1 /*
2  * ========================================================================
3  *
4  * Copyright 2003-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.integration.ant;
21
22 import java.io.File JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.ResourceBundle JavaDoc;
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,v 1.33 2004/07/02 07:03:49 vmassol Exp $
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 JavaDoc earFile;
67
68     /**
69      * The archive that contains the web-app that is ready to be tested.
70      */

71     private File JavaDoc warFile;
72
73     /**
74      * System properties that will be set in the container JVM.
75      */

76     private List JavaDoc systemProperties = new ArrayList JavaDoc();
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     public CactusTask() throws Exception JavaDoc
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     public void init()
103     {
104         super.init();
105         
106         addClasspathEntry("/org/aspectj/lang/JoinPoint.class");
107         addClasspathEntry("/org/apache/cactus/ServletTestCase.class");
108         addClasspathEntry(
109             "/org/apache/cactus/integration/ant/CactusTask.class");
110         addClasspathEntry("/org/apache/commons/logging/Log.class");
111         addClasspathEntry("/org/apache/commons/httpclient/HttpClient.class");
112     }
113
114     /**
115      * @see org.apache.tools.ant.Task#execute()
116      */

117     public void execute() throws BuildException
118     {
119         if ((this.warFile == null) && (this.earFile == null))
120         {
121             throw new BuildException("You must specify either the [warfile] or "
122                 + "the [earfile] attribute");
123         }
124
125         if ((this.warFile != null) && (this.earFile != null))
126         {
127             throw new BuildException("You must specify either the [warfile] or "
128                 + "the [earfile] attribute but not both");
129         }
130
131         // Parse deployment descriptors for WAR or EAR files
132
DeployableFile deployableFile;
133         if (this.warFile != null)
134         {
135             deployableFile = WarParser.parse(this.warFile);
136         }
137         else
138         {
139             deployableFile = EarParser.parse(this.earFile);
140         }
141
142         addRedirectorNameProperties(deployableFile);
143         
144         if (this.containerSet == null)
145         {
146             log("No containers specified, tests will run locally",
147                 Project.MSG_VERBOSE);
148             super.execute();
149         }
150         else
151         {
152             Container[] containers = this.containerSet.getContainers();
153             Variable contextUrl = new Variable();
154             contextUrl.setKey("cactus.contextURL");
155             addSysproperty(contextUrl);
156
157             AntTaskFactory antTaskFactory = new DefaultAntTaskFactory(
158                 getProject(), getTaskName(), getLocation(), getOwningTarget());
159             
160             for (int i = 0; i < containers.length; i++)
161             {
162                 containers[i].setAntTaskFactory(antTaskFactory);
163                 containers[i].setLog(new AntLog(this));
164
165                 // Clone the DeployableFile instance as each container can
166
// override default deployment properties (e.g. port, context
167
// root, etc).
168
DeployableFile thisDeployable = null;
169                 try
170                 {
171                     thisDeployable = (DeployableFile) deployableFile.clone();
172                 }
173                 catch (CloneNotSupportedException JavaDoc e)
174                 {
175                     throw new BuildException(e);
176                 }
177                 containers[i].setDeployableFile(thisDeployable);
178
179                 // Allow the container to override the default test context.
180
// This is to support container extensions to the web.xml file.
181
// Most containers allow defining the root context in these
182
// extensions.
183
if (containers[i].getTestContext() != null)
184                 {
185                     thisDeployable.setTestContext(
186                         containers[i].getTestContext());
187                 }
188                 
189                 containers[i].setSystemProperties(
190                     (Variable[]) this.systemProperties.toArray(
191                         new Variable[0]));
192
193                 // Add extra classpath entries
194
containers[i].setContainerClasspath(this.containerClasspath);
195                 
196                 if (containers[i].isEnabled())
197                 {
198                     containers[i].init();
199                     log("--------------------------------------------------"
200                         + "---------------",
201                         Project.MSG_INFO);
202                     log("Running tests against " + containers[i].getName(),
203                         Project.MSG_INFO);
204                     log("--------------------------------------------------"
205                         + "---------------",
206                         Project.MSG_INFO);
207                     contextUrl.setValue(
208                         "http://localhost:" + containers[i].getPort() + "/"
209                         + thisDeployable.getTestContext());
210                     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     public final void addContainerSet(ContainerSet theContainerSet)
222     {
223         if (this.containerSet != null)
224         {
225             throw new BuildException(
226                 "Only one nested containerset element supported");
227         }
228         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     public final void setEarFile(File JavaDoc theEarFile)
239     {
240         if (this.warFile != null)
241         {
242             throw new BuildException(
243                 "You may only specify one of [earfile] and [warfile]");
244         }
245         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     public final void setWarFile(File JavaDoc theWarFile)
255     {
256         if (this.earFile != null)
257         {
258             throw new BuildException(
259                 "You may only specify one of [earfile] and [warfile]");
260         }
261         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     public void addSysproperty(Environment.Variable theProperty)
269     {
270         addCactusServerProperty(theProperty);
271         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     public void addConfiguredSysproperty(Environment.Variable theProperty)
280     {
281         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     public void addConfiguredCactusproperty(PropertySet thePropertySet)
291     {
292         // Add all properties from the properties file
293
ResourceBundle JavaDoc bundle = thePropertySet.readProperties();
294         Enumeration JavaDoc keys = bundle.getKeys();
295         while (keys.hasMoreElements())
296         {
297             String JavaDoc key = (String JavaDoc) keys.nextElement();
298             Variable var = new Variable();
299             var.setKey(key);
300             var.setValue(bundle.getString(key));
301             if (thePropertySet.isServer())
302             {
303                 addCactusServerProperty(var);
304             }
305             else
306             {
307                 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     public Path createContainerClasspath()
320     {
321         if (this.containerClasspath == null)
322         {
323             this.containerClasspath = new Path(this.project);
324         }
325         
326         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     private void addCactusClientProperty(String JavaDoc theKey, String JavaDoc theValue)
338     {
339         log("Adding Cactus client system property [" + theKey
340             + "] with value [" + theValue + "]", Project.MSG_VERBOSE);
341         Variable sysProperty = new Variable();
342         sysProperty.setKey(theKey);
343         sysProperty.setValue(theValue);
344         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     private void addCactusServerProperty(Variable theProperty)
353     {
354         log("Adding Cactus server system property ["
355             + theProperty.getKey() + "] with value ["
356             + theProperty.getValue() + "]", Project.MSG_VERBOSE);
357         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     private void addCactusServerProperty(String JavaDoc theKey, String JavaDoc theValue)
367     {
368         Variable property = new Variable();
369         property.setKey(theKey);
370         property.setValue(theValue);
371         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     private void addRedirectorNameProperties(DeployableFile theFile)
381     {
382         String JavaDoc filterRedirectorMapping =
383             theFile.getFilterRedirectorMapping();
384         if (filterRedirectorMapping != null)
385         {
386             addCactusClientProperty("cactus.filterRedirectorName",
387                 filterRedirectorMapping.substring(1));
388         }
389         else
390         {
391             log("No mapping of the filter redirector found",
392                 Project.MSG_VERBOSE);
393         }
394
395         String JavaDoc jspRedirectorMapping =
396             theFile.getJspRedirectorMapping();
397         if (jspRedirectorMapping != null)
398         {
399             addCactusClientProperty("cactus.jspRedirectorName",
400                 jspRedirectorMapping.substring(1));
401         }
402         else
403         {
404             log("No mapping of the JSP redirector found",
405                 Project.MSG_VERBOSE);
406         }
407
408         String JavaDoc servletRedirectorMapping =
409             theFile.getServletRedirectorMapping();
410         if (servletRedirectorMapping != null)
411         {
412             addCactusClientProperty("cactus.servletRedirectorName",
413                 servletRedirectorMapping.substring(1));
414         }
415         else
416         {
417             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     private void executeInContainer(Container theContainer,
428         DeployableFile theFile)
429     {
430         log("Starting up container", Project.MSG_VERBOSE);
431         ContainerRunner runner = new ContainerRunner(theContainer);
432         runner.setLog(new AntLog(this));
433         try
434         {
435             URL JavaDoc url =
436                 new URL JavaDoc("http", "localhost", theContainer.getPort(), "/"
437                 + theFile.getTestContext()
438                 + theFile.getServletRedirectorMapping()
439                 + "?Cactus_Service=RUN_TEST");
440             runner.setURL(url);
441             if (this.containerSet.getTimeout() > 0)
442             {
443                 runner.setTimeout(this.containerSet.getTimeout());
444             }
445             runner.startUpContainer();
446             log("Server name retrieved from 'Server' HTTP header: ["
447                 + runner.getServerName() + "]", Project.MSG_VERBOSE);
448             try
449             {
450                 Enumeration JavaDoc tests = getIndividualTests();
451                 while (tests.hasMoreElements())
452                 {
453                     JUnitTest test = (JUnitTest) tests.nextElement();
454                     if (test.shouldRun(getProject())
455                      && !theContainer.isExcluded(test.getName()))
456                     {
457                         if (theContainer.getToDir() != null)
458                         {
459                             test.setTodir(theContainer.getToDir());
460                         }
461                         execute(test);
462                     }
463                 }
464             }
465             finally
466             {
467                 log("Shutting down container", Project.MSG_VERBOSE);
468                 runner.shutDownContainer();
469                 log("Container shut down", Project.MSG_VERBOSE);
470             }
471         }
472         catch (MalformedURLException JavaDoc mue)
473         {
474             throw new BuildException("Malformed test URL", mue);
475         }
476     }
477 }
478
Popular Tags