KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * ========================================================================
3  *
4  * Copyright 2003 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.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28
29 import javax.xml.parsers.ParserConfigurationException JavaDoc;
30
31 import org.apache.cactus.integration.ant.util.AntLog;
32 import org.apache.cactus.integration.ant.util.ResourceUtils;
33 import org.apache.cactus.integration.ant.deployment.webapp.DefaultWarArchive;
34 import org.apache.cactus.integration.ant.deployment.webapp.WarArchive;
35 import org.apache.cactus.integration.ant.deployment.webapp.WebXml;
36 import org.apache.cactus.integration.ant.deployment.webapp.WebXmlIo;
37 import org.apache.cactus.integration.ant.deployment.webapp.WebXmlMerger;
38 import org.apache.cactus.integration.ant.deployment.webapp.WebXmlVersion;
39 import org.apache.tools.ant.BuildException;
40 import org.apache.tools.ant.Project;
41 import org.apache.tools.ant.taskdefs.War;
42 import org.apache.tools.ant.types.EnumeratedAttribute;
43 import org.apache.tools.ant.types.FileSet;
44 import org.apache.tools.ant.types.XMLCatalog;
45 import org.apache.tools.ant.types.ZipFileSet;
46 import org.apache.tools.ant.util.FileUtils;
47 import org.xml.sax.SAXException JavaDoc;
48
49 /**
50  * An Ant task that injects elements necessary to run Cactus tests into an
51  * existing WAR file.
52  *
53  * @version $Id: CactifyWarTask.java,v 1.32 2004/05/31 20:05:24 vmassol Exp $
54  */

