1 | /*
|
---|
2 | * Copyright 2001-2002,2004 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 |
|
---|
18 | package org.apache.tools.ant.taskdefs.optional.ejb;
|
---|
19 |
|
---|
20 | import java.io.File;
|
---|
21 | import java.io.IOException;
|
---|
22 | import java.util.Hashtable;
|
---|
23 | import javax.xml.parsers.SAXParser;
|
---|
24 | import org.apache.tools.ant.BuildException;
|
---|
25 | import org.apache.tools.ant.Project;
|
---|
26 | import org.xml.sax.SAXException;
|
---|
27 |
|
---|
28 | /**
|
---|
29 | * This class is used to generate iPlanet Application Server (iAS) 6.0 stubs and
|
---|
30 | * skeletons and build an EJB Jar file. It is designed to be used with the Ant
|
---|
31 | * <code>ejbjar</code> task. If only stubs and skeletons need to be generated
|
---|
32 | * (in other words, if no JAR file needs to be created), refer to the
|
---|
33 | * <code>iplanet-ejbc</code> task and the <code>IPlanetEjbcTask</code> class.
|
---|
34 | * <p>
|
---|
35 | * The following attributes may be specified by the user:
|
---|
36 | * <ul>
|
---|
37 | * <li><i>destdir</i> -- The base directory into which the generated JAR
|
---|
38 | * files will be written. Each JAR file is written
|
---|
39 | * in directories which correspond to their location
|
---|
40 | * within the "descriptordir" namespace. This is a
|
---|
41 | * required attribute.
|
---|
42 | * <li><i>classpath</i> -- The classpath used when generating EJB stubs and
|
---|
43 | * skeletons. This is an optional attribute (if
|
---|
44 | * omitted, the classpath specified in the "ejbjar"
|
---|
45 | * parent task will be used). If specified, the
|
---|
46 | * classpath elements will be prepended to the
|
---|
47 | * classpath specified in the parent "ejbjar" task.
|
---|
48 | * Note that nested "classpath" elements may also be
|
---|
49 | * used.
|
---|
50 | * <li><i>keepgenerated</i> -- Indicates whether or not the Java source
|
---|
51 | * files which are generated by ejbc will be
|
---|
52 | * saved or automatically deleted. If "yes",
|
---|
53 | * the source files will be retained. This is
|
---|
54 | * an optional attribute (if omitted, it
|
---|
55 | * defaults to "no").
|
---|
56 | * <li><i>debug</i> -- Indicates whether or not the ejbc utility should
|
---|
57 | * log additional debugging statements to the standard
|
---|
58 | * output. If "yes", the additional debugging statements
|
---|
59 | * will be generated (if omitted, it defaults to "no").
|
---|
60 | * <li><i>iashome</i> -- May be used to specify the "home" directory for
|
---|
61 | * this iPlanet Application server installation. This
|
---|
62 | * is used to find the ejbc utility if it isn't
|
---|
63 | * included in the user's system path. This is an
|
---|
64 | * optional attribute (if specified, it should refer
|
---|
65 | * to the <code>[install-location]/iplanet/ias6/ias
|
---|
66 | * </code> directory). If omitted, the ejbc utility
|
---|
67 | * must be on the user's system path.
|
---|
68 | * <li><i>suffix</i> -- String value appended to the JAR filename when
|
---|
69 | * creating each JAR. This attribute is not required
|
---|
70 | * (if omitted, it defaults to ".jar").
|
---|
71 | * </ul>
|
---|
72 | * <p>
|
---|
73 | * For each EJB descriptor found in the "ejbjar" parent task, this deployment
|
---|
74 | * tool will locate the three classes that comprise the EJB. If these class
|
---|
75 | * files cannot be located in the specified <code>srcdir</code> directory, the
|
---|
76 | * task will fail. The task will also attempt to locate the EJB stubs and
|
---|
77 | * skeletons in this directory. If found, the timestamps on the stubs and
|
---|
78 | * skeletons will be checked to ensure they are up to date. Only if these files
|
---|
79 | * cannot be found or if they are out of date will ejbc be called.
|
---|
80 | *
|
---|
81 | * @see IPlanetEjbc
|
---|
82 | */
|
---|
83 | public class IPlanetDeploymentTool extends GenericDeploymentTool {
|
---|
84 |
|
---|
85 | /* Attributes set by the Ant build file */
|
---|
86 | private File iashome;
|
---|
87 | private String jarSuffix = ".jar";
|
---|
88 | private boolean keepgenerated = false;
|
---|
89 | private boolean debug = false;
|
---|
90 |
|
---|
91 | /*
|
---|
92 | * Filenames of the standard EJB descriptor (which is passed to this class
|
---|
93 | * from the parent "ejbjar" task) and the iAS-specific EJB descriptor
|
---|
94 | * (whose name is determined by this class). Both filenames are relative
|
---|
95 | * to the directory specified by the "srcdir" attribute in the ejbjar task.
|
---|
96 | */
|
---|
97 | private String descriptorName;
|
---|
98 | private String iasDescriptorName;
|
---|
99 |
|
---|
100 | /*
|
---|
101 | * The displayName variable stores the value of the "display-name" element
|
---|
102 | * from the standard EJB descriptor. As a future enhancement to this task,
|
---|
103 | * we may determine the name of the EJB JAR file using this display-name,
|
---|
104 | * but this has not be implemented yet.
|
---|
105 | */
|
---|
106 | private String displayName;
|
---|
107 |
|
---|
108 | /*
|
---|
109 | * Regardless of the name of the iAS-specific EJB descriptor file, it will
|
---|
110 | * written in the completed JAR file as "ias-ejb-jar.xml". This is the
|
---|
111 | * naming convention implemented by iAS.
|
---|
112 | */
|
---|
113 | private static final String IAS_DD = "ias-ejb-jar.xml";
|
---|
114 |
|
---|
115 | /**
|
---|
116 | * Setter method used to store the "home" directory of the user's iAS
|
---|
117 | * installation. The directory specified should typically be
|
---|
118 | * <code>[install-location]/iplanet/ias6/ias</code>.
|
---|
119 | *
|
---|
120 | * @param iashome The home directory for the user's iAS installation.
|
---|
121 | */
|
---|
122 | public void setIashome(File iashome) {
|
---|
123 | this.iashome = iashome;
|
---|
124 | }
|
---|
125 |
|
---|
126 | /**
|
---|
127 | * Setter method used to specify whether the Java source files generated by
|
---|
128 | * the ejbc utility should be saved or automatically deleted.
|
---|
129 | *
|
---|
130 | * @param keepgenerated boolean which, if <code>true</code>, indicates that
|
---|
131 | * Java source files generated by ejbc for the stubs
|
---|
132 | * and skeletons should be kept.
|
---|
133 | */
|
---|
134 | public void setKeepgenerated(boolean keepgenerated) {
|
---|
135 | this.keepgenerated = keepgenerated;
|
---|
136 | }
|
---|
137 |
|
---|
138 | /**
|
---|
139 | * Sets whether or not debugging output will be generated when ejbc is
|
---|
140 | * executed.
|
---|
141 | *
|
---|
142 | * @param debug A boolean indicating if debugging output should be generated
|
---|
143 | */
|
---|
144 | public void setDebug(boolean debug) {
|
---|
145 | this.debug = debug;
|
---|
146 | }
|
---|
147 |
|
---|
148 | /**
|
---|
149 | * Setter method used to specify the filename suffix (for example, ".jar")
|
---|
150 | * for the JAR files to be created.
|
---|
151 | *
|
---|
152 | * @param jarSuffix The string to use as the JAR filename suffix.
|
---|
153 | */
|
---|
154 | public void setSuffix(String jarSuffix) {
|
---|
155 | this.jarSuffix = jarSuffix;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /**
|
---|
159 | * Since iAS doesn't generate a "generic" JAR as part of its processing,
|
---|
160 | * this attribute is ignored and a warning message is displayed to the user.
|
---|
161 | *
|
---|
162 | * @param inString the string to use as the suffix. This parameter is
|
---|
163 | * ignored.
|
---|
164 | */
|
---|
165 | public void setGenericJarSuffix(String inString) {
|
---|
166 | log("Since a generic JAR file is not created during processing, the "
|
---|
167 | + "iPlanet Deployment Tool does not support the "
|
---|
168 | + "\"genericjarsuffix\" attribute. It will be ignored.",
|
---|
169 | Project.MSG_WARN);
|
---|
170 | }
|
---|
171 |
|
---|
172 | public void processDescriptor(String descriptorName, SAXParser saxParser) {
|
---|
173 | this.descriptorName = descriptorName;
|
---|
174 | this.iasDescriptorName = null;
|
---|
175 |
|
---|
176 | log("iPlanet Deployment Tool processing: " + descriptorName + " (and "
|
---|
177 | + getIasDescriptorName() + ")", Project.MSG_VERBOSE);
|
---|
178 |
|
---|
179 | super.processDescriptor(descriptorName, saxParser);
|
---|
180 | }
|
---|
181 |
|
---|
182 | /**
|
---|
183 | * Verifies that the user selections are valid.
|
---|
184 | *
|
---|
185 | * @param descriptorFileName String representing the file name of an EJB
|
---|
186 | * descriptor to be processed
|
---|
187 | * @param saxParser SAXParser which may be used to parse the XML
|
---|
188 | * descriptor
|
---|
189 | * @throws BuildException If the user selections are invalid.
|
---|
190 | */
|
---|
191 | protected void checkConfiguration(String descriptorFileName,
|
---|
192 | SAXParser saxParser) throws BuildException {
|
---|
193 |
|
---|
194 | int startOfName = descriptorFileName.lastIndexOf(File.separatorChar) + 1;
|
---|
195 | String stdXml = descriptorFileName.substring(startOfName);
|
---|
196 | if (stdXml.equals(EJB_DD) && (getConfig().baseJarName == null)) {
|
---|
197 | String msg = "No name specified for the completed JAR file. The EJB"
|
---|
198 | + " descriptor should be prepended with the JAR "
|
---|
199 | + "name or it should be specified using the "
|
---|
200 | + "attribute \"basejarname\" in the \"ejbjar\" task.";
|
---|
201 | throw new BuildException(msg, getLocation());
|
---|
202 | }
|
---|
203 |
|
---|
204 | File iasDescriptor = new File(getConfig().descriptorDir,
|
---|
205 | getIasDescriptorName());
|
---|
206 | if ((!iasDescriptor.exists()) || (!iasDescriptor.isFile())) {
|
---|
207 | String msg = "The iAS-specific EJB descriptor ("
|
---|
208 | + iasDescriptor + ") was not found.";
|
---|
209 | throw new BuildException(msg, getLocation());
|
---|
210 | }
|
---|
211 |
|
---|
212 | if ((iashome != null) && (!iashome.isDirectory())) {
|
---|
213 | String msg = "If \"iashome\" is specified, it must be a valid "
|
---|
214 | + "directory (it was set to " + iashome + ").";
|
---|
215 | throw new BuildException(msg, getLocation());
|
---|
216 | }
|
---|
217 | }
|
---|
218 |
|
---|
219 | /**
|
---|
220 | * This method returns a list of EJB files found when the specified EJB
|
---|
221 | * descriptor is parsed and processed.
|
---|
222 | *
|
---|
223 | * @param descriptorFileName String representing the file name of an EJB
|
---|
224 | * descriptor to be processed
|
---|
225 | * @param saxParser SAXParser which may be used to parse the XML
|
---|
226 | * descriptor
|
---|
227 | * @return Hashtable of EJB class (and other) files to be
|
---|
228 | * added to the completed JAR file
|
---|
229 | * @throws IOException An IOException from the parser, possibly from
|
---|
230 | * the byte stream or character stream
|
---|
231 | * @throws SAXException Any SAX exception, possibly wrapping another
|
---|
232 | * exception
|
---|
233 | */
|
---|
234 | protected Hashtable parseEjbFiles(String descriptorFileName,
|
---|
235 | SAXParser saxParser) throws IOException, SAXException {
|
---|
236 |
|
---|
237 | Hashtable files;
|
---|
238 |
|
---|
239 | /* Build and populate an instance of the ejbc utility */
|
---|
240 | IPlanetEjbc ejbc = new IPlanetEjbc(
|
---|
241 | new File(getConfig().descriptorDir,
|
---|
242 | descriptorFileName),
|
---|
243 | new File(getConfig().descriptorDir,
|
---|
244 | getIasDescriptorName()),
|
---|
245 | getConfig().srcDir,
|
---|
246 | getCombinedClasspath().toString(),
|
---|
247 | saxParser);
|
---|
248 | ejbc.setRetainSource(keepgenerated);
|
---|
249 | ejbc.setDebugOutput(debug);
|
---|
250 | if (iashome != null) {
|
---|
251 | ejbc.setIasHomeDir(iashome);
|
---|
252 | }
|
---|
253 |
|
---|
254 | /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
|
---|
255 | try {
|
---|
256 | ejbc.execute();
|
---|
257 | } catch (IPlanetEjbc.EjbcException e) {
|
---|
258 | throw new BuildException("An error has occurred while trying to "
|
---|
259 | + "execute the iAS ejbc utility", e, getLocation());
|
---|
260 | }
|
---|
261 |
|
---|
262 | displayName = ejbc.getDisplayName();
|
---|
263 | files = ejbc.getEjbFiles();
|
---|
264 |
|
---|
265 | /* Add CMP descriptors to the list of EJB files */
|
---|
266 | String[] cmpDescriptors = ejbc.getCmpDescriptors();
|
---|
267 | if (cmpDescriptors.length > 0) {
|
---|
268 | File baseDir = getConfig().descriptorDir;
|
---|
269 |
|
---|
270 | int endOfPath = descriptorFileName.lastIndexOf(File.separator);
|
---|
271 | String relativePath = descriptorFileName.substring(0, endOfPath + 1);
|
---|
272 |
|
---|
273 | for (int i = 0; i < cmpDescriptors.length; i++) {
|
---|
274 | int endOfCmp = cmpDescriptors[i].lastIndexOf('/');
|
---|
275 | String cmpDescriptor = cmpDescriptors[i].substring(endOfCmp + 1);
|
---|
276 |
|
---|
277 | File cmpFile = new File(baseDir, relativePath + cmpDescriptor);
|
---|
278 | if (!cmpFile.exists()) {
|
---|
279 | throw new BuildException("The CMP descriptor file ("
|
---|
280 | + cmpFile + ") could not be found.", getLocation());
|
---|
281 | }
|
---|
282 | files.put(cmpDescriptors[i], cmpFile);
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | return files;
|
---|
287 | }
|
---|
288 |
|
---|
289 | /**
|
---|
290 | * Add the iAS-specific EJB descriptor to the list of files which will be
|
---|
291 | * written to the JAR file.
|
---|
292 | *
|
---|
293 | * @param ejbFiles Hashtable of EJB class (and other) files to be added to
|
---|
294 | * the completed JAR file.
|
---|
295 | * @param ddPrefix not used
|
---|
296 | */
|
---|
297 | protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
|
---|
298 | ejbFiles.put(META_DIR + IAS_DD, new File(getConfig().descriptorDir,
|
---|
299 | getIasDescriptorName()));
|
---|
300 | }
|
---|
301 |
|
---|
302 | /**
|
---|
303 | * Get the name of the Jar that will be written. The modification date
|
---|
304 | * of this jar will be checked against the dependent bean classes.
|
---|
305 | *
|
---|
306 | * @param baseName String name of the EJB JAR file to be written (without
|
---|
307 | * a filename extension).
|
---|
308 | *
|
---|
309 | * @return File representing the JAR file which will be written.
|
---|
310 | */
|
---|
311 | File getVendorOutputJarFile(String baseName) {
|
---|
312 | File jarFile = new File(getDestDir(), baseName + jarSuffix);
|
---|
313 | log("JAR file name: " + jarFile.toString(), Project.MSG_VERBOSE);
|
---|
314 | return jarFile;
|
---|
315 | }
|
---|
316 |
|
---|
317 | /**
|
---|
318 | * The iAS ejbc utility doesn't require the Public ID of the descriptor's
|
---|
319 | * DTD for it to process correctly--this method always returns <code>null
|
---|
320 | * </code>.
|
---|
321 | *
|
---|
322 | * @return <code>null</code>.
|
---|
323 | */
|
---|
324 | protected String getPublicId() {
|
---|
325 | return null;
|
---|
326 | }
|
---|
327 |
|
---|
328 | /**
|
---|
329 | * Determines the name of the iAS-specific EJB descriptor using the
|
---|
330 | * specified standard EJB descriptor name. In general, the standard
|
---|
331 | * descriptor will be named "[basename]-ejb-jar.xml", and this method will
|
---|
332 | * return "[basename]-ias-ejb-jar.xml".
|
---|
333 | *
|
---|
334 | * @return The name of the iAS-specific EJB descriptor file.
|
---|
335 | */
|
---|
336 | private String getIasDescriptorName() {
|
---|
337 |
|
---|
338 | /* Only calculate the descriptor name once */
|
---|
339 | if (iasDescriptorName != null) {
|
---|
340 | return iasDescriptorName;
|
---|
341 | }
|
---|
342 |
|
---|
343 | String path = ""; // Directory path of the EJB descriptor
|
---|
344 | String basename; // Filename appearing before name terminator
|
---|
345 | String remainder; // Filename appearing after the name terminator
|
---|
346 |
|
---|
347 | /* Find the end of the standard descriptor's relative path */
|
---|
348 | int startOfFileName = descriptorName.lastIndexOf(File.separatorChar);
|
---|
349 | if (startOfFileName != -1) {
|
---|
350 | path = descriptorName.substring(0, startOfFileName + 1);
|
---|
351 | }
|
---|
352 |
|
---|
353 | /* Check to see if the standard name is used (there's no basename) */
|
---|
354 | if (descriptorName.substring(startOfFileName + 1).equals(EJB_DD)) {
|
---|
355 | basename = "";
|
---|
356 | remainder = EJB_DD;
|
---|
357 |
|
---|
358 | } else {
|
---|
359 | int endOfBaseName = descriptorName.indexOf(
|
---|
360 | getConfig().baseNameTerminator,
|
---|
361 | startOfFileName);
|
---|
362 | /*
|
---|
363 | * Check for the odd case where the terminator and/or filename
|
---|
364 | * extension aren't found. These will ensure "ias-" appears at the
|
---|
365 | * end of the name and before the '.' (if present).
|
---|
366 | */
|
---|
367 | if (endOfBaseName < 0) {
|
---|
368 | endOfBaseName = descriptorName.lastIndexOf('.') - 1;
|
---|
369 | if (endOfBaseName < 0) {
|
---|
370 | endOfBaseName = descriptorName.length() - 1;
|
---|
371 | }
|
---|
372 | }
|
---|
373 |
|
---|
374 | basename = descriptorName.substring(startOfFileName + 1,
|
---|
375 | endOfBaseName + 1);
|
---|
376 | remainder = descriptorName.substring(endOfBaseName + 1);
|
---|
377 | }
|
---|
378 |
|
---|
379 | iasDescriptorName = path + basename + "ias-" + remainder;
|
---|
380 | return iasDescriptorName;
|
---|
381 | }
|
---|
382 | }
|
---|