KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas > ant > GenericDeploymentTool


1 /**
2  * Copyright 2000-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.objectweb.jonas.ant;
18
19 import java.io.File JavaDoc;
20 import java.io.FileInputStream JavaDoc;
21 import java.io.FileOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.jar.JarOutputStream JavaDoc;
30 import java.util.jar.Manifest JavaDoc;
31 import java.util.zip.ZipEntry JavaDoc;
32 import javax.xml.parsers.SAXParser JavaDoc;
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.DirectoryScanner;
35 import org.apache.tools.ant.Location;
36 import org.apache.tools.ant.Project;
37 import org.apache.tools.ant.Task;
38 import org.apache.tools.ant.types.FileSet;
39 import org.apache.tools.ant.types.Path;
40 import org.apache.tools.ant.util.depend.DependencyAnalyzer;
41 import org.xml.sax.InputSource JavaDoc;
42 import org.xml.sax.SAXException JavaDoc;
43
44
45 /**
46  * A deployment tool which creates generic EJB jars. Generic jars contains
47  * only those classes and META-INF entries specified in the EJB 1.1 standard
48  *
49  * This class is also used as a framework for the creation of vendor specific
50  * deployment tools. A number of template methods are provided through which the
51  * vendor specific tool can hook into the EJB creation process.
52  *
53  */

54
55
56 /**
57  * @WARNING :
58  * Method writeJar is modified. It allows to include or not inner classes for some classes).
59  * protected void writeJar(String baseName, File jarfile, Hashtable files,
60  * String publicId, boolean includeInnerClasses) throws BuildException {
61 */

