001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs.optional.ejb;
020:
021: import java.io.File;
022: import java.io.IOException;
023: import javax.xml.parsers.ParserConfigurationException;
024: import javax.xml.parsers.SAXParser;
025: import javax.xml.parsers.SAXParserFactory;
026: import org.apache.tools.ant.BuildException;
027: import org.apache.tools.ant.Task;
028: import org.apache.tools.ant.types.Path;
029: import org.xml.sax.SAXException;
030:
031: /**
032: * Compiles EJB stubs and skeletons for the iPlanet Application Server.
033: * The EJBs to be processed are specified by the EJB 1.1 standard XML
034: * descriptor, and additional attributes are obtained from the iPlanet Application
035: * Server-specific XML descriptor. Since the XML descriptors can include
036: * multiple EJBs, this is a convenient way of specifying many EJBs in a single
037: * Ant task. The following attributes are allowed:
038: * <ul>
039: * <li><i>ejbdescriptor</i> -- Standard EJB 1.1 XML descriptor (typically
040: * titled "ejb-jar.xml"). This attribute is
041: * required.
042: * <li><i>iasdescriptor</i> -- EJB XML descriptor for iPlanet Application
043: * Server (typically titled "ias-ejb-jar.xml).
044: * This attribute is required.
045: * <li><i>dest</i> -- The is the base directory where the RMI stubs and
046: * skeletons are written. In addition, the class files
047: * for each bean (home interface, remote interface, and
048: * EJB implementation) must be found in this directory.
049: * This attribute is required.
050: * <li><i>classpath</i> -- The classpath used when generating EJB stubs and
051: * skeletons. This is an optional attribute (if
052: * omitted, the classpath specified when Ant was
053: * started will be used). Nested "classpath"
054: * elements may also be used.
055: * <li><i>keepgenerated</i> -- Indicates whether or not the Java source
056: * files which are generated by ejbc will be
057: * saved or automatically deleted. If "yes",
058: * the source files will be retained. This is
059: * an optional attribute (if omitted, it
060: * defaults to "no").
061: * <li><i>debug</i> -- Indicates whether or not the ejbc utility should
062: * log additional debugging statements to the standard
063: * output. If "yes", the additional debugging statements
064: * will be generated (if omitted, it defaults to "no").
065: * <li><i>iashome</i> -- May be used to specify the "home" directory for
066: * this iPlanet Application Server installation. This
067: * is used to find the ejbc utility if it isn't
068: * included in the user's system path. This is an
069: * optional attribute (if specified, it should refer
070: * to the <code>[install-location]/iplanet/ias6/ias
071: * </code> directory). If omitted, the ejbc utility
072: * must be on the user's system path.
073: * </ul>
074: * <p>
075: * For each EJB specified, this task will locate the three classes that comprise
076: * the EJB. If these class files cannot be located in the <code>dest</code>
077: * directory, the task will fail. The task will also attempt to locate the EJB
078: * stubs and skeletons in this directory. If found, the timestamps on the
079: * stubs and skeletons will be checked to ensure they are up to date. Only if
080: * these files cannot be found or if they are out of date will ejbc be called
081: * to generate new stubs and skeletons.
082: *
083: * @see IPlanetEjbc
084: *
085: * @ant.task name="iplanet-ejbc" category="ejb"
086: */
087: public class IPlanetEjbcTask extends Task {
088:
089: /* Attributes set by the Ant build file */
090: private File ejbdescriptor;
091: private File iasdescriptor;
092: private File dest;
093: private Path classpath;
094: private boolean keepgenerated = false;
095: private boolean debug = false;
096: private File iashome;
097:
098: /**
099: * Sets the location of the standard XML EJB descriptor. Typically, this
100: * file is named "ejb-jar.xml".
101: *
102: * @param ejbdescriptor The name and location of the EJB descriptor.
103: */
104: public void setEjbdescriptor(File ejbdescriptor) {
105: this .ejbdescriptor = ejbdescriptor;
106: }
107:
108: /**
109: * Sets the location of the iAS-specific XML EJB descriptor. Typically,
110: * this file is named "ias-ejb-jar.xml".
111: *
112: * @param iasdescriptor The name and location of the iAS-specific EJB
113: * descriptor.
114: */
115: public void setIasdescriptor(File iasdescriptor) {
116: this .iasdescriptor = iasdescriptor;
117: }
118:
119: /**
120: * Sets the destination directory where the EJB source classes must exist
121: * and where the stubs and skeletons will be written. The destination
122: * directory must exist before this task is executed.
123: *
124: * @param dest The directory where the compiled classes will be written.
125: */
126: public void setDest(File dest) {
127: this .dest = dest;
128: }
129:
130: /**
131: * Sets the classpath to be used when compiling the EJB stubs and skeletons.
132: *
133: * @param classpath The classpath to be used.
134: */
135: public void setClasspath(Path classpath) {
136: if (this .classpath == null) {
137: this .classpath = classpath;
138: } else {
139: this .classpath.append(classpath);
140: }
141: }
142:
143: /**
144: * Adds to the classpath used when compiling the EJB stubs and skeletons.
145: * @return the class path.
146: */
147: public Path createClasspath() {
148: if (classpath == null) {
149: classpath = new Path(getProject());
150: }
151: return classpath.createPath();
152: }
153:
154: /**
155: * If true, the Java source files which are generated by ejbc will be saved .
156: *
157: * @param keepgenerated A boolean indicating if the Java source files for
158: * the stubs and skeletons should be retained.
159: */
160: public void setKeepgenerated(boolean keepgenerated) {
161: this .keepgenerated = keepgenerated;
162: }
163:
164: /**
165: * If true, debugging output will be generated when ejbc is
166: * executed.
167: *
168: * @param debug A boolean indicating if debugging output should be generated
169: */
170: public void setDebug(boolean debug) {
171: this .debug = debug;
172: }
173:
174: /**
175: * May be used to specify the "home" directory for this iAS installation.
176: * The directory specified should typically be
177: * <code>[install-location]/iplanet/ias6/ias</code>.
178: *
179: * @param iashome The home directory for the user's iAS installation.
180: */
181: public void setIashome(File iashome) {
182: this .iashome = iashome;
183: }
184:
185: /**
186: * Does the work.
187: * @throws BuildException if there is a problem.
188: */
189: public void execute() throws BuildException {
190: checkConfiguration();
191:
192: executeEjbc(getParser());
193: }
194:
195: /**
196: * Verifies that the user selections are valid.
197: *
198: * @throws BuildException If the user selections are invalid.
199: */
200: private void checkConfiguration() throws BuildException {
201:
202: if (ejbdescriptor == null) {
203: String msg = "The standard EJB descriptor must be specified using "
204: + "the \"ejbdescriptor\" attribute.";
205: throw new BuildException(msg, getLocation());
206: }
207: if ((!ejbdescriptor.exists()) || (!ejbdescriptor.isFile())) {
208: String msg = "The standard EJB descriptor ("
209: + ejbdescriptor
210: + ") was not found or isn't a file.";
211: throw new BuildException(msg, getLocation());
212: }
213:
214: if (iasdescriptor == null) {
215: String msg = "The iAS-speific XML descriptor must be specified using"
216: + " the \"iasdescriptor\" attribute.";
217: throw new BuildException(msg, getLocation());
218: }
219: if ((!iasdescriptor.exists()) || (!iasdescriptor.isFile())) {
220: String msg = "The iAS-specific XML descriptor ("
221: + iasdescriptor
222: + ") was not found or isn't a file.";
223: throw new BuildException(msg, getLocation());
224: }
225:
226: if (dest == null) {
227: String msg = "The destination directory must be specified using "
228: + "the \"dest\" attribute.";
229: throw new BuildException(msg, getLocation());
230: }
231: if ((!dest.exists()) || (!dest.isDirectory())) {
232: String msg = "The destination directory (" + dest
233: + ") was not " + "found or isn't a directory.";
234: throw new BuildException(msg, getLocation());
235: }
236:
237: if ((iashome != null) && (!iashome.isDirectory())) {
238: String msg = "If \"iashome\" is specified, it must be a valid "
239: + "directory (it was set to " + iashome + ").";
240: throw new BuildException(msg, getLocation());
241: }
242: }
243:
244: /**
245: * Returns a SAXParser that may be used to process the XML descriptors.
246: *
247: * @return Parser which may be used to process the EJB descriptors.
248: * @throws BuildException If the parser cannot be created or configured.
249: */
250: private SAXParser getParser() throws BuildException {
251:
252: SAXParser saxParser = null;
253: try {
254: SAXParserFactory saxParserFactory = SAXParserFactory
255: .newInstance();
256: saxParserFactory.setValidating(true);
257: saxParser = saxParserFactory.newSAXParser();
258: } catch (SAXException e) {
259: String msg = "Unable to create a SAXParser: "
260: + e.getMessage();
261: throw new BuildException(msg, e, getLocation());
262: } catch (ParserConfigurationException e) {
263: String msg = "Unable to create a SAXParser: "
264: + e.getMessage();
265: throw new BuildException(msg, e, getLocation());
266: }
267:
268: return saxParser;
269: }
270:
271: /**
272: * Executes the EJBc utility using the SAXParser provided.
273: *
274: * @param saxParser SAXParser that may be used to process the EJB
275: * descriptors
276: * @throws BuildException If there is an error reading or parsing the XML
277: * descriptors
278: */
279: private void executeEjbc(SAXParser saxParser) throws BuildException {
280: IPlanetEjbc ejbc = new IPlanetEjbc(ejbdescriptor,
281: iasdescriptor, dest, getClasspath().toString(),
282: saxParser);
283: ejbc.setRetainSource(keepgenerated);
284: ejbc.setDebugOutput(debug);
285: if (iashome != null) {
286: ejbc.setIasHomeDir(iashome);
287: }
288:
289: try {
290: ejbc.execute();
291: } catch (IOException e) {
292: String msg = "An IOException occurred while trying to read the XML "
293: + "descriptor file: " + e.getMessage();
294: throw new BuildException(msg, e, getLocation());
295: } catch (SAXException e) {
296: String msg = "A SAXException occurred while trying to read the XML "
297: + "descriptor file: " + e.getMessage();
298: throw new BuildException(msg, e, getLocation());
299: } catch (IPlanetEjbc.EjbcException e) {
300: String msg = "An exception occurred while trying to run the ejbc "
301: + "utility: " + e.getMessage();
302: throw new BuildException(msg, e, getLocation());
303: }
304: }
305:
306: /**
307: * Returns the CLASSPATH to be used when calling EJBc. If no user CLASSPATH
308: * is specified, the System classpath is returned instead.
309: *
310: * @return Path The classpath to be used for EJBc.
311: */
312: private Path getClasspath() {
313: Path cp = null;
314: if (classpath == null) {
315: cp = (new Path(getProject())).concatSystemClasspath("last");
316: } else {
317: cp = classpath.concatSystemClasspath("ignore");
318: }
319:
320: return cp;
321: }
322: }
|