package org.mobicents.ant;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.util.FileUtils;
// SleeJar defines common behaviour amongst all the various types of deployable jars.
// Specifically construction of classpaths, properties that define whether the task should
// use deployment descriptor info to deduce what classes should be included etc.
//
// A default name for the deployment descriptor is assumed if one is not provided, which means
// in the common case the 'foo'jarxml property can safely be ommitted. This task also defines
// an extxml property to allow oc extension descriptors to be defined.
public abstract class SleeJar extends org.apache.tools.ant.taskdefs.Jar implements Component {
public SleeJar(String archiveType, String emptyBehaviour) {
super();
this.archiveType = archiveType;
this.emptyBehavior = emptyBehavior;
this.jarXmlStr = archiveType + ".xml";
}
public void setMetainfbase(String metainfbase) {
this.metainfbase = new File(metainfbase);
}
public void setMetaInfBase(File metainfbase) {
this.metainfbase = metainfbase;
}
// Component interface
public File getComponentFile(Project project) throws BuildException {
if (generateName && zipFile == null) {
// Use an autogenerated name.
try {
zipFile = File.createTempFile(getComponentType(), ".jar");
zipFile.deleteOnExit();
// Create the ZIP file entry table, else the ANT Jar task
// grumbles loudly and generates lots of spam warning
// messages when it tries to open a completely empty file
// as a ZIP file.
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
// Add an empty directory - ZIP files must have at least one
// entry.
ZipEntry ze = new ZipEntry("META-INF/");
ze.setSize (0);
ze.setMethod (ZipEntry.STORED);
// An empty CRC for the directory.
ze.setCrc(new CRC32().getValue());
zos.putNextEntry(ze);
zos.close();
} catch (IOException ioe) {
throw new BuildException(ioe);
}
}
return zipFile;
}
// Main execution entry point.
public void execute() throws BuildException {
long start = System.currentTimeMillis();
if (autoinclude && super.isInUpdateMode())
throw new BuildException("update mode not supported when autoinclude=true");
if (null == jarXmlStr)
throw new BuildException(getJarXmlName() + " attribute is required", getLocation());
if (autoinclude) {
includeClasses();
autoinclude = false; // On subsequent executions, don't add them again.
}
/* (discard) */ getComponentFile(getProject()); // Ensure zipFile is set.
super.execute();
long end = System.currentTimeMillis();
}
// Setters:
// classpath="..."
public void setClasspath(Path newClasspath) {
if (this.classpath == null)
this.classpath = newClasspath;
else
this.classpath.append(newClasspath);
}
// nested <classpath>
public Path createClasspath() {
if (classpath == null)
classpath = new Path(getProject());
return classpath.createPath();
}
// classpathref="..."
public void setClasspathRef(Reference r) {
createClasspath().setRefid(r);
}
public void setGeneratename(boolean onoff) {
this.generateName = onoff;
}
// autoinclude="..."
public void setAutoinclude(boolean onoff) {
this.autoinclude = onoff;
}
// subclasses implement these operations
protected abstract void includeTypeSpecificClasses() throws BuildException;
protected abstract String getComponentType();
protected abstract String getJarXmlName();
private void includeClasses() throws BuildException {
if (classpathFileList == null) {
// Initialize the classpath once.
if (classpath == null)
throw new BuildException("autoinclude set, but classpath attribute not set");
String[] classpathList = classpath.list();
classpathFileList = new File[classpathList.length];
classpathZipList = new ZipFile[classpathList.length];
for (int i = 0; i < classpathList.length; ++i)
classpathFileList[i] = fileUtils.normalize(classpathList[i]);
}
processJarXml();
includeTypeSpecificClasses();
}
protected final void includeClass(String className) throws BuildException {
String osPath = className.replace('.', File.separatorChar) + ".class";
String urlPath = className.replace('.', '/') + ".class";
// Search classpath elements.
for (int i = 0; i < classpathFileList.length; ++i) {
File cpBase = classpathFileList[i];
if (!cpBase.exists())
continue; // Missing.
if (cpBase.isDirectory()) {
File testFile = fileUtils.resolveFile(cpBase, osPath);
if (testFile.exists()) {
// Found it as a .class file
FileSet fileSet = new FileSet();
fileSet.setDir(cpBase);
fileSet.setIncludes(osPath);
super.addFileset(fileSet);
return;
}
continue;
}
if (cpBase.isFile()) {
// Assume it's a zip/jarfile.
if (classpathZipList[i] == null) {
// Initialize the zipfile once.
try {
classpathZipList[i] = new ZipFile(cpBase);
} catch (IOException ioe) {
// Can't read the zipfile, ignore it.
classpathZipList[i] = null;
continue;
}
}
if (classpathZipList[i].getEntry(urlPath) != null) {
// Found it within a .zip/.jar
ZipFileSet zipFileSet = new ZipFileSet();
zipFileSet.setSrc(classpathFileList[i]);
zipFileSet.setIncludes(urlPath);
super.addZipfileset(zipFileSet);
return;
}
continue;
}
// unknown classpath entry -- ignore it.
}
throw new BuildException("Cannot locate class in classpath: " + className);
}
// subclasses will define jar specific 'foojarxml' attributes
protected final void setJarXml(String jarXmlStr) {
this.jarXmlStr = jarXmlStr;
}
public final void setExtjarxml(String extJarXmlStr) {
this.extJarXmlStr = extJarXmlStr;
}
private void processJarXml() {
// process the normal descriptor
jarxml = (null == metainfbase) ? new File(jarXmlStr) : new File(metainfbase, jarXmlStr);
processDescriptor(jarxml, archiveType + ".xml");
if (null != extJarXmlStr) {
// process the ext descriptor if we have one
final File extXml = (null == metainfbase) ? new File(extJarXmlStr) : new File(metainfbase, extJarXmlStr);
processDescriptor(extXml, extXml.getName());
}
}
private void processDescriptor(File xmlDtor, String xmlDtorName) {
if (!xmlDtor.exists())
throw new BuildException("Deployment descriptor: " + xmlDtor + " does not exist.");
// Add a new fileset for the DD.
ZipFileSet fs = new ZipFileSet();
fs.setFile(xmlDtor);
fs.setFullpath("META-INF/" + xmlDtorName);
super.addFileset(fs);
}
protected void cleanUp() {
// Clean up zipfiles
if (classpathZipList != null) {
for (int i = 0; i < classpathZipList.length; ++i) {
if (classpathZipList[i] != null) {
try { classpathZipList[i].close(); }
catch (IOException e) {}
}
}
classpathFileList = null;
classpathZipList = null;
}
}
// protected final File getMetaInfBase() { return metainfbase; }
protected final File getJarXml() { return jarxml; }
private String jarXmlStr;
private String extJarXmlStr;
private File metainfbase = null;
private File jarxml = null;
private Path classpath;
private boolean autoinclude = true;
private boolean generateName;
private File[] classpathFileList;
private ZipFile[] classpathZipList;
protected static final FileUtils fileUtils = FileUtils.newFileUtils();
protected static final SleeDTDResolver entityResolver = new SleeDTDResolver();
}