62
63 public class GenericDeploymentTool implements EJBDeploymentTool {
64     /** The standard META-INF directory in jar files */
65     protected static final String JavaDoc META_DIR = "META-INF/";
66
67     /** The standard MANIFEST file */
68     protected static final String JavaDoc MANIFEST = META_DIR + "MANIFEST.MF";
69
70     /** Name for EJB Deployment descriptor within EJB jars */
71     protected static final String JavaDoc EJB_DD = "ejb-jar.xml";
72
73     /** A dependency analyzer name to find ancestor classes */
74     public static final String JavaDoc ANALYZER_SUPER = "super";
75     /** A dependency analyzer name to find all related classes */
76     public static final String JavaDoc ANALYZER_FULL = "full";
77     /** A dependency analyzer name for no analyzer */
78     public static final String JavaDoc ANALYZER_NONE = "none";
79
80     /** The default analyzer */
81     public static final String JavaDoc DEFAULT_ANALYZER = ANALYZER_SUPER;
82
83     /** The analyzer class for the super analyzer */
84     public static final String JavaDoc ANALYZER_CLASS_SUPER
85         = "org.apache.tools.ant.util.depend.bcel.AncestorAnalyzer";
86     /** The analyzer class for the super analyzer */
87     public static final String JavaDoc ANALYZER_CLASS_FULL
88         = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
89
90     /**
91      * The configuration from the containing task. This config combined
92      * with the settings of the individual attributes here constitues the
93      * complete config for this deployment tool.
94      */

95     private EjbJar.Config config;
96
97     /** Stores a handle to the directory to put the Jar files in */
98     private File JavaDoc destDir;
99
100     /** The classpath to use with this deployment tool. This is appended to
101         any paths from the ejbjar task itself.*/

102     private Path classpath;
103
104     /** Instance variable that stores the suffix for the generated jarfile. */
105     private String JavaDoc genericJarSuffix = "-generic.jar";
106
107     /**
108      * The task to which this tool belongs. This is used to access services
109      * provided by the ant core, such as logging.
110      */

111     private Task task;
112
113     /**
114      * The classloader generated from the given classpath to load
115      * the super classes and super interfaces.
116      */

117     private ClassLoader JavaDoc classpathLoader = null;
118
119      /**
120      * List of files have been loaded into the EJB jar
121      */

122     private List JavaDoc addedfiles;
123
124     /**
125      * Handler used to parse the EJB XML descriptor
126      */

127     private DescriptorHandler handler;
128
129     /**
130      * Dependency analyzer used to collect class dependencies
131      */

132     private DependencyAnalyzer dependencyAnalyzer;
133
134     public GenericDeploymentTool() {
135     }
136
137
138     /**
139      * Set the destination directory; required.
140      * @param inDir the destination directory.
141      */

142     public void setDestdir(File JavaDoc inDir) {
143         this.destDir = inDir;
144     }
145
146     /**
147      * Get the destination directory.
148      *
149      * @return the destination directory into which EJB jars are to be written
150      */

151     protected File JavaDoc getDestDir() {
152         return destDir;
153     }
154
155
156     /**
157      * Set the task which owns this tool
158      *
159      * @param task the Task to which this deployment tool is associated.
160      */

161     public void setTask(Task task) {
162         this.task = task;
163     }
164
165     /**
166      * Get the task for this tool.
167      *
168      * @return the Task instance this tool is associated with.
169      */

170     protected Task getTask() {
171         return task;
172     }
173
174     /**
175      * Get the basename terminator.
176      *
177      * @return an ejbjar task configuration
178      */

179     protected EjbJar.Config getConfig() {
180         return config;
181     }
182
183     /**
184      * Indicate if this build is using the base jar name.
185      *
186      * @return true if the name of the generated jar is coming from the
187      * basejarname attribute
188      */

189     protected boolean usingBaseJarName() {
190         return config.baseJarName != null;
191     }
192
193     /**
194      * Set the suffix for the generated jar file.
195      * @param inString the string to use as the suffix.
196      */

197     public void setGenericJarSuffix(String JavaDoc inString) {
198         this.genericJarSuffix = inString;
199     }
200
201     /**
202      * Add the classpath for the user classes
203      *
204      * @return a Path instance to be configured by Ant.
205      */

206     public Path createClasspath() {
207         if (classpath == null) {
208             classpath = new Path(task.getProject());
209         }
210         return classpath.createPath();
211     }
212
213     /**
214      * Set the classpath to be used for this compilation.
215      *
216      * @param classpath the classpath to be used for this build.
217      */

218     public void setClasspath(Path classpath) {
219         this.classpath = classpath;
220     }
221
222     /**
223      * Get the classpath by combining the one from the surrounding task, if any
224      * and the one from this tool.
225      *
226      * @return the combined classpath
227      */

228     protected Path getCombinedClasspath() {
229         Path combinedPath = classpath;
230         if (config.classpath != null) {
231             if (combinedPath == null) {
232                 combinedPath = config.classpath;
233             } else {
234                 combinedPath.append(config.classpath);
235             }
236         }
237
238         return combinedPath;
239     }
240
241     /**
242      * Log a message to the Ant output.
243      *
244      * @param message the message to be logged.
245      * @param level the severity of this message.
246      */

247     protected void log(String JavaDoc message, int level) {
248         getTask().log(message, level);
249     }
250
251     /**
252      * Get the build file location associated with this element's task.
253      *
254      * @return the task's location instance.
255      */

256     protected Location getLocation() {
257         return getTask().getLocation();
258     }
259
260     private void createAnalyzer() {
261         String JavaDoc analyzer = config.analyzer;
262         if (analyzer == null) {
263             analyzer = DEFAULT_ANALYZER;
264         }
265
266         if (analyzer.equals(ANALYZER_NONE)) {
267             return;
268         }
269
270         String JavaDoc analyzerClassName = null;
271         if (analyzer.equals(ANALYZER_SUPER)) {
272             analyzerClassName = ANALYZER_CLASS_SUPER;
273         } else if (analyzer.equals(ANALYZER_FULL)) {
274             analyzerClassName = ANALYZER_CLASS_FULL;
275         } else {
276             analyzerClassName = analyzer;
277         }
278
279         try {
280             Class JavaDoc analyzerClass = Class.forName(analyzerClassName);
281             dependencyAnalyzer
282                 = (DependencyAnalyzer) analyzerClass.newInstance();
283             dependencyAnalyzer.addClassPath(new Path(task.getProject(),
284                 config.srcDir.getPath()));
285             dependencyAnalyzer.addClassPath(config.classpath);
286         } catch (NoClassDefFoundError JavaDoc e) {
287             dependencyAnalyzer = null;
288             task.log("Unable to load dependency analyzer: " + analyzerClassName
289                 + " - dependent class not found: " + e.getMessage(),
290                 Project.MSG_WARN);
291         } catch (Exception JavaDoc e) {
292             dependencyAnalyzer = null;
293             task.log("Unable to load dependency analyzer: " + analyzerClassName
294                      + " - exception: " + e.getMessage(),
295                 Project.MSG_WARN);
296         }
297     }
298
299
300     /**
301      * Configure this tool for use in the ejbjar task.
302      *
303      * @param config the configuration from the surrounding ejbjar task.
304      */

305     public void configure(EjbJar.Config config) {
306         this.config = config;
307
308         createAnalyzer();
309         classpathLoader = null;
310     }
311
312     /**
313      * Utility method that encapsulates the logic of adding a file entry to
314      * a .jar file. Used by execute() to add entries to the jar file as it is
315      * constructed.
316      * @param jStream A JarOutputStream into which to write the
317      * jar entry.
318      * @param inputFile A File from which to read the
319      * contents the file being added.
320      * @param logicalFilename A String representing the name, including
321      * all relevant path information, that should be stored for the entry
322      * being added.
323      */

324     protected void addFileToJar(JarOutputStream JavaDoc jStream,
325                                 File JavaDoc inputFile,
326                                 String JavaDoc logicalFilename)
327         throws BuildException {
328         FileInputStream JavaDoc iStream = null;
329         try {
330             if (!addedfiles.contains(logicalFilename)) {
331                 iStream = new FileInputStream JavaDoc(inputFile);
332                 // Create the zip entry and add it to the jar file
333
ZipEntry JavaDoc zipEntry = new ZipEntry JavaDoc(logicalFilename.replace('\\', '/'));
334                 jStream.putNextEntry(zipEntry);
335
336                 // Create the file input stream, and buffer everything over
337
// to the jar output stream
338
byte[] byteBuffer = new byte[2 * 1024];
339                 int count = 0;
340                 do {
341                     jStream.write(byteBuffer, 0, count);
342                     count = iStream.read(byteBuffer, 0, byteBuffer.length);
343                 } while (count != -1);
344
345                 //add it to list of files in jar
346
addedfiles.add(logicalFilename);
347            }
348         } catch (IOException JavaDoc ioe) {
349             log("WARNING: IOException while adding entry "
350                 + logicalFilename + " to jarfile from "
351                 + inputFile.getPath() + " " + ioe.getClass().getName()
352                 + "-" + ioe.getMessage(), Project.MSG_WARN);
353         } finally {
354             // Close up the file input stream for the class file
355
if (iStream != null) {
356                 try {
357                     iStream.close();
358                 } catch (IOException JavaDoc closeException) {
359                     // ignore
360
}
361             }
362         }
363     }
364
365     protected DescriptorHandler getDescriptorHandler(File JavaDoc srcDir) {
366         DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir);
367
368         registerKnownDTDs(handler);
369
370         // register any DTDs supplied by the user
371
for (Iterator JavaDoc i = getConfig().dtdLocations.iterator(); i.hasNext();) {
372             EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
373             handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
374         }
375         return handler;
376     }
377
378     /**
379      * Register the locations of all known DTDs.
380      *
381      * vendor-specific subclasses should override this method to define
382      * the vendor-specific locations of the EJB DTDs
383      */

