KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > ejb > IPlanetEjbc


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

18
19 package org.apache.tools.ant.taskdefs.optional.ejb;
20
21 import java.io.BufferedReader JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.InputStreamReader JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Hashtable JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Properties JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36 import javax.xml.parsers.SAXParser JavaDoc;
37 import javax.xml.parsers.SAXParserFactory JavaDoc;
38 import org.xml.sax.AttributeList JavaDoc;
39 import org.xml.sax.HandlerBase JavaDoc;
40 import org.xml.sax.InputSource JavaDoc;
41 import org.xml.sax.SAXException JavaDoc;
42
43 /**
44  * Compiles EJB stubs and skeletons for the iPlanet Application
45  * Server (iAS). The class will read a standard EJB descriptor (as well as an
46  * EJB descriptor specific to iPlanet Application Server) to identify one or
47  * more EJBs to process. It will search for EJB "source" classes (the remote
48 ; * interface, home interface, and EJB implementation class) and the EJB stubs
49  * and skeletons in the specified destination directory. Only if the stubs and
50  * skeletons cannot be found or if they're out of date will the iPlanet
51  * Application Server ejbc utility be run.
52  * <p>
53  * Because this class (and it's assorted inner classes) may be bundled into the
54  * iPlanet Application Server distribution at some point (and removed from the
55  * Ant distribution), the class has been written to be independent of all
56  * Ant-specific classes. It is also for this reason (and to avoid cluttering
57  * the Apache Ant source files) that this utility has been packaged into a
58  * single source file.
59  * <p>
60  * For more information on Ant Tasks for iPlanet Application Server, see the
61  * <code>IPlanetDeploymentTool</code> and <code>IPlanetEjbcTask</code> classes.
62  *
63  * @see IPlanetDeploymentTool
64  * @see IPlanetEjbcTask
65  * @ant.task ignore="true"
66  */

