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             currentText += new String JavaDoc(ch).substring(start, start + len);
784         }
785
786         /**
787          * Receive notification that the end of an XML element has been found.
788          *
789          * @param name String name of the element.
790          * @throws SAXException If the parser cannot process the document.
791          */

792         public void endElement(String JavaDoc name) throws SAXException JavaDoc {
793
794             /*
795              * If this is a standard EJB 1.1 descriptor, we are looking for one
796              * set of data, while if this is an iAS-specific descriptor, we're
797              * looking for different set of data. Hand the processing off to
798              * the appropriate method.
799              */

800             if (iasDescriptor) {
801                 iasCharacters(currentText);
802             } else {
803                 stdCharacters(currentText);
804             }
805
806             /*
807              * I need to "pop" the element off the String (currentLoc) which
808              * always represents my current location in the XML document.
809              */

810
811             int nameLength = name.length() + 1; // Add one for the "\"
812
int locLength = currentLoc.length();
813
814             currentLoc = currentLoc.substring(0, locLength - nameLength);
815         }
816
817         /**
818          * Receive notification that character data has been found in a standard
819          * EJB 1.1 descriptor. We're interested in retrieving the home
820          * interface, remote interface, implementation class, the type of bean,
821          * and if the bean uses CMP.
822          *
823          * @param value String data found in the XML document.
824          */

825         private void stdCharacters(String JavaDoc value) {
826
827             if (currentLoc.equals("\\ejb-jar\\display-name")) {
828                 displayName = value;
829                 return;
830             }
831
832             String JavaDoc base = "\\ejb-jar\\enterprise-beans\\" + ejbType;
833
834             if (currentLoc.equals(base + "\\ejb-name")) {
835                 currentEjb = (EjbInfo) ejbs.get(value);
836                 if (currentEjb == null) {
837                     currentEjb = new EjbInfo(value);
838                     ejbs.put(value, currentEjb);
839                 }
840             } else if (currentLoc.equals(base + "\\home")) {
841                 currentEjb.setHome(value);
842             } else if (currentLoc.equals(base + "\\remote")) {
843                 currentEjb.setRemote(value);
844             } else if (currentLoc.equals(base + "\\ejb-class")) {
845                 currentEjb.setImplementation(value);
846             } else if (currentLoc.equals(base + "\\prim-key-class")) {
847                 currentEjb.setPrimaryKey(value);
848             } else if (currentLoc.equals(base + "\\session-type")) {
849                 currentEjb.setBeantype(value);
850             } else if (currentLoc.equals(base + "\\persistence-type")) {
851                 currentEjb.setCmp(value);
852             }
853         }
854
855         /**
856          * Receive notification that character data has been found in an
857          * iAS-specific descriptor. We're interested in retrieving data
858          * indicating whether the bean must support RMI/IIOP access, whether
859          * the bean must provide highly available stubs and skeletons (in the
860          * case of stateful session beans), and if this bean uses additional
861          * CMP XML descriptors (in the case of entity beans with CMP).
862          *
863          * @param value String data found in the XML document.
864          */

865         private void iasCharacters(String JavaDoc value) {
866             String JavaDoc base = "\\ias-ejb-jar\\enterprise-beans\\" + ejbType;
867
868             if (currentLoc.equals(base + "\\ejb-name")) {
869                 currentEjb = (EjbInfo) ejbs.get(value);
870                 if (currentEjb == null) {
871                     currentEjb = new EjbInfo(value);
872                     ejbs.put(value, currentEjb);
873                 }
874             } else if (currentLoc.equals(base + "\\iiop")) {
875                 currentEjb.setIiop(value);
876             } else if (currentLoc.equals(base + "\\failover-required")) {
877                 currentEjb.setHasession(value);
878             } else if (currentLoc.equals(base + "\\persistence-manager"
879                                               + "\\properties-file-location")) {
880                 currentEjb.addCmpDescriptor(value);
881             }
882         }
883     } // End of EjbcHandler inner class
884

885
886     /**
887      * This inner class represents an EJB that will be compiled using ejbc.
888      *
889      */