384     protected void registerKnownDTDs(DescriptorHandler handler) {
385         // none to register for generic
386
}
387
388     public void processDescriptor(String JavaDoc descriptorFileName, SAXParser JavaDoc saxParser) {
389
390         checkConfiguration(descriptorFileName, saxParser);
391
392         try {
393             handler = getDescriptorHandler(config.srcDir);
394
395             // Retrive the files to be added to JAR from EJB descriptor
396
Hashtable JavaDoc ejbFiles = parseEjbFiles(descriptorFileName, saxParser);
397
398             // Add any support classes specified in the build file
399
addSupportClasses(ejbFiles);
400
401             // Determine the JAR filename (without filename extension)
402
String JavaDoc baseName = getJarBaseName(descriptorFileName);
403
404             String JavaDoc ddPrefix = getVendorDDPrefix(baseName, descriptorFileName);
405
406             File JavaDoc manifestFile = getManifestFile(ddPrefix);
407             if (manifestFile != null) {
408                 ejbFiles.put(MANIFEST, manifestFile);
409             }
410
411
412
413             // First the regular deployment descriptor
414
ejbFiles.put(META_DIR + EJB_DD,
415                          new File JavaDoc(config.descriptorDir, descriptorFileName));
416
417             // now the vendor specific files, if any
418
addVendorFiles(ejbFiles, ddPrefix);
419
420             // add any dependent files
421
checkAndAddDependants(ejbFiles);
422
423             // Lastly create File object for the Jar files. If we are using
424
// a flat destination dir, then we need to redefine baseName!
425
if (config.flatDestDir && baseName.length() != 0) {
426                 int startName = baseName.lastIndexOf(File.separator);
427                 if (startName == -1) {
428                     startName = 0;
429                 }
430
431                 int endName = baseName.length();
432                 baseName = baseName.substring(startName, endName);
433             }
434
435             File JavaDoc jarFile = getVendorOutputJarFile(baseName);
436
437
438             // Check to see if we need a build and start doing the work!
439
if (needToRebuild(ejbFiles, jarFile)) {
440                 // Log that we are going to build...
441
log("building "
442                               + jarFile.getName()
443                               + " with "
444                               + String.valueOf(ejbFiles.size())
445                               + " files",
446                               Project.MSG_INFO);
447
448                 // Use helper method to write the jarfile
449
String JavaDoc publicId = getPublicId();
450                 writeJar(baseName, jarFile, ejbFiles, publicId, true);
451
452             } else {
453                 // Log that the file is up to date...
454
log(jarFile.toString() + " is up to date.",
455                               Project.MSG_VERBOSE);
456             }
457
458         } catch (SAXException JavaDoc se) {
459             String JavaDoc msg = "SAXException while parsing '"
460                 + descriptorFileName.toString()
461                 + "'. This probably indicates badly-formed XML."
462                 + " Details: "
463                 + se.getMessage();
464             throw new BuildException(msg, se);
465         } catch (IOException JavaDoc ioe) {
466             String JavaDoc msg = "IOException while parsing'"
467                 + descriptorFileName.toString()
468                 + "'. This probably indicates that the descriptor"
469                 + " doesn't exist. Details: "
470                 + ioe.getMessage();
471             throw new BuildException(msg, ioe);
472         }
473     }
474
475     /**
476      * This method is called as the first step in the processDescriptor method
477      * to allow vendor-specific subclasses to validate the task configuration
478      * prior to processing the descriptor. If the configuration is invalid,
479      * a BuildException should be thrown.
480      *
481      * @param descriptorFileName String representing the file name of an EJB
482      * descriptor to be processed
483      * @param saxParser SAXParser which may be used to parse the XML
484      * descriptor
485      * @exception BuildException Thrown if the configuration is invalid
486      */

