Application Server 6.0 Nested element to support iPlanet in ejbjar task Submitted by: Greg Nelson <greg@netscape.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268990 13f79535-47bb-0310-9956-ffa450edef68master
@@ -189,6 +189,7 @@ | |||
<exclude name="${optional.package}/ejb/WLStop.java" unless="ejb.wls.present" /> | |||
<exclude name="${optional.package}/ejb/EjbJar.java" unless="jdk1.2+" /> | |||
<exclude name="${optional.package}/ejb/*DeploymentTool.java" unless="jdk1.2+" /> | |||
<exclude name="${optional.package}/ejb/IPlanet*.java" unless="jdk1.2+" /> | |||
<exclude name="${optional.package}/Javah.java" unless="jdk1.2+" /> | |||
<exclude name="${optional.package}/junit/*" unless="junit.present" /> | |||
<exclude name="${optional.package}/net/*.java" unless="netcomp.present" /> | |||
@@ -100,6 +100,7 @@ rpm=org.apache.tools.ant.taskdefs.optional.Rpm | |||
xmlvalidate=org.apache.tools.ant.taskdefs.optional.XMLValidateTask | |||
vsscheckin=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKIN | |||
vsscheckout=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKOUT | |||
iplanet-ejbc=org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbcTask | |||
# deprecated ant tasks (kept for back compatibility) | |||
javadoc2=org.apache.tools.ant.taskdefs.Javadoc | |||
@@ -208,6 +208,21 @@ public class EjbJar extends MatchingTask { | |||
return tool; | |||
} | |||
/** | |||
* Create a nested element used to configure 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(); | |||
tool.setTask(this); | |||
deploymentTools.add(tool); | |||
return tool; | |||
} | |||
/** | |||
* Create a nested element for weblogic when using the Toplink | |||
* Object- Relational mapping. | |||
@@ -113,6 +113,11 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
*/ | |||
private List addedfiles; | |||
/** | |||
* Handler used to parse the EJB XML descriptor | |||
*/ | |||
private DescriptorHandler handler; | |||
/** | |||
* Setter used to store the value of destination directory prior to execute() | |||
* being called. | |||
@@ -205,6 +210,10 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
getTask().log(message, level); | |||
} | |||
protected Location getLocation() { | |||
return getTask().getLocation(); | |||
} | |||
/** | |||
* Configure this tool for use in the ejbjar task. | |||
@@ -293,54 +302,18 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
} | |||
public void processDescriptor(String descriptorFileName, SAXParser saxParser) { | |||
FileInputStream descriptorStream = null; | |||
try { | |||
DescriptorHandler handler = getDescriptorHandler(config.srcDir); | |||
/* Parse the ejb deployment descriptor. While it may not | |||
* look like much, we use a SAXParser and an inner class to | |||
* get hold of all the classfile names for the descriptor. | |||
*/ | |||
descriptorStream = new FileInputStream(new File(config.descriptorDir, descriptorFileName)); | |||
saxParser.parse(new InputSource(descriptorStream), handler); | |||
Hashtable ejbFiles = handler.getFiles(); | |||
checkConfiguration(descriptorFileName, saxParser); | |||
// add in support classes if any | |||
Project project = task.getProject(); | |||
for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) { | |||
FileSet supportFileSet = (FileSet)i.next(); | |||
File supportBaseDir = supportFileSet.getDir(project); | |||
DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project); | |||
supportScanner.scan(); | |||
String[] supportFiles = supportScanner.getIncludedFiles(); | |||
for (int j = 0; j < supportFiles.length; ++j) { | |||
ejbFiles.put(supportFiles[j], new File(supportBaseDir, supportFiles[j])); | |||
} | |||
} | |||
try { | |||
// Retrive the files to be added to JAR from EJB descriptor | |||
Hashtable ejbFiles = parseEjbFiles(descriptorFileName, saxParser); | |||
String baseName = ""; | |||
// Work out what the base name is | |||
if (config.baseJarName != null) { | |||
baseName = config.baseJarName; | |||
} else { | |||
int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator); | |||
int endBaseName = -1; | |||
if (lastSeparatorIndex != -1) { | |||
endBaseName = descriptorFileName.indexOf(config.baseNameTerminator, | |||
lastSeparatorIndex); | |||
} | |||
else { | |||
endBaseName = descriptorFileName.indexOf(config.baseNameTerminator); | |||
} | |||
// Add any support classes specified in the build file | |||
addSupportClasses(ejbFiles); | |||
if (endBaseName != -1) { | |||
baseName = descriptorFileName.substring(0, endBaseName); | |||
} | |||
baseName = descriptorFileName.substring(0, endBaseName); | |||
} | |||
// Determine the JAR filename (without filename extension) | |||
String baseName = getJarBaseName(descriptorFileName); | |||
// First the regular deployment descriptor | |||
ejbFiles.put(META_DIR + EJB_DD, | |||
@@ -366,30 +339,9 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
File jarFile = getVendorOutputJarFile(baseName); | |||
// By default we assume we need to build. | |||
boolean needBuild = true; | |||
if (jarFile.exists()) { | |||
long lastBuild = jarFile.lastModified(); | |||
Iterator fileIter = ejbFiles.values().iterator(); | |||
// Set the need build to false until we find out otherwise. | |||
needBuild = false; | |||
// Loop through the files seeing if any has been touched | |||
// more recently than the destination jar. | |||
while( (needBuild == false) && (fileIter.hasNext()) ) { | |||
File currentFile = (File) fileIter.next(); | |||
needBuild = ( lastBuild < currentFile.lastModified() ); | |||
if (needBuild) { | |||
log("Build needed because " + currentFile.getPath() + " is out of date", | |||
Project.MSG_VERBOSE); | |||
} | |||
} | |||
} | |||
// Check to see if we need a build and start | |||
// doing the work! | |||
if (needBuild) { | |||
// Check to see if we need a build and start doing the work! | |||
if (needToRebuild(ejbFiles, jarFile)) { | |||
// Log that we are going to build... | |||
log( "building " | |||
+ jarFile.getName() | |||
@@ -399,7 +351,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
Project.MSG_INFO); | |||
// Use helper method to write the jarfile | |||
writeJar(baseName, jarFile, ejbFiles, handler.getPublicId()); | |||
String publicId = getPublicId(); | |||
writeJar(baseName, jarFile, ejbFiles, publicId); | |||
} | |||
else { | |||
@@ -425,7 +378,63 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
+ ioe.getMessage(); | |||
throw new BuildException(msg, ioe); | |||
} | |||
finally { | |||
} | |||
/** | |||
* This method is called as the first step in the processDescriptor method | |||
* to allow vendor-specific subclasses to validate the task configuration | |||
* prior to processing the descriptor. If the configuration is invalid, | |||
* a BuildException should be thrown. | |||
* | |||
* @param descriptorFileName String representing the file name of an EJB | |||
* descriptor to be processed | |||
* @param saxParser SAXParser which may be used to parse the XML | |||
* descriptor | |||
* @thows BuildException Thrown if the configuration is invalid | |||
*/ | |||
protected void checkConfiguration(String descriptorFileName, | |||
SAXParser saxParser) throws BuildException { | |||
/* | |||
* For the GenericDeploymentTool, do nothing. Vendor specific | |||
* subclasses should throw a BuildException if the configuration is | |||
* invalid for their server. | |||
*/ | |||
} | |||
/** | |||
* This method returns a list of EJB files found when the specified EJB | |||
* descriptor is parsed and processed. | |||
* | |||
* @param descriptorFileName String representing the file name of an EJB | |||
* descriptor to be processed | |||
* @param saxParser SAXParser which may be used to parse the XML | |||
* descriptor | |||
* @return Hashtable of EJB class (and other) files to be | |||
* added to the completed JAR file | |||
* @throws SAXException Any SAX exception, possibly wrapping another | |||
* exception | |||
* @throws IOException An IOException from the parser, possibly from a | |||
* the byte stream or character stream | |||
*/ | |||
protected Hashtable parseEjbFiles(String descriptorFileName, SAXParser saxParser) | |||
throws IOException, SAXException { | |||
FileInputStream descriptorStream = null; | |||
Hashtable ejbFiles = null; | |||
try { | |||
handler = getDescriptorHandler(config.srcDir); | |||
/* Parse the ejb deployment descriptor. While it may not | |||
* look like much, we use a SAXParser and an inner class to | |||
* get hold of all the classfile names for the descriptor. | |||
*/ | |||
descriptorStream = new FileInputStream(new File(config.descriptorDir, descriptorFileName)); | |||
saxParser.parse(new InputSource(descriptorStream), handler); | |||
ejbFiles = handler.getFiles(); | |||
} finally { | |||
if (descriptorStream != null) { | |||
try { | |||
descriptorStream.close(); | |||
@@ -433,8 +442,70 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
catch (IOException closeException) {} | |||
} | |||
} | |||
} | |||
return ejbFiles; | |||
} | |||
/** | |||
* Adds any classes the user specifies using <i>support</i> nested elements | |||
* to the <code>ejbFiles</code> Hashtable. | |||
* | |||
* @param ejbFiles Hashtable of EJB classes (and other) files that will be | |||
* added to the completed JAR file | |||
*/ | |||
protected void addSupportClasses(Hashtable ejbFiles) { | |||
// add in support classes if any | |||
Project project = task.getProject(); | |||
for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) { | |||
FileSet supportFileSet = (FileSet)i.next(); | |||
File supportBaseDir = supportFileSet.getDir(project); | |||
DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project); | |||
supportScanner.scan(); | |||
String[] supportFiles = supportScanner.getIncludedFiles(); | |||
for (int j = 0; j < supportFiles.length; ++j) { | |||
ejbFiles.put(supportFiles[j], new File(supportBaseDir, supportFiles[j])); | |||
} | |||
} | |||
} | |||
/** | |||
* Using the EJB descriptor file name passed from the <code>ejbjar</code> | |||
* task, this method returns the "basename" which will be used to name the | |||
* completed JAR file. | |||
* | |||
* @param descriptorFileName String representing the file name of an EJB | |||
* descriptor to be processed | |||
* @return The "basename" which will be used to name the | |||
* completed JAR file | |||
*/ | |||
protected String getJarBaseName(String descriptorFileName) { | |||
String baseName = ""; | |||
// Work out what the base name is | |||
if (config.baseJarName != null) { | |||
baseName = config.baseJarName; | |||
} else { | |||
int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator); | |||
int endBaseName = -1; | |||
if (lastSeparatorIndex != -1) { | |||
endBaseName = descriptorFileName.indexOf(config.baseNameTerminator, | |||
lastSeparatorIndex); | |||
} else { | |||
endBaseName = descriptorFileName.indexOf(config.baseNameTerminator); | |||
} | |||
if (endBaseName != -1) { | |||
baseName = descriptorFileName.substring(0, endBaseName); | |||
} | |||
baseName = descriptorFileName.substring(0, endBaseName); | |||
} | |||
return baseName; | |||
} | |||
/** | |||
* Add any vendor specific files which should be included in the | |||
* EJB Jar. | |||
@@ -452,6 +523,56 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
return new File(destDir, baseName + genericJarSuffix); | |||
} | |||
/** | |||
* This method checks the timestamp on each file listed in the <code> | |||
* ejbFiles</code> and compares them to the timestamp on the <code>jarFile | |||
* </code>. If the <code>jarFile</code>'s timestamp is more recent than | |||
* each EJB file, <code>false</code> is returned. Otherwise, <code>true | |||
* </code> is returned. | |||
* | |||
* @param ejbFiles Hashtable of EJB classes (and other) files that will be | |||
* added to the completed JAR file | |||
* @param jarFile JAR file which will contain all of the EJB classes (and | |||
* other) files | |||
* @return boolean indicating whether or not the <code>jarFile</code> | |||
* is up to date | |||
*/ | |||
protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) { | |||
// By default we assume we need to build. | |||
boolean needBuild = true; | |||
if (jarFile.exists()) { | |||
long lastBuild = jarFile.lastModified(); | |||
Iterator fileIter = ejbFiles.values().iterator(); | |||
// Set the need build to false until we find out otherwise. | |||
needBuild = false; | |||
// Loop through the files seeing if any has been touched | |||
// more recently than the destination jar. | |||
while( (needBuild == false) && (fileIter.hasNext()) ) { | |||
File currentFile = (File) fileIter.next(); | |||
needBuild = ( lastBuild < currentFile.lastModified() ); | |||
if (needBuild) { | |||
log("Build needed because " + currentFile.getPath() + " is out of date", | |||
Project.MSG_VERBOSE); | |||
} | |||
} | |||
} | |||
return needBuild; | |||
} | |||
/** | |||
* Returns the Public ID of the DTD specified in the EJB descriptor. Not | |||
* every vendor-specific <code>DeploymentTool</code> will need to reference | |||
* this value or may want to determine this value in a vendor-specific way. | |||
* | |||
* @return Public ID of the DTD specified in the EJB descriptor. | |||
*/ | |||
protected String getPublicId() { | |||
return handler.getPublicId(); | |||
} | |||
/** | |||
* Method used to encapsulate the writing of the JAR file. Iterates over the | |||
* filenames/java.io.Files in the Hashtable stored on the instance variable | |||
@@ -664,10 +785,14 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||
/** | |||
* Called to validate that the tool parameters have been configured. | |||
* | |||
* @throws BuildException If the Deployment Tool's configuration isn't | |||
* valid | |||
*/ | |||
public void validateConfigured() throws BuildException { | |||
if (destDir == null) { | |||
throw new BuildException("The destdir attribute must be specified"); | |||
if ((destDir == null) || (!destDir.isDirectory())) { | |||
String msg = "A valid destination directory must be specified " | |||
+ "using the \"destdir\" attribute."; | |||
throw new BuildException(msg, getLocation()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,423 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2000 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in | |||
* the documentation and/or other materials provided with the | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.ejb; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Hashtable; | |||
import javax.xml.parsers.SAXParser; | |||
import org.xml.sax.SAXException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.BuildException; | |||
/** | |||
* This class is used to generate iPlanet Application Server (iAS) 6.0 stubs and | |||
* skeletons and build an EJB Jar file. It is designed to be used with the Ant | |||
* <code>ejbjar</code> task. If only stubs and skeletons need to be generated | |||
* (in other words, if no JAR file needs to be created), refer to the | |||
* <code>iplanet-ejbc</code> task and the <code>IPlanetEjbcTask</code> class. | |||
* <p> | |||
* The following attributes may be specified by the user: | |||
* <ul> | |||
* <li><i>destdir</i> -- The base directory into which the generated JAR | |||
* files will be written. Each JAR file is written | |||
* in directories which correspond to their location | |||
* within the "descriptordir" namespace. This is a | |||
* required attribute. | |||
* <li><i>classpath</i> -- The classpath used when generating EJB stubs and | |||
* skeletons. This is an optional attribute (if | |||
* omitted, the classpath specified in the "ejbjar" | |||
* parent task will be used). If specified, the | |||
* classpath elements will be prepended to the | |||
* classpath specified in the parent "ejbjar" task. | |||
* Note that nested "classpath" elements may also be | |||
* used. | |||
* <li><i>keepgenerated</i> -- Indicates whether or not the Java source | |||
* files which are generated by ejbc will be | |||
* saved or automatically deleted. If "yes", | |||
* the source files will be retained. This is | |||
* an optional attribute (if omitted, it | |||
* defaults to "no"). | |||
* <li><i>debug</i> -- Indicates whether or not the ejbc utility should | |||
* log additional debugging statements to the standard | |||
* output. If "yes", the additional debugging statements | |||
* will be generated (if omitted, it defaults to "no"). | |||
* <li><i>iashome</i> -- May be used to specify the "home" directory for | |||
* this iPlanet Application server installation. This | |||
* is used to find the ejbc utility if it isn't | |||
* included in the user's system path. This is an | |||
* optional attribute (if specified, it should refer | |||
* to the <code>[install-location]/iplanet/ias6/ias | |||
* </code> directory). If omitted, the ejbc utility | |||
* must be on the user's system path. | |||
* <li><i>suffix</i> -- String value appended to the JAR filename when | |||
* creating each JAR. This attribute is not required | |||
* (if omitted, it defaults to ".jar"). | |||
* </ul> | |||
* <p> | |||
* For each EJB descriptor found in the "ejbjar" parent task, this deployment | |||
* tool will locate the three classes that comprise the EJB. If these class | |||
* files cannot be located in the specified <code>srcdir</code> directory, the | |||
* task will fail. The task will also attempt to locate the EJB stubs and | |||
* skeletons in this directory. If found, the timestamps on the stubs and | |||
* skeletons will be checked to ensure they are up to date. Only if these files | |||
* cannot be found or if they are out of date will ejbc be called. | |||
* | |||
* @see IPlanetEjbc | |||
* @author Greg Nelson <a href="mailto:greg@netscape.com">greg@netscape.com</a> | |||
*/ | |||
public class IPlanetDeploymentTool extends GenericDeploymentTool { | |||
/* Attributes set by the Ant build file */ | |||
private File iashome; | |||
private String jarSuffix = ".jar"; | |||
private boolean keepgenerated = false; | |||
private boolean debug = false; | |||
/* | |||
* Filenames of the standard EJB descriptor (which is passed to this class | |||
* from the parent "ejbjar" task) and the iAS-specific EJB descriptor | |||
* (whose name is determined by this class). Both filenames are relative | |||
* to the directory specified by the "srcdir" attribute in the ejbjar task. | |||
*/ | |||
private String descriptorName; | |||
private String iasDescriptorName; | |||
/* | |||
* The displayName variable stores the value of the "display-name" element | |||
* from the standard EJB descriptor. As a future enhancement to this task, | |||
* we may determine the name of the EJB JAR file using this display-name, | |||
* but this has not be implemented yet. | |||
*/ | |||
private String displayName; | |||
/* | |||
* Regardless of the name of the iAS-specific EJB descriptor file, it will | |||
* written in the completed JAR file as "ias-ejb-jar.xml". This is the | |||
* naming convention implemented by iAS. | |||
*/ | |||
private static final String IAS_DD = "ias-ejb-jar.xml"; | |||
/** | |||
* Setter method used to store the "home" directory of the user's iAS | |||
* installation. The directory specified should typically be | |||
* <code>[install-location]/iplanet/ias6/ias</code>. | |||
* | |||
* @param iashome The home directory for the user's iAS installation. | |||
*/ | |||
public void setIashome(File iashome) { | |||
this.iashome = iashome; | |||
} | |||
/** | |||
* Setter method used to specify whether the Java source files generated by | |||
* the ejbc utility should be saved or automatically deleted. | |||
* | |||
* @param keepgenerated boolean which, if <code>true</code>, indicates that | |||
* Java source files generated by ejbc for the stubs | |||
* and skeletons should be kept. | |||
*/ | |||
public void setKeepgenerated(boolean keepgenerated) { | |||
this.keepgenerated = keepgenerated; | |||
} | |||
/** | |||
* Sets whether or not debugging output will be generated when ejbc is | |||
* executed. | |||
* | |||
* @param debug A boolean indicating if debugging output should be generated | |||
*/ | |||
public void setDebug(boolean debug) { | |||
this.debug = debug; | |||
} | |||
/** | |||
* Setter method used to specify the filename suffix (for example, ".jar") | |||
* for the JAR files to be created. | |||
* | |||
* @param jarSuffix The string to use as the JAR filename suffix. | |||
*/ | |||
public void setSuffix(String jarSuffix) { | |||
this.jarSuffix = jarSuffix; | |||
} | |||
/** | |||
* Since iAS doesn't generate a "generic" JAR as part of its processing, | |||
* this attribute is ignored and a warning message is displayed to the user. | |||
* | |||
* @param inString the string to use as the suffix. This parameter is | |||
* ignored. | |||
*/ | |||
public void setGenericJarSuffix(String inString) { | |||
log("Since a generic JAR file is not created during processing, the " | |||
+ "iPlanet Deployment Tool does not support the " | |||
+ "\"genericjarsuffix\" attribute. It will be ignored.", | |||
Project.MSG_WARN); | |||
} | |||
public void processDescriptor(String descriptorName, SAXParser saxParser) { | |||
this.descriptorName = descriptorName; | |||
log("iPlanet Deployment Tool processing: " + descriptorName + " (and " | |||
+ getIasDescriptorName() + ")", Project.MSG_VERBOSE); | |||
super.processDescriptor(descriptorName, saxParser); | |||
} | |||
/** | |||
* Verifies that the user selections are valid. | |||
* | |||
* @param descriptorFileName String representing the file name of an EJB | |||
* descriptor to be processed | |||
* @param saxParser SAXParser which may be used to parse the XML | |||
* descriptor | |||
* @throws BuildException If the user selections are invalid. | |||
*/ | |||
protected void checkConfiguration(String descriptorFileName, | |||
SAXParser saxParser) throws BuildException { | |||
int startOfName = descriptorFileName.lastIndexOf(File.separatorChar) + 1; | |||
String stdXml = descriptorFileName.substring(startOfName); | |||
if (stdXml.equals(EJB_DD) && (getConfig().baseJarName == null)) { | |||
String msg = "No name specified for the completed JAR file. The EJB" | |||
+ " descriptor should be prepended with the JAR " | |||
+ "name or it should be specified using the " | |||
+ "attribute \"basejarname\" in the \"ejbjar\" task."; | |||
throw new BuildException(msg, getLocation()); | |||
} | |||
File iasDescriptor = new File(getConfig().descriptorDir, | |||
getIasDescriptorName()); | |||
if ((!iasDescriptor.exists()) || (!iasDescriptor.isFile())) { | |||
String msg = "The iAS-specific EJB descriptor (" | |||
+ iasDescriptor + ") was not found."; | |||
throw new BuildException(msg, getLocation()); | |||
} | |||
if ((iashome != null) && (!iashome.isDirectory())) { | |||
String msg = "If \"iashome\" is specified, it must be a valid " | |||
+ "directory (it was set to " + iashome + ")."; | |||
throw new BuildException(msg, getLocation()); | |||
} | |||
} | |||
/** | |||
* This method returns a list of EJB files found when the specified EJB | |||
* descriptor is parsed and processed. | |||
* | |||
* @param descriptorFileName String representing the file name of an EJB | |||
* descriptor to be processed | |||
* @param saxParser SAXParser which may be used to parse the XML | |||
* descriptor | |||
* @return Hashtable of EJB class (and other) files to be | |||
* added to the completed JAR file | |||
* @throws IOException An IOException from the parser, possibly from | |||
* the byte stream or character stream | |||
* @throws SAXException Any SAX exception, possibly wrapping another | |||
* exception | |||
*/ | |||
protected Hashtable parseEjbFiles(String descriptorFileName, | |||
SAXParser saxParser) throws IOException, SAXException { | |||
Hashtable files; | |||
/* Build and populate an instance of the ejbc utility */ | |||
IPlanetEjbc ejbc = new IPlanetEjbc( | |||
new File(getConfig().descriptorDir, | |||
descriptorFileName), | |||
new File(getConfig().descriptorDir, | |||
getIasDescriptorName()), | |||
getConfig().srcDir, | |||
getCombinedClasspath().toString(), | |||
saxParser); | |||
ejbc.setRetainSource(keepgenerated); | |||
ejbc.setDebugOutput(debug); | |||
if (iashome != null) { | |||
ejbc.setIasHomeDir(iashome); | |||
} | |||
/* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */ | |||
try { | |||
ejbc.execute(); | |||
} catch (IPlanetEjbc.EjbcException e) { | |||
throw new BuildException("An error has occurred while trying to " | |||
+ "execute the iAS ejbc utility", e, getLocation()); | |||
} | |||
displayName = ejbc.getDisplayName(); | |||
files = ejbc.getEjbFiles(); | |||
/* Add CMP descriptors to the list of EJB files */ | |||
String[] cmpDescriptors = ejbc.getCmpDescriptors(); | |||
if (cmpDescriptors.length > 0) { | |||
File baseDir = getConfig().descriptorDir; | |||
int endOfPath = descriptorFileName.lastIndexOf(File.separator); | |||
String relativePath = descriptorFileName.substring(0, endOfPath + 1); | |||
for (int i = 0; i < cmpDescriptors.length; i++) { | |||
int endOfCmp = cmpDescriptors[i].lastIndexOf('/'); | |||
String cmpDescriptor = cmpDescriptors[i].substring(endOfCmp + 1); | |||
File cmpFile = new File(baseDir, relativePath + cmpDescriptor); | |||
if (!cmpFile.exists()) { | |||
throw new BuildException("The CMP descriptor file (" | |||
+ cmpFile + ") could not be found.", getLocation()); | |||
} | |||
files.put(cmpDescriptors[i], cmpFile); | |||
} | |||
} | |||
return files; | |||
} | |||
/** | |||
* Add the iAS-specific EJB descriptor to the list of files which will be | |||
* written to the JAR file. | |||
* | |||
* @param ejbFiles Hashtable of EJB class (and other) files to be added to | |||
* the completed JAR file. | |||
* @param baseName String name of the EJB JAR file to be written (without | |||
* a filename extension). | |||
*/ | |||
protected void addVendorFiles(Hashtable ejbFiles, String baseName) { | |||
ejbFiles.put(META_DIR + IAS_DD, new File(getConfig().descriptorDir, | |||
getIasDescriptorName())); | |||
} | |||
/** | |||
* Get the name of the Jar that will be written. The modification date | |||
* of this jar will be checked against the dependent bean classes. | |||
* | |||
* @param baseName String name of the EJB JAR file to be written (without | |||
* a filename extension). | |||
* | |||
* @return File representing the JAR file which will be written. | |||
*/ | |||
File getVendorOutputJarFile(String baseName) { | |||
File jarFile = new File(getDestDir(), baseName + jarSuffix); | |||
log("JAR file name: " + jarFile.toString(), Project.MSG_VERBOSE); | |||
return jarFile; | |||
} | |||
/** | |||
* The iAS ejbc utility doesn't require the Public ID of the descriptor's | |||
* DTD for it to process correctly--this method always returns <code>null | |||
* </code>. | |||
* | |||
* @return <code>null</code>. | |||
*/ | |||
protected String getPublicId() { | |||
return null; | |||
} | |||
/** | |||
* Determines the name of the iAS-specific EJB descriptor using the | |||
* specified standard EJB descriptor name. In general, the standard | |||
* descriptor will be named "[basename]-ejb-jar.xml", and this method will | |||
* return "[basename]-ias-ejb-jar.xml". | |||
* | |||
* @return The name of the iAS-specific EJB descriptor file. | |||
*/ | |||
private String getIasDescriptorName() { | |||
/* Only calculate the descriptor name once */ | |||
if (iasDescriptorName != null) { | |||
return iasDescriptorName; | |||
} | |||
String path = ""; // Directory path of the EJB descriptor | |||
String basename; // Filename appearing before name terminator | |||
String remainder; // Filename appearing after the name terminator | |||
/* Find the end of the standard descriptor's relative path */ | |||
int startOfFileName = descriptorName.lastIndexOf(File.separatorChar); | |||
if (startOfFileName != -1) { | |||
path = descriptorName.substring(0, startOfFileName + 1); | |||
} | |||
/* Check to see if the standard name is used (there's no basename) */ | |||
if (descriptorName.substring(startOfFileName + 1).equals(EJB_DD)) { | |||
basename = ""; | |||
remainder = EJB_DD; | |||
} else { | |||
int endOfBaseName = descriptorName.indexOf( | |||
getConfig().baseNameTerminator, | |||
startOfFileName); | |||
/* | |||
* Check for the odd case where the terminator and/or filename | |||
* extension aren't found. These will ensure "ias-" appears at the | |||
* end of the name and before the '.' (if present). | |||
*/ | |||
if (endOfBaseName < 0) { | |||
endOfBaseName = descriptorName.lastIndexOf('.') - 1; | |||
if (endOfBaseName < 0) { | |||
endOfBaseName = descriptorName.length() - 1; | |||
} | |||
} | |||
basename = descriptorName.substring(startOfFileName + 1, | |||
endOfBaseName + 1); | |||
remainder = descriptorName.substring(endOfBaseName + 1); | |||
} | |||
iasDescriptorName = path + basename + "ias-" + remainder; | |||
return iasDescriptorName; | |||
} | |||
} |
@@ -0,0 +1,353 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2000 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in | |||
* the documentation and/or other materials provided with the | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.ejb; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import javax.xml.parsers.SAXParserFactory; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import org.xml.sax.SAXException; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.BuildException; | |||
/** | |||
* Task to compile EJB stubs and skeletons for the iPlanet Application Server. | |||
* The EJBs to be processed are specified by the EJB 1.1 standard XML | |||
* descriptor, and additional attributes are obtained from the iPlanet Application | |||
* Server-specific XML descriptor. Since the XML descriptors can include | |||
* multiple EJBs, this is a convenient way of specifying many EJBs in a single | |||
* Ant task. The following attributes are allowed: | |||
* <ul> | |||
* <li><i>ejbdescriptor</i> -- Standard EJB 1.1 XML descriptor (typically | |||
* titled "ejb-jar.xml"). This attribute is | |||
* required. | |||
* <li><i>iasdescriptor</i> -- EJB XML descriptor for iPlanet Application | |||
* Server (typically titled "ias-ejb-jar.xml). | |||
* This attribute is required. | |||
* <li><i>dest</i> -- The is the base directory where the RMI stubs and | |||
* skeletons are written. In addition, the class files | |||
* for each bean (home interface, remote interface, and | |||
* EJB implementation) must be found in this directory. | |||
* This attribute is required. | |||
* <li><i>classpath</i> -- The classpath used when generating EJB stubs and | |||
* skeletons. This is an optional attribute (if | |||
* omitted, the classpath specified when Ant was | |||
* started will be used). Nested "classpath" | |||
* elements may also be used. | |||
* <li><i>keepgenerated</i> -- Indicates whether or not the Java source | |||
* files which are generated by ejbc will be | |||
* saved or automatically deleted. If "yes", | |||
* the source files will be retained. This is | |||
* an optional attribute (if omitted, it | |||
* defaults to "no"). | |||
* <li><i>debug</i> -- Indicates whether or not the ejbc utility should | |||
* log additional debugging statements to the standard | |||
* output. If "yes", the additional debugging statements | |||
* will be generated (if omitted, it defaults to "no"). | |||
* <li><i>iashome</i> -- May be used to specify the "home" directory for | |||
* this iPlanet Application Server installation. This | |||
* is used to find the ejbc utility if it isn't | |||
* included in the user's system path. This is an | |||
* optional attribute (if specified, it should refer | |||
* to the <code>[install-location]/iplanet/ias6/ias | |||
* </code> directory). If omitted, the ejbc utility | |||
* must be on the user's system path. | |||
* </ul> | |||
* <p> | |||
* For each EJB specified, this task will locate the three classes that comprise | |||
* the EJB. If these class files cannot be located in the <code>dest</code> | |||
* directory, the task will fail. The task will also attempt to locate the EJB | |||
* stubs and skeletons in this directory. If found, the timestamps on the | |||
* stubs and skeletons will be checked to ensure they are up to date. Only if | |||
* these files cannot be found or if they are out of date will ejbc be called | |||
* to generate new stubs and skeletons. | |||
* | |||
* @see IPlanetEjbc | |||
* @author Greg Nelson <a href="mailto:greg@netscape.com">greg@netscape.com</a> | |||
*/ | |||
public class IPlanetEjbcTask extends Task { | |||
/* Attributes set by the Ant build file */ | |||
private File ejbdescriptor; | |||
private File iasdescriptor; | |||
private File dest; | |||
private Path classpath; | |||
private boolean keepgenerated = false; | |||
private boolean debug = false; | |||
private File iashome; | |||
/** | |||
* Sets the location of the standard XML EJB descriptor. Typically, this | |||
* file is named "ejb-jar.xml". | |||
* | |||
* @param ejbdescriptor The name and location of the EJB descriptor. | |||
*/ | |||
public void setEjbdescriptor(File ejbdescriptor) { | |||
this.ejbdescriptor = ejbdescriptor; | |||
} | |||
/** | |||
* Sets the location of the iAS-specific XML EJB descriptor. Typically, | |||
* this file is named "ias-ejb-jar.xml". | |||
* | |||
* @param iasdescriptor The name and location of the iAS-specific EJB | |||
* descriptor. | |||
*/ | |||
public void setIasdescriptor (File iasdescriptor) { | |||
this.iasdescriptor = iasdescriptor; | |||
} | |||
/** | |||
* Sets the destination directory where the EJB "source" classes must exist | |||
* and where the stubs and skeletons will be written. The destination | |||
* directory must exist before this task is executed. | |||
* | |||
* @param dest The directory where the compiled classes will be written. | |||
*/ | |||
public void setDest(File dest) { | |||
this.dest = dest; | |||
} | |||
/** | |||
* Sets the classpath to be used when compiling the EJB stubs and skeletons. | |||
* | |||
* @param classpath The classpath to be used. | |||
*/ | |||
public void setClasspath(Path classpath) { | |||
if (this.classpath == null) { | |||
this.classpath = classpath; | |||
} else { | |||
this.classpath.append(classpath); | |||
} | |||
} | |||
/** | |||
* Creates a nested classpath element. | |||
*/ | |||
public Path createClasspath() { | |||
if (classpath == null) { | |||
classpath = new Path(project); | |||
} | |||
return classpath.createPath(); | |||
} | |||
/** | |||
* Sets whether or not the Java source files which are generated by the | |||
* ejbc process should be retained or automatically deleted. | |||
* | |||
* @param keepgenerated A boolean indicating if the Java source files for | |||
* the stubs and skeletons should be retained. | |||
*/ | |||
public void setKeepgenerated(boolean keepgenerated) { | |||
this.keepgenerated = keepgenerated; | |||
} | |||
/** | |||
* Sets whether or not debugging output will be generated when ejbc is | |||
* executed. | |||
* | |||
* @param debug A boolean indicating if debugging output should be generated | |||
*/ | |||
public void setDebug(boolean debug) { | |||
this.debug = debug; | |||
} | |||
/** | |||
* Setter method used to store the "home" directory of the user's iAS | |||
* installation. The directory specified should typically be | |||
* <code>[install-location]/iplanet/ias6/ias</code>. | |||
* | |||
* @param iashome The home directory for the user's iAS installation. | |||
*/ | |||
public void setIashome(File iashome) { | |||
this.iashome = iashome; | |||
} | |||
/** | |||
* Does the work. | |||
*/ | |||
public void execute() throws BuildException { | |||
checkConfiguration(); | |||
executeEjbc(getParser()); | |||
} | |||
/** | |||
* Verifies that the user selections are valid. | |||
* | |||
* @throws BuildException If the user selections are invalid. | |||
*/ | |||
private void checkConfiguration() throws BuildException { | |||
if (ejbdescriptor == null) { | |||
String msg = "The standard EJB descriptor must be specified using " | |||
+ "the \"ejbdescriptor\" attribute."; | |||
throw new BuildException(msg, location); | |||
} | |||
if ((!ejbdescriptor.exists()) || (!ejbdescriptor.isFile())) { | |||
String msg = "The standard EJB descriptor (" + ejbdescriptor | |||
+ ") was not found or isn't a file."; | |||
throw new BuildException(msg, location); | |||
} | |||
if (iasdescriptor == null) { | |||
String msg = "The iAS-speific XML descriptor must be specified using" | |||
+ " the \"iasdescriptor\" attribute."; | |||
throw new BuildException(msg, location); | |||
} | |||
if ((!iasdescriptor.exists()) || (!iasdescriptor.isFile())) { | |||
String msg = "The iAS-specific XML descriptor (" + iasdescriptor | |||
+ ") was not found or isn't a file."; | |||
throw new BuildException(msg, location); | |||
} | |||
if (dest == null) { | |||
String msg = "The destination directory must be specified using " | |||
+ "the \"dest\" attribute."; | |||
throw new BuildException(msg, location); | |||
} | |||
if ((!dest.exists()) || (!dest.isDirectory())) { | |||
String msg = "The destination directory (" + dest + ") was not " | |||
+ "found or isn't a directory."; | |||
throw new BuildException(msg, location); | |||
} | |||
if ((iashome != null) && (!iashome.isDirectory())) { | |||
String msg = "If \"iashome\" is specified, it must be a valid " | |||
+ "directory (it was set to " + iashome + ")."; | |||
throw new BuildException(msg, getLocation()); | |||
} | |||
} | |||
/** | |||
* Returns a SAXParser that may be used to process the XML descriptors. | |||
* | |||
* @return Parser which may be used to process the EJB descriptors. | |||
* @throws BuildException If the parser cannot be created or configured. | |||
*/ | |||
private SAXParser getParser() throws BuildException { | |||
SAXParser saxParser = null; | |||
try { | |||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||
saxParserFactory.setValidating(true); | |||
saxParser = saxParserFactory.newSAXParser(); | |||
} catch (SAXException e) { | |||
String msg = "Unable to create a SAXParser: " + e.getMessage(); | |||
throw new BuildException(msg, e, location); | |||
} | |||
catch (ParserConfigurationException e) { | |||
String msg = "Unable to create a SAXParser: " + e.getMessage(); | |||
throw new BuildException(msg, e, location); | |||
} | |||
return saxParser; | |||
} | |||
/** | |||
* Executes the EJBc utility using the SAXParser provided. | |||
* | |||
* @param saxParser SAXParser that may be used to process the EJB | |||
* descriptors | |||
* @throws BuildException If there is an error reading or parsing the XML | |||
* descriptors | |||
*/ | |||
private void executeEjbc(SAXParser saxParser) throws BuildException { | |||
IPlanetEjbc ejbc = new IPlanetEjbc(ejbdescriptor, | |||
iasdescriptor, | |||
dest, | |||
getClasspath().toString(), | |||
saxParser); | |||
ejbc.setRetainSource(keepgenerated); | |||
ejbc.setDebugOutput(debug); | |||
if (iashome != null) { | |||
ejbc.setIasHomeDir(iashome); | |||
} | |||
try { | |||
ejbc.execute(); | |||
} catch (IOException e) { | |||
String msg = "An IOException occurred while trying to read the XML " | |||
+ "descriptor file: " + e.getMessage(); | |||
throw new BuildException(msg, e, location); | |||
} catch (SAXException e) { | |||
String msg = "A SAXException occurred while trying to read the XML " | |||
+ "descriptor file: " + e.getMessage(); | |||
throw new BuildException(msg, e, location); | |||
} catch (IPlanetEjbc.EjbcException e) { | |||
String msg = "An exception occurred while trying to run the ejbc " | |||
+ "utility: " + e.getMessage(); | |||
throw new BuildException(msg, e, location); | |||
} | |||
} | |||
/** | |||
* Returns the CLASSPATH to be used when calling EJBc. If no user CLASSPATH | |||
* is specified, the System classpath is returned instead. | |||
* | |||
* @return Path The classpath to be used for EJBc. | |||
*/ | |||
private Path getClasspath() { | |||
if (classpath == null) { | |||
classpath = Path.systemClasspath; | |||
} | |||
return classpath; | |||
} | |||
} |