blob: f161ca07871b8e3ca9d97149b6cb39c060a4b1a2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional.ejb;
// Standard java imports
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.xml.sax.SAXException;
/**
* Provides automated EJB JAR file creation.
* <p>
* Extends the
* MatchingTask class provided in the default ant distribution to provide a
* directory scanning EJB jarfile generator.
* </p>
*
* <p>
* The task works by taking the deployment descriptors one at a time and
* parsing them to locate the names of the classes which should be placed in
* the jar. The classnames are translated to java.io.Files by replacing
* periods with File.separatorChar and resolving the generated filename as a
* relative path under the srcDir attribute. All necessary files are then
* assembled into a jarfile. One jarfile is constructed for each deployment
* descriptor found.
* </p>
*
* */
public class EjbJar extends MatchingTask {
/**
* Inner class used to record information about the location of a local DTD
*/
public static class DTDLocation
extends org.apache.tools.ant.types.DTDLocation {
}
/**
* A class which contains the configuration state of the ejbjar task.
* This state is passed to the deployment tools for configuration
*/
static class Config {
// CheckStyle:VisibilityModifier OFF - bc
/**
* Stores a handle to the directory under which to search for class
* files
*/
public File srcDir;
/**
* Stores a handle to the directory under which to search for
* deployment descriptors
*/
public File descriptorDir;
/** Instance variable that marks the end of the 'basename' */
public String baseNameTerminator = "-";
/** Stores a handle to the destination EJB Jar file */
public String baseJarName;
/**
* Instance variable that determines whether to use a package structure
* of a flat directory as the destination for the jar files.
*/
public boolean flatDestDir = false;
/**
* The classpath to use when loading classes
*/
public Path classpath;
/**
* A Fileset of support classes
*/
public List supportFileSets = new ArrayList();
/**
* The list of configured DTD locations
*/
public ArrayList dtdLocations = new ArrayList();
/**
* The naming scheme used to determine the generated jar name
* from the descriptor information
*/
public NamingScheme namingScheme;
/**
* The Manifest file
*/
public File manifest;
/**
* The dependency analyzer to use to add additional classes to the jar
*/
public String analyzer;
// CheckStyle:VisibilityModifier ON
}
/**
* An EnumeratedAttribute class for handling different EJB jar naming
* schemes
*/
public static class NamingScheme extends EnumeratedAttribute {
/**
* Naming scheme where generated jar is determined from the ejb-name in
* the deployment descripor
*/
public static final String EJB_NAME = "ejb-name";
/**
* Naming scheme where the generated jar name is based on the
* name of the directory containing the deployment descriptor
*/
public static final String DIRECTORY = "directory";
/**
* Naming scheme where the generated jar name is based on the name of
* the deployment descriptor file
*/
public static final String DESCRIPTOR = "descriptor";
/**
* Naming scheme where the generated jar is named by the basejarname
* attribute
*/
public static final String BASEJARNAME = "basejarname";
/**
* Gets the values of the NamingScheme
*
* @return an array of the values of this attribute class.
*/
public String[] getValues() {
return new String[] {EJB_NAME, DIRECTORY, DESCRIPTOR, BASEJARNAME};
}
}
/**
* CMP versions supported
* valid CMP versions are 1.0 and 2.0
* @since ant 1.6
*/
public static class CMPVersion extends EnumeratedAttribute {
/** 1.0 value */
public static final String CMP1_0 = "1.0";
/** 2.0 value */
public static final String CMP2_0 = "2.0";
/** {@inheritDoc}. */
public String[] getValues() {
return new String[]{
CMP1_0,
CMP2_0,
};
}
}
/**
* The config which is built by this task and used by the various deployment
* tools to access the configuration of the ejbjar task
*/
private Config config = new Config();
/**
* Stores a handle to the directory to put the Jar files in. This is
* only used by the generic deployment descriptor tool which is created
* if no other deployment descriptor tools are provided. Normally each
* deployment tool will specify the desitination dir itself.
*/
private File destDir;
/** Instance variable that stores the suffix for the generated jarfile. */
private String genericJarSuffix = "-generic.jar";
/** Instance variable that stores the CMP version for the jboss jarfile. */
private String cmpVersion = CMPVersion.CMP1_0;
/** The list of deployment tools we are going to run. */
private ArrayList deploymentTools = new ArrayList();
/**
* Add a deployment tool to the list of deployment tools that will be
* processed
*
* @param deploymentTool a deployment tool instance to which descriptors
* will be passed for processing.
*/
protected void addDeploymentTool(EJBDeploymentTool deploymentTool) {
deploymentTool.setTask(this);
deploymentTools.add(deploymentTool);
}
/**
* Adds a deployment tool for Weblogic server.
*
* @return the deployment tool instance to be configured.
*/
public WeblogicDeploymentTool createWeblogic() {
WeblogicDeploymentTool tool = new WeblogicDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Websphere 4.0 server.
*
* @return the deployment tool instance to be configured.
*/
public WebsphereDeploymentTool createWebsphere() {
WebsphereDeploymentTool tool = new WebsphereDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Borland server.
*
* @return the deployment tool instance to be configured.
*/
public BorlandDeploymentTool createBorland() {
log("Borland deployment tools", Project.MSG_VERBOSE);
BorlandDeploymentTool tool = new BorlandDeploymentTool();
tool.setTask(this);
deploymentTools.add(tool);
return tool;
}
/**
* Adds a deployment tool for iPlanet Application Server.
*
* @return the deployment tool instance to be configured.
*/
public IPlanetDeploymentTool createIplanet() {
log("iPlanet Application Server deployment tools", Project.MSG_VERBOSE);
IPlanetDeploymentTool tool = new IPlanetDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for JBoss server.
*
* @return the deployment tool instance to be configured.
*/
public JbossDeploymentTool createJboss() {
JbossDeploymentTool tool = new JbossDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for JOnAS server.
*
* @return the deployment tool instance to be configured.
*/
public JonasDeploymentTool createJonas() {
log("JOnAS deployment tools", Project.MSG_VERBOSE);
JonasDeploymentTool tool = new JonasDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds a deployment tool for Weblogic when using the Toplink
* Object-Relational mapping.
*
* @return the deployment tool instance to be configured.
*/
public WeblogicTOPLinkDeploymentTool createWeblogictoplink() {
log("The <weblogictoplink> element is no longer required. Please use "
+ "the <weblogic> element and set newCMP=\"true\"",
Project.MSG_INFO);
WeblogicTOPLinkDeploymentTool tool
= new WeblogicTOPLinkDeploymentTool();
addDeploymentTool(tool);
return tool;
}
/**
* Adds to the classpath used to locate the super classes and
* interfaces of the classes that will make up the EJB JAR.
*
* @return the path to be configured.
*/
public Path createClasspath() {
if (config.classpath == null) {
config.classpath = new Path(getProject());
}
return config.classpath.createPath();
}
/**
* Create a DTD location record. This stores the location of a DTD. The
* DTD is identified by its public Id. The location may either be a file
* location or a resource location.
*
* @return the DTD location object to be configured by Ant
*/
public DTDLocation createDTD() {
DTDLocation dtdLocation = new DTDLocation();
config.dtdLocations.add(dtdLocation);
return dtdLocation;
}
/**
* Adds a fileset for support elements.
*
* @return a fileset which can be populated with support files.
*/
public FileSet createSupport() {
FileSet supportFileSet = new FileSet();
config.supportFileSets.add(supportFileSet);
return supportFileSet;
}
/**
* Set the Manifest file to use when jarring. As of EJB 1.1, manifest
* files are no longer used to configure the EJB. However, they still
* have a vital importance if the EJB is intended to be packaged in an
* EAR file. By adding "Class-Path" settings to a Manifest file, the EJB
* can look for classes inside the EAR file itself, allowing for easier
* deployment. This is outlined in the J2EE specification, and all J2EE
* components are meant to support it.
*
* @param manifest the manifest to be used in the EJB jar
*/
public void setManifest(File manifest) {
config.manifest = manifest;
}
/**
* Sets the source directory, which is the directory that
* contains the classes that will be added to the EJB jar. Typically
* this will include the home and remote interfaces and the bean class.
*
* @param inDir the source directory.
*/
public void setSrcdir(File inDir) {
config.srcDir = inDir;
}
/**
* Set the descriptor directory. The descriptor directory contains the
* EJB deployment descriptors. These are XML files that declare the
* properties of a bean in a particular deployment scenario. Such
* properties include, for example, the transactional nature of the bean
* and the security access control to the bean's methods.
*
* @param inDir the directory containing the deployment descriptors.
*/
public void setDescriptordir(File inDir) {
config.descriptorDir = inDir;
}
/**
* Set the analyzer to use when adding in dependencies to the JAR.
*
* @param analyzer the name of the dependency analyzer or a class.
*/
public void setDependency(String analyzer) {
config.analyzer = analyzer;
}
/**
* Set the base name of the EJB JAR that is to be created if it is not
* to be determined from the name of the deployment descriptor files.
*
* @param inValue the basename that will be used when writing the jar
* file containing the EJB
*/
public void setBasejarname(String inValue) {
config.baseJarName = inValue;
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.BASEJARNAME);
} else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
throw new BuildException("The basejarname attribute is not "
+ "compatible with the "
+ config.namingScheme.getValue() + " naming scheme");
}
}
/**
* Set the naming scheme used to determine the name of the generated jars
* from the deployment descriptor
*
* @param namingScheme the naming scheme to be used
*/
public void setNaming(NamingScheme namingScheme) {
config.namingScheme = namingScheme;
if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
&& config.baseJarName != null) {
throw new BuildException("The basejarname attribute is not "
+ "compatible with the "
+ config.namingScheme.getValue() + " naming scheme");
}
}
/**
* Gets the destination directory.
*
* @return destination directory
* @since ant 1.6
*/
public File getDestdir() {
return this.destDir;
}
/**
* Set the destination directory. The EJB jar files will be written into
* this directory. The jar files that exist in this directory are also
* used when determining if the contents of the jar file have changed.
* Note that this parameter is only used if no deployment tools are
* specified. Typically each deployment tool will specify its own
* destination directory.
*
* @param inDir the destination directory in which to generate jars
*/
public void setDestdir(File inDir) {
this.destDir = inDir;
}
/**
* Gets the CMP version.
*
* @return CMP version
* @since ant 1.6
*/
public String getCmpversion() {
return this.cmpVersion;
}
/**
* Sets the CMP version.
*
* @param version CMP version.
* Must be either <code>1.0</code> or <code>2.0</code>.<br/>
* Default is <code>1.0</code>.<br/>
* Initially, only the JBoss implementation does something specific for CMP 2.0.<br/>
* @since ant 1.6
*/
public void setCmpversion(CMPVersion version) {
this.cmpVersion = version.getValue();
}
/**
* Set the classpath to use when resolving classes for inclusion in the jar.
*
* @param classpath the classpath to use.
*/
public void setClasspath(Path classpath) {
config.classpath = classpath;
}
/**
* Controls whether the
* destination JARs are written out in the destination directory with
* the same hierarchical structure from which the deployment descriptors
* have been read. If this is set to true the generated EJB jars are
* written into the root of the destination directory, otherwise they
* are written out in the same relative position as the deployment
* descriptors in the descriptor directory.
*
* @param inValue the new value of the flatdestdir flag.
*/
public void setFlatdestdir(boolean inValue) {
config.flatDestDir = inValue;
}
/**
* Set the suffix for the generated jar file. When generic jars are
* generated, they have a suffix which is appended to the the bean name
* to create the name of the jar file. Note that this suffix includes
* the extension fo te jar file and should therefore end with an
* appropriate extension such as .jar or .ear
*
* @param inString the string to use as the suffix.
*/
public void setGenericjarsuffix(String inString) {
this.genericJarSuffix = inString;
}
/**
* The string which terminates the bean name.
* The convention used by this task is
* that bean descriptors are named as the BeanName with some suffix. The
* baseNameTerminator string separates the bean name and the suffix and
* is used to determine the bean name.
*
* @param inValue a string which marks the end of the basename.
*/
public void setBasenameterminator(String inValue) {
config.baseNameTerminator = inValue;
}
/**
* Validate the config that has been configured from the build file
*
* @throws BuildException if the config is not valid
*/
private void validateConfig() throws BuildException {
if (config.srcDir == null) {
throw new BuildException("The srcDir attribute must be specified");
}
if (config.descriptorDir == null) {
config.descriptorDir = config.srcDir;
}
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.DESCRIPTOR);
} else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
&& config.baseJarName == null) {
throw new BuildException("The basejarname attribute must "
+ "be specified with the basejarname naming scheme");
}
}
/**
* Invoked by Ant after the task is prepared, when it is ready to execute
* this task.
*
* This will configure all of the nested deployment tools to allow them to
* process the jar. If no deployment tools have been configured a generic
* tool is created to handle the jar.
*
* A parser is configured and then each descriptor found is passed to all
* the deployment tool elements for processing.
*
* @exception BuildException thrown whenever a problem is
* encountered that cannot be recovered from, to signal to ant
* that a major problem occurred within this task.
*/
public void execute() throws BuildException {
validateConfig();
if (deploymentTools.size() == 0) {
GenericDeploymentTool genericTool = new GenericDeploymentTool();
genericTool.setTask(this);
genericTool.setDestdir(destDir);
genericTool.setGenericJarSuffix(genericJarSuffix);
deploymentTools.add(genericTool);
}
for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
tool.configure(config);
tool.validateConfigured();
}
try {
// Create the parser using whatever parser the system dictates
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setValidating(true);
SAXParser saxParser = saxParserFactory.newSAXParser();
DirectoryScanner ds = getDirectoryScanner(config.descriptorDir);
ds.scan();
String[] files = ds.getIncludedFiles();
log(files.length + " deployment descriptors located.",
Project.MSG_VERBOSE);
// Loop through the files. Each file represents one deployment
// descriptor, and hence one bean in our model.
for (int index = 0; index < files.length; ++index) {
// process the deployment descriptor in each tool
for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
tool.processDescriptor(files[index], saxParser);
}
}
} catch (SAXException se) {
String msg = "SAXException while creating parser."
+ " Details: "
+ se.getMessage();
throw new BuildException(msg, se);
} catch (ParserConfigurationException pce) {
String msg = "ParserConfigurationException while creating parser. "
+ "Details: " + pce.getMessage();
throw new BuildException(msg, pce);
}
} // end of execute()
}