487     protected void checkConfiguration(String JavaDoc descriptorFileName,
488                                     SAXParser JavaDoc saxParser) throws BuildException {
489
490         /*
491          * For the GenericDeploymentTool, do nothing. Vendor specific
492          * subclasses should throw a BuildException if the configuration is
493          * invalid for their server.
494          */

495     }
496
497     /**
498      * This method returns a list of EJB files found when the specified EJB
499      * descriptor is parsed and processed.
500      *
501      * @param descriptorFileName String representing the file name of an EJB
502      * descriptor to be processed
503      * @param saxParser SAXParser which may be used to parse the XML
504      * descriptor
505      * @return Hashtable of EJB class (and other) files to be
506      * added to the completed JAR file
507      * @throws SAXException Any SAX exception, possibly wrapping another
508      * exception
509      * @throws IOException An IOException from the parser, possibly from a
510      * the byte stream or character stream
511      */

512     protected Hashtable JavaDoc parseEjbFiles(String JavaDoc descriptorFileName, SAXParser JavaDoc saxParser)
513                             throws IOException JavaDoc, SAXException JavaDoc {
514         FileInputStream JavaDoc descriptorStream = null;
515         Hashtable JavaDoc ejbFiles = null;
516
517         try {
518
519             /* Parse the ejb deployment descriptor. While it may not
520              * look like much, we use a SAXParser and an inner class to
521              * get hold of all the classfile names for the descriptor.
522              */

523             descriptorStream
524                 = new FileInputStream JavaDoc(new File JavaDoc(config.descriptorDir, descriptorFileName));
525             saxParser.parse(new InputSource JavaDoc(descriptorStream), handler);
526
527             ejbFiles = handler.getFiles();
528
529         } finally {
530             if (descriptorStream != null) {
531                 try {
532                     descriptorStream.close();
533                 } catch (IOException JavaDoc closeException) {
534                     // ignore
535
}
536             }
537         }
538
539         return ejbFiles;
540     }
541
542     /**
543      * Adds any classes the user specifies using <i>support</i> nested elements
544      * to the <code>ejbFiles</code> Hashtable.
545      *
546      * @param ejbFiles Hashtable of EJB classes (and other) files that will be
547      * added to the completed JAR file
548      */

