blob: 30da2f43238e75aa6545b1e9458f11907345cd08 [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() + ". Or 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]);
}
}
}
}
// eof.