67 public class IPlanetEjbc {
68
69     private static final int MIN_NUM_ARGS = 2;
70     private static final int MAX_NUM_ARGS = 8;
71     private static final int NUM_CLASSES_WITH_IIOP = 15;
72     private static final int NUM_CLASSES_WITHOUT_IIOP = 9;
73
74     /* Constants used for the "beantype" attribute */
75     private static final String JavaDoc ENTITY_BEAN = "entity";
76     private static final String JavaDoc STATELESS_SESSION = "stateless";
77     private static final String JavaDoc STATEFUL_SESSION = "stateful";
78
79     /* Filenames of the standard EJB descriptor and the iAS-specific descriptor */
80     private File JavaDoc stdDescriptor;
81     private File JavaDoc iasDescriptor;
82
83     /*
84      * Directory where "source" EJB files are stored and where stubs and
85      * skeletons will also be written.
86      */

87     private File JavaDoc destDirectory;
88
89     /* Classpath used when the iAS ejbc is called */
90     private String JavaDoc classpath;
91     private String JavaDoc[] classpathElements;
92
93     /* Options passed to the iAS ejbc */
94     private boolean retainSource = false;
95     private boolean debugOutput = false;
96
97     /* iAS installation directory (used if ejbc isn't on user's PATH) */
98     private File JavaDoc iasHomeDir;
99
100     /* Parser and handler used to process both EJB descriptor files */
101     private SAXParser JavaDoc parser;
102     private EjbcHandler handler = new EjbcHandler();
103
104     /*
105      * This Hashtable maintains a list of EJB class files processed by the ejbc
106      * utility (both "source" class files as well as stubs and skeletons). The
107      * key for the Hashtable is a String representing the path to the class file
108      * (relative to the destination directory). The value for the Hashtable is
109      * a File object which reference the actual class file.
110      */

111     private Hashtable JavaDoc ejbFiles = new Hashtable JavaDoc();
112
113     /* Value of the display-name element read from the standard EJB descriptor */
114     private String JavaDoc displayName;
115
116     /**
117      * Constructs an instance which may be used to process EJB descriptors and
118      * generate EJB stubs and skeletons, if needed.
119      *
120      * @param stdDescriptor File referencing a standard EJB descriptor.
121      * @param iasDescriptor File referencing an iAS-specific EJB descriptor.
122      * @param destDirectory File referencing the base directory where both
123      * EJB "source" files are found and where stubs and
124      * skeletons will be written.
125      * @param classpath String representation of the classpath to be used
126      * by the iAS ejbc utility.
127      * @param parser SAXParser to be used to process both of the EJB
128      * descriptors.
129      * @todo classpathElements is not needed here, its never used
130      * (at least IDEA tells me so! :)
131      */

132     public IPlanetEjbc(File JavaDoc stdDescriptor,
133                        File JavaDoc iasDescriptor,
134                        File JavaDoc destDirectory,
135                        String JavaDoc classpath,
136                        SAXParser JavaDoc parser) {
137         this.stdDescriptor = stdDescriptor;
138         this.iasDescriptor = iasDescriptor;
139         this.destDirectory = destDirectory;
140         this.classpath = classpath;
141         this.parser = parser;
142
143         /*
144          * Parse the classpath into it's individual elements and store the
145          * results in the "classpathElements" instance variable.
146          */

147         List JavaDoc elements = new ArrayList JavaDoc();
148         if (classpath != null) {
149             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(classpath,
150                                                         File.pathSeparator);
151             while (st.hasMoreTokens()) {
152                 elements.add(st.nextToken());
153             }
154             classpathElements
155                     = (String JavaDoc[]) elements.toArray(new String JavaDoc[elements.size()]);
156         }
157     }
158
159     /**
160      * If true, the Java source files which are generated by the
161      * ejbc process are retained.
162      *
163      * @param retainSource A boolean indicating if the Java source files for
164      * the stubs and skeletons should be retained.
165      * @todo This is not documented in the HTML. On purpose?
166      */

167     public void setRetainSource(boolean retainSource) {
168         this.retainSource = retainSource;
169     }
170
171     /**
172      * If true, enables debugging output when ejbc is executed.
173      *
174      * @param debugOutput A boolean indicating if debugging output should be
175      * generated
176      */

177     public void setDebugOutput(boolean debugOutput) {
178         this.debugOutput = debugOutput;
179     }
180
181     /**
182      * Registers the location of a local DTD file or resource. By registering
183      * a local DTD, EJB descriptors can be parsed even when the remote servers
184      * which contain the "public" DTDs cannot be accessed.
185      *
186      * @param publicID The public DTD identifier found in an XML document.
187      * @param location The file or resource name for the appropriate DTD stored
188      * on the local machine.
189      */

190     public void registerDTD(String JavaDoc publicID, String JavaDoc location) {
191         handler.registerDTD(publicID, location);
192     }
193
194     /**
195      * May be used to specify the "home" directory for this iAS installation.
196      * The directory specified should typically be
197      * <code>[install-location]/iplanet/ias6/ias</code>.
198      *
199      * @param iasHomeDir The home directory for the user's iAS installation.
200      */

201     public void setIasHomeDir(File JavaDoc iasHomeDir) {
202         this.iasHomeDir = iasHomeDir;
203     }
204
205     /**
206      * Returns a Hashtable which contains a list of EJB class files processed by
207      * the ejbc utility (both "source" class files as well as stubs and
208      * skeletons). The key for the Hashtable is a String representing the path
209      * to the class file (relative to the destination directory). The value for
210      * the Hashtable is a File object which reference the actual class file.
211      *
212      * @return The list of EJB files processed by the ejbc utility.
213      */

214     public Hashtable JavaDoc getEjbFiles() {
215         return ejbFiles;
216     }
217
218     /**
219      * Returns the display-name element read from the standard EJB descriptor.
220      *
221      * @return The EJB-JAR display name.
222      */

223     public String JavaDoc getDisplayName() {
224         return displayName;
225     }
226
227     /**
228      * Returns the list of CMP descriptors referenced in the EJB descriptors.
229      *
230      * @return An array of CMP descriptors.
231      */

232     public String JavaDoc[] getCmpDescriptors() {
233         List JavaDoc returnList = new ArrayList JavaDoc();
234
235         EjbInfo[] ejbs = handler.getEjbs();
236
237         for (int i = 0; i < ejbs.length; i++) {
238             List JavaDoc descriptors = (List JavaDoc) ejbs[i].getCmpDescriptors();
239             returnList.addAll(descriptors);
240         }
241
242         return (String JavaDoc[]) returnList.toArray(new String JavaDoc[returnList.size()]);
243     }
244
245     /**
246      * Main application method for the iPlanet Application Server ejbc utility.
247      * If the application is run with no commandline arguments, a usage
248      * statement is printed for the user.
249      *
250      * @param args The commandline arguments passed to the application.
251      */

252     public static void main(String JavaDoc[] args) {
253         File JavaDoc stdDescriptor;
254         File JavaDoc iasDescriptor;
255         File JavaDoc destDirectory = null;
256         String JavaDoc classpath = null;
257         SAXParser JavaDoc parser = null;
258         boolean debug = false;
259         boolean retainSource = false;
260         IPlanetEjbc ejbc;
261
262         if ((args.length < MIN_NUM_ARGS) || (args.length > MAX_NUM_ARGS)) {
263             usage();
264             return;
265         }
266
267         stdDescriptor = new File JavaDoc(args[args.length - 2]);
268         iasDescriptor = new File JavaDoc(args[args.length - 1]);
269
270         for (int i = 0; i < args.length - 2; i++) {
271             if (args[i].equals("-classpath")) {
272                 classpath = args[++i];
273             } else if (args[i].equals("-d")) {
274                 destDirectory = new File JavaDoc(args[++i]);
275             } else if (args[i].equals("-debug")) {
276                 debug = true;
277             } else if (args[i].equals("-keepsource")) {
278                 retainSource = true;
279             } else {
280                 usage();
281                 return;
282             }
283         }
284
285         /* If the -classpath flag isn't specified, use the system classpath */
286         if (classpath == null) {
287             Properties JavaDoc props = System.getProperties();
288             classpath = props.getProperty("java.class.path");
289         }
290
291         /*
292          * If the -d flag isn't specified, use the working directory as the
293          * destination directory
294          */

295         if (destDirectory == null) {
296             Properties JavaDoc props = System.getProperties();
297             destDirectory = new File JavaDoc(props.getProperty("user.dir"));
298         }
299
300         /* Construct a SAXParser used to process the descriptors */
301         SAXParserFactory JavaDoc parserFactory = SAXParserFactory.newInstance();
302         parserFactory.setValidating(true);
303         try {
304             parser = parserFactory.newSAXParser();
305         } catch (Exception JavaDoc e) {
306             // SAXException or ParserConfigurationException may be thrown
307
System.out.println("An exception was generated while trying to ");
308             System.out.println("create a new SAXParser.");
309             e.printStackTrace();
310             return;
311         }
312
313         /* Build and populate an instance of the ejbc utility */
314         ejbc = new IPlanetEjbc(stdDescriptor, iasDescriptor, destDirectory,
315                                 classpath, parser);
316         ejbc.setDebugOutput(debug);
317         ejbc.setRetainSource(retainSource);
318
319         /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
320         try {
321             ejbc.execute();
322         } catch (IOException JavaDoc e) {
323             System.out.println("An IOException has occurred while reading the "
324                     + "XML descriptors (" + e.getMessage() + ").");
325             return;
326         } catch (SAXException JavaDoc e) {
327             System.out.println("A SAXException has occurred while reading the "
328                     + "XML descriptors (" + e.getMessage() + ").");
329             return;
330         } catch (IPlanetEjbc.EjbcException e) {
331             System.out.println("An error has occurred while executing the ejbc "
332                     + "utility (" + e.getMessage() + ").");
333             return;
334         }
335     }
336
337     /**
338      * Print a usage statement.
339      */

340     private static void usage() {
341         System.out.println("java org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbc \\");
342         System.out.println(" [OPTIONS] [EJB 1.1 descriptor] [iAS EJB descriptor]");
343         System.out.println("");
344         System.out.println("Where OPTIONS are:");
345         System.out.println(" -debug -- for additional debugging output");
346         System.out.println(" -keepsource -- to retain Java source files generated");
347         System.out.println(" -classpath [classpath] -- classpath used for compilation");
348         System.out.println(" -d [destination directory] -- directory for compiled classes");
349         System.out.println("");
350         System.out.println("If a classpath is not specified, the system classpath");
351         System.out.println("will be used. If a destination directory is not specified,");
352         System.out.println("the current working directory will be used (classes will");
353         System.out.println("still be placed in subfolders which correspond to their");
354         System.out.println("package name).");
355         System.out.println("");
356         System.out.println("The EJB home interface, remote interface, and implementation");
357         System.out.println("class must be found in the destination directory. In");
358         System.out.println("addition, the destination will look for the stubs and skeletons");
359         System.out.println("in the destination directory to ensure they are up to date.");
360     }
361
362     /**
363      * Compiles the stub and skeletons for the specified EJBs, if they need to
364      * be updated.
365      *
366      * @throws EjbcException If the ejbc utility cannot be correctly configured
367      * or if one or more of the EJB "source" classes
368      * cannot be found in the destination directory
369      * @throws IOException If the parser encounters a problem reading the XML
370      * file
371      * @throws SAXException If the parser encounters a problem processing the
372      * XML descriptor (it may wrap another exception)
373      */

374     public void execute() throws EjbcException, IOException JavaDoc, SAXException JavaDoc {
375
376         checkConfiguration(); // Throws EjbcException if unsuccessful
377

378         EjbInfo[] ejbs = getEjbs(); // Returns list of EJBs for processing
379

380         for (int i = 0; i < ejbs.length; i++) {
381             log("EJBInfo...");
382             log(ejbs[i].toString());
383         }
384
385         for (int i = 0; i < ejbs.length; i++) {
386             EjbInfo ejb = ejbs[i];
387
388             ejb.checkConfiguration(destDirectory); // Throws EjbcException
389

390             if (ejb.mustBeRecompiled(destDirectory)) {
391                 log(ejb.getName() + " must be recompiled using ejbc.");
392
393                 String JavaDoc[] arguments = buildArgumentList(ejb);
394                 callEjbc(arguments);
395
396             } else {
397                 log(ejb.getName() + " is up to date.");
398             }
399         }
400     }
401
402     /**
403      * Executes the iPlanet Application Server ejbc command-line utility.
404      *
405      * @param arguments Command line arguments to be passed to the ejbc utility.
406      */

407     private void callEjbc(String JavaDoc[] arguments) {
408
409         /* Concatenate all of the command line arguments into a single String */
410         StringBuffer JavaDoc args = new StringBuffer JavaDoc();
411         for (int i = 0; i < arguments.length; i++) {
412             args.append(arguments[i]).append(" ");
413         }
414
415         /* If an iAS home directory is specified, prepend it to the commmand */
416         String JavaDoc command;
417         if (iasHomeDir == null) {
418             command = "";
419         } else {
420             command = iasHomeDir.toString() + File.separator + "bin"
421                                                         + File.separator;
422         }
423         command += "ejbc ";
424
425         log(command + args);
426
427         /*
428          * Use the Runtime object to execute an external command. Use the
429          * RedirectOutput inner class to direct the standard and error output
430          * from the command to the JRE's standard output
431          */

432         try {
433             Process JavaDoc p = Runtime.getRuntime().exec(command + args);
434             RedirectOutput output = new RedirectOutput(p.getInputStream());
435             RedirectOutput error = new RedirectOutput(p.getErrorStream());
436             output.start();
437             error.start();
438             p.waitFor();
439             p.destroy();
440         } catch (IOException JavaDoc e) {
441             log("An IOException has occurred while trying to execute ejbc.");
442             e.printStackTrace();
443         } catch (InterruptedException JavaDoc e) {
444             // Do nothing
445
}
446     }
447
448     /**
449      * Verifies that the user selections are valid.
450      *
451      * @throws EjbcException If the user selections are invalid.
452      */

453     protected void checkConfiguration() throws EjbcException {
454
455         String JavaDoc msg = "";
456
457         if (stdDescriptor == null) {
458             msg += "A standard XML descriptor file must be specified. ";
459         }
460         if (iasDescriptor == null) {
461             msg += "An iAS-specific XML descriptor file must be specified. ";
462         }
463         if (classpath == null) {
464             msg += "A classpath must be specified. ";
465         }
466         if (parser == null) {
467             msg += "An XML parser must be specified. ";
468         }
469
470         if (destDirectory == null) {
471             msg += "A destination directory must be specified. ";
472         } else if (!destDirectory.exists()) {
473             msg += "The destination directory specified does not exist. ";
474         } else if (!destDirectory.isDirectory()) {
475             msg += "The destination specified is not a directory. ";
476         }
477
478         if (msg.length() > 0) {
479             throw new EjbcException(msg);
480         }
481     }
482
483     /**
484      * Parses the EJB descriptors and returns a list of EJBs which may need to
485      * be compiled.
486      *
487      * @return An array of objects which describe the EJBs to be
488      * processed.
489      * @throws IOException If the parser encounters a problem reading the XML
490      * files
491      * @throws SAXException If the parser encounters a problem processing the
492      * XML descriptor (it may wrap another exception)
493      */

494     private EjbInfo[] getEjbs() throws IOException JavaDoc, SAXException JavaDoc {
495         EjbInfo[] ejbs = null;
496
497         /*
498          * The EJB information is gathered from the standard XML EJB descriptor
499          * and the iAS-specific XML EJB descriptor using a SAX parser.
500          */

501
502         parser.parse(stdDescriptor, handler);
503         parser.parse(iasDescriptor, handler);
504         ejbs = handler.getEjbs();
505
506         return ejbs;
507     }
508
509     /**
510      * Based on this object's instance variables as well as the EJB to be
511      * processed, the correct flags and parameters are set for the ejbc
512      * command-line utility.
513      * @param ejb The EJB for which stubs and skeletons will be compiled.
514      * @return An array of Strings which are the command-line parameters for
515      * for the ejbc utility.
516      */

517     private String JavaDoc[] buildArgumentList(EjbInfo ejb) {
518
519         List JavaDoc arguments = new ArrayList JavaDoc();
520
521         /* OPTIONAL COMMAND LINE PARAMETERS */
522
523         if (debugOutput) {
524             arguments.add("-debug");
525         }
526
527         /* No beantype flag is needed for an entity bean */
528         if (ejb.getBeantype().equals(STATELESS_SESSION)) {
529             arguments.add("-sl");
530         } else if (ejb.getBeantype().equals(STATEFUL_SESSION)) {
531             arguments.add("-sf");
532         }
533
534         if (ejb.getIiop()) {
535             arguments.add("-iiop");
536         }
537
538         if (ejb.getCmp()) {
539             arguments.add("-cmp");
540         }
541
542         if (retainSource) {
543             arguments.add("-gs");
544         }
545
546         if (ejb.getHasession()) {
547             arguments.add("-fo");
548         }
549
550         /* REQUIRED COMMAND LINE PARAMETERS */
551
552         arguments.add("-classpath");
553         arguments.add(classpath);
554
555         arguments.add("-d");
556         arguments.add(destDirectory.toString());
557
558         arguments.add(ejb.getHome().getQualifiedClassName());
559         arguments.add(ejb.getRemote().getQualifiedClassName());
560         arguments.add(ejb.getImplementation().getQualifiedClassName());
561
562         /* Convert the List into an Array and return it */
563         return (String JavaDoc[]) arguments.toArray(new String JavaDoc[arguments.size()]);
564     }
565
566     /**
567      * Convenience method used to print messages to the user if debugging
568      * messages are enabled.
569      *
570      * @param msg The String to print to standard output.
571      */

572     private void log(String JavaDoc msg) {
573         if (debugOutput) {
574             System.out.println(msg);
575         }
576     }
577
578
579     /* Inner classes follow */
580
581
582     /**
583      * This inner class is used to signal any problems during the execution of
584      * the ejbc compiler.
585      *
586      */

587     public class EjbcException extends Exception JavaDoc {
588
589         /**
590          * Constructs an exception with the given descriptive message.
591          *
592          * @param msg Description of the exception which has occurred.
593          */

594         public EjbcException(String JavaDoc msg) {
595             super(msg);
596         }
597     } // End of EjbcException inner class
598

599
600     /**
601      * This inner class is an XML document handler that can be used to parse EJB
602      * descriptors (both the standard EJB descriptor as well as the iAS-specific
603      * descriptor that stores additional values for iAS). Once the descriptors
604      * have been processed, the list of EJBs found can be obtained by calling
605      * the <code>getEjbs()</code> method.
606      *
607      * @see IPlanetEjbc.EjbInfo
608      */

609     private class EjbcHandler extends HandlerBase JavaDoc {
610         /** EJB 1.1 ID */
611         private static final String JavaDoc PUBLICID_EJB11 =
612             "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
613         /** IPlanet ID */
614         private static final String JavaDoc PUBLICID_IPLANET_EJB_60 =
615             "-//Sun Microsystems, Inc.//DTD iAS Enterprise JavaBeans 1.0//EN";
616         /** EJB 1.1 location */
617         private static final String JavaDoc DEFAULT_IAS60_EJB11_DTD_LOCATION =
618             "ejb-jar_1_1.dtd";
619         /** IAS60 location */
620         private static final String JavaDoc DEFAULT_IAS60_DTD_LOCATION =
621             "IASEjb_jar_1_0.dtd";
622
623         /*
624          * Two Maps are used to track local DTDs that will be used in case the
625          * remote copies of these DTDs cannot be accessed. The key for the Map
626          * is the DTDs public ID and the value is the local location for the DTD
627          */

628         private Map JavaDoc resourceDtds = new HashMap JavaDoc();
629         private Map JavaDoc fileDtds = new HashMap JavaDoc();
630
631         private Map JavaDoc ejbs = new HashMap JavaDoc(); // List of EJBs found in XML
632
private EjbInfo currentEjb; // One item within the Map
633
private boolean iasDescriptor = false; // Is doc iAS or EJB descriptor
634

635         private String JavaDoc currentLoc = ""; // Tracks current element
636
private String JavaDoc currentText; // Tracks current text data
637
private String JavaDoc ejbType; // "session" or "entity"
638

639         /**
640          * Constructs a new instance of the handler and registers local copies
641          * of the standard EJB 1.1 descriptor DTD as well as iAS's EJB
642          * descriptor DTD.
643          */

644         public EjbcHandler() {
645             registerDTD(PUBLICID_EJB11, DEFAULT_IAS60_EJB11_DTD_LOCATION);
646             registerDTD(PUBLICID_IPLANET_EJB_60, DEFAULT_IAS60_DTD_LOCATION);
647         }
648
649         /**
650          * Returns the list of EJB objects found during the processing of the
651          * standard EJB 1.1 descriptor and iAS-specific EJB descriptor.
652          *
653          * @return An array of EJBs which were found during the descriptor
654          * parsing.
655          */

656         public EjbInfo[] getEjbs() {
657             return (EjbInfo[]) ejbs.values().toArray(new EjbInfo[ejbs.size()]);
658         }
659
660         /**
661          * Returns the value of the display-name element found in the standard
662          * EJB 1.1 descriptor.
663          *
664          * @return String display-name value.
665          */

666         public String JavaDoc getDisplayName() {
667             return displayName;
668         }
669
670         /**
671          * Registers a local DTD that will be used when parsing an EJB
672          * descriptor. When the DTD's public identifier is found in an XML
673          * document, the parser will reference the local DTD rather than the
674          * remote DTD. This enables XML documents to be processed even when the
675          * public DTD isn't available.
676          *
677          * @param publicID The DTD's public identifier.
678          * @param location The location of the local DTD copy -- the location
679          * may either be a resource found on the classpath or a
680          * local file.
681          */

682         public void registerDTD(String JavaDoc publicID, String JavaDoc location) {
683             log("Registering: " + location);
684             if ((publicID == null) || (location == null)) {
685                 return;
686             }
687
688             if (ClassLoader.getSystemResource(location) != null) {
689                 log("Found resource: " + location);
690                 resourceDtds.put(publicID, location);
691             } else {
692                 File JavaDoc dtdFile = new File JavaDoc(location);
693                 if (dtdFile.exists() && dtdFile.isFile()) {
694                     log("Found file: " + location);
695                     fileDtds.put(publicID, location);
696                 }
697             }
698         }
699
700         /**
701          * Resolves an external entity found during XML processing. If a public
702          * ID is found that has been registered with the handler, an <code>
703          * InputSource</code> will be returned which refers to the local copy.
704          * If the public ID hasn't been registered or if an error occurs, the
705          * superclass implementation is used.
706          *
707          * @param publicId The DTD's public identifier.
708          * @param systemId The location of the DTD, as found in the XML document.
709          */

710         public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
711                 throws SAXException JavaDoc {
712             InputStream JavaDoc inputStream = null;
713
714
715             try {
716
717                 /* Search the resource Map and (if not found) file Map */
718
719                 String JavaDoc location = (String JavaDoc) resourceDtds.get(publicId);
720                 if (location != null) {
721                     inputStream
722                         = ClassLoader.getSystemResource(location).openStream();
723                 } else {
724                     location = (String JavaDoc) fileDtds.get(publicId);
725                     if (location != null) {
726                         inputStream = new FileInputStream JavaDoc(location);
727                     }
728                 }
729             } catch (IOException JavaDoc e) {
730                 return super.resolveEntity(publicId, systemId);
731             }
732
733             if (inputStream == null) {
734                 return super.resolveEntity(publicId, systemId);
735             } else {
736                 return new InputSource JavaDoc(inputStream);
737             }
738         }
739
740         /**
741          * Receive notification that the start of an XML element has been found.
742          *
743          * @param name String name of the element found.
744          * @param atts AttributeList of the attributes included with the element
745          * (if any).
746          * @throws SAXException If the parser cannot process the document.
747          */

748         public void startElement(String JavaDoc name, AttributeList JavaDoc atts)
749                 throws SAXException JavaDoc {
750
751             /*
752              * I need to "push" the element onto the String (currentLoc) which
753              * always represents the current location in the XML document.
754              */

755             currentLoc += "\\" + name;
756
757             /* A new element has started, so reset the text being captured */
758             currentText = "";
759
760             if (currentLoc.equals("\\ejb-jar")) {
761                 iasDescriptor = false;
762             } else if (currentLoc.equals("\\ias-ejb-jar")) {
763                 iasDescriptor = true;
764             }
765
766             if ((name.equals("session")) || (name.equals("entity"))) {
767                 ejbType = name;
768             }
769         }
770
771         /**
772          * Receive notification that character data has been found in the XML
773          * document
774          *
775          * @param ch Array of characters which have been found in the document.
776          * @param start Starting index of the data found in the document.
777          * @param len The number of characters found in the document.
778          * @throws SAXException If the parser cannot process the document.
779          */

780         public void characters(char[] ch, int start, int len)
781                 throws SAXException JavaDoc {
782
783 &nbs