549     protected void addSupportClasses(Hashtable JavaDoc ejbFiles) {
550         // add in support classes if any
551
Project project = task.getProject();
552         for (Iterator JavaDoc i = config.supportFileSets.iterator(); i.hasNext();) {
553             FileSet supportFileSet = (FileSet) i.next();
554             File JavaDoc supportBaseDir = supportFileSet.getDir(project);
555             DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project);
556             supportScanner.scan();
557             String JavaDoc[] supportFiles = supportScanner.getIncludedFiles();
558             for (int j = 0; j < supportFiles.length; ++j) {
559                 ejbFiles.put(supportFiles[j], new File JavaDoc(supportBaseDir, supportFiles[j]));
560             }
561         }
562     }
563
564
565     /**
566      * Using the EJB descriptor file name passed from the <code>ejbjar</code>
567      * task, this method returns the "basename" which will be used to name the
568      * completed JAR file.
569      *
570      * @param descriptorFileName String representing the file name of an EJB
571      * descriptor to be processed
572      * @return The "basename" which will be used to name the
573      * completed JAR file
574      */

575     protected String JavaDoc getJarBaseName(String JavaDoc descriptorFileName) {
576
577         String JavaDoc baseName = "";
578
579         // Work out what the base name is
580
if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)) {
581             String JavaDoc canonicalDescriptor = descriptorFileName.replace('\\', '/');
582             int index = canonicalDescriptor.lastIndexOf('/');
583             if (index != -1) {
584                 baseName = descriptorFileName.substring(0, index + 1);
585             }
586             baseName += config.baseJarName;
587         } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
588             int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator);
589             int endBaseName = -1;
590             if (lastSeparatorIndex != -1) {
591                 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator,
592                                                             lastSeparatorIndex);
593             } else {
594                 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator);
595             }
596
597             if (endBaseName != -1) {
598                 baseName = descriptorFileName.substring(0, endBaseName);
599             } else {
600                 throw new BuildException("Unable to determine jar name "
601                     + "from descriptor \"" + descriptorFileName + "\"");
602             }
603         } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
604             File JavaDoc descriptorFile = new File JavaDoc(config.descriptorDir, descriptorFileName);
605             String JavaDoc path = descriptorFile.getAbsolutePath();
606             int lastSeparatorIndex
607                 = path.lastIndexOf(File.separator);
608             if (lastSeparatorIndex == -1) {
609                 throw new BuildException("Unable to determine directory name holding descriptor");
610             }
611             String JavaDoc dirName = path.substring(0, lastSeparatorIndex);
612             int dirSeparatorIndex = dirName.lastIndexOf(File.separator);
613             if (dirSeparatorIndex != -1) {
614                 dirName = dirName.substring(dirSeparatorIndex + 1);
615             }
616
617             baseName = dirName;
618         } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)) {
619             baseName = handler.getEjbName();
620         }
621         return baseName;
622     }
623
624     /**
625      * Get the prefix for vendor deployment descriptors.
626      *
627      * This will contain the path and the start of the descriptor name,
628      * depending on the naming scheme
629      */