890     private class EjbInfo {
891         private String JavaDoc name; // EJB's display name
892
private Classname home; // EJB's home interface name
893
private Classname remote; // EJB's remote interface name
894
private Classname implementation; // EJB's implementation class
895
private Classname primaryKey; // EJB's primary key class
896
private String JavaDoc beantype = "entity"; // or "stateful" or "stateless"
897
private boolean cmp = false; // Does this EJB support CMP?
898
private boolean iiop = false; // Does this EJB support IIOP?
899
private boolean hasession = false; // Does this EJB require failover?
900
private List JavaDoc cmpDescriptors = new ArrayList JavaDoc(); // CMP descriptor list
901

902         /**
903          * Construct a new EJBInfo object with the given name.
904          *
905          * @param name The display name for the EJB.
906          */

907         public EjbInfo(String JavaDoc name) {
908             this.name = name;
909         }
910
911         /**
912          * Returns the display name of the EJB. If a display name has not been
913          * set, it returns the EJB implementation classname (if the
914          * implementation class is not set, it returns "[unnamed]").
915          *
916          * @return The display name for the EJB.
917          */

918         public String JavaDoc getName() {
919             if (name == null) {
920                 if (implementation == null) {
921                     return "[unnamed]";
922                 } else {
923                     return implementation.getClassName();
924                 }
925             }
926             return name;
927         }
928
929         /*
930          * Below are getter's and setter's for each of the instance variables.
931          * Note that (in addition to supporting setters with the same type as
932          * the instance variable) a setter is provided with takes a String
933          * argument -- this are provided so the XML document handler can set
934          * the EJB values using the Strings it parses.
935          */

936
937         public void setHome(String JavaDoc home) {
938             setHome(new Classname(home));
939         }
940
941         public void setHome(Classname home) {
942             this.home = home;
943         }
944
945         public Classname getHome() {
946             return home;
947         }
948
949         public void setRemote(String JavaDoc remote) {
950             setRemote(new Classname(remote));
951         }
952
953         public void setRemote(Classname remote) {
954             this.remote = remote;
955         }
956
957         public Classname getRemote() {
958             return remote;
959         }
960
961         public void setImplementation(String JavaDoc implementation) {
962             setImplementation(new Classname(implementation));
963         }
964
965         public void setImplementation(Classname implementation) {
966             this.implementation = implementation;
967         }
968
969         public Classname getImplementation() {
970             return implementation;
971         }
972
973         public void setPrimaryKey(String JavaDoc primaryKey) {
974             setPrimaryKey(new Classname(primaryKey));
975         }
976
977         public void setPrimaryKey(Classname primaryKey) {
978             this.primaryKey = primaryKey;
979         }
980
981         public Classname getPrimaryKey() {
982             return primaryKey;
983         }
984
985         public void setBeantype(String JavaDoc beantype) {
986             this.beantype = beantype.toLowerCase();
987         }
988
989         public String JavaDoc getBeantype() {
990             return beantype;
991         }
992
993         public void setCmp(boolean cmp) {
994             this.cmp = cmp;
995         }
996
997         public void setCmp(String JavaDoc cmp) {
998             setCmp(cmp.equals("Container"));
999         }
1000
1001        public boolean getCmp() {
1002            return cmp;
1003        }
1004
1005        public void setIiop(boolean iiop) {
1006            this.iiop = iiop;
1007        }
1008
1009        public void setIiop(String JavaDoc iiop) {
1010            setIiop(iiop.equals("true"));
1011        }
1012
1013        public boolean getIiop() {
1014            return iiop;
1015        }
1016
1017        public void setHasession(boolean hasession) {
1018            this.hasession = hasession;
1019        }
1020
1021        public void setHasession(String JavaDoc hasession) {
1022            setHasession(hasession.equals("true"));
1023        }
1024
1025        public boolean getHasession() {
1026            return hasession;
1027        }
1028
1029        public void addCmpDescriptor(String JavaDoc descriptor) {
1030            cmpDescriptors.add(descriptor);
1031        }
1032
1033        public List JavaDoc getCmpDescriptors() {
1034            return cmpDescriptors;
1035        }
1036
1037        /**
1038         * Verifies that the EJB is valid--if it is invalid, an exception is
1039         * thrown
1040         *
1041         *
1042         * @param buildDir The directory where the EJB remote interface, home
1043         * interface, and implementation class must be found.
1044         * @throws EjbcException If the EJB is invalid.
1045         */

1046        private void checkConfiguration(File JavaDoc buildDir) throws EjbcException {
1047
1048            /* Check that the specified instance variables are valid */
1049            if (home == null) {
1050                throw new EjbcException("A home interface was not found "
1051                            + "for the " + name + " EJB.");
1052            }
1053            if (remote == null) {
1054                throw new EjbcException("A remote interface was not found "
1055                            + "for the " + name + " EJB.");
1056            }
1057            if (implementation == null) {
1058                throw new EjbcException("An EJB implementation class was not "
1059                            + "found for the " + name + " EJB.");
1060            }
1061
1062            if ((!beantype.equals(ENTITY_BEAN))
1063                        && (!beantype.equals(STATELESS_SESSION))
1064                        && (!beantype.equals(STATEFUL_SESSION))) {
1065                throw new EjbcException("The beantype found (" + beantype + ") "
1066                            + "isn't valid in the " + name + " EJB.");
1067            }
1068
1069            if (cmp && (!beantype.equals(ENTITY_BEAN))) {
1070                System.out.println("CMP stubs and skeletons may not be generated"
1071                    + " for a Session Bean -- the \"cmp\" attribute will be"
1072                    + " ignoredfor the " + name + " EJB.");
1073            }
1074
1075            if (hasession && (!beantype.equals(STATEFUL_SESSION))) {
1076                System.out.println("Highly available stubs and skeletons may "
1077                    + "only be generated for a Stateful Session Bean -- the "
1078                    + "\"hasession\" attribute will be ignored for the "
1079                    + name + " EJB.");
1080            }
1081
1082            /* Check that the EJB "source" classes all exist */
1083            if (!remote.getClassFile(buildDir).exists()) {
1084                throw new EjbcException("The remote interface "
1085                            + remote.getQualifiedClassName() + " could not be "
1086                            + "found.");
1087            }
1088            if (!home.getClassFile(buildDir).exists()) {
1089                throw new EjbcException("The home interface "
1090                            + home.getQualifiedClassName() + " could not be "
1091                            + "found.");
1092            }
1093            if (!implementation.getClassFile(buildDir).exists()) {
1094                throw new EjbcException("The EJB implementation class "
1095                            + implementation.getQualifiedClassName() + " could "
1096                            + "not be found.");
1097            }
1098        }
1099
1100        /**
1101         * Determines if the ejbc utility needs to be run or not. If the stubs
1102         * and skeletons can all be found in the destination directory AND all
1103         * of their timestamps are more recent than the EJB source classes
1104         * (home, remote, and implementation classes), the method returns
1105         * <code>false</code>. Otherwise, the method returns <code>true</code>.
1106         *
1107         * @param destDir The directory where the EJB source classes, stubs and
1108         * skeletons are located.
1109         * @return A boolean indicating whether or not the ejbc utility needs to
1110         * be run to bring the stubs and skeletons up to date.
1111         */

1112        public boolean mustBeRecompiled(File JavaDoc destDir) {
1113
1114            long sourceModified = sourceClassesModified(destDir);
1115
1116            long destModified = destClassesModified(destDir);
1117
1118            return (destModified < sourceModified);
1119        }
1120
1121        /**
1122         * Examines each of the EJB source classes (home, remote, and
1123         * implementation) and returns the modification timestamp for the
1124         * "oldest" class.
1125         *
1126         * @param classpath The classpath to be used to find the source EJB
1127         * classes. If <code>null</code>, the system classpath
1128         * is used.
1129         * @return The modification timestamp for the "oldest" EJB source class.
1130         * @throws BuildException If one of the EJB source classes cannot be
1131         * found on the classpath.
1132         */

1133        private long sourceClassesModified(File JavaDoc buildDir) {
1134            long latestModified; // The timestamp of the "newest" class
1135
long modified; // Timestamp for a given class
1136
File JavaDoc remoteFile; // File for the remote interface class
1137
File JavaDoc homeFile; // File for the home interface class
1138
File JavaDoc implFile; // File for the EJB implementation class
1139
File JavaDoc pkFile; // File for the EJB primary key class
1140

1141            /* Check the timestamp on the remote interface */
1142            remoteFile = remote.getClassFile(buildDir);
1143            modified = remoteFile.lastModified();
1144            if (modified == -1) {
1145                System.out.println("The class "
1146                                + remote.getQualifiedClassName() + " couldn't "
1147                                + "be found on the classpath");
1148                return -1;
1149            }
1150            latestModified = modified;
1151
1152            /* Check the timestamp on the home interface */
1153            homeFile = home.getClassFile(buildDir);
1154            modified = homeFile.lastModified();
1155            if (modified == -1) {
1156                System.out.println("The class "
1157                                + home.getQualifiedClassName() + " couldn't be "
1158                                + "found on the classpath");
1159                return -1;
1160            }
1161            latestModified = Math.max(latestModified, modified);
1162
1163            /* Check the timestamp of the primary key class */
1164            if (primaryKey != null) {
1165                pkFile = primaryKey.getClassFile(buildDir);
1166                modified = pkFile.lastModified();
1167                if (modified == -1) {
1168                    System.out.println("The class "
1169                                    + primaryKey.getQualifiedClassName() + "couldn't be "
1170                                    + "found on the classpath");
1171                    return -1;
1172                }
1173                latestModified = Math.max(latestModified, modified);
1174            } else {
1175                pkFile = null;
1176            }
1177
1178            /* Check the timestamp on the EJB implementation class.
1179             *
1180             * Note that if ONLY the implementation class has changed, it's not
1181             * necessary to rebuild the EJB stubs and skeletons. For this
1182             * reason, we ensure the file exists (using lastModified above), but
1183             * we DON'T compare it's timestamp with the timestamps of the home
1184             * and remote interfaces (because it's irrelevant in determining if
1185             * ejbc must be run)
1186             */

1187            implFile = implementation.getClassFile(buildDir);
1188            modified = implFile.lastModified();
1189            if (modified == -1) {
1190                System.out.println("The class "
1191                                + implementation.getQualifiedClassName()
1192                                + " couldn't be found on the classpath");
1193                return -1;
1194            }
1195
1196            String JavaDoc pathToFile = remote.getQualifiedClassName();
1197            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
1198            ejbFiles.put(pathToFile, remoteFile);
1199
1200            pathToFile = home.getQualifiedClassName();
1201            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
1202            ejbFiles.put(pathToFile, homeFile);
1203
1204            pathToFile = implementation.getQualifiedClassName();
1205            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
1206            ejbFiles.put(pathToFile, implFile);
1207
1208            if (pkFile != null) {
1209                pathToFile = primaryKey.getQualifiedClassName();
1210                pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
1211                ejbFiles.put(pathToFile, pkFile);
1212            }
1213
1214            return latestModified;
1215        }
1216
1217        /**
1218         * Examines each of the EJB stubs and skeletons in the destination
1219         * directory and returns the modification timestamp for the "oldest"
1220         * class. If one of the stubs or skeletons cannot be found, <code>-1
1221         * </code> is returned.
1222         *
1223         * @param dest The directory in which the EJB stubs and skeletons are
1224         * stored.
1225         * @return The modification timestamp for the "oldest" EJB stub or
1226         * skeleton. If one of the classes cannot be found, <code>-1
1227         * </code> is returned.
1228         * @throws BuildException If the canonical path of the destination
1229         * directory cannot be found.
1230         */

1231        private long destClassesModified(File JavaDoc destDir) {
1232            String JavaDoc[] classnames = classesToGenerate(); // List of all stubs & skels
1233
long destClassesModified = new Date JavaDoc().getTime(); // Earliest mod time
1234
boolean allClassesFound = true; // Has each been found?
1235

1236            /*
1237             * Loop through each stub/skeleton class that must be generated, and
1238             * determine (if all exist) which file has the most recent timestamp
1239             */

1240            for (int i = 0; i < classnames.length; i++) {
1241
1242                String JavaDoc pathToClass =
1243                        classnames[i].replace('.', File.separatorChar) + ".class";
1244                File JavaDoc classFile = new File JavaDoc(destDir, pathToClass);
1245
1246                /*
1247                 * Add each stub/skeleton class to the list of EJB files. Note
1248                 * that each class is added even if it doesn't exist now.
1249                 */

1250                ejbFiles.put(pathToClass, classFile);
1251
1252                allClassesFound = allClassesFound && classFile.exists();
1253
1254                if (allClassesFound) {
1255                    long fileMod = classFile.lastModified();
1256
1257                    /* Keep track of the oldest modification timestamp */
1258                    destClassesModified = Math.min(destClassesModified, fileMod);
1259                }
1260            }
1261
1262            return (allClassesFound) ? destClassesModified : -1;
1263        }
1264
1265        /**
1266         * Builds an array of class names which represent the stubs and
1267         * skeletons which need to be generated for a given EJB. The class
1268         * names are fully qualified. Nine classes are generated for all EJBs
1269         * while an additional six classes are generated for beans requiring
1270         * RMI/IIOP access.
1271         *
1272         * @return An array of Strings representing the fully-qualified class
1273         * names for the stubs and skeletons to be generated.
1274         */

1275        private String JavaDoc[] classesToGenerate() {
1276            String JavaDoc[] classnames = (iiop)
1277                ? new String JavaDoc[NUM_CLASSES_WITH_IIOP]
1278                : new String JavaDoc[NUM_CLASSES_WITHOUT_IIOP];
1279
1280            final String JavaDoc remotePkg = remote.getPackageName() + ".";
1281            final String JavaDoc remoteClass = remote.getClassName();
1282            final String JavaDoc homePkg = home.getPackageName() + ".";
1283            final String JavaDoc homeClass = home.getClassName();
1284            final String JavaDoc implPkg = implementation.getPackageName() + ".";
1285            final String JavaDoc implFullClass = implementation.getQualifiedWithUnderscores();
1286            int index = 0;
1287
1288            classnames[index++] = implPkg + "ejb_fac_" + implFullClass;
1289            classnames[index++] = implPkg + "ejb_home_" + implFullClass;
1290            classnames[index++] = implPkg + "ejb_skel_" + implFullClass;
1291            classnames[index++] = remotePkg + "ejb_kcp_skel_" + remoteClass;
1292            classnames[index++] = homePkg + "ejb_kcp_skel_" + homeClass;
1293            classnames[index++] = remotePkg + "ejb_kcp_stub_" + remoteClass;
1294            classnames[index++] = homePkg + "ejb_kcp_stub_" + homeClass;
1295            classnames[index++] = remotePkg + "ejb_stub_" + remoteClass;
1296            classnames[index++] = homePkg + "ejb_stub_" + homeClass;
1297
1298            if (!iiop) {
1299                return classnames;
1300            }
1301
1302            classnames[index++] = "org.omg.stub." + remotePkg + "_"
1303                                    + remoteClass + "_Stub";
1304            classnames[index++] = "org.omg.stub." + homePkg + "_"
1305                                    + homeClass + "_Stub";
1306            classnames[index++] = "org.omg.stub." + remotePkg
1307                                    + "_ejb_RmiCorbaBridge_"
1308                                    + remoteClass + "_Tie";
1309            classnames[index++] = "org.omg.stub." + homePkg
1310                                    + "_ejb_RmiCorbaBridge_"
1311                                    + homeClass + "_Tie";
1312
1313            classnames[index++] = remotePkg + "ejb_RmiCorbaBridge_"
1314                                                        + remoteClass;
1315            classnames[index++] = homePkg + "ejb_RmiCorbaBridge_" + homeClass;
1316
1317            return classnames;
1318        }
1319
1320        /**
1321         * Convenience method which creates a String representation of all the
1322         * instance variables of an EjbInfo object.
1323         *
1324         * @return A String representing the EjbInfo instance.
1325         */

1326        public String JavaDoc toString() {
1327            String JavaDoc s = "EJB name: " + name
1328                        + "\n\r home: " + home
1329                        + "\n\r remote: " + remote
1330                        + "\n\r impl: " + implementation
1331                        + "\n\r primaryKey: " + primaryKey
1332                        + "\n\r beantype: " + beantype
1333                        + "\n\r cmp: " + cmp
1334                        + "\n\r iiop: " + iiop
1335                        + "\n\r hasession: " + hasession;
1336
1337            Iterator JavaDoc i = cmpDescriptors.iterator();
1338            while (i.hasNext()) {
1339                s += "\n\r CMP Descriptor: " + i.next();
1340            }
1341
1342            return s;
1343        }
1344
1345    } // End of EjbInfo inner class
1346