55 public class CactifyWarTask extends War
56 {
57
58     // Constants ---------------------------------------------------------------
59

60     /**
61      * The name of the Cactus filter redirector class.
62      */

63     private static final String JavaDoc FILTER_REDIRECTOR_CLASS =
64         "org.apache.cactus.server.FilterTestRedirector";
65
66     /**
67      * The default mapping of the Cactus filter redirector.
68      */

69     private static final String JavaDoc DEFAULT_FILTER_REDIRECTOR_MAPPING =
70         "/FilterRedirector";
71
72     /**
73      * The default mapping of the Cactus JSP redirector.
74      */

75     private static final String JavaDoc DEFAULT_JSP_REDIRECTOR_MAPPING =
76         "/JspRedirector";
77
78     /**
79      * The name of the Cactus servlet redirector class.
80      */

81     private static final String JavaDoc SERVLET_REDIRECTOR_CLASS =
82         "org.apache.cactus.server.ServletTestRedirector";
83
84     /**
85      * The default mapping of the Cactus servlet redirector.
86      */

87     private static final String JavaDoc DEFAULT_SERVLET_REDIRECTOR_MAPPING =
88         "/ServletRedirector";
89
90     // Inner Classes -----------------------------------------------------------
91

92     /**
93      * Abstract base class for nested redirector elements.
94      */

95     public abstract static class Redirector
96     {
97
98         // Instance Variables --------------------------------------------------
99

100         /**
101          * The name of the redirector.
102          */

103         protected String JavaDoc name;
104
105         /**
106          * The URL pattern that the redirector will be mapped to.
107          */

108         protected String JavaDoc mapping;
109         
110         /**
111          * Comma-separated list of role names that should be granted access to
112          * the redirector.
113          */

114         protected String JavaDoc roles;
115
116         // Abstract Methods ----------------------------------------------------
117

118         /**
119          * Merges the definition of the redirector into the provided deployment
120          * descriptor.
121          *
122          * @param theWebXml The deployment descriptor into which the redirector
123          * definition should be merged
124          */

125         public abstract void mergeInto(WebXml theWebXml);
126
127         // Public Methods ------------------------------------------------------
128

129         /**
130          * Sets the name of the redirector.
131          *
132          * @param theName The name to set
133          */

134         public final void setName(String JavaDoc theName)
135         {
136             this.name = theName;
137         }
138
139         /**
140          * Sets the URL pattern that the redirector should be mapped to.
141          *
142          * @param theMapping The URL pattern to set
143          */

144         public final void setMapping(String JavaDoc theMapping)
145         {
146             this.mapping = theMapping;
147         }
148
149         /**
150          * Sets the comma-separated list of role names that should be granted
151          * access to the redirector.
152          *
153          * @param theRoles The roles to set
154          */

155         public final void setRoles(String JavaDoc theRoles)
156         {
157             this.roles = theRoles;
158         }
159
160         // Protected Methods ---------------------------------------------------
161

162         /**
163          * Adds the comma-separated list of security roles to a deployment
164          * descriptor.
165          *
166          * @param theWebXml The deployment descriptor
167          */

168         protected final void addSecurity(WebXml theWebXml)
169         {
170             StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(this.roles, ",");
171             List JavaDoc roles = new ArrayList JavaDoc();
172             while (tokenizer.hasMoreTokens())
173             {
174                 String JavaDoc role = tokenizer.nextToken().trim();
175                 if (!theWebXml.hasSecurityRole(role))
176                 {
177                     theWebXml.addSecurityRole(role);
178                 }
179                 roles.add(role);
180             }
181             if (!roles.isEmpty())
182             {
183                 if (!theWebXml.hasLoginConfig())
184                 {
185                     theWebXml.setLoginConfig("BASIC", "myrealm");
186                 }
187                 if (!theWebXml.hasSecurityConstraint(this.mapping))
188                 {
189                     theWebXml.addSecurityConstraint("Cactus Test Redirector",
190                         this.mapping, roles);
191                 }
192             }
193         }
194
195     }
196
197     /**
198      * Implementation of <code>Redirector</code> for filter test redirectors.
199      */

200     public static final class FilterRedirector extends Redirector
201     {
202
203         /**
204          * Default constructor.
205          */

206         public FilterRedirector()
207         {
208             this.name = "FilterRedirector";
209             this.mapping = DEFAULT_FILTER_REDIRECTOR_MAPPING;
210         }
211
212         /**
213          * @see CactifyWarTask.Redirector#mergeInto
214          */

215         public void mergeInto(WebXml theWebXml)
216         {
217             if (WebXmlVersion.V2_3.compareTo(theWebXml.getVersion()) <= 0)
218             {
219                 theWebXml.addFilter(this.name, FILTER_REDIRECTOR_CLASS);
220                 theWebXml.addFilterMapping(this.name, this.mapping);
221                 if (this.roles != null)
222                 {
223                     addSecurity(theWebXml);
224                 }
225             }
226         }
227         
228     }
229
230     /**
231      * Implementation of <code>Redirector</code> for JSP test redirectors.
232      */

233     public static final class JspRedirector extends Redirector
234     {
235
236         /**
237          * Default constructor.
238          */

239         public JspRedirector()
240         {
241             this.name = "JspRedirector";
242             this.mapping = DEFAULT_JSP_REDIRECTOR_MAPPING;
243         }
244
245         /**
246          * @see CactifyWarTask.Redirector#mergeInto
247          */

248         public void mergeInto(WebXml theWebXml)
249         {
250             theWebXml.addJspFile(this.name, "/jspRedirector.jsp");
251             theWebXml.addServletMapping(this.name, this.mapping);
252             if (this.roles != null)
253             {
254                 addSecurity(theWebXml);
255             }
256         }
257         
258     }
259
260     /**
261      * Implementation of <code>Redirector</code> for servlet test redirectors.
262      */

263     public static final class ServletRedirector extends Redirector
264     {
265
266         /**
267          * Default constructor.
268          */

269         public ServletRedirector()
270         {
271             this.name = "ServletRedirector";
272             this.mapping = DEFAULT_SERVLET_REDIRECTOR_MAPPING;
273         }
274
275         /**
276          * @see CactifyWarTask.Redirector#mergeInto
277          */

278         public void mergeInto(WebXml theWebXml)
279         {
280             theWebXml.addServlet(this.name, SERVLET_REDIRECTOR_CLASS);
281             theWebXml.addServletMapping(this.name, this.mapping);
282             if (this.roles != null)
283             {
284                 addSecurity(theWebXml);
285             }
286         }
287         
288     }
289
290     /**
291      * Enumeration for the <em>version</em> attribute.
292      */

293     public static final class Version extends EnumeratedAttribute
294     {
295
296         /**
297          * @see org.apache.tools.ant.types.EnumeratedAttribute#getValues()
298          */

299         public String JavaDoc[] getValues()
300         {
301             return new String JavaDoc[] {"2.2", "2.3"};
302         }
303
304     }
305
306     // Instance Variables ------------------------------------------------------
307

308     /**
309      * The archive that contains the web-app that should be cactified.
310      */

311     private File JavaDoc srcFile;
312
313     /**
314      * Location of the descriptor of which the content should be merged into
315      * the descriptor of the cactified archive.
316      */

317     private File JavaDoc mergeWebXml;
318
319     /**
320      * The Cactus test redirectors.
321      */

322     private List JavaDoc redirectors = new ArrayList JavaDoc();
323
324     /**
325      * For resolving entities such as DTDs.
326      */

327     private XMLCatalog xmlCatalog = null;
328
329     /**
330      * The web-app version to use when creating a WAR from scratch.
331      */

332     private String JavaDoc version = null;
333
334     // Public Methods ----------------------------------------------------------
335

336     /**
337      * @see org.apache.tools.ant.Task#execute()
338      */

339     public void execute() throws BuildException
340     {
341         WebXml webXml = null;
342         if (this.srcFile != null)
343         {
344             log("Analyzing war: " + this.srcFile.getAbsolutePath(),
345                 Project.MSG_INFO);
346
347             // Add everything that's in the source WAR to the destination WAR
348
ZipFileSet currentFiles = new ZipFileSet();
349             currentFiles.setSrc(this.srcFile);
350             currentFiles.createExclude().setName("WEB-INF/web.xml");
351             addZipfileset(currentFiles);
352
353             // Parse the original deployment descriptor
354
webXml = getOriginalWebXml();
355         }
356         else
357         {
358             if (this.version == null)
359             {
360                 throw new BuildException("You need to specify either the "
361                     + "[srcfile] or the [version] attribute");
362             }
363             WebXmlVersion webXmlVersion = null;
364             if (this.version.equals("2.2"))
365             {
366                 webXmlVersion = WebXmlVersion.V2_2;
367             }
368             else
369             {
370                 webXmlVersion = WebXmlVersion.V2_3;
371             }
372             try
373             {
374                 webXml = WebXmlIo.newWebXml(webXmlVersion);
375             }
376             catch (ParserConfigurationException JavaDoc pce)
377             {
378                 throw new BuildException(
379                     "Could not create deployment descriptor", pce);
380             }
381         }
382
383         File JavaDoc tmpWebXml = cactifyWebXml(webXml);
384         setWebxml(tmpWebXml);
385
386         addCactusJars();
387
388         try
389         {
390             super.execute();
391         }
392         finally
393         {
394             // Even though the temporary descriptor will get deleted
395
// automatically when the VM exits, delete it explicitly here just
396
// to be a better citizen
397
tmpWebXml.delete();
398         }
399     }
400
401     /**
402      * Adds a Cactus filter test redirector.
403      *
404      * @param theFilterRedirector The redirector to add
405      */

406     public final void addFilterRedirector(FilterRedirector theFilterRedirector)
407     {
408         this.redirectors.add(theFilterRedirector);
409     }
410
411     /**
412      * Adds a Cactus JSP test redirector.
413      *
414      * @param theJspRedirector The redirector to add
415      */

416     public final void addJspRedirector(JspRedirector theJspRedirector)
417     {
418         this.redirectors.add(theJspRedirector);
419     }
420
421     /**
422      * Adds a Cactus servlet test redirector.
423      *
424      * @param theServletRedirector The redirector to add
425      */

426     public final void addServletRedirector(
427         ServletRedirector theServletRedirector)
428     {
429         this.redirectors.add(theServletRedirector);
430     }
431
432     /**
433      * Adds an XML catalog to the internal catalog.
434      *
435      * @param theXmlCatalog the XMLCatalog instance to use to look up DTDs
436      */

437     public final void addConfiguredXMLCatalog(XMLCatalog theXmlCatalog)
438     {
439         if (this.xmlCatalog == null)
440         {
441             this.xmlCatalog = new XMLCatalog();
442             this.xmlCatalog.setProject(getProject());
443         }
444         this.xmlCatalog.addConfiguredXMLCatalog(theXmlCatalog);
445     }
446
447     /**
448      * The descriptor to merge into the original file.
449      *
450      * @param theMergeFile the <code>web.xml</code> to merge
451      */

452     public final void setMergeWebXml(File JavaDoc theMergeFile)
453     {
454         this.mergeWebXml = theMergeFile;
455     }
456
457     /**
458      * Sets the web application archive that should be cactified.
459      *
460      * @param theSrcFile The WAR file to set
461      */

462     public final void setSrcFile(File JavaDoc theSrcFile)
463     {
464         this.srcFile = theSrcFile;
465     }
466
467     /**
468      * Sets the web-app version to use when creating a WAR file from scratch.
469      *
470      * @param theVersion The version
471      */

472     public final void setVersion(Version theVersion)
473     {
474         this.version = theVersion.getValue();
475     }
476
477     // Private Methods ---------------------------------------------------------
478

479     /**
480      * Adds the libraries required by Cactus on the server side.
481      */

482     private void addCactusJars()
483     {
484         addJarWithClass("org.aspectj.lang.JoinPoint", "AspectJ Runtime");
485         addJarWithClass("org.apache.cactus.ServletTestCase",
486             "Cactus Framework");
487         addJarWithClass("org.apache.commons.logging.Log",
488             "Commons-Logging");
489         addJarWithClass("org.apache.commons.httpclient.HttpClient",
490             "Commons-HttpClient");
491         addJarWithClass("junit.framework.TestCase", "JUnit");
492     }
493
494     /**
495      * Adds the JAR file containing the specified resource to the WEB-INF/lib
496      * folder of a web-application archive.
497      *
498      * @param theClassName The name of the class that the JAR contains
499      * @param theDescription A description of the JAR that should be displayed
500      * to the user in log messages
501      */

502     private void addJarWithClass(String JavaDoc theClassName, String JavaDoc theDescription)
503     {
504         String JavaDoc resourceName = "/" + theClassName.replace('.', '/') + ".class";
505         if (this.srcFile != null)
506         {
507             try
508             {
509                 WarArchive srcWar = new DefaultWarArchive(srcFile);
510                 if (srcWar.containsClass(theClassName))
511                 {
512                     log("The " + theDescription + " JAR is already present in "
513                         + "the WAR", Project.MSG_VERBOSE);
514                     return;
515                 }
516             }
517             catch (IOException JavaDoc ioe)
518             {
519                 log("Problem reading source WAR to when trying to detect "
520                     + "already present JAR files (" + ioe + ")",
521                     Project.MSG_WARN);
522             }
523         }
524         ZipFileSet jar = new ZipFileSet();
525         File JavaDoc file = ResourceUtils.getResourceLocation(resourceName);
526         if (file != null)
527         {
528             jar.setFile(file);
529             addLib(jar);
530         }
531         else
532         {
533             log("Could not find the " + theDescription + " JAR",
534                 Project.MSG_WARN);
535             log("You need to add the JAR to the classpath of the task",
536                 Project.MSG_INFO);
537             log("(Searched for class " + theClassName + ")", Project.MSG_DEBUG);
538         }
539     }
540
541     /**
542      * Adds the Cactus JSP redirector file to the web application.
543      */

544     private void addJspRedirector()
545     {
546         // Now copy the actual JSP redirector file into the web application
547
File JavaDoc jspRedirectorFile = new File JavaDoc(
548             new File JavaDoc(System.getProperty("java.io.tmpdir")),
549             "jspRedirector.jsp");
550         jspRedirectorFile.deleteOnExit();
551         try
552         {
553             ResourceUtils.copyResource(getProject(),
554                 "/org/apache/cactus/server/jspRedirector.jsp",
555                 jspRedirectorFile);
556         }
557         catch (IOException JavaDoc e)
558         {
559             log("Could not copy the JSP redirector (" + e.getMessage() + ")",
560                 Project.MSG_WARN);
561         }
562         FileSet fileSet = new FileSet();
563         fileSet.setFile(jspRedirectorFile);
564         addFileset(fileSet);
565     }
566
567     /**
568      * Adds the definitions corresponding to the nested redirector elements to
569      * the provided deployment descriptor.
570      *
571      * @param theWebXml The deployment descriptor
572      */

573     private void addRedirectorDefinitions(WebXml theWebXml)
574     {
575         boolean filterRedirectorDefined = false;
576         boolean jspRedirectorDefined = false;
577         boolean servletRedirectorDefined = false;
578         
579         // add the user defined redirectors
580
for (Iterator JavaDoc i = this.redirectors.iterator(); i.hasNext();)
581         {
582             Redirector redirector = (Redirector) i.next();
583             if (redirector instanceof FilterRedirector)
584             {
585                 filterRedirectorDefined = true;
586             }
587             else if (redirector instanceof JspRedirector)
588             {
589                 jspRedirectorDefined = true;
590             }
591             else if (redirector instanceof ServletRedirector)
592             {
593                 servletRedirectorDefined = true;
594             }
595             redirector.mergeInto(theWebXml);
596         }
597
598         // now add the default redirectors if they haven't been provided by
599
// the user
600
if (!filterRedirectorDefined)
601         {
602             new FilterRedirector().mergeInto(theWebXml);
603         }
604         if (!servletRedirectorDefined)
605         {
606             new ServletRedirector().mergeInto(theWebXml);
607         }
608         if (!jspRedirectorDefined)
609         {
610             new JspRedirector().mergeInto(theWebXml);
611         }
612     }
613
614     /**
615      * Enhances the provided web deployment descriptor with the definitions
616      * required for testing with Cactus.
617      *
618      * @param theWebXml The original deployment descriptor
619      * @return A temporary file containing the cactified descriptor
620      */

621     private File JavaDoc cactifyWebXml(WebXml theWebXml)
622     {
623         addRedirectorDefinitions(theWebXml);
624         addJspRedirector();
625         
626         // If the user has specified a deployment descriptor to merge into the
627
// cactified descriptor, perform the merge
628
if (this.mergeWebXml != null)
629         {
630             try
631             {
632                 WebXml parsedMergeWebXml = WebXmlIo.parseWebXmlFromFile(
633                     this.mergeWebXml, this.xmlCatalog);
634                 WebXmlMerger merger = new WebXmlMerger(theWebXml);
635                 merger.setLog(new AntLog(this));
636                 merger = new WebXmlMerger(theWebXml);
637                 merger.setLog(new AntLog(this));
638                 merger.merge(parsedMergeWebXml);
639             }
640             catch (IOException JavaDoc e)
641             {
642                 throw new BuildException(
643                     "Could not merge deployment descriptors", e);
644             }
645             catch (SAXException JavaDoc e)
646             {
647                 throw new BuildException("Parsing of merge file failed", e);
648             }
649             catch (ParserConfigurationException JavaDoc e)
650             {
651                 throw new BuildException("XML parser configuration error", e);
652             }
653         }
654         
655         // Serialize the cactified deployment descriptor into a temporary file,
656
// so that it can get picked up by the War task
657
FileUtils fileUtils = FileUtils.newFileUtils();
658         File JavaDoc tmpWebXml = fileUtils.createTempFile("cactus", "web.xml",
659             getProject().getBaseDir());
660         tmpWebXml.deleteOnExit();
661         try
662         {
663             WebXmlIo.writeWebXml(theWebXml, tmpWebXml, null, true);
664         }
665         catch (IOException JavaDoc ioe)
666         {
667             throw new BuildException(
668                 "Could not write temporary deployment descriptor", ioe);
669         }
670         return tmpWebXml;
671     }
672
673     /**
674      * Extracts and parses the original web deployment descriptor from the
675      * web-app.
676      *
677      * @return The parsed descriptor
678      * @throws BuildException If the descriptor is not found or could not be
679      * parsed
680      */

681     private WebXml getOriginalWebXml() throws BuildException
682     {
683         // Open the archive as JAR file and extract the deployment descriptor
684
WarArchive war = null;
685         try
686         {
687             war = new DefaultWarArchive(this.srcFile);
688             WebXml webXml = war.getWebXml();
689             if (webXml == null)
690             {
691                 throw new BuildException("The WAR source file does not "
692                     + "contain a WEB-INF/web.xml deployment descriptor");
693             }
694             return webXml;
695         }
696         catch (SAXException JavaDoc e)
697         {
698             throw new BuildException(
699                 "Parsing of web.xml deployment descriptor failed", e);
700         }
701         catch (IOException JavaDoc e)
702         {
703             throw new BuildException("Failed to open WAR", e);
704         }
705         catch (ParserConfigurationException JavaDoc e)
706         {
707             throw new BuildException("XML parser configuration error", e);
708         }
709     }
710
711 }
712
Popular Tags