630     public String JavaDoc getVendorDDPrefix(String JavaDoc baseName, String JavaDoc descriptorFileName) {
631         String JavaDoc ddPrefix = null;
632
633         if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
634             ddPrefix = baseName + config.baseNameTerminator;
635         } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)
636             || config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)
637             || config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
638             String JavaDoc canonicalDescriptor = descriptorFileName.replace('\\', '/');
639             int index = canonicalDescriptor.lastIndexOf('/');
640             if (index == -1) {
641                 ddPrefix = "";
642             } else {
643                 ddPrefix = descriptorFileName.substring(0, index + 1);
644             }
645         }
646         return ddPrefix;
647     }
648
649     /**
650      * Add any vendor specific files which should be included in the
651      * EJB Jar.
652      */

653     protected void addVendorFiles(Hashtable JavaDoc ejbFiles, String JavaDoc ddPrefix) {
654         // nothing to add for generic tool.
655
}
656
657
658     /**
659      * Get the vendor specific name of the Jar that will be output. The modification date
660      * of this jar will be checked against the dependent bean classes.
661      */

662     File JavaDoc getVendorOutputJarFile(String JavaDoc baseName) {
663         return new File JavaDoc(destDir, baseName + genericJarSuffix);
664     }
665
666     /**
667      * This method checks the timestamp on each file listed in the <code>
668      * ejbFiles</code> and compares them to the timestamp on the <code>jarFile
669      * </code>. If the <code>jarFile</code>'s timestamp is more recent than
670      * each EJB file, <code>true</code> is returned. Otherwise, <code>false
671      * </code> is returned.
672      * TODO: find a way to check the manifest-file, that is found by naming convention
673      *
674      * @param ejbFiles Hashtable of EJB classes (and other) files that will be
675      * added to the completed JAR file
676      * @param jarFile JAR file which will contain all of the EJB classes (and
677      * other) files
678      * @return boolean indicating whether or not the <code>jarFile</code>
679      * is up to date
680      */

681     protected boolean needToRebuild(Hashtable JavaDoc ejbFiles, File JavaDoc jarFile) {
682         if (jarFile.exists()) {
683             long lastBuild = jarFile.lastModified();
684
685             Iterator JavaDoc fileIter = ejbFiles.values().iterator();
686
687             // Loop through the files seeing if any has been touched
688
// more recently than the destination jar.
689
while (fileIter.hasNext()) {
690                 File JavaDoc currentFile = (File JavaDoc) fileIter.next();
691                 if (lastBuild < currentFile.lastModified()) {
692                     log("Build needed because " + currentFile.getPath() + " is out of date",
693                         Project.MSG_VERBOSE);
694                     return true;
695                 }
696             }
697             return false;
698         }
699
700         return true;
701     }
702
703     /**
704      * Returns the Public ID of the DTD specified in the EJB descriptor. Not
705      * every vendor-specific <code>DeploymentTool</code> will need to reference
706      * this value or may want to determine this value in a vendor-specific way.
707      *
708      * @return Public ID of the DTD specified in the EJB descriptor.
709      */