1347    /**
1348     * Convenience class used to represent the fully qualified name of a Java
1349     * class. It provides an easy way to retrieve components of the class name
1350     * in a format that is convenient for building iAS stubs and skeletons.
1351     *
1352     */

1353    private static class Classname {
1354        private String JavaDoc qualifiedName; // Fully qualified name of the Java class
1355
private String JavaDoc packageName; // Name of the package for this class
1356
private String JavaDoc className; // Name of the class without the package
1357

1358        /**
1359         * This constructor builds an object which represents the name of a Java
1360         * class.
1361         *
1362         * @param qualifiedName String representing the fully qualified class
1363         * name of the Java class.
1364         */

1365        public Classname(String JavaDoc qualifiedName) {
1366            if (qualifiedName == null) {
1367                return;
1368            }
1369
1370            this.qualifiedName = qualifiedName;
1371
1372            int index = qualifiedName.lastIndexOf('.');
1373            if (index == -1) {
1374                className = qualifiedName;
1375                packageName = "";
1376            } else {
1377                packageName = qualifiedName.substring(0, index);
1378                className = qualifiedName.substring(index + 1);
1379            }
1380        }
1381
1382        /**
1383         * Gets the fully qualified name of the Java class.
1384         *
1385         * @return String representing the fully qualified class name.
1386         */

1387        public String JavaDoc getQualifiedClassName() {
1388            return qualifiedName;
1389        }
1390
1391        /**
1392         * Gets the package name for the Java class.
1393         *
1394         * @return String representing the package name for the class.
1395         */

1396        public String JavaDoc getPackageName() {
1397            return packageName;
1398        }
1399
1400        /**
1401         * Gets the Java class name without the package structure.
1402         *
1403         * @return String representing the name for the class.
1404         */

1405        public String JavaDoc getClassName() {
1406            return className;
1407        }
1408
1409        /**
1410         * Gets the fully qualified name of the Java class with underscores
1411         * separating the components of the class name rather than periods.
1412         * This format is used in naming some of the stub and skeleton classes
1413         * for the iPlanet Application Server.
1414         *
1415         * @return String representing the fully qualified class name using
1416         * underscores instead of periods.
1417         */

1418        public String JavaDoc getQualifiedWithUnderscores() {
1419            return qualifiedName.replace('.', '_');
1420        }
1421
1422        /**
1423         * Returns a File which references the class relative to the specified
1424         * directory. Note that the class file may or may not exist.
1425         *
1426         * @param directory A File referencing the base directory containing
1427         * class files.
1428         * @return File referencing this class.
1429         */

1430        public File JavaDoc getClassFile(File JavaDoc directory) {
1431            String JavaDoc pathToFile = qualifiedName.replace('.', File.separatorChar)
1432                                            + ".class";
1433            return new File JavaDoc(directory, pathToFile);
1434        }
1435
1436        /**
1437         * String representation of this class name. It returns the fully
1438         * qualified class name.
1439         *
1440         * @return String representing the fully qualified class name.
1441         */

1442        public String JavaDoc toString() {
1443            return getQualifiedClassName();
1444        }
1445    } // End of Classname inner class
1446

