1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
|
/*
* Copyright 2000-2004 Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional.ejb;
// Standard java imports
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.xml.sax.SAXException;
/**
* Provides automated EJB JAR file creation.
* <p>
* Extends the
* MatchingTask class provided in the default ant distribution to provide a
* directory scanning EJB jarfile generator.
* </p>
*
* <p>
* The task works by taking the deployment descriptors one at a time and
* parsing them to locate the names of the classes which should be placed in
* the jar. The classnames are translated to java.io.Files by replacing
* periods with File.separatorChar and resolving the generated filename as a
* relative path under the srcDir attribute. All necessary files are then
* assembled into a jarfile. One jarfile is constructed for each deployment
* descriptor found.
* </p>
*
* @author <a href="mailto:tfennell@sapient.com">Tim Fennell</a>
* @author Conor MacNeill
* @author <a href="mailto:rob@springwellfarms.ca">Rob van Oostrum</a>
* */
public class EjbJar extends MatchingTask {
/**
* Inner class used to record information about the location of a local DTD
*/
public static class DTDLocation
extends org.apache.tools.ant.types.DTDLocation {
}
/**
* A class which contains the configuration state of the ejbjar task.
* This state is passed to the deployment tools for configuration
*/
static class Config {
/**
* Stores a handle to the directory under which to search for class
* files
*/
public File srcDir;
/**
* Stores a handle to the directory under which to search for
* deployment descriptors
*/
public File descriptorDir;
/** Instance variable that marks the end of the 'basename' */
public String baseNameTerminator = "-";
/** Stores a handle to the destination EJB Jar file */
public String baseJarName;
/**
* Instance variable that determines whether to use a package structure
* of a flat directory as the destination for the jar files.
*/
public boolean flatDestDir = false;
/**
* The classpath to use when loading classes
*/
public Path classpath;
/**
* A Fileset of support classes
*/
public List supportFileSets = new ArrayList();
/**
* The list of configured DTD locations
*/
public ArrayList dtdLocations = new ArrayList();
/**
* The naming scheme used to determine the generated jar name
* from the descriptor information
*/
public NamingScheme namingScheme;
/**
* The Manifest file
*/
public File manifest;
/**
* The dependency analyzer to use to add additional classes to the jar
*/
public String analyzer;
}
/**
* An EnumeratedAttribute class for handling different EJB jar naming
* schemes
*/
public static class NamingScheme extends EnumeratedAttribute {
/**
* Naming scheme where generated jar is determined from the ejb-name in
* the deployment descripor
*/
public static final String EJB_NAME = "ejb-name";
/**
* Naming scheme where the generated jar name is based on the
* name of the directory containing the deployment descriptor
*/
public static final String DIRECTORY = "directory";
/**
* Naming scheme where the generated jar name is based on the name of
* the deployment descriptor file
*/
public static final String DESCRIPTOR = "descriptor";
/**
* Naming scheme where the generated jar is named by the basejarname
* attribute
*/
public static final String BASEJARNAME = "basejarname";
/**
* Gets the values of the NamingScheme
*
* @return an array of the values of this attribute class.
*/
public String[] getValues() {
return new String[] {EJB_NAME, DIRECTORY, DESCRIPTOR, BASEJARNAME};
}
}
/**
* CMP versions supported
* valid CMP versions are 1.0 and 2.0
* @since ant 1.6
*/
public static class CMPVersion extends EnumeratedAttribute {
public static final String CMP1_0 = "1.0";
public static final String CMP2_0 = "2.0";
public String[] getValues() {
return new String[]{
CMP1_0,
CMP2_0,
};
}
}
/**
* The config which is built by this task and used by the various deployment
* tools to access the configuration of the ejbjar task
*/
private Config config = new Config();
/**
* Stores a handle to the directory to put the Jar files in. This is
* only used by the generic deployment descriptor tool which is created
* if no other deployment descriptor tools are provided. Normally each
* deployment tool will specify the desitination dir itself.
*/
private File destDir;
/** Instance variable that stores the suffix for the generated jarfile. */
private String genericJarSuffix = "-generic.jar";
/** Instance variable that stores the CMP version for the jboss jarfile. */
private String cmpVersion = CMPVersion.CMP1_0;
/** The list of deployment tools we are going to run. */
private ArrayList deploymentTools = new ArrayList();
/**
* Add a deployment tool to the list of deployment tools that will be
* processed
*
* @param deploymentTool a deployment tool instance to which descriptors
* will be passed for processing.
*/
protected void addDeploymentTool(EJBDeploymentTool deploymentTool) {
deploymentTool.setTask(this);
deploymentTools.add(deploymentTool);
}
/**
* Adds a deployment tool for Weblogic server.
*
* @return the deployment tool instance to be configured.
*/
public WeblogicDeploymentTool createWeblogic() {
WeblogicDeploymentTool tool = new WeblogicDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Websphere 4.0 server.
*
* @return the deployment tool instance to be configured.
*/
public WebsphereDeploymentTool createWebsphere() {
WebsphereDeploymentTool tool = new WebsphereDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Borland server.
*
* @return the deployment tool instance to be configured.
*/
public BorlandDeploymentTool createBorland() {
log("Borland deployment tools", Project.MSG_VERBOSE);
BorlandDeploymentTool tool = new BorlandDeploymentTool();
tool.setTask(this);
deploymentTools.add(tool);
return tool;
}
/**
* Adds a deployment tool for iPlanet Application Server.
*
* @return the deployment tool instance to be configured.
*/
public IPlanetDeploymentTool createIplanet() {
log("iPlanet Application Server deployment tools", Project.MSG_VERBOSE);
IPlanetDeploymentTool tool = new IPlanetDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for JBoss server.
*
* @return the deployment tool instance to be configured.
*/
public JbossDeploymentTool createJboss() {
JbossDeploymentTool tool = new JbossDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for JOnAS server.
*
* @return the deployment tool instance to be configured.
*/
public JonasDeploymentTool createJonas() {
log("JOnAS deployment tools", Project.MSG_VERBOSE);
JonasDeploymentTool tool = new JonasDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Weblogic when using the Toplink
* Object-Relational mapping.
*
* @return the deployment tool instance to be configured.
*/
public WeblogicTOPLinkDeploymentTool createWeblogictoplink() {
log("The <weblogictoplink> element is no longer required. Please use "
+ "the <weblogic> element and set newCMP=\"true\"",
Project.MSG_INFO);
WeblogicTOPLinkDeploymentTool tool
= new WeblogicTOPLinkDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds to the classpath used to locate the super classes and
* interfaces of the classes that will make up the EJB JAR.
*
* @return the path to be configured.
*/
public Path createClasspath() {
if (config.classpath == null) {
config.classpath = new Path(getProject());
}
return config.classpath.createPath();
}
/**
* Create a DTD location record. This stores the location of a DTD. The
* DTD is identified by its public Id. The location may either be a file
* location or a resource location.
*
* @return the DTD location object to be configured by Ant
*/
public DTDLocation createDTD() {
DTDLocation dtdLocation = new DTDLocation();
config.dtdLocations.add(dtdLocation);
return dtdLocation;
}
/**
* Adds a fileset for support elements.
*
* @return a fileset which can be populated with support files.
*/
public FileSet createSupport() {
FileSet supportFileSet = new FileSet();
config.supportFileSets.add(supportFileSet);
return supportFileSet;
}
/**
* Set the Manifest file to use when jarring. As of EJB 1.1, manifest
* files are no longer used to configure the EJB. However, they still
* have a vital importance if the EJB is intended to be packaged in an
* EAR file. By adding "Class-Path" settings to a Manifest file, the EJB
* can look for classes inside the EAR file itself, allowing for easier
* deployment. This is outlined in the J2EE specification, and all J2EE
* components are meant to support it.
*
* @param manifest the manifest to be used in the EJB jar
*/
public void setManifest(File manifest) {
config.manifest = manifest;
}
/**
* Sets the source directory, which is the directory that
* contains the classes that will be added to the EJB jar. Typically
* this will include the home and remote interfaces and the bean class.
*
* @param inDir the source directory.
*/
public void setSrcdir(File inDir) {
config.srcDir = inDir;
}
/**
* Set the descriptor directory. The descriptor directory contains the
* EJB deployment descriptors. These are XML files that declare the
* properties of a bean in a particular deployment scenario. Such
* properties include, for example, the transactional nature of the bean
* and the security access control to the bean's methods.
*
* @param inDir the directory containing the deployment descriptors.
*/
public void setDescriptordir(File inDir) {
config.descriptorDir = inDir;
}
/**
* Set the analyzer to use when adding in dependencies to the JAR.
*
* @param analyzer the name of the dependency analyzer or a class.
*/
public void setDependency(String analyzer) {
config.analyzer = analyzer;
}
/**
* Set the base name of the EJB JAR that is to be created if it is not
* to be determined from the name of the deployment descriptor files.
*
* @param inValue the basename that will be used when writing the jar
* file containing the EJB
*/
public void setBasejarname(String inValue) {
config.baseJarName = inValue;
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.BASEJARNAME);
} else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
throw new BuildException("The basejarname attribute is not "
+ "compatible with the "
+ config.namingScheme.getValue() + " naming scheme");
}
}
/**
* Set the naming scheme used to determine the name of the generated jars
* from the deployment descriptor
*
* @param namingScheme the naming scheme to be used
*/
public void setNaming(NamingScheme namingScheme) {
config.namingScheme = namingScheme;
if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
&& config.baseJarName != null) {
throw new BuildException("The basejarname attribute is not "
+ "compatible with the "
+ config.namingScheme.getValue() + " naming scheme");
}
}
/**
* Gets the destination directory.
*
* @return destination directory
* @since ant 1.6
*/
public File getDestdir() {
return this.destDir;
}
/**
* Set the destination directory. The EJB jar files will be written into
* this directory. The jar files that exist in this directory are also
* used when determining if the contents of the jar file have changed.
* Note that this parameter is only used if no deployment tools are
* specified. Typically each deployment tool will specify its own
* destination directory.
*
* @param inDir the destination directory in which to generate jars
*/
public void setDestdir(File inDir) {
this.destDir = inDir;
}
/**
* Gets the CMP version.
*
* @return CMP version
* @since ant 1.6
*/
public String getCmpversion() {
return this.cmpVersion;
}
/**
* Sets the CMP version.
*
* @param version CMP version.
* Must be either <code>1.0</code> or <code>2.0</code>.<br/>
* Default is <code>1.0</code>.<br/>
* Initially, only the JBoss implementation does something specific for CMP 2.0.<br/>
* @since ant 1.6
*/
public void setCmpversion(CMPVersion version) {
this.cmpVersion = version.getValue();
}
/**
* Set the classpath to use when resolving classes for inclusion in the jar.
*
* @param classpath the classpath to use.
*/
public void setClasspath(Path classpath) {
config.classpath = classpath;
}
/**
* Controls whether the
* destination JARs are written out in the destination directory with
* the same hierarchical structure from which the deployment descriptors
* have been read. If this is set to true the generated EJB jars are
* written into the root of the destination directory, otherwise they
* are written out in the same relative position as the deployment
* descriptors in the descriptor directory.
*
* @param inValue the new value of the flatdestdir flag.
*/
public void setFlatdestdir(boolean inValue) {
config.flatDestDir = inValue;
}
/**
* Set the suffix for the generated jar file. When generic jars are
* generated, they have a suffix which is appended to the the bean name
* to create the name of the jar file. Note that this suffix includes
* the extension fo te jar file and should therefore end with an
* appropriate extension such as .jar or .ear
*
* @param inString the string to use as the suffix.
*/
public void setGenericjarsuffix(String inString) {
this.genericJarSuffix = inString;
}
/**
* The string which terminates the bean name.
* The convention used by this task is
* that bean descriptors are named as the BeanName with some suffix. The
* baseNameTerminator string separates the bean name and the suffix and
* is used to determine the bean name.
*
* @param inValue a string which marks the end of the basename.
*/
public void setBasenameterminator(String inValue) {
config.baseNameTerminator = inValue;
}
/**
* Validate the config that has been configured from the build file
*
* @throws BuildException if the config is not valid
*/
private void validateConfig() throws BuildException {
if (config.srcDir == null) {
throw new BuildException("The srcDir attribute must be specified");
}
if (config.descriptorDir == null) {
config.descriptorDir = config.srcDir;
}
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.DESCRIPTOR);
} else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
&& config.baseJarName == null) {
throw new BuildException("The basejarname attribute must "
+ "be specified with the basejarname naming scheme");
}
}
/**
* Invoked by Ant after the task is prepared, when it is ready to execute
* this task.
*
* This will configure all of the nested deployment tools to allow them to
* process the jar. If no deployment tools have been configured a generic
* tool is created to handle the jar.
*
* A parser is configured and then each descriptor found is passed to all
* the deployment tool elements for processing.
*
* @exception BuildException thrown whenever a problem is
* encountered that cannot be recovered from, to signal to ant
* that a major problem occurred within this task.
*/
public void execute() throws BuildException {
validateConfig();
if (deploymentTools.size() == 0) {
GenericDeploymentTool genericTool = new GenericDeploymentTool();
genericTool.setTask(this);
genericTool.setDestdir(destDir);
genericTool.setGenericJarSuffix(genericJarSuffix);
deploymentTools.add(genericTool);
}
for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
tool.configure(config);
tool.validateConfigured();
}
try {
// Create the parser using whatever parser the system dictates
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setValidating(true);
SAXParser saxParser = saxParserFactory.newSAXParser();
DirectoryScanner ds = getDirectoryScanner(config.descriptorDir);
ds.scan();
String[] files = ds.getIncludedFiles();
log(files.length + " deployment descriptors located.",
Project.MSG_VERBOSE);
// Loop through the files. Each file represents one deployment
// descriptor, and hence one bean in our model.
for (int index = 0; index < files.length; ++index) {
// process the deployment descriptor in each tool
for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
tool.processDescriptor(files[index], saxParser);
}
}
} catch (SAXException se) {
String msg = "SAXException while creating parser."
+ " Details: "
+ se.getMessage();
throw new BuildException(msg, se);
} catch (ParserConfigurationException pce) {
String msg = "ParserConfigurationException while creating parser. "
+ "Details: " + pce.getMessage();
throw new BuildException(msg, pce);
}
} // end of execute()
}
|