diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java | 932 |
1 files changed, 932 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java new file mode 100644 index 00000000..550f59ce --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java @@ -0,0 +1,932 @@ +/* + * 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; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Java; +import org.apache.tools.ant.types.Environment; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.FileUtils; +import org.xml.sax.InputSource; + +/** + The weblogic element is used to control the weblogic.ejbc compiler for + generating weblogic EJB jars. Prior to Ant 1.3, the method of locating CMP + descriptors was to use the ejbjar naming convention. So if your ejb-jar was + called, Customer-ejb-jar.xml, your weblogic descriptor was called Customer- + weblogic-ejb-jar.xml and your CMP descriptor had to be Customer-weblogic-cmp- + rdbms-jar.xml. In addition, the <type-storage> element in the weblogic + descriptor had to be set to the standard name META-INF/weblogic-cmp-rdbms- + jar.xml, as that is where the CMP descriptor was mapped to in the generated + jar. +*/ +public class WeblogicDeploymentTool extends GenericDeploymentTool { + /** EJB11 id */ + public static final String PUBLICID_EJB11 + = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"; + /** EJB20 id */ + public static final String PUBLICID_EJB20 + = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"; + /** Weblogic 5.1.0 id */ + public static final String PUBLICID_WEBLOGIC_EJB510 + = "-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN"; + /** Weblogic 6.0.0 id */ + public static final String PUBLICID_WEBLOGIC_EJB600 + = "-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN"; + /** Weblogic 7.0.0 id */ + public static final String PUBLICID_WEBLOGIC_EJB700 + = "-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN"; + + /** Weblogic 5.1 dtd location */ + protected static final String DEFAULT_WL51_EJB11_DTD_LOCATION + = "/weblogic/ejb/deployment/xml/ejb-jar.dtd"; + /** Weblogic 6.0 ejb 1.1 dtd location */ + protected static final String DEFAULT_WL60_EJB11_DTD_LOCATION + = "/weblogic/ejb20/dd/xml/ejb11-jar.dtd"; + /** Weblogic 6.0 ejb 2.0 dtd location */ + protected static final String DEFAULT_WL60_EJB20_DTD_LOCATION + = "/weblogic/ejb20/dd/xml/ejb20-jar.dtd"; + + protected static final String DEFAULT_WL51_DTD_LOCATION + = "/weblogic/ejb/deployment/xml/weblogic-ejb-jar.dtd"; + protected static final String DEFAULT_WL60_51_DTD_LOCATION + = "/weblogic/ejb20/dd/xml/weblogic510-ejb-jar.dtd"; + protected static final String DEFAULT_WL60_DTD_LOCATION + = "/weblogic/ejb20/dd/xml/weblogic600-ejb-jar.dtd"; + protected static final String DEFAULT_WL70_DTD_LOCATION + = "/weblogic/ejb20/dd/xml/weblogic700-ejb-jar.dtd"; + + protected static final String DEFAULT_COMPILER = "default"; + + protected static final String WL_DD = "weblogic-ejb-jar.xml"; + protected static final String WL_CMP_DD = "weblogic-cmp-rdbms-jar.xml"; + + protected static final String COMPILER_EJB11 = "weblogic.ejbc"; + protected static final String COMPILER_EJB20 = "weblogic.ejbc20"; + + /** File utilities instance for copying jars */ + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + /** Instance variable that stores the suffix for the weblogic jarfile. */ + private String jarSuffix = ".jar"; + + /** Instance variable that stores the location of the weblogic DTD file. */ + private String weblogicDTD; + + /** Instance variable that stores the location of the ejb 1.1 DTD file. */ + private String ejb11DTD; + + /** Instance variable that determines whether generic ejb jars are kept. */ + private boolean keepgenerated = false; + + /** + * Instance variable that stores the fully qualified classname of the + * weblogic EJBC compiler + */ + private String ejbcClass = null; + + private String additionalArgs = ""; + + /** + * additional args to pass to the spawned jvm + */ + private String additionalJvmArgs = ""; + + private boolean keepGeneric = false; + + private String compiler = null; + + private boolean alwaysRebuild = true; + + /** controls whether ejbc is run on the generated jar */ + private boolean noEJBC = false; + + /** Indicates if the old CMP location convention is to be used. */ + private boolean newCMP = false; + + /** The classpath to the weblogic classes. */ + private Path wlClasspath = null; + + /** System properties for the JVM. */ + private Vector sysprops = new Vector(); + + /** + * The weblogic.StdoutSeverityLevel to use when running the JVM that + * executes ejbc. Set to 16 to avoid the warnings about EJB Home and + * Remotes being in the classpath + */ + private Integer jvmDebugLevel = null; + + private File outputDir; + + /** + * Add a nested sysproperty element. + * @param sysp the element to add. + */ + public void addSysproperty(Environment.Variable sysp) { + sysprops.add(sysp); + } + + + /** + * Get the classpath to the weblogic classpaths. + * @return the classpath to configure. + */ + public Path createWLClasspath() { + if (wlClasspath == null) { + wlClasspath = new Path(getTask().getProject()); + } + return wlClasspath.createPath(); + } + + /** + * If set ejbc will use this directory as the output + * destination rather than a jar file. This allows for the + * generation of "exploded" jars. + * @param outputDir the directory to be used. + */ + public void setOutputDir(File outputDir) { + this.outputDir = outputDir; + } + + + /** + * Optional classpath to WL6.0. + * Weblogic 6.0 will give a warning if the home and remote interfaces + * of a bean are on the system classpath used to run weblogic.ejbc. + * In that case, the standard weblogic classes should be set with + * this attribute (or equivalent nested element) and the + * home and remote interfaces located with the standard classpath + * attribute. + * @param wlClasspath the path to be used. + */ + public void setWLClasspath(Path wlClasspath) { + this.wlClasspath = wlClasspath; + } + + + /** + * The compiler (switch <code>-compiler</code>) to use; optional. + * This allows for the selection of a different compiler + * to be used for the compilation of the generated Java + * files. This could be set, for example, to Jikes to + * compile with the Jikes compiler. If this is not set + * and the <code>build.compiler</code> property is set + * to jikes, the Jikes compiler will be used. If this + * is not desired, the value "<code>default</code>" + * may be given to use the default compiler. + * @param compiler the compiler to be used. + */ + public void setCompiler(String compiler) { + this.compiler = compiler; + } + + + /** + * Set the rebuild flag to false to only update changes in the jar rather + * than rerunning ejbc; optional, default true. + * This flag controls whether weblogic.ejbc is always + * invoked to build the jar file. In certain circumstances, + * such as when only a bean class has been changed, the jar + * can be generated by merely replacing the changed classes + * and not rerunning ejbc. Setting this to false will reduce + * the time to run ejbjar. + * @param rebuild a <code>boolean</code> value. + */ + public void setRebuild(boolean rebuild) { + this.alwaysRebuild = rebuild; + } + + + /** + * Sets the weblogic.StdoutSeverityLevel to use when running the JVM that + * executes ejbc; optional. Set to 16 to avoid the warnings about EJB Home and + * Remotes being in the classpath + * @param jvmDebugLevel the value to use. + */ + public void setJvmDebugLevel(Integer jvmDebugLevel) { + this.jvmDebugLevel = jvmDebugLevel; + } + + + /** + * Get the debug level. + * @return the jvm debug level (may be null). + */ + public Integer getJvmDebugLevel() { + return jvmDebugLevel; + } + + + + /** + * Setter used to store the suffix for the generated weblogic jar file. + * + * @param inString the string to use as the suffix. + */ + public void setSuffix(String inString) { + this.jarSuffix = inString; + } + + + /** + * controls whether the generic file used as input to + * ejbc is retained; defaults to false + * + * @param inValue true for keep generic + */ + public void setKeepgeneric(boolean inValue) { + this.keepGeneric = inValue; + } + + + /** + * Controls whether weblogic will keep the generated Java + * files used to build the class files added to the + * jar. This can be useful when debugging; default is false. + * + * @param inValue either 'true' or 'false' + */ + public void setKeepgenerated(String inValue) { + this.keepgenerated = Boolean.valueOf(inValue).booleanValue(); + } + + + /** + * Any optional extra arguments pass to the weblogic.ejbc + * tool. + * @param args extra arguments to pass to the ejbc tool. + */ + public void setArgs(String args) { + this.additionalArgs = args; + } + + + /** + * Set any additional arguments to pass to the weblogic JVM; optional. + * @param args the arguments to be passed to the JVM + */ + public void setJvmargs(String args) { + this.additionalJvmArgs = args; + } + + /** + * Set the classname of the ejbc compiler; optional + * Normally ejbjar determines + * the appropriate class based on the DTD used for the EJB. The EJB 2.0 compiler + * featured in weblogic 6 has, however, been deprecated in version 7. When + * using with version 7 this attribute should be set to + * "weblogic.ejbc" to avoid the deprecation warning. + * @param ejbcClass the name of the class to use. + */ + public void setEjbcClass(String ejbcClass) { + this.ejbcClass = ejbcClass; + } + + + /** + * Get the ejbc compiler class. + * @return the name of the ejbc compiler class. + */ + public String getEjbcClass() { + return ejbcClass; + } + + + /** + * <b>Deprecated</b>. Defines the location of the ejb-jar DTD in + * the weblogic class hierarchy. Should not be needed, and the + * nested <dtd> element is recommended when it is. + * + * @param inString the string to use as the DTD location. + */ + public void setWeblogicdtd(String inString) { + setEJBdtd(inString); + } + + + /** + * <b>Deprecated</b>. Defines the location of weblogic DTD in + * the weblogic class hierarchy. Should not be needed, and the + * nested <dtd> element is recommended when it is. + * + * @param inString the string to use as the DTD location. + */ + public void setWLdtd(String inString) { + this.weblogicDTD = inString; + } + + + /** + * <b>Deprecated</b>. Defines the location of Sun's EJB DTD in + * the weblogic class hierarchy. Should not be needed, and the + * nested <dtd> element is recommended when it is. + * + * @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 + * @ant.attribute ignore="true' + * @param oldCMP a <code>boolean</code> value. + */ + public void setOldCMP(boolean oldCMP) { + this.newCMP = !oldCMP; + } + + + /** + * If this is set to true, the new method for locating + * CMP descriptors will be used; optional, default false. + * <P> + * The old CMP scheme locates the + * weblogic CMP descriptor based on the naming convention where the + * weblogic 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 weblogic EJB descriptor. Also, + * descriptors which contain multiple CMP references could not be used. + * @param newCMP a <code>boolean</code> value. + */ + public void setNewCMP(boolean newCMP) { + this.newCMP = newCMP; + } + + + /** + * Do not EJBC the jar after it has been put together; + * optional, default false + * @param noEJBC a <code>boolean</code> value. + */ + public void setNoEJBC(boolean noEJBC) { + this.noEJBC = noEJBC; + } + + + /** + * Register the DTDs. + * @param handler the handler to use. + */ + protected void registerKnownDTDs(DescriptorHandler handler) { + // register all the known DTDs + handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL51_EJB11_DTD_LOCATION); + handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL60_EJB11_DTD_LOCATION); + handler.registerDTD(PUBLICID_EJB11, ejb11DTD); + handler.registerDTD(PUBLICID_EJB20, DEFAULT_WL60_EJB20_DTD_LOCATION); + } + + + /** + * Get the weblogic descriptor handler. + * @param srcDir the source directory. + * @return the descriptor. + */ + protected DescriptorHandler getWeblogicDescriptorHandler(final File srcDir) { + DescriptorHandler handler = + new DescriptorHandler(getTask(), srcDir) { + protected void processElement() { + if (currentElement.equals("type-storage")) { + // Get the filename of vendor specific descriptor + String fileNameWithMETA = currentText; + //trim the META_INF\ off of the file name + String fileName + = fileNameWithMETA.substring(META_DIR.length(), + fileNameWithMETA.length()); + File descriptorFile = new File(srcDir, fileName); + + ejbFiles.put(fileNameWithMETA, descriptorFile); + } + } + }; + + handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL51_DTD_LOCATION); + handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL60_51_DTD_LOCATION); + handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, DEFAULT_WL60_DTD_LOCATION); + handler.registerDTD(PUBLICID_WEBLOGIC_EJB700, DEFAULT_WL70_DTD_LOCATION); + handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, weblogicDTD); + handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, weblogicDTD); + + 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. + * @param ejbFiles the hash table to be populated. + * @param ddPrefix the prefix to use. + */ + protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) { + File weblogicDD = new File(getConfig().descriptorDir, ddPrefix + WL_DD); + + if (weblogicDD.exists()) { + ejbFiles.put(META_DIR + WL_DD, + weblogicDD); + } else { + log("Unable to locate weblogic deployment descriptor. " + + "It was expected to be in " + + weblogicDD.getPath(), Project.MSG_WARN); + return; + } + + if (!newCMP) { + log("The old method for locating CMP files has been DEPRECATED.", Project.MSG_VERBOSE); + log("Please adjust your weblogic descriptor and set " + + "newCMP=\"true\" to use the new CMP descriptor " + + "inclusion mechanism. ", Project.MSG_VERBOSE); + // The the weblogic cmp deployment descriptor + File weblogicCMPDD = new File(getConfig().descriptorDir, ddPrefix + WL_CMP_DD); + + if (weblogicCMPDD.exists()) { + ejbFiles.put(META_DIR + WL_CMP_DD, + weblogicCMPDD); + } + } else { + // now that we have the weblogic descriptor, we parse the file + // to find other descriptors needed to deploy the bean. + // this could be the weblogic-cmp-rdbms.xml or any other O/R + // mapping tool descriptors. + try { + File ejbDescriptor = (File) ejbFiles.get(META_DIR + EJB_DD); + SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + + saxParserFactory.setValidating(true); + + SAXParser saxParser = saxParserFactory.newSAXParser(); + DescriptorHandler handler + = getWeblogicDescriptorHandler(ejbDescriptor.getParentFile()); + + saxParser.parse(new InputSource + (new FileInputStream(weblogicDD)), + handler); + + Hashtable ht = handler.getFiles(); + Enumeration e = ht.keys(); + + while (e.hasMoreElements()) { + String key = (String) e.nextElement(); + + ejbFiles.put(key, ht.get(key)); + } + } 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); + } + + + /** + * Helper method invoked by execute() for each WebLogic jar to be built. + * Encapsulates the logic of constructing a java task for calling + * weblogic.ejbc and executing it. + * + * @param sourceJar java.io.File representing the source (EJB1.1) jarfile. + * @param destJar java.io.File representing the destination, WebLogic + * jarfile. + */ + private void buildWeblogicJar(File sourceJar, File destJar, String publicId) { + Java javaTask = null; + + if (noEJBC) { + try { + FILE_UTILS.copyFile(sourceJar, destJar); + if (!keepgenerated) { + sourceJar.delete(); + } + return; + } catch (IOException e) { + throw new BuildException("Unable to write EJB jar", e); + } + } + + String ejbcClassName = ejbcClass; + + try { + javaTask = new Java(getTask()); + javaTask.setTaskName("ejbc"); + + javaTask.createJvmarg().setLine(additionalJvmArgs); + if (!(sysprops.isEmpty())) { + for (Enumeration en = sysprops.elements(); en.hasMoreElements();) { + Environment.Variable entry + = (Environment.Variable) en.nextElement(); + javaTask.addSysproperty(entry); + } + } + + if (getJvmDebugLevel() != null) { + javaTask.createJvmarg().setLine(" -Dweblogic.StdoutSeverityLevel=" + jvmDebugLevel); + } + + if (ejbcClassName == null) { + // try to determine it from publicId + if (PUBLICID_EJB11.equals(publicId)) { + ejbcClassName = COMPILER_EJB11; + } else if (PUBLICID_EJB20.equals(publicId)) { + ejbcClassName = COMPILER_EJB20; + } else { + log("Unrecognized publicId " + publicId + + " - using EJB 1.1 compiler", Project.MSG_WARN); + ejbcClassName = COMPILER_EJB11; + } + } + + javaTask.setClassname(ejbcClassName); + javaTask.createArg().setLine(additionalArgs); + if (keepgenerated) { + javaTask.createArg().setValue("-keepgenerated"); + } + if (compiler == null) { + // try to use the compiler specified by build.compiler. + // Right now we are just going to allow Jikes + String buildCompiler + = getTask().getProject().getProperty("build.compiler"); + + if (buildCompiler != null && buildCompiler.equals("jikes")) { + javaTask.createArg().setValue("-compiler"); + javaTask.createArg().setValue("jikes"); + } + } else { + if (!compiler.equals(DEFAULT_COMPILER)) { + javaTask.createArg().setValue("-compiler"); + javaTask.createArg().setLine(compiler); + } + } + + Path combinedClasspath = getCombinedClasspath(); + if (wlClasspath != null && combinedClasspath != null + && combinedClasspath.toString().trim().length() > 0) { + javaTask.createArg().setValue("-classpath"); + javaTask.createArg().setPath(combinedClasspath); + } + + javaTask.createArg().setValue(sourceJar.getPath()); + if (outputDir == null) { + javaTask.createArg().setValue(destJar.getPath()); + } else { + javaTask.createArg().setValue(outputDir.getPath()); + } + + Path classpath = wlClasspath; + + if (classpath == null) { + classpath = getCombinedClasspath(); + } + + javaTask.setFork(true); + if (classpath != null) { + javaTask.setClasspath(classpath); + } + + log("Calling " + ejbcClassName + " for " + sourceJar.toString(), + Project.MSG_VERBOSE); + + if (javaTask.executeJava() != 0) { + throw new BuildException("Ejbc reported an error"); + } + } catch (Exception e) { + // Have to catch this because of the semantics of calling main() + String msg = "Exception while calling " + ejbcClassName + + ". 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. + * @param baseName the base name. + * @param jarFile the jar file to populate. + * @param files the hash table of files to write. + * @param publicId the id to use. + * @throws BuildException if there is a problem. + */ + 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); + + if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) { + buildWeblogicJar(genericJarFile, jarFile, publicId); + } + if (!keepGeneric) { + log("deleting generic jar " + genericJarFile.toString(), + Project.MSG_VERBOSE); + genericJarFile.delete(); + } + } + + + /** + * Called to validate that the tool parameters have been configured. + * @throws BuildException if there is an error. + */ + public void validateConfigured() throws BuildException { + super.validateConfigured(); + } + + + /** + * Helper method to check to see if a weblogic EBJ1.1 jar needs to be + * rebuilt using ejbc. 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 weblogic + * jar needs to be regened with ejbc. This allows faster build times for + * working developers. <p> + * + * The way weblogic ejbc 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 + * weblogic jar file can remain the same. If the Interfaces, ie. the + * method signatures change or if the xml deployment descriptors changed, + * the whole jar needs to be rebuilt with ejbc. This is not strictly true + * for the xml files. If the JNDI name changes then the jar doesn't have to + * be rebuild, but if the resources references change then it does. At + * this point the weblogic jar gets rebuilt if the xml files change at + * all. + * + * @param genericJarFile java.io.File The generic jar file. + * @param weblogicJarFile java.io.File The weblogic jar file to check to + * see if it needs to be rebuilt. + * @return true if the jar needs to be rebuilt. + */ + // CheckStyle:MethodLength OFF - this will no be fixed + protected boolean isRebuildRequired(File genericJarFile, File weblogicJarFile) { + boolean rebuild = false; + + JarFile genericJar = null; + JarFile wlJar = null; + File newWLJarFile = null; + JarOutputStream newJarStream = null; + ClassLoader genericLoader = null; + + try { + log("Checking if weblogic Jar needs to be rebuilt for jar " + weblogicJarFile.getName(), + Project.MSG_VERBOSE); + // Only go forward if the generic and the weblogic file both exist + if (genericJarFile.exists() && genericJarFile.isFile() + && weblogicJarFile.exists() && weblogicJarFile.isFile()) { + //open jar files + genericJar = new JarFile(genericJarFile); + wlJar = new JarFile(weblogicJarFile); + + Hashtable genericEntries = new Hashtable(); + Hashtable wlEntries = 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 weblogic jar entries + for (Enumeration e = wlJar.entries(); e.hasMoreElements();) { + JarEntry je = (JarEntry) e.nextElement(); + + wlEntries.put(je.getName(), je); + } + + //Cycle Through generic and make sure its in weblogic + genericLoader = getClassLoaderFromJar(genericJarFile); + + for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) { + String filepath = (String) e.nextElement(); + + if (wlEntries.containsKey(filepath)) { + // File name/path match + + // Check files see if same + JarEntry genericEntry = (JarEntry) genericEntries.get(filepath); + JarEntry wlEntry = (JarEntry) wlEntries.get(filepath); + + if ((genericEntry.getCrc() != wlEntry.getCrc()) + || (genericEntry.getSize() != wlEntry.getSize())) { + + if (genericEntry.getName().endsWith(".class")) { + //File are different see if its an object or an interface + String classname + = genericEntry.getName() + .replace(File.separatorChar, '.') + .replace('/', '.'); + + 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 doesn't exist rebuild + + log("File " + filepath + " not present in weblogic jar", + Project.MSG_VERBOSE); + rebuild = true; + break; + } + } + + if (!rebuild) { + log("No rebuild needed - updating jar", Project.MSG_VERBOSE); + newWLJarFile = new File(weblogicJarFile.getAbsolutePath() + ".temp"); + if (newWLJarFile.exists()) { + newWLJarFile.delete(); + } + + newJarStream = new JarOutputStream(new FileOutputStream(newWLJarFile)); + newJarStream.setLevel(0); + + //Copy files from old weblogic jar + for (Enumeration e = wlEntries.elements(); e.hasMoreElements();) { + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + int bytesRead; + InputStream is; + JarEntry je = (JarEntry) e.nextElement(); + + if (je.getCompressedSize() == -1 + || je.getCompressedSize() == je.getSize()) { + newJarStream.setLevel(0); + } else { + newJarStream.setLevel(JAR_COMPRESS_LEVEL); + } + + // 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 weblogic jar + + is = wlJar.getInputStream(je); + } + newJarStream.putNextEntry(new JarEntry(je.getName())); + + while ((bytesRead = is.read(buffer)) != -1) { + newJarStream.write(buffer, 0, bytesRead); + } + is.close(); + } + } else { + log("Weblogic 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) { + // empty + } + } + + if (wlJar != null) { + try { + wlJar.close(); + } catch (IOException closeException) { + // empty + } + } + + if (newJarStream != null) { + try { + newJarStream.close(); + } catch (IOException closeException) { + // empty + } + + try { + FILE_UTILS.rename(newWLJarFile, weblogicJarFile); + } catch (IOException renameException) { + log(renameException.getMessage(), Project.MSG_WARN); + rebuild = true; + } + } + if (genericLoader != null + && genericLoader instanceof AntClassLoader) { + AntClassLoader loader = (AntClassLoader) genericLoader; + loader.cleanup(); + } + } + + 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. + * @return the classloader for the jarfile. + * @throws IOException if there is a problem. + */ + 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 getTask().getProject().createClassLoader(lookupPath); + } +} |