jarFile
's timestamp is more recent than
* each EJB file, true
is returned. Otherwise, false
*
is returned.
+ * TODO: find a way to check the manifest-file, that is found by naming convention
*
* @param ejbFiles Hashtable of EJB classes (and other) files that will be
* added to the completed JAR file
@@ -596,6 +608,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) {
if (jarFile.exists()) {
long lastBuild = jarFile.lastModified();
+
if (config.manifest != null && config.manifest.exists() &&
config.manifest.lastModified() > lastBuild) {
log("Build needed because manifest " + config.manifest + " is out of date",
@@ -660,7 +673,11 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
InputStream in = null;
Manifest manifest = null;
try {
- if (config.manifest != null) {
+ File manifestFile = new File(getConfig().descriptorDir, baseName + "-manifest.mf");
+ if (manifestFile.exists()) {
+ in = new FileInputStream(manifestFile);
+ }
+ else if (config.manifest != null) {
in = new FileInputStream(config.manifest);
if ( in == null ) {
throw new BuildException("Could not find manifest file: " + config.manifest,
@@ -744,106 +761,63 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
}
} // end of writeJar
+
/**
- * Check if a EJB Class Inherits from a Superclass, and if a Remote Interface
- * extends an interface other then javax.ejb.EJBObject directly. Then add those
- * classes to the generic-jar so they dont have to added elsewhere.
- *
+ * Add all available classes, that depend on Remote, Home, Bean, PK
+ * @param checkEntries files, that are extracted from the deployment descriptor
*/
- protected void checkAndAddInherited(Hashtable checkEntries) throws BuildException
+ protected void checkAndAddDependants(Hashtable checkEntries)
+ throws BuildException
{
- //Copy hashtable so were not changing the one we iterate through
- Hashtable copiedHash = (Hashtable)checkEntries.clone();
+ Dependencies visitor = new Dependencies();
+ Set set = new TreeSet();
+ Set newSet = new HashSet();
+ final String base = config.srcDir.getAbsolutePath() + File.separator;
+
+ Iterator i = checkEntries.keySet().iterator();
+ while (i.hasNext()) {
+ String entryName = (String)i.next();
+ if (entryName.endsWith(".class"))
+ newSet.add(entryName.substring(0, entryName.length() - ".class".length()).replace(File.separatorChar, '/'));
+ }
+ set.addAll(newSet);
- // Walk base level EJBs and see if they have superclasses or extend extra interfaces which extend EJBObject
- for (Iterator entryIterator = copiedHash.keySet().iterator(); entryIterator.hasNext(); )
- {
- String entryName = (String)entryIterator.next();
- File entryFile = (File)copiedHash.get(entryName);
+ do {
+ i = newSet.iterator();
+ while (i.hasNext()) {
+ String fileName = base + ((String)i.next()).replace('/', File.separatorChar) + ".class";
- // only want class files, xml doesnt reflect very well =)
- if (entryName.endsWith(".class"))
- {
- String classname = entryName.substring(0,entryName.lastIndexOf(".class")).replace(File.separatorChar,'.');
- ClassLoader loader = getClassLoaderForBuild();
try {
- Class c = loader.loadClass(classname);
-
- // No primatives!! sanity check, probably not nessesary
- if (!c.isPrimitive())
- {
- if (c.isInterface()) //get as an interface
- {
- log("looking at interface " + c.getName(), Project.MSG_VERBOSE);
- Class[] interfaces = c.getInterfaces();
- for (int i = 0; i < interfaces.length; i++){
- log(" implements " + interfaces[i].getName(), Project.MSG_VERBOSE);
- addInterface(interfaces[i], checkEntries);
- }
- }
- else // get as a class
- {
- log("looking at class " + c.getName(), Project.MSG_VERBOSE);
- Class s = c.getSuperclass();
- addSuperClass(c.getSuperclass(), checkEntries);
- }
- } //if primative
+ JavaClass javaClass = new ClassParser(fileName).parse();
+ javaClass.accept(visitor);
}
- catch (ClassNotFoundException cnfe) {
- log("Could not load class " + classname + " for super class check",
- Project.MSG_WARN);
- }
- catch (NoClassDefFoundError ncdfe) {
- log("Could not fully load class " + classname + " for super class check",
- Project.MSG_WARN);
- }
- } //if
- } // while
- }
-
- private void addInterface(Class theInterface, Hashtable checkEntries) {
- if (!theInterface.getName().startsWith("java")) // do not add system interfaces
- {
- File interfaceFile = new File(config.srcDir.getAbsolutePath()
- + File.separatorChar
- + theInterface.getName().replace('.',File.separatorChar)
- + ".class"
- );
- if (interfaceFile.exists() && interfaceFile.isFile())
- {
- checkEntries.put(theInterface.getName().replace('.',File.separatorChar)+".class",
- interfaceFile);
- Class[] superInterfaces = theInterface.getInterfaces();
- for (int i = 0; i < superInterfaces.length; i++) {
- addInterface(superInterfaces[i], checkEntries);
+ catch (IOException e) {
+ log("exception: " + e.getMessage(), Project.MSG_INFO);
}
}
+ newSet.clear();
+ newSet.addAll(visitor.getDependencies());
+ visitor.clearDependencies();
+
+ Dependencies.applyFilter(newSet, new Filter() {
+ public boolean accept(Object object) {
+ String fileName = base + ((String)object).replace('/', File.separatorChar) + ".class";
+ return new File(fileName).exists();
+ }
+ });
+ newSet.removeAll(set);
+ set.addAll(newSet);
}
- }
-
- private void addSuperClass(Class superClass, Hashtable checkEntries) {
-
- if (!superClass.getName().startsWith("java"))
- {
- File superClassFile = new File(config.srcDir.getAbsolutePath()
- + File.separatorChar
- + superClass.getName().replace('.',File.separatorChar)
- + ".class");
- if (superClassFile.exists() && superClassFile.isFile())
- {
- checkEntries.put(superClass.getName().replace('.',File.separatorChar) + ".class",
- superClassFile);
-
- // now need to get super classes and interfaces for this class
- Class[] superInterfaces = superClass.getInterfaces();
- for (int i = 0; i < superInterfaces.length; i++) {
- addInterface(superInterfaces[i], checkEntries);
- }
-
- addSuperClass(superClass.getSuperclass(), checkEntries);
- }
+ while (newSet.size() > 0);
+
+ i = set.iterator();
+ while (i.hasNext()) {
+ String next = ((String)i.next()).replace('/', File.separatorChar);
+ checkEntries.put(next + ".class", new File(base + next + ".class"));
+ log("dependent class: " + next + ".class" + " - " + base + next + ".class", Project.MSG_VERBOSE);
}
}
+
/**
* Returns a Classloader object which parses the passed in generic EjbJar classpath.
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
new file mode 100644
index 000000000..25a4d3eb2
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
@@ -0,0 +1,1712 @@
+/*
+
+ * 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 acknowasegement:
+
+ * "This product includes software developed by the
+
+ * Apache Software Foundation (http://www.apache.org/)."
+
+ * Alternately, this acknowasegement may appear in the software itself,
+
+ * if and wherever such third-party acknowasegements 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
+
+ * -compiler
) to use
+
+ */
+
+ public void setCompiler(String compiler) {
+
+ this.compiler = compiler;
+
+ }
+
+
+
+ /**
+
+ * Set the rebuild flag to false to only update changes in the
+
+ * jar rather than rerunning ejbdeploy
+
+ */
+
+ public void setRebuild(boolean rebuild) {
+
+ this.alwaysRebuild = rebuild;
+
+ }
+
+
+
+
+
+ /**
+
+ * Setter used to store the suffix for the generated websphere 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(boolean inValue) {
+
+ this.keepGeneric = inValue;
+
+ }
+
+
+
+ /**
+
+ * Sets whether -keepgenerated is passed to ejbdeploy (that is,
+
+ * the .java source files are kept).
+
+ * @param inValue either 'true' or 'false'
+
+ */
+
+ public void setKeepgenerated(String inValue) {
+
+ this.keepgenerated = Boolean.valueOf(inValue).booleanValue();
+
+ }
+
+
+
+ /**
+
+ * Decide, wether ejbdeploy should be called or not
+
+ * @param ejbdeploy
+
+ */
+
+ public void setEjbdeploy(boolean ejbdeploy) {
+
+ this.ejbdeploy = ejbdeploy;
+
+ }
+
+
+
+ /**
+
+ * sets some additional args to send to ejbdeploy.
+
+ */
+
+ public void setArgs(String args) {
+
+ this.additionalArgs = args;
+
+ }
+
+
+
+ /**
+
+ * Setter used to store the location of the Sun's Generic EJB DTD.
+
+ * This can be a file on the system or a resource on the classpath.
+
+ * @param inString the string to use as the DTD location.
+
+ */
+
+ public void setEJBdtd(String inString) {
+
+ this.ejb11DTD = inString;
+
+ }
+
+
+
+ /**
+
+ * Set the value of the oldCMP scheme. This is an antonym for
+
+ * newCMP
+
+ */
+
+ public void setOldCMP(boolean oldCMP) {
+
+ this.newCMP = !oldCMP;
+
+ }
+
+
+
+ /**
+
+ * Set the value of the newCMP scheme. The old CMP scheme locates the
+
+ * websphere CMP descriptor based on the naming convention where the
+
+ * websphere CMP file is expected to be named with the bean name as the prefix.
+
+ *
+
+ * Under this scheme the name of the CMP descriptor does not match the name
+
+ * actually used in the main websphere EJB descriptor. Also, descriptors which
+
+ * contain multiple CMP references could not be used.
+
+ *
+
+ */
+
+ public void setNewCMP(boolean newCMP) {
+
+ this.newCMP = newCMP;
+
+ }
+
+
+
+ /**
+
+ * Sets the temporary directory for the ejbdeploy task
+
+ */
+
+ public void setTempdir(String tempdir) {
+
+ this.tempdir = tempdir;
+
+ }
+
+
+
+ protected DescriptorHandler getDescriptorHandler(File srcDir) {
+
+ DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir);
+
+ // register all the DTDs, both the ones that are known and
+
+ // any supplied by the user
+
+ handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
+
+
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation)i.next();
+
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+
+ }
+
+
+
+ return handler;
+
+ }
+
+
+
+ protected DescriptorHandler getWebsphereDescriptorHandler(final File srcDir) {
+
+ DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir) {
+
+ protected void processElement() {
+
+ }
+
+ };
+
+
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation)i.next();
+
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+
+ }
+
+ return handler;
+
+ }
+
+
+
+ /**
+
+ * Add any vendor specific files which should be included in the
+
+ * EJB Jar.
+
+ */
+
+ protected void addVendorFiles(Hashtable ejbFiles, String baseName) {
+
+
+
+ String ddPrefix = (usingBaseJarName() ? "" : baseName);
+
+ String dbPrefix = (dbVendor == null)? "": dbVendor + "-";
+
+
+
+ // Get the Extensions document
+
+ File websphereEXT = new File(getConfig().descriptorDir, ddPrefix + WAS_EXT);
+
+ if (websphereEXT.exists()) {
+
+ ejbFiles.put(META_DIR + WAS_EXT,
+
+ websphereEXT);
+
+ } else {
+
+ log("Unable to locate websphere extensions. It was expected to be in " +
+
+ websphereEXT.getPath(), Project.MSG_VERBOSE);
+
+ }
+
+
+
+ File websphereBND = new File(getConfig().descriptorDir, ddPrefix + WAS_BND);
+
+ if (websphereBND.exists()) {
+
+ ejbFiles.put(META_DIR + WAS_BND,
+
+ websphereBND);
+
+ }else {
+
+ log("Unable to locate websphere bindings. It was expected to be in " +
+
+ websphereBND.getPath(), Project.MSG_VERBOSE);
+
+ }
+
+
+
+ if (!newCMP) {
+
+ log("The old method for locating CMP files has been DEPRECATED.", Project.MSG_VERBOSE);
+
+ log("Please adjust your websphere descriptor and set newCMP=\"true\" " +
+
+ "to use the new CMP descriptor inclusion mechanism. ", Project.MSG_VERBOSE);
+
+ }
+
+ else {
+
+ // We attempt to put in the MAP and Schema files of CMP beans
+
+ try
+
+ {
+
+ // Add the Map file
+
+ File websphereMAP = new File(getConfig().descriptorDir,
+
+ ddPrefix + dbPrefix + WAS_CMP_MAP);
+
+ if (websphereMAP.exists()) {
+
+ ejbFiles.put(META_DIR + WAS_CMP_MAP,
+
+ websphereMAP);
+
+ } else {
+
+ log("Unable to locate the websphere Map: " +
+
+ websphereMAP.getPath(), Project.MSG_VERBOSE);
+
+ }
+
+ File websphereSchema = new File(getConfig().descriptorDir,
+
+ ddPrefix + dbPrefix + WAS_CMP_SCHEMA);
+
+ if (websphereSchema.exists()) {
+
+ ejbFiles.put(META_DIR + SCHEMA_DIR + WAS_CMP_SCHEMA,
+
+ websphereSchema);
+
+ } else {
+
+ log("Unable to locate the websphere Schema: " +
+
+ websphereSchema.getPath(), Project.MSG_VERBOSE);
+
+ }
+
+ // Theres nothing else to see here...keep moving sonny
+
+ }
+
+ catch(Exception e)
+
+ {
+
+ String msg = "Exception while adding Vendor specific files: " +
+
+ e.toString();
+
+ throw new BuildException(msg, e);
+
+ }
+
+ }
+
+ }
+
+
+
+ /**
+
+ * 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);
+
+ }
+
+
+
+ /**
+
+ * Gets the options for the EJB Deploy operation
+
+ * @return String
+
+ */
+
+ protected String getOptions() {
+
+ // Set the options
+
+ StringBuffer options = new StringBuffer();
+
+ if (dbVendor != null) {
+
+ options.append(" -dbvendor ").append(dbVendor);
+
+ }
+
+ if (dbName != null) {
+
+ options.append(" -dbname \"").append(dbName).append("\"");
+
+ }
+
+
+
+ if (dbSchema != null) {
+
+ options.append(" -dbschema \"").append(dbSchema).append("\"");
+
+ }
+
+
+
+ if (codegen) {
+
+ options.append(" -codegen");
+
+ }
+
+
+
+ if (quiet) {
+
+ options.append(" -quiet");
+
+ }
+
+
+
+ if (novalidate) {
+
+ options.append(" -novalidate");
+
+ }
+
+
+
+ if (nowarn) {
+
+ options.append(" -nowarn");
+
+ }
+
+
+
+ if (noinform) {
+
+ options.append(" -noinform");
+
+ }
+
+
+
+ if (trace) {
+
+ options.append(" -trace");
+
+ }
+
+
+
+ if (use35MappingRules) {
+
+ options.append(" -35");
+
+ }
+
+
+
+ if (rmicOptions != null) {
+
+ options.append(" -rmic \"").append(rmicOptions).append("\"");
+
+ }
+
+
+
+ return options.toString();
+
+ } // end getOptions
+
+
+
+ /**
+
+ * Helper method invoked by execute() for each websphere jar to be built.
+
+ * Encapsulates the logic of constructing a java task for calling
+
+ * websphere.ejbdeploy and executing it.
+
+ * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
+
+ * @param destJar java.io.File representing the destination, websphere
+
+ * jarfile.
+
+ */
+
+ private void buildWebsphereJar(File sourceJar, File destJar) {
+
+ try {
+
+ if (ejbdeploy) {
+
+ String args =
+
+ " " + sourceJar.getPath() +
+
+ " " + tempdir +
+
+ " " + destJar.getPath() +
+
+ " " + getOptions();
+
+
+
+ if (getCombinedClasspath() != null && getCombinedClasspath().toString().length() > 0)
+
+ args += " -cp " + getCombinedClasspath();
+
+
+
+ // Why do my ""'s get stripped away???
+
+ log("EJB Deploy Options: " + args, Project.MSG_VERBOSE);
+
+
+
+ Java javaTask = (Java)getTask().getProject().createTask("java");
+
+ // Set the JvmArgs
+
+ javaTask.createJvmarg().setValue("-Xms64m");
+
+ javaTask.createJvmarg().setValue("-Xmx128m");
+
+
+
+ // Set the Environment variable
+
+ Environment.Variable var = new Environment.Variable();
+
+ var.setKey("websphere.lib.dir");
+
+ var.setValue(getTask().getProject().getProperty("websphere.home") + "/lib");
+
+ javaTask.addSysproperty(var);
+
+
+
+ // Set the working directory
+
+ javaTask.setDir(new File(getTask().getProject().getProperty("websphere.home")));
+
+
+
+ // Set the Java class name
+
+ javaTask.setTaskName("ejbdeploy");
+
+ javaTask.setClassname("com.ibm.etools.ejbdeploy.EJBDeploy");
+
+
+
+ Commandline.Argument arguments = javaTask.createArg();
+
+ arguments.setLine(args);
+
+
+
+ Path classpath = wasClasspath;
+
+ if (classpath == null) {
+
+ classpath = getCombinedClasspath();
+
+ }
+
+
+
+ if (classpath != null) {
+
+ javaTask.setClasspath(classpath);
+
+ javaTask.setFork(true);
+
+ }
+
+ else {
+
+ javaTask.setFork(true);
+
+ }
+
+
+
+ log("Calling websphere.ejbdeploy 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 ejbdeploy. 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, String publicId)
+
+ throws BuildException
+
+ {
+
+ if (ejbdeploy) {
+
+ // create the -generic.jar, if required
+
+ File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+ super.writeJar(baseName, genericJarFile, files, publicId);
+
+
+
+ // create the output .jar, if required
+
+ if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+
+ buildWebsphereJar(genericJarFile, jarFile);
+
+ }
+
+ if (!keepGeneric) {
+
+ log("deleting generic jar " + genericJarFile.toString(),
+
+ Project.MSG_VERBOSE);
+
+ genericJarFile.delete();
+
+ }
+
+ }
+
+ else {
+
+ // create the "undeployed" output .jar, if required
+
+ super.writeJar(baseName, jarFile, files, publicId);
+
+ }
+
+ /*
+
+ // need to create a generic jar first.
+
+ File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+ super.writeJar(baseName, genericJarFile, files, publicId);
+
+
+
+ if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+
+ buildWebsphereJar(genericJarFile, jarFile);
+
+ }
+
+ if (!keepGeneric) {
+
+ 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();
+
+ }
+
+
+
+
+
+ /**
+
+ * Helper method to check to see if a websphere EBJ1.1 jar needs to be rebuilt using
+
+ * ejbdeploy. Called from writeJar it sees if the "Bean" classes are the only thing that needs
+
+ * to be updated and either updates the Jar with the Bean classfile or returns true,
+
+ * saying that the whole websphere jar needs to be regened with ejbdeploy. This allows faster
+
+ * build times for working developers.
+
+ * + + * The way websphere ejbdeploy works is it creates wrappers for the publicly defined methods as + + * they are exposed in the remote interface. If the actual bean changes without changing the + + * the method signatures then only the bean classfile needs to be updated and the rest of the + + * websphere jar file can remain the same. If the Interfaces, ie. the method signatures change + + * or if the xml deployment dicriptors changed, the whole jar needs to be rebuilt with ejbdeploy. + + * This is not strictly true for the xml files. If the JNDI name changes then the jar doesnt + + * have to be rebuild, but if the resources references change then it does. At this point the + + * websphere jar gets rebuilt if the xml files change at all. + + * + + * @param genericJarFile java.io.File The generic jar file. + + * @param websphereJarFile java.io.File The websphere jar file to check to see if it needs to be rebuilt. + + */ + + protected boolean isRebuildRequired(File genericJarFile, File websphereJarFile) + + { + + boolean rebuild = false; + + + + JarFile genericJar = null; + + JarFile wasJar = null; + + File newwasJarFile = null; + + JarOutputStream newJarStream = null; + + + + try + + { + + log("Checking if websphere Jar needs to be rebuilt for jar " + websphereJarFile.getName(), + + Project.MSG_VERBOSE); + + // Only go forward if the generic and the websphere file both exist + + if (genericJarFile.exists() && genericJarFile.isFile() + + && websphereJarFile.exists() && websphereJarFile.isFile()) + + { + + //open jar files + + genericJar = new JarFile(genericJarFile); + + wasJar = new JarFile(websphereJarFile); + + + + Hashtable genericEntries = new Hashtable(); + + Hashtable wasEntries = new Hashtable(); + + Hashtable replaceEntries = new Hashtable(); + + + + //get the list of generic jar entries + + for (Enumeration e = genericJar.entries(); e.hasMoreElements();) + + { + + JarEntry je = (JarEntry)e.nextElement(); + + genericEntries.put(je.getName().replace('\\', '/'), je); + + } + + //get the list of websphere jar entries + + for (Enumeration e = wasJar.entries() ; e.hasMoreElements();) + + { + + JarEntry je = (JarEntry)e.nextElement(); + + wasEntries.put(je.getName(), je); + + } + + + + //Cycle Through generic and make sure its in websphere + + ClassLoader genericLoader = getClassLoaderFromJar(genericJarFile); + + for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) + + { + + String filepath = (String)e.nextElement(); + + if (wasEntries.containsKey(filepath)) // File name/path match + + { + + // Check files see if same + + JarEntry genericEntry = (JarEntry)genericEntries.get(filepath); + + JarEntry wasEntry = (JarEntry)wasEntries.get(filepath); + + if ((genericEntry.getCrc() != wasEntry.getCrc()) || // Crc's Match + + (genericEntry.getSize() != wasEntry.getSize()) ) // Size Match + + { + + if (genericEntry.getName().endsWith(".class")) + + { + + //File are different see if its an object or an interface + + String classname = genericEntry.getName().replace(File.separatorChar,'.'); + + classname = classname.substring(0,classname.lastIndexOf(".class")); + + Class genclass = genericLoader.loadClass(classname); + + if (genclass.isInterface()) + + { + + //Interface changed rebuild jar. + + log("Interface " + genclass.getName() + " has changed",Project.MSG_VERBOSE); + + rebuild = true; + + break; + + } + + else + + { + + //Object class Changed update it. + + replaceEntries.put(filepath, genericEntry); + + } + + } + + else + + { + + // is it the manifest. If so ignore it + + if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) { + + //File other then class changed rebuild + + log("Non class file " + genericEntry.getName() + " has changed",Project.MSG_VERBOSE); + + rebuild = true; + + } + + break; + + } + + } + + } + + else // a file doesnt exist rebuild + + { + + log("File " + filepath + " not present in websphere jar",Project.MSG_VERBOSE); + + rebuild = true; + + break; + + } + + } + + + + if (!rebuild) + + { + + log("No rebuild needed - updating jar",Project.MSG_VERBOSE); + + newwasJarFile = new File(websphereJarFile.getAbsolutePath() + ".temp"); + + if (newwasJarFile.exists()) { + + newwasJarFile.delete(); + + } + + + + newJarStream = new JarOutputStream(new FileOutputStream(newwasJarFile)); + + newJarStream.setLevel(0); + + + + //Copy files from old websphere jar + + for (Enumeration e = wasEntries.elements() ; e.hasMoreElements();) + + { + + byte[] buffer = new byte[1024]; + + int bytesRead; + + InputStream is; + + JarEntry je = (JarEntry)e.nextElement(); + + if (je.getCompressedSize() == -1 || + + je.getCompressedSize() == je.getSize()) { + + newJarStream.setLevel(0); + + } + + else { + + newJarStream.setLevel(9); + + } + + + + // Update with changed Bean class + + if (replaceEntries.containsKey(je.getName())) + + { + + log("Updating Bean class from generic Jar " + je.getName(), + + Project.MSG_VERBOSE); + + // Use the entry from the generic jar + + je = (JarEntry)replaceEntries.get(je.getName()); + + is = genericJar.getInputStream(je); + + } + + else //use fle from original websphere jar + + { + + is = wasJar.getInputStream(je); + + } + + newJarStream.putNextEntry(new JarEntry(je.getName())); + + + + while ((bytesRead = is.read(buffer)) != -1) + + { + + newJarStream.write(buffer,0,bytesRead); + + } + + is.close(); + + } + + } + + else + + { + + log("websphere Jar rebuild needed due to changed interface or XML",Project.MSG_VERBOSE); + + } + + } + + else + + { + + rebuild = true; + + } + + } + + catch(ClassNotFoundException cnfe) + + { + + String cnfmsg = "ClassNotFoundException while processing ejb-jar file" + + + ". Details: " + + + cnfe.getMessage(); + + throw new BuildException(cnfmsg, cnfe); + + } + + catch(IOException ioe) { + + String msg = "IOException while processing ejb-jar file " + + + ". Details: " + + + ioe.getMessage(); + + throw new BuildException(msg, ioe); + + } + + finally { + + // need to close files and perhaps rename output + + if (genericJar != null) { + + try { + + genericJar.close(); + + } + + catch (IOException closeException) {} + + } + + + + if (wasJar != null) { + + try { + + wasJar.close(); + + } + + catch (IOException closeException) {} + + } + + + + if (newJarStream != null) { + + try { + + newJarStream.close(); + + } + + catch (IOException closeException) {} + + + + websphereJarFile.delete(); + + newwasJarFile.renameTo(websphereJarFile); + + if (!websphereJarFile.exists()) { + + rebuild = true; + + } + + } + + } + + + + return rebuild; + + } + + + + /** + + * Helper method invoked by isRebuildRequired to get a ClassLoader for + + * a Jar File passed to it. + + * + + * @param classjar java.io.File representing jar file to get classes from. + + */ + + protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException + + { + + Path lookupPath = new Path(getTask().getProject()); + + lookupPath.setLocation(classjar); + + + + Path classpath = getCombinedClasspath(); + + if (classpath != null) { + + lookupPath.append(classpath); + + } + + + + return new AntClassLoader(getTask().getProject(), lookupPath); + + } + +} +