blob: a7aaebc126680cd007e7982f319bbf2ca4922a83 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 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 org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
/**
* The deployment tool to add the jonas specific deployment descriptors to the
* ejb jar file. JONAS only requires one additional file jonas-ejb-jar.xml.
*
* @author <a href="cmorvan@ingenosya.com">Cyrille Morvan</a> , <a
* href="http://www.ingenosya.com">Ingenosya France</a>
* @version 1.0
* @see EjbJar#createJonas
*/
public class JonasDeploymentTool extends GenericDeploymentTool {
protected static final String JONAS_DD = "jonas-ejb-jar.xml";
protected static final String GENIC_CLASS =
"org.objectweb.jonas_ejb.tools.GenWholeIC";
protected static final String OLD_GENIC_CLASS =
"org.objectweb.jonas_ejb.tools.GenIC";
protected static final String DEFAULT_ORB = "RMI";
/** Instance variable that stores the suffix for the jonas jarfile. */
private String jarSuffix = ".jar";
/**
* Instance variable that stores the fully qualified classname of the
* JOnAS GenIC compiler.
*/
private String genicClass;
private String additionalArgs = "";
/**
* Instance variable that determines do not delete intermediate generated
* source files
*/
private boolean keepgenerated = false;
/** as websphere and WebLogic taskes */
private boolean keepGeneric = false;
/** Instance variable that determines the JOnAS Root directory */
private File jonasroot;
/** Instance variable that determines if we could -secpropag */
private boolean secpropag = false;
/** Instance variable that determines the ouput directory */
private File ouputdirectory;
/** Instance variable that determines the path to the compiler to use */
private String compiler;
/** Instance variable that determines if GenIC is verbose */
private boolean verbose;
/** Instance variable that determines the ORB to use (RMI, JEREMIE, DAVID) */
private String orb;
/** clean the working directory after work * */
private boolean cleanWorkDir = false;
private boolean noGENIC = false;
/** set the name of the GenIC compiler class. */
public void setGenicClass(final String inGenicClass) {
genicClass = inGenicClass;
}
/**
* Set the ORB to construct classpath.
*
* @param inValue RMI, JEREMIE, DAVID,...
*/
public void setOrb(final String inValue) {
orb = inValue;
}
/** The compiler (switch <code>-javac</code>) to use. */
public void setCompiler(final String inCompiler) {
compiler = inCompiler;
}
/**
* Setter used to store the value of keepGeneric
*
* @param inValue a string, either 'true' or 'false'.
*/
public void setKeepgeneric(boolean inValue) {
this.keepGeneric = inValue;
}
/**
* GenIC verbose or not
*
* @param inValue either 'true' or 'false'
*/
public void setVerbose(final boolean inValue) {
verbose = inValue;
}
/**
* GenIC run or not.
*
* @param inValue run or not
*/
public void setNoGENIC(final boolean inValue) {
noGENIC = inValue;
}
/**
* Sets whether -keepgenerated is passed to GenIC (that is, the .java
* source files are kept).
*
* @param inValue either 'true' or 'false'
*/
public void setKeepgenerated(final boolean inValue) {
keepgenerated = inValue;
}
/**
* set the jonas root directory (-Dinstall.root=).
*
* @throws BuildException if the file doesn't exist.
*/
public void setJonasroot(final File inValue) {
jonasroot = inValue;
}
/**
* Modify the RMI Skeleton and Stub to implement the implicit propagation
* of the transactionnal context and security context. For JOnAS 2.4 and
* next.
*/
public void setSecpropag(final boolean inValue) {
secpropag = inValue;
}
/**
* set the output directory (-d ...). <br>
* It's the GenIC working directory. It's not the DestDir, which is the
* 'jar' destination directory.
*
* @param inValue a file
*/
public void setOuputdir(final File inValue) {
ouputdirectory = inValue;
}
/**
* set the output directory (-d ...). Same as setOuputdir(). <br>
* But do not override setDestDir()
*/
public void setWorkdir(final File inValue) {
setOuputdir(inValue);
}
/**
* Clean the specified Work dir after work.
*
* @param inValue true : clean ; false : not clean
*/
public void setCleanworkdir(final boolean inValue) {
cleanWorkDir = inValue;
}
/**
* Setter used to store the suffix for the generated JOnAS jar file.
*
* @param inString the string to use as the suffix.
*/
public void setSuffix(String inString) {
this.jarSuffix = inString;
}
/** sets some additional args to send to GenIC. */
public void setArgs(final String inArgs) {
additionalArgs = inArgs;
}
/**
* Add any vendor specific files which should be included in the EJB Jar.
*
* @param aDdPrefix MyDirectories/MyEjb- or MyDirectories/
*/
protected void addVendorFiles(final Hashtable someEjbFiles,
final String aDdPrefix) {
// Use Ant Naming convention
File aJonasDD
= new File(getConfig().descriptorDir, aDdPrefix + JONAS_DD);
if (aJonasDD.exists()) {
someEjbFiles.put(META_DIR + JONAS_DD, aJonasDD);
} else {
// try with JOnAS Naming convention
if (!addJonasVendorFiles(someEjbFiles, aDdPrefix)) {
log("Unable to locate JOnAS deployment descriptor. It was "
+ "expected to be in " + aJonasDD.getPath()
+ ". Alternatively, please use JOnAS naming convention.",
Project.MSG_WARN);
}
}
}
/**
* try to add JOnAS specific file, using JOnAS naming convention. For
* example : jonas-Account.xml or jonas-ejb-jar.xml
*
* @param aDdPrefix MyDirectories/MyEjb- or MyDirectories/
* @return true if Ok
*/
private boolean addJonasVendorFiles(final Hashtable someEjbFiles,
final String aDdPrefix) {
// replace \ by /, remove the last letter ( a dash - )
final String aCanonicalDD
= aDdPrefix.replace('\\', '/').substring(0, aDdPrefix.length() - 1);
final int index = aCanonicalDD.lastIndexOf('/') + 1;
String anEjbJarName = aCanonicalDD.substring(index);
if ("ejb".equals(anEjbJarName)) {
anEjbJarName = "ejb-jar";
}
final String aNewDdPrefix =
aDdPrefix.substring(0, index) + "jonas-" + anEjbJarName + ".xml";
File aConventionNamingJonasDD
= new File(getConfig().descriptorDir, aNewDdPrefix);
log("look for jonas specific file using jonas naming convention "
+ aConventionNamingJonasDD,
Project.MSG_VERBOSE);
if (aConventionNamingJonasDD.exists()) {
someEjbFiles.put(META_DIR + JONAS_DD, aConventionNamingJonasDD);
return true;
} else {
return false;
}
}
// include javadoc
// Determine the JAR filename (without filename extension)
protected String getJarBaseName(String aDescriptorFileName) {
String aBaseName = null;
EjbJar.Config aConfig = super.getConfig();
if (aConfig.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
// try to find JOnAS specific convention name
// ??/MyEJB.xml ( I will find later the ??/jonas-MyEJB.xml file )
if (aDescriptorFileName.indexOf(aConfig.baseNameTerminator) == -1) {
String aCanonicalDescriptor = aDescriptorFileName.replace('\\', '/');
int lastSeparatorIndex = aCanonicalDescriptor.lastIndexOf('/');
int endBaseName;
if (lastSeparatorIndex != -1) {
endBaseName = aDescriptorFileName.indexOf(".xml", lastSeparatorIndex);
} else {
endBaseName = aDescriptorFileName.indexOf(".xml");
}
if (endBaseName != -1) {
aBaseName = aDescriptorFileName.substring(0, endBaseName);
}
}
}
if (aBaseName == null) {
// else get standard BaseName
aBaseName = super.getJarBaseName(aDescriptorFileName);
}
return aBaseName;
}
/**
* 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,
String publicId) throws BuildException {
// need to create a generic jar first.
File genericJarFile = super.getVendorOutputJarFile(baseName);
super.writeJar(baseName, genericJarFile, files, publicId);
// todo ? if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile))
buildJOnASJar(baseName, genericJarFile, jarFile, files, publicId);
if (!keepGeneric) {
log("deleting generic jar " + genericJarFile.toString(),
Project.MSG_VERBOSE);
genericJarFile.delete();
}
}
/**
* Helper method invoked by execute() for each JOnAS jar to be built.
* Encapsulates the logic of constructing a java task for calling GenIC
* and executing it.
*
* @param inBaseName the base name of the jar
* @param inSourceJar java.io.File representing the source (EJB1.1)
* jarfile.
* @param someFiles list of files in the jar. Add all the new genererated
* files.
* @param inPublicId the link to DTD (to rewrite JAR).
*/
private void buildJOnASJar(final String inBaseName,
final File inSourceJar, final File inDestJar,
final Hashtable someFiles, String inPublicId) {
org.apache.tools.ant.taskdefs.Java aJavaTask = null;
String aGenIcClassName = genicClass;
boolean isOldGenIC = false;
boolean isTempDirectory = false;
File anOutputDirectoryFile = null;
// do not call GenIC
// only copy file
if (noGENIC) {
try {
FileUtils.newFileUtils().copyFile(inSourceJar, inDestJar);
return;
} catch (IOException anIOException) {
throw new BuildException("Unable to write EJB jar", anIOException);
}
}
// call GenIC
try {
aJavaTask = (Java) getTask().getProject().createTask("java");
aJavaTask.setTaskName("genic");
if (aGenIcClassName == null) {
aGenIcClassName = GENIC_CLASS;
} else if (OLD_GENIC_CLASS.equals(aGenIcClassName)) {
isOldGenIC = true;
}
// ClassName
aJavaTask.setClassname(aGenIcClassName);
// JVM Args
if (jonasroot == null) {
throw new BuildException("Error : set the jonasroot parameter");
} else if (!jonasroot.isDirectory()) {
log("jonasroot attribut '" + jonasroot + "' is not a valid directory",
Project.MSG_ERR);
}
aJavaTask.createJvmarg().setValue("-Dinstall.root=" + jonasroot);
File aJavaPolicyFile = new File(jonasroot, "config/java.policy");
if (aJavaPolicyFile.exists()) {
aJavaTask.createJvmarg().setValue("-Djava.security.policy="
+ aJavaPolicyFile.toString());
}
// Find output directory
if (ouputdirectory == null) {
anOutputDirectoryFile = createTempDir();
isTempDirectory = true;
log("Use temporary output directory : " +
anOutputDirectoryFile, Project.MSG_VERBOSE);
} else {
anOutputDirectoryFile = ouputdirectory;
log("Use temporary specific output directory : " +
anOutputDirectoryFile, Project.MSG_VERBOSE);
}
aJavaTask.createArg().setValue("-d");
aJavaTask.createArg().setFile(anOutputDirectoryFile);
// Additionnal args
aJavaTask.createArg().setLine(additionalArgs);
// KeepGenerated
if (keepgenerated) {
aJavaTask.createArg().setValue("-keepgenerated");
}
// Verbose
if (verbose) {
aJavaTask.createArg().setValue("-verbose");
}
// -secpropag
if (secpropag) {
aJavaTask.createArg().setValue("-secpropag");
}
// The compiler
if (compiler == null) {
// try to use the compiler specified by build.compiler. Right now we are just going
// to allow Jikes
String aBuildCompiler = getTask().getProject().getProperty("build.compiler");
if ("jikes".equals(aBuildCompiler)) {
aJavaTask.createArg().setValue("-javac");
aJavaTask.createArg().setValue("jikes");
}
} else {
if (!"default".equals(compiler)) {
aJavaTask.createArg().setValue("-javac");
aJavaTask.createArg().setLine(compiler);
}
}
if (!isOldGenIC) {
// the add in jar features is buggy...
aJavaTask.createArg().setValue("-noaddinjar");
}
aJavaTask.createArg().setValue(inSourceJar.getPath());
// try to create the classpath for the correct ORB
Path aClasspath = getCombinedClasspath();
if (aClasspath == null) {
aClasspath = new Path(getTask().getProject());
}
if (orb != null) {
String aOrbJar = new File(jonasroot, "lib/" + orb + "_jonas.jar").toString();
String aConfigDir = new File(jonasroot, "config/").toString();
Path aJOnASOrbPath = new Path(aClasspath.getProject(),
aOrbJar + File.pathSeparator + aConfigDir);
aClasspath.append(aJOnASOrbPath);
} else {
log("No ORB propertie setup (RMI, JEREMIE, DAVID).", Project.MSG_WARN);
}
// append the output directory
aClasspath.append(new Path(aClasspath.getProject(), anOutputDirectoryFile.getPath()));
aJavaTask.setClasspath(aClasspath);
aJavaTask.setFork(true);
log("Calling " + aGenIcClassName + " for " + inSourceJar.toString(),
Project.MSG_VERBOSE);
if (aJavaTask.executeJava() != 0) {
throw new BuildException("GenIC reported an error");
}
// Update the list of files.
addAllFiles(anOutputDirectoryFile, "", someFiles);
// rewrite the jar with the new files
super.writeJar(inBaseName, inDestJar, someFiles, inPublicId);
} catch (BuildException aBuildException) {
throw aBuildException;
} catch (Exception e) {
// Have to catch this because of the semantics of calling main()
String msg = "Exception while calling " + aGenIcClassName + ". Details: " + e.toString();
throw new BuildException(msg, e);
} finally {
if (isTempDirectory && anOutputDirectoryFile != null) {
dellAllFiles(anOutputDirectoryFile);
} else if (cleanWorkDir && anOutputDirectoryFile != null) {
dellAllFilesInside(anOutputDirectoryFile);
}
}
}
/**
* 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(final String aBaseName) {
return new File(getDestDir(), aBaseName + jarSuffix);
}
/**
* Create a free tempory directory for GenIC output.
*
* @return directory file
* @throws BuildException if impossible to find a tempory directory
*/
private File createTempDir() {
String theTempDir = System.getProperty("java.io.tmpdir");
int anIndice = 0;
File aFile = null;
// try 50 times to find a free tempory directory
while (anIndice < 50 && aFile == null) {
aFile = new File(theTempDir, "GenicTemp" + anIndice);
if (aFile.exists()) {
anIndice++;
aFile = null;
}
}
if (aFile == null) {
// problem in temp directory
throw new BuildException("Impossible to find a free temp directory for output.");
} else {
aFile.mkdirs();
return (aFile);
}
}
/**
* add all files in anOutputDir + ' / ' + aRootDir to the HashTable
* someFiles.
*
* @param anOutputDir - start directory
* @param aCurrentDirOrFile - a sub-directory to scan or a file to add.
* @param someFiles - where to add the files
*/
private void addAllFiles(final File anOutputDir, String aCurrentDirOrFile, Hashtable someFiles) {
File aFile = new File(anOutputDir, aCurrentDirOrFile);
if (aFile.isDirectory()) {
String aCurrentDir = "";
if (aCurrentDirOrFile.length() > 0) {
aCurrentDir = aCurrentDirOrFile + '/';
}
File theFiles[] = aFile.listFiles();
for (int i = 0; i < theFiles.length; i++) {
addAllFiles(anOutputDir, aCurrentDir + theFiles[i].getName(), someFiles);
}
} else {
// is a file
someFiles.put(aCurrentDirOrFile, aFile);
}
}
/**
* Delete all the files in a directory
*
* @param aFile file to delete recursivly
*/
private void dellAllFiles(File aFile) {
if (aFile.isDirectory()) {
File someFiles[] = aFile.listFiles();
for (int i = 0; i < someFiles.length; i++) {
dellAllFiles(someFiles[i]);
}
}
aFile.delete();
}
/**
* Delete all the files in a directory, but don't delete the directory
*
* @param aFile file to delete recursivly
*/
private void dellAllFilesInside(File aFile) {
if (aFile.isDirectory()) {
File someFiles[] = aFile.listFiles();
for (int i = 0; i < someFiles.length; i++) {
dellAllFiles(someFiles[i]);
}
}
}
}