1447
1448    /**
1449     * Thread class used to redirect output from an <code>InputStream</code> to
1450     * the JRE standard output. This class may be used to redirect output from
1451     * an external process to the standard output.
1452     *
1453     */

1454    private static class RedirectOutput extends Thread JavaDoc {
1455
1456        private InputStream JavaDoc stream; // Stream to read and redirect to standard output
1457

1458        /**
1459         * Constructs a new instance that will redirect output from the
1460         * specified stream to the standard output.
1461         *
1462         * @param stream InputStream which will be read and redirected to the
1463         * standard output.
1464         */

1465        public RedirectOutput(InputStream JavaDoc stream) {
1466            this.stream = stream;
1467        }
1468
1469        /**
1470         * Reads text from the input stream and redirects it to standard output
1471         * using a separate thread.
1472         */

1473        public void run() {
1474            BufferedReader JavaDoc reader = new BufferedReader JavaDoc(
1475                                            new InputStreamReader JavaDoc(stream));
1476            String JavaDoc text;
1477            try {
1478                while ((text = reader.readLine()) != null) {
1479                    System.out.println(text);
1480                }
1481            } catch (IOException JavaDoc e) {
1482                e.printStackTrace();
1483            } finally {
1484                try {
1485                    reader.close();
1486                } catch (IOException JavaDoc e) {
1487                    // Do nothing
1488
}
1489            }
1490        }
1491    } // End of RedirectOutput inner class
1492

1493}
1494
Popular Tags