| /* |
| * 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 doesnt 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, '.'); |
| |
| 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 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); |
| } |
| } |