tool classes.
Split the Descriptor handler to a separate class
Allow local DTDs to be loaded to resolve the external entities
Moved all Weblogic specific code into a separate deployment tool object.
Usage for generic jars is now
<ejbjar srcdir="${descriptor.dir}" destdir="${deploymentjar.dir}">
<include name="**/*-ejb-jar.xml"/>
</ejbjar>
For a weblogic deployment you now add a nested element with the weblogic specific
configs
<ejbjar srcdir="${descriptor.dir}">
<weblogic destdir="${deploymentjar.dir}"
classpath="${descriptorbuild.classpath}"
keepgeneric="false"
suffix=".jar"/>
<include name="**/*-ejb-jar.xml"/>
<exclude name="**/*-weblogic-ejb-jar.xml"/>
</ejbjar>
git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267868 13f79535-47bb-0310-9956-ffa450edef68
master
| @@ -0,0 +1,239 @@ | |||||
| /* | |||||
| * 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", "Tomcat", 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.util.*; | |||||
| import java.io.*; | |||||
| import org.xml.sax.InputSource; | |||||
| import org.xml.sax.SAXException; | |||||
| import org.xml.sax.AttributeList; | |||||
| /** | |||||
| * Inner class used by EjbJar to facilitate the parsing of deployment | |||||
| * descriptors and the capture of appropriate information. Extends | |||||
| * HandlerBase so it only implements the methods needed. During parsing | |||||
| * creates a hashtable consisting of entries mapping the name it should be | |||||
| * inserted into an EJB jar as to a File representing the file on disk. This | |||||
| * list can then be accessed through the getFiles() method. | |||||
| */ | |||||
| public class DescriptorHandler extends org.xml.sax.HandlerBase { | |||||
| /** | |||||
| * Bunch of constants used for storing entries in a hashtable, and for | |||||
| * constructing the filenames of various parts of the ejb jar. | |||||
| */ | |||||
| private static final String HOME_INTERFACE = "home"; | |||||
| private static final String REMOTE_INTERFACE = "remote"; | |||||
| private static final String BEAN_CLASS = "ejb-class"; | |||||
| private static final String PK_CLASS = "prim-key-class"; | |||||
| /** | |||||
| * Instance variable used to store the name of the current element being | |||||
| * processed by the SAX parser. Accessed by the SAX parser call-back methods | |||||
| * startElement() and endElement(). | |||||
| */ | |||||
| private String currentElement = null; | |||||
| /** | |||||
| * The text of the current element | |||||
| */ | |||||
| private String currentText = null; | |||||
| /** | |||||
| * Instance variable that stores the names of the files as they will be | |||||
| * put into the jar file, mapped to File objects Accessed by the SAX | |||||
| * parser call-back method characters(). | |||||
| */ | |||||
| private Hashtable ejbFiles = null; | |||||
| private Hashtable fileDTDs = new Hashtable(); | |||||
| private Hashtable resourceDTDs = new Hashtable(); | |||||
| /** | |||||
| * The directory containing the bean classes and interfaces. This is | |||||
| * used for performing dependency file lookups. | |||||
| */ | |||||
| private File srcDir; | |||||
| public DescriptorHandler(File srcDir) { | |||||
| this.srcDir = srcDir; | |||||
| } | |||||
| public void registerFileDTD(String publicId, File dtdFile) { | |||||
| fileDTDs.put(publicId, dtdFile); | |||||
| } | |||||
| public void registerResourceDTD(String publicId, String resourceName) { | |||||
| resourceDTDs.put(publicId, resourceName); | |||||
| } | |||||
| public InputSource resolveEntity(String publicId, String systemId) | |||||
| throws SAXException | |||||
| { | |||||
| File dtdFile = (File) fileDTDs.get(publicId); | |||||
| if (dtdFile != null && dtdFile.exists()) { | |||||
| try { | |||||
| return new InputSource(new FileInputStream(dtdFile)); | |||||
| } catch( FileNotFoundException ex ) { | |||||
| // ignore | |||||
| } | |||||
| } | |||||
| String dtdResourceName = (String)resourceDTDs.get(publicId); | |||||
| if (dtdResourceName != null) { | |||||
| InputStream is = this.getClass().getResourceAsStream(dtdResourceName); | |||||
| if( is != null ) { | |||||
| return new InputSource(is); | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| /** | |||||
| * Getter method that returns the set of files to include in the EJB jar. | |||||
| */ | |||||
| public Hashtable getFiles() { | |||||
| return (ejbFiles == null) ? new Hashtable() : ejbFiles; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is used to initialize the values of some | |||||
| * instance variables to ensure safe operation. | |||||
| */ | |||||
| public void startDocument() throws SAXException { | |||||
| this.ejbFiles = new Hashtable(10, 1); | |||||
| this.currentElement = null; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is invoked when a new element is entered | |||||
| * into. Used to store the context (attribute name) in the currentAttribute | |||||
| * instance variable. | |||||
| * @param name The name of the element being entered. | |||||
| * @param attrs Attributes associated to the element. | |||||
| */ | |||||
| public void startElement(String name, AttributeList attrs) | |||||
| throws SAXException { | |||||
| this.currentElement = name; | |||||
| currentText = ""; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is invoked when an element is exited. | |||||
| * Used to blank out (set to the empty string, not nullify) the name of | |||||
| * the currentAttribute. A better method would be to use a stack as an | |||||
| * instance variable, however since we are only interested in leaf-node | |||||
| * data this is a simpler and workable solution. | |||||
| * @param name The name of the attribute being exited. Ignored | |||||
| * in this implementation. | |||||
| */ | |||||
| public void endElement(String name) throws SAXException { | |||||
| processElement(); | |||||
| currentText = ""; | |||||
| this.currentElement = ""; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method invoked whenever characters are located within | |||||
| * an element. currentAttribute (modified by startElement and endElement) | |||||
| * tells us whether we are in an interesting element (one of the up to four | |||||
| * classes of an EJB). If so then converts the classname from the format | |||||
| * org.apache.tools.ant.Parser to the convention for storing such a class, | |||||
| * org/apache/tools/ant/Parser.class. This is then resolved into a file | |||||
| * object under the srcdir which is stored in a Hashtable. | |||||
| * @param ch A character array containing all the characters in | |||||
| * the element, and maybe others that should be ignored. | |||||
| * @param start An integer marking the position in the char | |||||
| * array to start reading from. | |||||
| * @param length An integer representing an offset into the | |||||
| * char array where the current data terminates. | |||||
| */ | |||||
| public void characters(char[] ch, int start, int length) | |||||
| throws SAXException { | |||||
| currentText += new String(ch, start, length); | |||||
| } | |||||
| private void processElement() { | |||||
| if (currentElement.equals(HOME_INTERFACE) || | |||||
| currentElement.equals(REMOTE_INTERFACE) || | |||||
| currentElement.equals(BEAN_CLASS) || | |||||
| currentElement.equals(PK_CLASS)) { | |||||
| // Get the filename into a String object | |||||
| File classFile = null; | |||||
| String className = currentText; | |||||
| // If it's a primitive wrapper then we shouldn't try and put | |||||
| // it into the jar, so ignore it. | |||||
| if (!className.startsWith("java.lang")) { | |||||
| // Translate periods into path separators, add .class to the | |||||
| // name, create the File object and add it to the Hashtable. | |||||
| className = className.replace('.', File.separatorChar); | |||||
| className += ".class"; | |||||
| classFile = new File(srcDir, className); | |||||
| ejbFiles.put(className, classFile); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,90 @@ | |||||
| /* | |||||
| * 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", "Tomcat", 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.*; | |||||
| import javax.xml.parsers.SAXParser; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Task; | |||||
| public interface EJBDeploymentTool { | |||||
| /** | |||||
| * Process a deployment descriptor, generating the necessary vendor specifi | |||||
| * deployment files. | |||||
| * | |||||
| * @param descriptorFilename the name of the deployment descriptor | |||||
| * @param saxParser a SAX parser which can be used to parse the deployment descriptor. | |||||
| */ | |||||
| public void processDescriptor(File srcDir, String descriptorFilename, SAXParser saxParser) | |||||
| throws BuildException; | |||||
| /** | |||||
| * Called to validate that the tool parameters have been configured. | |||||
| * | |||||
| */ | |||||
| public void validateConfigured() throws BuildException; | |||||
| /** | |||||
| * Set the task which owns this tool | |||||
| */ | |||||
| public void setTask(Task task); | |||||
| /** | |||||
| * Configure this tool for use in the ejbjar task. | |||||
| */ | |||||
| public void configure(String basenameTerminator, boolean flatDestDir); | |||||
| } | |||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * The Apache Software License, Version 1.1 | ||||
| * | * | ||||
| * Copyright (c) 1999 The Apache Software Foundation. All rights | |||||
| * Copyright (c) 2000 The Apache Software Foundation. All rights | |||||
| * reserved. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| @@ -55,37 +55,20 @@ | |||||
| package org.apache.tools.ant.taskdefs.optional.ejb; | package org.apache.tools.ant.taskdefs.optional.ejb; | ||||
| // Standard java imports | // Standard java imports | ||||
| import java.io.FileInputStream; | |||||
| import java.io.FileOutputStream; | |||||
| import java.io.PrintWriter; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.jar.*; | |||||
| import java.util.zip.*; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Iterator; | |||||
| import java.io.*; | |||||
| import java.util.*; | |||||
| // XML imports | // XML imports | ||||
| import javax.xml.parsers.SAXParser; | import javax.xml.parsers.SAXParser; | ||||
| import javax.xml.parsers.SAXParserFactory; | import javax.xml.parsers.SAXParserFactory; | ||||
| import javax.xml.parsers.ParserConfigurationException; | import javax.xml.parsers.ParserConfigurationException; | ||||
| import org.xml.sax.Parser; | |||||
| import org.xml.sax.Locator; | |||||
| import org.xml.sax.InputSource; | |||||
| import org.xml.sax.AttributeList; | |||||
| import org.xml.sax.DocumentHandler; | |||||
| import org.xml.sax.SAXException; | import org.xml.sax.SAXException; | ||||
| import org.xml.sax.SAXParseException; | |||||
| import org.xml.sax.helpers.ParserFactory; | |||||
| // Apache/Ant imports | // Apache/Ant imports | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
| import org.apache.tools.ant.taskdefs.MatchingTask; | import org.apache.tools.ant.taskdefs.MatchingTask; | ||||
| import org.apache.tools.ant.taskdefs.Java; | |||||
| /** | /** | ||||
| * <p>Provides automated ejb jar file creation for ant. Extends the MatchingTask | * <p>Provides automated ejb jar file creation for ant. Extends the MatchingTask | ||||
| @@ -104,146 +87,21 @@ import org.apache.tools.ant.taskdefs.Java; | |||||
| * 5.1 jars. The weblogic deployment descriptors, used in constructing the | * 5.1 jars. The weblogic deployment descriptors, used in constructing the | ||||
| * Weblogic jar, are located based on a simple naming convention. The name of the | * Weblogic jar, are located based on a simple naming convention. The name of the | ||||
| * standard deployment descriptor is taken upto the first instance of a String, | * standard deployment descriptor is taken upto the first instance of a String, | ||||
| * specified by the attribute basenameterminator, and then the regular Weblogic | |||||
| * descriptor name is appended. For example if basenameterminator is set to '-', | |||||
| * specified by the attribute basenameTerminator, and then the regular Weblogic | |||||
| * descriptor name is appended. For example if basenameTerminator is set to '-', | |||||
| * its default value, and a standard descriptor is called Foo-ejb-jar.xml then | * its default value, and a standard descriptor is called Foo-ejb-jar.xml then | ||||
| * the files Foo-weblogic-ejb-jar.xml and Foo-weblogic-cmp-rdbms-jar.xml will be | * the files Foo-weblogic-ejb-jar.xml and Foo-weblogic-cmp-rdbms-jar.xml will be | ||||
| * looked for, and if found, included in the jarfile.</p> | * looked for, and if found, included in the jarfile.</p> | ||||
| * | * | ||||
| * <p>Attributes and setter methods are provided to support optional generation | * <p>Attributes and setter methods are provided to support optional generation | ||||
| * of Weblogic5.1 jars, optional deletion of generic jar files, setting alternate | * of Weblogic5.1 jars, optional deletion of generic jar files, setting alternate | ||||
| * values for basenameterminator, and setting the strings to append to the names | |||||
| * values for basenameTerminator, and setting the strings to append to the names | |||||
| * of the generated jarfiles.</p> | * of the generated jarfiles.</p> | ||||
| * | * | ||||
| * @author <a href="mailto:tfennell@sapient.com">Tim Fennell</a> | * @author <a href="mailto:tfennell@sapient.com">Tim Fennell</a> | ||||
| */ | */ | ||||
| public class EjbJar extends MatchingTask { | public class EjbJar extends MatchingTask { | ||||
| /** | |||||
| * Inner class used by EjbJar to facilitate the parsing of deployment | |||||
| * descriptors and the capture of appropriate information. Extends | |||||
| * HandlerBase so it only implements the methods needed. During parsing | |||||
| * creates a hashtable consisting of entries mapping the name it should be | |||||
| * inserted into an EJB jar as to a File representing the file on disk. This | |||||
| * list can then be accessed through the getFiles() method. | |||||
| */ | |||||
| protected class DescriptorHandler extends org.xml.sax.HandlerBase { | |||||
| /** | |||||
| * Bunch of constants used for storing entries in a hashtable, and for | |||||
| * constructing the filenames of various parts of the ejb jar. | |||||
| */ | |||||
| private static final String HOME_INTERFACE = "home"; | |||||
| private static final String REMOTE_INTERFACE = "remote"; | |||||
| private static final String BEAN_CLASS = "ejb-class"; | |||||
| private static final String PK_CLASS = "prim-key-class"; | |||||
| /** | |||||
| * Instance variable used to store the name of the current attribute being | |||||
| * processed by the SAX parser. Accessed by the SAX parser call-back methods | |||||
| * startElement() and endElement(). | |||||
| */ | |||||
| private String currentAttribute = null; | |||||
| /** | |||||
| * Instance variable that stores the names of the files as they will be | |||||
| * put into the jar file, mapped to File objects Accessed by the SAX | |||||
| * parser call-back method characters(). | |||||
| */ | |||||
| private Hashtable ejbFiles = null; | |||||
| /** Instance variable to store the source directory of the task */ | |||||
| /** | |||||
| * Getter method that returns the set of files to include in the EJB jar. | |||||
| */ | |||||
| public Hashtable getFiles() { | |||||
| return (ejbFiles == null) ? new Hashtable() : ejbFiles; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is used to initialize the values of some | |||||
| * instance variables to ensure safe operation. | |||||
| */ | |||||
| public void startDocument() throws SAXException { | |||||
| this.ejbFiles = new Hashtable(10, 1); | |||||
| this.currentAttribute = null; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is invoked when a new element is entered | |||||
| * into. Used to store the context (attribute name) in the currentAttribute | |||||
| * instance variable. | |||||
| * @param name The name of the element being entered. | |||||
| * @param attrs Attributes associated to the element. | |||||
| */ | |||||
| public void startElement(String name, AttributeList attrs) | |||||
| throws SAXException { | |||||
| this.currentAttribute = name; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method that is invoked when an element is exited. | |||||
| * Used to blank out (set to the empty string, not nullify) the name of | |||||
| * the currentAttribute. A better method would be to use a stack as an | |||||
| * instance variable, however since we are only interested in leaf-node | |||||
| * data this is a simpler and workable solution. | |||||
| * @param name The name of the attribute being exited. Ignored | |||||
| * in this implementation. | |||||
| */ | |||||
| public void endElement(String name) throws SAXException { | |||||
| this.currentAttribute = ""; | |||||
| } | |||||
| /** | |||||
| * SAX parser call-back method invoked whenever characters are located within | |||||
| * an element. currentAttribute (modified by startElement and endElement) | |||||
| * tells us whether we are in an interesting element (one of the up to four | |||||
| * classes of an EJB). If so then converts the classname from the format | |||||
| * org.apache.tools.ant.Parser to the convention for storing such a class, | |||||
| * org/apache/tools/ant/Parser.class. This is then resolved into a file | |||||
| * object under the srcdir which is stored in a Hashtable. | |||||
| * @param ch A character array containing all the characters in | |||||
| * the element, and maybe others that should be ignored. | |||||
| * @param start An integer marking the position in the char | |||||
| * array to start reading from. | |||||
| * @param length An integer representing an offset into the | |||||
| * char array where the current data terminates. | |||||
| */ | |||||
| public void characters(char[] ch, int start, int length) | |||||
| throws SAXException { | |||||
| if (currentAttribute.equals(DescriptorHandler.HOME_INTERFACE) || | |||||
| currentAttribute.equals(DescriptorHandler.REMOTE_INTERFACE) || | |||||
| currentAttribute.equals(DescriptorHandler.BEAN_CLASS) || | |||||
| currentAttribute.equals(DescriptorHandler.PK_CLASS)) { | |||||
| // Get the filename into a String object | |||||
| File classFile = null; | |||||
| String className = new String(ch, start, length); | |||||
| // If it's a primitive wrapper then we shouldn't try and put | |||||
| // it into the jar, so ignore it. | |||||
| if (!className.startsWith("java.lang")) { | |||||
| // Translate periods into path separators, add .class to the | |||||
| // name, create the File object and add it to the Hashtable. | |||||
| className = className.replace('.', File.separatorChar); | |||||
| className += ".class"; | |||||
| classFile = new File(srcdir, className); | |||||
| ejbFiles.put(className, classFile); | |||||
| } | |||||
| } | |||||
| } | |||||
| } // End of DescriptorHandler | |||||
| /** Private constants that are used when constructing the standard jarfile */ | |||||
| private static final String META_DIR = "META-INF/"; | |||||
| private static final String EJB_DD = "ejb-jar.xml"; | |||||
| private static final String WL_DD = "weblogic-ejb-jar.xml"; | |||||
| private static final String WL_CMP_DD = "weblogic-cmp-rdbms-jar.xml"; | |||||
| /** Stores a handle to the directory under which to search for files */ | /** Stores a handle to the directory under which to search for files */ | ||||
| private File srcdir = null; | private File srcdir = null; | ||||
| @@ -255,47 +113,50 @@ public class EjbJar extends MatchingTask { | |||||
| * of a flat directory as the destination for the jar files. | * of a flat directory as the destination for the jar files. | ||||
| */ | */ | ||||
| private boolean flatdestdir = false; | private boolean flatdestdir = false; | ||||
| /** Instance variable that determines whether to generate weblogic jars. */ | |||||
| private boolean generateweblogic = false; | |||||
| /** Instance variable that determines whether generic ejb jars are kept. */ | |||||
| private boolean keepgeneric = true; | |||||
| /** Instance variable that marks the end of the 'basename' */ | /** Instance variable that marks the end of the 'basename' */ | ||||
| private String basenameterminator = "-"; | |||||
| private String basenameTerminator = "-"; | |||||
| /** Instance variable that stores the suffix for the generated jarfile. */ | /** Instance variable that stores the suffix for the generated jarfile. */ | ||||
| private String genericjarsuffix = "-generic.jar"; | private String genericjarsuffix = "-generic.jar"; | ||||
| /** Instance variable that stores the suffix for the weblogic jarfile. */ | |||||
| private String weblogicjarsuffix = "-wl.jar"; | |||||
| /** | |||||
| * The list of deployment tools we are going to run. | |||||
| */ | |||||
| private ArrayList deploymentTools = new ArrayList(); | |||||
| public EJBDeploymentTool createWeblogic() { | |||||
| EJBDeploymentTool tool = new WeblogicDeploymentTool(); | |||||
| tool.setTask(this); | |||||
| deploymentTools.add(tool); | |||||
| return tool; | |||||
| } | |||||
| /** | /** | ||||
| * Setter used to store the value of srcdir prior to execute() being called. | * Setter used to store the value of srcdir prior to execute() being called. | ||||
| * @param inDir The string indicating the source directory. | |||||
| * @param inDir the source directory. | |||||
| */ | */ | ||||
| public void setSrcdir(String inDir) { | |||||
| this.srcdir = this.project.resolveFile(inDir); | |||||
| public void setSrcdir(File inDir) { | |||||
| this.srcdir = inDir; | |||||
| } | } | ||||
| /** | /** | ||||
| * Setter used to store the value of destination directory prior to execute() | * Setter used to store the value of destination directory prior to execute() | ||||
| * being called. | * being called. | ||||
| * @param inFile The string indicating the source directory. | |||||
| * @param inFile the destination directory. | |||||
| */ | */ | ||||
| public void setDestdir(String inDir) { | |||||
| this.destdir = this.project.resolveFile(inDir); | |||||
| public void setDestdir(File inDir) { | |||||
| this.destdir = inDir; | |||||
| } | } | ||||
| /** | /** | ||||
| * Setter used to store the value of flatdestdir. | * Setter used to store the value of flatdestdir. | ||||
| * @param inValue a string, either 'true' or 'false'. | * @param inValue a string, either 'true' or 'false'. | ||||
| */ | */ | ||||
| public void setFlatdestdir(String inValue) { | |||||
| this.flatdestdir = Boolean.valueOf(inValue).booleanValue(); | |||||
| public void setFlatdestdir(boolean inValue) { | |||||
| this.flatdestdir = inValue; | |||||
| } | } | ||||
| /** | /** | ||||
| * Setter used to store the suffix for the generated jar file. | * Setter used to store the suffix for the generated jar file. | ||||
| * @param inString the string to use as the suffix. | * @param inString the string to use as the suffix. | ||||
| @@ -305,164 +166,13 @@ public class EjbJar extends MatchingTask { | |||||
| } | } | ||||
| /** | /** | ||||
| * Setter used to store the suffix for the generated weblogic jar file. | |||||
| * @param inString the string to use as the suffix. | |||||
| */ | |||||
| public void setWeblogicjarsuffix(String inString) { | |||||
| this.weblogicjarsuffix = inString; | |||||
| } | |||||
| /** | |||||
| * Setter used to store the value of generateweblogic. | |||||
| * @param inValue a string, either 'true' or 'false'. | |||||
| */ | |||||
| public void setGenerateweblogic(String inValue) { | |||||
| this.generateweblogic = Boolean.valueOf(inValue).booleanValue(); | |||||
| } | |||||
| /** | |||||
| * Setter used to store the value of keepgeneric | |||||
| * @param inValue a string, either 'true' or 'false'. | |||||
| */ | |||||
| public void setKeepgeneric(String inValue) { | |||||
| this.keepgeneric = Boolean.valueOf(inValue).booleanValue(); | |||||
| } | |||||
| /** | |||||
| * Setter used to store the value of basenameterminator | |||||
| * Setter used to store the value of basenameTerminator | |||||
| * @param inValue a string which marks the end of the basename. | * @param inValue a string which marks the end of the basename. | ||||
| */ | */ | ||||
| public void setBasenameterminator(String inValue) { | |||||
| if (inValue != null) this.basenameterminator = inValue; | |||||
| } | |||||
| /** | |||||
| * Utility method that encapsulates the logic of adding a file entry to | |||||
| * a .jar file. Used by execute() to add entries to the jar file as it is | |||||
| * constructed. | |||||
| * @param jStream A JarOutputStream into which to write the | |||||
| * jar entry. | |||||
| * @param iStream A FileInputStream from which to read the | |||||
| * contents the file being added. | |||||
| * @param filename A String representing the name, including | |||||
| * all relevant path information, that should be stored for the entry | |||||
| * being added. | |||||
| */ | |||||
| protected void addFileToJar(JarOutputStream jStream, | |||||
| FileInputStream iStream, | |||||
| String filename) | |||||
| throws BuildException { | |||||
| try { | |||||
| // Create the zip entry and add it to the jar file | |||||
| ZipEntry zipEntry = new ZipEntry(filename); | |||||
| jStream.putNextEntry(zipEntry); | |||||
| // Create the file input stream, and buffer everything over | |||||
| // to the jar output stream | |||||
| byte[] byteBuffer = new byte[2 * 1024]; | |||||
| int count = 0; | |||||
| do { | |||||
| jStream.write(byteBuffer, 0, count); | |||||
| count = iStream.read(byteBuffer, 0, byteBuffer.length); | |||||
| } while (count != -1); | |||||
| // Close up the file input stream for the class file | |||||
| iStream.close(); | |||||
| } | |||||
| catch (IOException ioe) { | |||||
| String msg = "IOException while adding entry " | |||||
| + filename + "to jarfile." | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 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 | |||||
| * ejbFiles. | |||||
| */ | |||||
| public void writeJar(File jarfile, Hashtable files) throws BuildException{ | |||||
| JarOutputStream jarStream = null; | |||||
| Iterator entryIterator = null; | |||||
| String entryName = null; | |||||
| File entryFile = null; | |||||
| try { | |||||
| /* If the jarfile already exists then whack it and recreate it. | |||||
| * Should probably think of a more elegant way to handle this | |||||
| * so that in case of errors we don't leave people worse off | |||||
| * than when we started =) | |||||
| */ | |||||
| if (jarfile.exists()) jarfile.delete(); | |||||
| jarfile.getParentFile().mkdirs(); | |||||
| jarfile.createNewFile(); | |||||
| // Create the streams necessary to write the jarfile | |||||
| jarStream = new JarOutputStream(new FileOutputStream(jarfile)); | |||||
| jarStream.setMethod(JarOutputStream.DEFLATED); | |||||
| // Loop through all the class files found and add them to the jar | |||||
| entryIterator = files.keySet().iterator(); | |||||
| while (entryIterator.hasNext()) { | |||||
| entryName = (String) entryIterator.next(); | |||||
| entryFile = (File) files.get(entryName); | |||||
| this.log("adding file '" + entryName + "'", | |||||
| Project.MSG_VERBOSE); | |||||
| addFileToJar(jarStream, | |||||
| new FileInputStream(entryFile), | |||||
| entryName); | |||||
| } | |||||
| // All done. Close the jar stream. | |||||
| jarStream.close(); | |||||
| } | |||||
| catch(IOException ioe) { | |||||
| String msg = "IOException while processing ejb-jar file '" | |||||
| + jarfile.toString() | |||||
| + "'. Details: " | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } // end of writeJar | |||||
| /** | |||||
| * Helper method invoked by execute() for each WebLogic jar to be built. | |||||
| * Encapsulates the logic of constructing a java task for calling | |||||
| * weblogic.ejbc and executing it. | |||||
| * @param sourceJar java.io.File representing the source (EJB1.1) jarfile. | |||||
| * @param destJar java.io.File representing the destination, WebLogic | |||||
| * jarfile. | |||||
| */ | |||||
| public void buildWeblogicJar(File sourceJar, File destJar) { | |||||
| org.apache.tools.ant.taskdefs.Java javaTask = null; | |||||
| try { | |||||
| // Unfortunately, because weblogic.ejbc calls system.exit(), we | |||||
| // cannot do it 'in-process'. If they ever fix this, we should | |||||
| // change this code - it would be much quicker! | |||||
| String args = "-noexit " + sourceJar + " " + destJar; | |||||
| javaTask = (Java) this.project.createTask("java"); | |||||
| javaTask.setClassname("weblogic.ejbc"); | |||||
| javaTask.setArgs(args); | |||||
| javaTask.setFork(false); | |||||
| this.log("Calling weblogic.ejbc for " + sourceJar.toString(), | |||||
| Project.MSG_INFO); | |||||
| javaTask.execute(); | |||||
| } | |||||
| catch (Exception e) { | |||||
| // Have to catch this because of the semantics of calling main() | |||||
| String msg = "Exception while calling ejbc. Details: " + e.toString(); | |||||
| throw new BuildException(msg, e); | |||||
| } | |||||
| public void setBasenameTerminator(String inValue) { | |||||
| if (inValue != null) this.basenameTerminator = inValue; | |||||
| } | } | ||||
| /** | /** | ||||
| * Invoked by Ant after the task is prepared, when it is ready to execute | * Invoked by Ant after the task is prepared, when it is ready to execute | ||||
| * this task. Parses the XML deployment descriptor to acquire the list of | * this task. Parses the XML deployment descriptor to acquire the list of | ||||
| @@ -475,173 +185,51 @@ public class EjbJar extends MatchingTask { | |||||
| * that a major problem occurred within this task. | * that a major problem occurred within this task. | ||||
| */ | */ | ||||
| public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
| boolean needBuild = true; | |||||
| DirectoryScanner ds = null; | |||||
| String[] files = null; | |||||
| int index = 0; | |||||
| File weblogicDD = null; | |||||
| File jarfile = null; | |||||
| File wlJarfile = null; | |||||
| File jarToCheck = null; | |||||
| DescriptorHandler handler = null; | |||||
| Hashtable ejbFiles = null; | |||||
| String baseName = null; | |||||
| // Lets do a little asserting to make sure we have all the | |||||
| // required attributes from the task processor | |||||
| StringBuffer sb = new StringBuffer(); | |||||
| boolean die = false; | |||||
| sb.append("Processing ejbjar - the following attributes "); | |||||
| sb.append("must be specified: "); | |||||
| if (this.srcdir == null) { sb.append("srcdir "); die = true; } | |||||
| if (this.destdir == null) { sb.append("destdir"); die = true; } | |||||
| if ( die ) throw new BuildException(sb.toString()); | |||||
| if (srcdir == null) { | |||||
| throw new BuildException("The srcdir attribute must be specified"); | |||||
| } | |||||
| if (deploymentTools.size() == 0) { | |||||
| GenericDeploymentTool genericTool = new GenericDeploymentTool(); | |||||
| genericTool.setDestdir(destdir); | |||||
| genericTool.setTask(this); | |||||
| genericTool.setGenericjarsuffix(genericjarsuffix); | |||||
| deploymentTools.add(genericTool); | |||||
| } | |||||
| for (Iterator i = deploymentTools.iterator(); i.hasNext(); ) { | |||||
| EJBDeploymentTool tool = (EJBDeploymentTool)i.next(); | |||||
| tool.configure(basenameTerminator, flatdestdir); | |||||
| tool.validateConfigured(); | |||||
| } | |||||
| try { | try { | ||||
| // Create the parser using whatever parser the system dictates | // Create the parser using whatever parser the system dictates | ||||
| SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | ||||
| saxParserFactory.setValidating(false); | |||||
| saxParserFactory.setValidating(true); | |||||
| SAXParser saxParser = saxParserFactory.newSAXParser(); | SAXParser saxParser = saxParserFactory.newSAXParser(); | ||||
| ds = this.getDirectoryScanner(this.srcdir); | |||||
| DirectoryScanner ds = getDirectoryScanner(srcdir); | |||||
| ds.scan(); | ds.scan(); | ||||
| files = ds.getIncludedFiles(); | |||||
| this.log(files.length + " deployment descriptors located.", | |||||
| Project.MSG_VERBOSE); | |||||
| String[] files = ds.getIncludedFiles(); | |||||
| log(files.length + " deployment descriptors located.", | |||||
| Project.MSG_VERBOSE); | |||||
| // Loop through the files. Each file represents one deployment | // Loop through the files. Each file represents one deployment | ||||
| // descriptor, and hence one bean in our model. | // descriptor, and hence one bean in our model. | ||||
| for (index=0; index < files.length; ++index) { | |||||
| // By default we assume we need to build. | |||||
| needBuild = true; | |||||
| // Work out what the base name is | |||||
| int endBaseName = | |||||
| files[index].indexOf(basenameterminator, | |||||
| files[index].lastIndexOf(File.separator)); | |||||
| baseName = files[index].substring(0, endBaseName); | |||||
| /* 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. | |||||
| */ | |||||
| handler = new DescriptorHandler(); | |||||
| saxParser.parse(new InputSource | |||||
| (new FileInputStream | |||||
| (new File(this.srcdir, files[index]))), | |||||
| handler); | |||||
| ejbFiles = handler.getFiles(); | |||||
| /* Now try to locate all of the deployment descriptors for the | |||||
| * jar, and if they exist, add them to the list of files. | |||||
| */ | |||||
| // First the regular deployment descriptor | |||||
| ejbFiles.put(EjbJar.META_DIR + EjbJar.EJB_DD, | |||||
| new File(this.srcdir, files[index])); | |||||
| // Then the weblogic deployment descriptor | |||||
| weblogicDD = new File(this.srcdir, | |||||
| baseName | |||||
| + this.basenameterminator | |||||
| + EjbJar.WL_DD); | |||||
| if (weblogicDD.exists()) { | |||||
| ejbFiles.put(EjbJar.META_DIR + EjbJar.WL_DD, | |||||
| weblogicDD); | |||||
| 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(); | |||||
| processDescriptor(files[index], saxParser, tool); | |||||
| } | } | ||||
| // The the weblogic cmp deployment descriptor | |||||
| weblogicDD = new File(this.srcdir, | |||||
| baseName | |||||
| + this.basenameterminator | |||||
| + EjbJar.WL_CMP_DD); | |||||
| if (weblogicDD.exists()) { | |||||
| ejbFiles.put(EjbJar.META_DIR + EjbJar.WL_CMP_DD, | |||||
| weblogicDD); | |||||
| } | |||||
| // Lastly create File object for the Jar files. If we are using | |||||
| // a flat destination dir, then we need to redefine baseName! | |||||
| if (this.flatdestdir) { | |||||
| int startName = baseName.lastIndexOf(File.separator); | |||||
| int endName = baseName.length(); | |||||
| baseName = baseName.substring(startName, endName); | |||||
| } | |||||
| jarfile = new File(this.destdir, | |||||
| baseName | |||||
| + this.genericjarsuffix); | |||||
| wlJarfile = new File(this.destdir, | |||||
| baseName | |||||
| + this.weblogicjarsuffix); | |||||
| /* Check to see if the jar file is already up to date. | |||||
| * Unfortunately we have to parse the descriptor just to do | |||||
| * that, but it's still a saving over re-constructing the jar | |||||
| * file each time. Tertiary is used to determine which jarfile | |||||
| * we should check times against...think about it. | |||||
| */ | |||||
| jarToCheck = this.generateweblogic ? wlJarfile : jarfile; | |||||
| if (jarToCheck.exists()) { | |||||
| long lastBuild = jarToCheck.lastModified(); | |||||
| Iterator fileIter = ejbFiles.values().iterator(); | |||||
| File currentFile = null; | |||||
| // 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()) ) { | |||||
| currentFile = (File) fileIter.next(); | |||||
| needBuild = ( lastBuild < currentFile.lastModified() ); | |||||
| } | |||||
| } | |||||
| // Check to see if we need a build and start | |||||
| // doing the work! | |||||
| if (needBuild) { | |||||
| // Log that we are going to build... | |||||
| this.log( "building " | |||||
| + jarfile.getName() | |||||
| + " with " | |||||
| + String.valueOf(ejbFiles.size()) | |||||
| + " total files", | |||||
| Project.MSG_INFO); | |||||
| // Use helper method to write the jarfile | |||||
| this.writeJar(jarfile, ejbFiles); | |||||
| // Generate weblogic jar if requested | |||||
| if (this.generateweblogic) { | |||||
| this.buildWeblogicJar(jarfile, wlJarfile); | |||||
| } | |||||
| // Delete the original jar if we weren't asked to keep it. | |||||
| if (!this.keepgeneric) { | |||||
| this.log("deleting jar " + jarfile.toString(), | |||||
| Project.MSG_INFO); | |||||
| jarfile.delete(); | |||||
| } | |||||
| } | |||||
| else { | |||||
| // Log that the file is up to date... | |||||
| this.log(jarfile.toString() + " is up to date.", | |||||
| Project.MSG_INFO); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| catch (SAXException se) { | catch (SAXException se) { | ||||
| String msg = "SAXException while parsing '" | |||||
| + files[index].toString() | |||||
| + "'. This probably indicates badly-formed XML." | |||||
| String msg = "SAXException while creating parser." | |||||
| + " Details: " | + " Details: " | ||||
| + se.getMessage(); | + se.getMessage(); | ||||
| throw new BuildException(msg, se); | throw new BuildException(msg, se); | ||||
| @@ -651,15 +239,14 @@ public class EjbJar extends MatchingTask { | |||||
| + "Details: " + pce.getMessage(); | + "Details: " + pce.getMessage(); | ||||
| throw new BuildException(msg, pce); | throw new BuildException(msg, pce); | ||||
| } | } | ||||
| catch (IOException ioe) { | |||||
| String msg = "IOException while parsing'" | |||||
| + files[index].toString() | |||||
| + "'. This probably indicates that the descriptor" | |||||
| + " doesn't exist. Details:" | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } // end of execute() | } // end of execute() | ||||
| private void processDescriptor(String descriptorFilename, SAXParser saxParser, | |||||
| EJBDeploymentTool tool) { | |||||
| tool.processDescriptor(srcdir, descriptorFilename, saxParser); | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,377 @@ | |||||
| /* | |||||
| * 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", "Tomcat", 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.*; | |||||
| import java.util.*; | |||||
| import java.util.jar.*; | |||||
| import java.util.zip.*; | |||||
| import javax.xml.parsers.SAXParser; | |||||
| import org.xml.sax.InputSource; | |||||
| import org.xml.sax.SAXException; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
| /** Private constants that are used when constructing the standard jarfile */ | |||||
| protected static final String META_DIR = "META-INF/"; | |||||
| protected static final String EJB_DD = "ejb-jar.xml"; | |||||
| /** Stores a handle to the directory to put the Jar files in */ | |||||
| private File destDir = null; | |||||
| /** | |||||
| * Instance variable that determines whether to use a package structure | |||||
| * of a flat directory as the destination for the jar files. | |||||
| */ | |||||
| private boolean flatDestDir = false; | |||||
| /** Instance variable that marks the end of the 'basename' */ | |||||
| private String basenameTerminator = "-"; | |||||
| /** Instance variable that stores the suffix for the generated jarfile. */ | |||||
| private String genericjarsuffix = "-generic.jar"; | |||||
| /** | |||||
| * The task to which this tool belongs. | |||||
| */ | |||||
| private Task task; | |||||
| /** | |||||
| * Setter used to store the value of destination directory prior to execute() | |||||
| * being called. | |||||
| * @param inDir the destination directory. | |||||
| */ | |||||
| public void setDestdir(File inDir) { | |||||
| this.destDir = inDir; | |||||
| } | |||||
| /** | |||||
| * Get the desitination directory. | |||||
| */ | |||||
| protected File getDestDir() { | |||||
| return destDir; | |||||
| } | |||||
| /** | |||||
| * Set the task which owns this tool | |||||
| */ | |||||
| public void setTask(Task task) { | |||||
| this.task = task; | |||||
| } | |||||
| /** | |||||
| * Get the task for this tool. | |||||
| */ | |||||
| protected Task getTask() { | |||||
| return task; | |||||
| } | |||||
| /** | |||||
| * Get the basename terminator. | |||||
| */ | |||||
| protected String getBasenameTerminator() { | |||||
| return basenameTerminator; | |||||
| } | |||||
| /** | |||||
| * Setter used to store the suffix for the generated jar file. | |||||
| * @param inString the string to use as the suffix. | |||||
| */ | |||||
| public void setGenericjarsuffix(String inString) { | |||||
| this.genericjarsuffix = inString; | |||||
| } | |||||
| /** | |||||
| * Configure this tool for use in the ejbjar task. | |||||
| */ | |||||
| public void configure(String basenameTerminator, boolean flatDestDir) { | |||||
| this.basenameTerminator = basenameTerminator; | |||||
| this.flatDestDir = flatDestDir; | |||||
| } | |||||
| /** | |||||
| * Utility method that encapsulates the logic of adding a file entry to | |||||
| * a .jar file. Used by execute() to add entries to the jar file as it is | |||||
| * constructed. | |||||
| * @param jStream A JarOutputStream into which to write the | |||||
| * jar entry. | |||||
| * @param iStream A FileInputStream from which to read the | |||||
| * contents the file being added. | |||||
| * @param filename A String representing the name, including | |||||
| * all relevant path information, that should be stored for the entry | |||||
| * being added. | |||||
| */ | |||||
| protected void addFileToJar(JarOutputStream jStream, | |||||
| FileInputStream iStream, | |||||
| String filename) | |||||
| throws BuildException { | |||||
| try { | |||||
| // Create the zip entry and add it to the jar file | |||||
| ZipEntry zipEntry = new ZipEntry(filename); | |||||
| jStream.putNextEntry(zipEntry); | |||||
| // Create the file input stream, and buffer everything over | |||||
| // to the jar output stream | |||||
| byte[] byteBuffer = new byte[2 * 1024]; | |||||
| int count = 0; | |||||
| do { | |||||
| jStream.write(byteBuffer, 0, count); | |||||
| count = iStream.read(byteBuffer, 0, byteBuffer.length); | |||||
| } while (count != -1); | |||||
| // Close up the file input stream for the class file | |||||
| iStream.close(); | |||||
| } | |||||
| catch (IOException ioe) { | |||||
| String msg = "IOException while adding entry " | |||||
| + filename + "to jarfile." | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } | |||||
| protected DescriptorHandler getDescriptorHandler(File srcDir) { | |||||
| return new DescriptorHandler(srcDir); | |||||
| } | |||||
| public void processDescriptor(File srcDir, String descriptorFilename, SAXParser saxParser) { | |||||
| try { | |||||
| DescriptorHandler handler = getDescriptorHandler(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. | |||||
| */ | |||||
| saxParser.parse(new InputSource | |||||
| (new FileInputStream | |||||
| (new File(srcDir, descriptorFilename))), | |||||
| handler); | |||||
| Hashtable ejbFiles = handler.getFiles(); | |||||
| String baseName = ""; | |||||
| // Work out what the base name is | |||||
| int lastSeparatorIndex = descriptorFilename.lastIndexOf(File.separator); | |||||
| int endBaseName = -1; | |||||
| if (lastSeparatorIndex != -1) { | |||||
| endBaseName = descriptorFilename.indexOf(basenameTerminator, | |||||
| lastSeparatorIndex); | |||||
| } | |||||
| else { | |||||
| endBaseName = descriptorFilename.indexOf(basenameTerminator); | |||||
| } | |||||
| if (endBaseName != -1) { | |||||
| baseName = descriptorFilename.substring(0, endBaseName); | |||||
| } | |||||
| // First the regular deployment descriptor | |||||
| ejbFiles.put(META_DIR + EJB_DD, | |||||
| new File(srcDir, descriptorFilename)); | |||||
| addVendorFiles(ejbFiles, srcDir, baseName); | |||||
| // Lastly create File object for the Jar files. If we are using | |||||
| // a flat destination dir, then we need to redefine baseName! | |||||
| if (flatDestDir && baseName.length() != 0) { | |||||
| int startName = baseName.lastIndexOf(File.separator); | |||||
| int endName = baseName.length(); | |||||
| baseName = baseName.substring(startName, endName); | |||||
| } | |||||
| 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() ); | |||||
| } | |||||
| } | |||||
| // Check to see if we need a build and start | |||||
| // doing the work! | |||||
| if (needBuild) { | |||||
| // Log that we are going to build... | |||||
| getTask().log( "building " | |||||
| + jarFile.getName() | |||||
| + " with " | |||||
| + String.valueOf(ejbFiles.size()) | |||||
| + " files", | |||||
| Project.MSG_INFO); | |||||
| // Use helper method to write the jarfile | |||||
| writeJar(baseName, jarFile, ejbFiles); | |||||
| } | |||||
| else { | |||||
| // Log that the file is up to date... | |||||
| getTask().log(jarFile.toString() + " is up to date.", | |||||
| Project.MSG_INFO); | |||||
| } | |||||
| } | |||||
| catch (SAXException se) { | |||||
| String msg = "SAXException while parsing '" | |||||
| + descriptorFilename.toString() | |||||
| + "'. This probably indicates badly-formed XML." | |||||
| + " Details: " | |||||
| + se.getMessage(); | |||||
| throw new BuildException(msg, se); | |||||
| } | |||||
| catch (IOException ioe) { | |||||
| String msg = "IOException while parsing'" | |||||
| + descriptorFilename.toString() | |||||
| + "'. This probably indicates that the descriptor" | |||||
| + " doesn't exist. Details:" | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Add any vendor specific files which should be included in the | |||||
| * EJB Jar. | |||||
| */ | |||||
| protected void addVendorFiles(Hashtable ejbFiles, File srcDir, String baseName) { | |||||
| } | |||||
| /** | |||||
| * Get the vendor specific name of the Jar that will be output. The modification date | |||||
| * of this jar will be checked against the dependent bean classes. | |||||
| */ | |||||
| File getVendorOutputJarFile(String baseName) { | |||||
| return new File(destDir, baseName + genericjarsuffix); | |||||
| } | |||||
| /** | |||||
| * 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 | |||||
| * ejbFiles. | |||||
| */ | |||||
| protected void writeJar(String baseName, File jarfile, Hashtable files) throws BuildException{ | |||||
| JarOutputStream jarStream = null; | |||||
| Iterator entryIterator = null; | |||||
| String entryName = null; | |||||
| File entryFile = null; | |||||
| try { | |||||
| /* If the jarfile already exists then whack it and recreate it. | |||||
| * Should probably think of a more elegant way to handle this | |||||
| * so that in case of errors we don't leave people worse off | |||||
| * than when we started =) | |||||
| */ | |||||
| if (jarfile.exists()) { | |||||
| jarfile.delete(); | |||||
| } | |||||
| jarfile.getParentFile().mkdirs(); | |||||
| jarfile.createNewFile(); | |||||
| // Create the streams necessary to write the jarfile | |||||
| jarStream = new JarOutputStream(new FileOutputStream(jarfile)); | |||||
| jarStream.setMethod(JarOutputStream.DEFLATED); | |||||
| // Loop through all the class files found and add them to the jar | |||||
| entryIterator = files.keySet().iterator(); | |||||
| while (entryIterator.hasNext()) { | |||||
| entryName = (String) entryIterator.next(); | |||||
| entryFile = (File) files.get(entryName); | |||||
| getTask().log("adding file '" + entryName + "'", | |||||
| Project.MSG_VERBOSE); | |||||
| addFileToJar(jarStream, | |||||
| new FileInputStream(entryFile), | |||||
| entryName); | |||||
| } | |||||
| // All done. Close the jar stream. | |||||
| jarStream.close(); | |||||
| } | |||||
| catch(IOException ioe) { | |||||
| String msg = "IOException while processing ejb-jar file '" | |||||
| + jarfile.toString() | |||||
| + "'. Details: " | |||||
| + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe); | |||||
| } | |||||
| } // end of writeJar | |||||
| /** | |||||
| * Called to validate that the tool parameters have been configured. | |||||
| * | |||||
| */ | |||||
| public void validateConfigured() throws BuildException { | |||||
| if (destDir == null) { | |||||
| throw new BuildException("The destdir attribute must be specified"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,203 @@ | |||||
| /* | |||||
| * 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", "Tomcat", 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.*; | |||||
| import java.util.*; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.taskdefs.Java; | |||||
| public class WeblogicDeploymentTool extends GenericDeploymentTool { | |||||
| protected static final String WL_DD = "weblogic-ejb-jar.xml"; | |||||
| protected static final String WL_CMP_DD = "weblogic-cmp-rdbms-jar.xml"; | |||||
| /** Instance variable that stores the suffix for the weblogic jarfile. */ | |||||
| private String jarSuffix = "-wl.jar"; | |||||
| private Path classpath; | |||||
| /** Instance variable that determines whether generic ejb jars are kept. */ | |||||
| private boolean keepgeneric = true; | |||||
| /** | |||||
| * Set the classpath to be used for this compilation. | |||||
| */ | |||||
| public void setClasspath(Path classpath) { | |||||
| this.classpath = classpath; | |||||
| } | |||||
| /** | |||||
| * Setter used to store the suffix for the generated weblogic jar file. | |||||
| * @param inString the string to use as the suffix. | |||||
| */ | |||||
| public void setSuffix(String inString) { | |||||
| this.jarSuffix = inString; | |||||
| } | |||||
| /** | |||||
| * Setter used to store the value of keepgeneric | |||||
| * @param inValue a string, either 'true' or 'false'. | |||||
| */ | |||||
| public void setKeepgeneric(String inValue) { | |||||
| this.keepgeneric = Boolean.valueOf(inValue).booleanValue(); | |||||
| } | |||||
| protected DescriptorHandler getDescriptorHandler(File srcDir) { | |||||
| DescriptorHandler handler = new DescriptorHandler(srcDir); | |||||
| handler.registerResourceDTD("-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN", | |||||
| "/weblogic/ejb/deployment/xml/ejb-jar.dtd"); | |||||
| return handler; | |||||
| } | |||||
| /** | |||||
| * Add any vendor specific files which should be included in the | |||||
| * EJB Jar. | |||||
| */ | |||||
| protected void addVendorFiles(Hashtable ejbFiles, File srcdir, String baseName) { | |||||
| // Then the weblogic deployment descriptor | |||||
| File weblogicDD = new File(srcdir, | |||||
| baseName + getBasenameTerminator() + WL_DD); | |||||
| if (weblogicDD.exists()) { | |||||
| ejbFiles.put(META_DIR + WL_DD, | |||||
| weblogicDD); | |||||
| } | |||||
| // The the weblogic cmp deployment descriptor | |||||
| File weblogicCMPDD = new File(srcdir, | |||||
| baseName + getBasenameTerminator() + WL_CMP_DD); | |||||
| if (weblogicCMPDD.exists()) { | |||||
| ejbFiles.put(META_DIR + WL_CMP_DD, | |||||
| weblogicCMPDD); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the vendor specific name of the Jar that will be output. The modification date | |||||
| * of this jar will be checked against the dependent bean classes. | |||||
| */ | |||||
| File getVendorOutputJarFile(String baseName) { | |||||
| return new File(getDestDir(), baseName + jarSuffix); | |||||
| } | |||||
| /** | |||||
| * Helper method invoked by execute() for each WebLogic jar to be built. | |||||
| * Encapsulates the logic of constructing a java task for calling | |||||
| * weblogic.ejbc and executing it. | |||||
| * @param sourceJar java.io.File representing the source (EJB1.1) jarfile. | |||||
| * @param destJar java.io.File representing the destination, WebLogic | |||||
| * jarfile. | |||||
| */ | |||||
| private void buildWeblogicJar(File sourceJar, File destJar) { | |||||
| org.apache.tools.ant.taskdefs.Java javaTask = null; | |||||
| try { | |||||
| String args = "-noexit " + sourceJar.getPath().replace('\\', '/') + " " + destJar.getPath().replace('\\', '/'); | |||||
| javaTask = (Java) getTask().getProject().createTask("java"); | |||||
| javaTask.setClassname("weblogic.ejbc"); | |||||
| javaTask.setArgs(args); | |||||
| if (classpath != null) { | |||||
| javaTask.setClasspath(classpath); | |||||
| javaTask.setFork(true); | |||||
| } | |||||
| else { | |||||
| javaTask.setFork(false); | |||||
| } | |||||
| getTask().log("Calling weblogic.ejbc for " + sourceJar.toString(), | |||||
| Project.MSG_VERBOSE); | |||||
| javaTask.execute(); | |||||
| } | |||||
| catch (Exception e) { | |||||
| // Have to catch this because of the semantics of calling main() | |||||
| String msg = "Exception while calling ejbc. Details: " + e.toString(); | |||||
| throw new BuildException(msg, e); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 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 | |||||
| * ejbFiles. | |||||
| */ | |||||
| protected void writeJar(String baseName, File jarFile, Hashtable files) throws BuildException { | |||||
| // need to create a generic jar first. | |||||
| File genericJarFile = super.getVendorOutputJarFile(baseName); | |||||
| super.writeJar(baseName, genericJarFile, files); | |||||
| buildWeblogicJar(genericJarFile, jarFile); | |||||
| if (!keepgeneric) { | |||||
| getTask().log("deleting generic jar " + genericJarFile.toString(), | |||||
| Project.MSG_VERBOSE); | |||||
| genericJarFile.delete(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Called to validate that the tool parameters have been configured. | |||||
| * | |||||
| */ | |||||
| public void validateConfigured() throws BuildException { | |||||
| super.validateConfigured(); | |||||
| } | |||||
| } | |||||