710     protected String JavaDoc getPublicId() {
711         return handler.getPublicId();
712     }
713
714     /**
715      * Get the manifets file to use for building the generic jar.
716      *
717      * If the file does not exist the global manifest from the config is used
718      * otherwise the default Ant manifest will be used.
719      *
720      * @param prefix the prefix where to llook for the manifest file based on
721      * the naming convention.
722      *
723      * @return the manifest file or null if the manifest file does not exist
724      */

725     protected File JavaDoc getManifestFile(String JavaDoc prefix) {
726         File JavaDoc manifestFile
727             = new File JavaDoc(getConfig().descriptorDir, prefix + "manifest.mf");
728         if (manifestFile.exists()) {
729             return manifestFile;
730         }
731
732         if (config.manifest != null) {
733             return config.manifest;
734         }
735         return null;
736     }
737
738     /**
739      * Method used to encapsulate the writing of the JAR file. Iterates over the
740      * filenames/java.io.Files in the Hashtable stored on the instance variable
741      * ejbFiles.
742      * @param includeInnerClasses if true, include inner classes
743      */

744     protected void writeJar(String JavaDoc baseName, File JavaDoc jarfile, Hashtable JavaDoc files,
745                             String JavaDoc publicId, boolean includeInnerClasses) throws BuildException {
746
747         JarOutputStream JavaDoc jarStream = null;
748         try {
749             // clean the addedfiles Vector
750
addedfiles = new ArrayList JavaDoc();
751
752             /* If the jarfile already exists then whack it and recreate it.
753              * Should probably think of a more elegant way to handle this
754              * so that in case of errors we don't leave people worse off
755              * than when we started =)
756              */

757             if (jarfile.exists()) {
758                 jarfile.delete();
759             }
760             jarfile.getParentFile().mkdirs();
761             jarfile.createNewFile();
762
763             InputStream JavaDoc in = null;
764             Manifest JavaDoc manifest = null;
765             try {
766                 File JavaDoc manifestFile = (File JavaDoc) files.get(MANIFEST);
767                 if (manifestFile != null && manifestFile.exists()) {
768                     in = new FileInputStream JavaDoc(manifestFile);
769                 } else {
770                     String JavaDoc defaultManifest = "/org/apache/tools/ant/defaultManifest.mf";
771                     in = this.getClass().getResourceAsStream(defaultManifest);
772                     if (in == null) {
773                         throw new BuildException("Could not find "
774                             + "default manifest: " + defaultManifest);
775                     }
776                 }
777
778                 manifest = new Manifest JavaDoc(in);
779             } catch (IOException JavaDoc e) {
780                 throw new BuildException ("Unable to read manifest", e, getLocation());
781             } finally {
782                 if (in != null) {
783                     in.close();
784                 }
785             }
786
787             // Create the streams necessary to write the jarfile
788

789             jarStream = new JarOutputStream JavaDoc(new FileOutputStream JavaDoc(jarfile), manifest);
790             jarStream.setMethod(JarOutputStream.DEFLATED);
791
792             // Loop through all the class files found and add them to the jar
793
for (Iterator JavaDoc entryIterator = files.keySet().iterator(); entryIterator.hasNext();) {
794                 String JavaDoc entryName = (String JavaDoc) entryIterator.next();
795                 if (entryName.equals(MANIFEST)) {
796                     continue;
797                 }
798
799                 File JavaDoc entryFile = (File JavaDoc) files.get(entryName);
800
801                 log("adding file '" + entryName + "'",
802                               Project.MSG_VERBOSE);
803
804                 addFileToJar(jarStream, entryFile, entryName);
805
806                 // See if there are any inner classes for this class and add them in if there are
807
InnerClassFilenameFilter flt = new InnerClassFilenameFilter(entryFile.getName());
808                 File JavaDoc entryDir = entryFile.getParentFile();
809                 String JavaDoc[] innerfiles = entryDir.list(flt);
810                 if (innerfiles != null && includeInnerClasses) {
811                     for (int i = 0, n = innerfiles.length; i < n; i++) {
812
813                         //get and clean up innerclass name
814
int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1;
815                         if (entryIndex < 0) {
816                             entryName = innerfiles[i];
817                         } else {
818                             entryName = entryName.substring(0, entryIndex)
819                                 + File.separatorChar + innerfiles[i];
820                         }
821                         // link the file
822
entryFile = new File JavaDoc(config.srcDir, entryName);
823
824                         log("adding innerclass file '" + entryName + "'",
825                                 Project.MSG_VERBOSE);
826
827                         addFileToJar(jarStream, entryFile, entryName);
828
829                     }
830                 }
831             }
832         } catch (IOException JavaDoc ioe) {
833             String JavaDoc msg = "IOException while processing ejb-jar file '"
834                 + jarfile.toString()
835                 + "'. Details: "
836                 + ioe.getMessage();
837             throw new BuildException(msg, ioe);
838         } finally {
839             if (jarStream != null) {
840                 try {
841                     jarStream.close();
842                 } catch (IOException JavaDoc closeException) {
843                     // ignore
844
}
845             }
846         }
847     } // end of writeJar
848

849
850     /**
851      * Add all available classes, that depend on Remote, Home, Bean, PK
852      * @param checkEntries files, that are extracted from the deployment descriptor
853      */

854     protected void checkAndAddDependants(Hashtable JavaDoc checkEntries)
855         throws BuildException {
856
857         if (dependencyAnalyzer == null) {
858             return;
859         }
860
861         dependencyAnalyzer.reset();
862
863         Iterator JavaDoc i = checkEntries.keySet().iterator();
864         while (i.hasNext()) {
865             String JavaDoc entryName = (String JavaDoc) i.next();
866             if (entryName.endsWith(".class")) {
867                 String JavaDoc className = entryName.substring(0,
868                     entryName.length() - ".class".length());
869                 className = className.replace(File.separatorChar, '/');
870                 className = className.replace('/', '.');
871
872                 dependencyAnalyzer.addRootClass(className);
873             }
874         }
875
876         Enumeration JavaDoc e = dependencyAnalyzer.getClassDependencies();
877
878         while (e.hasMoreElements()) {
879             String JavaDoc classname = (String JavaDoc) e.nextElement();
880             String JavaDoc location
881                 = classname.replace('.', File.separatorChar) + ".class";
882             File JavaDoc classFile = new File JavaDoc(config.srcDir, location);
883             if (classFile.exists()) {
884                 checkEntries.put(location, classFile);
885                 log("dependent class: " + classname + " - " + classFile,
886                     Project.MSG_VERBOSE);
887             }
888         }
889     }
890
891
892     /**
893      * Returns a Classloader object which parses the passed in generic EjbJar classpath.
894      * The loader is used to dynamically load classes from javax.ejb.* and the classes
895      * being added to the jar.
896      *
897      */

898     protected ClassLoader JavaDoc getClassLoaderForBuild() {
899         if (classpathLoader != null) {
900             return classpathLoader;
901         }
902
903         Path combinedClasspath = getCombinedClasspath();
904
905         // only generate a new ClassLoader if we have a classpath
906
if (combinedClasspath == null) {
907             classpathLoader = getClass().getClassLoader();
908         } else {
909             classpathLoader
910                 = getTask().getProject().createClassLoader(combinedClasspath);
911         }
912
913         return classpathLoader;
914     }
915
916     /**
917      * Called to validate that the tool parameters have been configured.
918      *
919      * @throws BuildException If the Deployment Tool's configuration isn't
920      * valid
921      */

922     public void validateConfigured() throws BuildException {
923         if ((destDir == null) || (!destDir.isDirectory())) {
924             String JavaDoc msg = "A valid destination directory must be specified "
925                             + "using the \"destdir\" attribute.";
926             throw new BuildException(msg, getLocation());
927         }
928     }
929 }
930
Popular Tags