All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.greenpepper.shaded.org.apache.tools.ant.taskdefs.optional.ejb.WebsphereDeploymentTool Maven / Gradle / Ivy

There is a newer version: 4.2.4
Show newest version
/*
 *  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 com.greenpepper.shaded.org.apache.tools.ant.taskdefs.optional.ejb;

import java.io.File;
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.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import com.greenpepper.shaded.org.apache.tools.ant.BuildException;
import com.greenpepper.shaded.org.apache.tools.ant.Project;
import com.greenpepper.shaded.org.apache.tools.ant.taskdefs.Java;
import com.greenpepper.shaded.org.apache.tools.ant.types.Environment;
import com.greenpepper.shaded.org.apache.tools.ant.types.Path;
import com.greenpepper.shaded.org.apache.tools.ant.util.FileUtils;

/**
 * Websphere deployment tool that augments the ejbjar task.
 * Searches for the websphere specific deployment descriptors and
 * adds them to the final ejb jar file. Websphere has two specific descriptors for session
 * beans:
 * 
    *
  • ibm-ejb-jar-bnd.xmi
  • *
  • ibm-ejb-jar-ext.xmi
  • *
* and another two for container managed entity beans: *
    *
  • Map.mapxmi
  • *
  • Schema.dbxmi
  • *
* In terms of WebSphere, the generation of container code and stubs is * called deployment. This step can be performed by the websphere * element as part of the jar generation process. If the switch * ejbdeploy is on, the ejbdeploy tool from the websphere toolset * is called for every ejb-jar. Unfortunately, this step only works, if you * use the ibm jdk. Otherwise, the rmic (called by ejbdeploy) throws a * ClassFormatError. Be sure to switch ejbdeploy off, if run ant with * sun jdk. * */ public class WebsphereDeploymentTool extends GenericDeploymentTool { /** ID for ejb 1.1 */ public static final String PUBLICID_EJB11 = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"; /** ID for ejb 2.0 */ public static final String PUBLICID_EJB20 = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"; /** Schema directory */ protected static final String SCHEMA_DIR = "Schema/"; protected static final String WAS_EXT = "ibm-ejb-jar-ext.xmi"; protected static final String WAS_BND = "ibm-ejb-jar-bnd.xmi"; protected static final String WAS_CMP_MAP = "Map.mapxmi"; protected static final String WAS_CMP_SCHEMA = "Schema.dbxmi"; private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); /** Instance variable that stores the suffix for the websphere jarfile. */ private String jarSuffix = ".jar"; /** 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 keepGeneric = false; private boolean alwaysRebuild = true; private boolean ejbdeploy = true; /** Indicates if the old CMP location convention is to be used. */ private boolean newCMP = false; /** The classpath to the websphere classes. */ private Path wasClasspath = null; /** The DB Vendor name, the EJB is persisted against */ private String dbVendor; /** The name of the database to create. (For top-down mapping only) */ private String dbName; /** The name of the schema to create. (For top-down mappings only) */ private String dbSchema; /** true - Only generate the deployment code, do not run RMIC or Javac */ private boolean codegen; /** true - Only output error messages, suppress informational messages */ private boolean quiet = true; /** true - Disable the validation steps */ private boolean novalidate; /** true - Disable warning and informational messages */ private boolean nowarn; /** true - Disable informational messages */ private boolean noinform; /** true - Enable internal tracing */ private boolean trace; /** Additional options for RMIC */ private String rmicOptions; /** true- Use the WebSphere 3.5 compatible mapping rules */ private boolean use35MappingRules; /** the scratchdir for the ejbdeploy operation */ private String tempdir = "_ejbdeploy_temp"; /** the home directory for websphere */ private File websphereHome; /** * Get the classpath to the websphere classpaths. * @return the websphere classpath. */ public Path createWASClasspath() { if (wasClasspath == null) { wasClasspath = new Path(getTask().getProject()); } return wasClasspath.createPath(); } /** * Set the websphere classpath. * @param wasClasspath the websphere classpath. */ public void setWASClasspath(Path wasClasspath) { this.wasClasspath = wasClasspath; } /** Sets the DB Vendor for the Entity Bean mapping ; optional. *

* Valid options can be obtained by running the following command: * * <WAS_HOME>/bin/EJBDeploy.[sh/bat] -help * *

*

* This is also used to determine the name of the Map.mapxmi and * Schema.dbxmi files, for example Account-DB2UDB_V81-Map.mapxmi * and Account-DB2UDB_V81-Schema.dbxmi. *

* * @param dbvendor database vendor type */ public void setDbvendor(String dbvendor) { this.dbVendor = dbvendor; } /** * Sets the name of the Database to create; optional. * * @param dbName name of the database */ public void setDbname(String dbName) { this.dbName = dbName; } /** * Sets the name of the schema to create; optional. * * @param dbSchema name of the schema */ public void setDbschema(String dbSchema) { this.dbSchema = dbSchema; } /** * Flag, default false, to only generate the deployment * code, do not run RMIC or Javac * * @param codegen option */ public void setCodegen(boolean codegen) { this.codegen = codegen; } /** * Flag, default true, to only output error messages. * * @param quiet option */ public void setQuiet(boolean quiet) { this.quiet = quiet; } /** * Flag to disable the validation steps; optional, default false. * * @param novalidate option */ public void setNovalidate(boolean novalidate) { this.novalidate = novalidate; } /** * Flag to disable warning and informational messages; optional, default false. * * @param nowarn option */ public void setNowarn(boolean nowarn) { this.nowarn = nowarn; } /** * Flag to disable informational messages; optional, default false. * * @param noinform if true disables informational messages */ public void setNoinform(boolean noinform) { this.noinform = noinform; } /** * Flag to enable internal tracing when set, optional, default false. * * @param trace a boolean vaule. */ public void setTrace(boolean trace) { this.trace = trace; } /** * Set the rmic options. * * @param options the options to use. */ public void setRmicoptions(String options) { this.rmicOptions = options; } /** * Flag to use the WebSphere 3.5 compatible mapping rules ; optional, default false. * * @param attr a boolean value. */ public void setUse35(boolean attr) { use35MappingRules = attr; } /** * Set the rebuild flag to false to only update changes in the jar rather * than rerunning ejbdeploy; optional, default true. * @param rebuild a boolean value. */ public void setRebuild(boolean rebuild) { this.alwaysRebuild = rebuild; } /** * String value appended to the basename of the deployment * descriptor to create the filename of the WebLogic EJB * jar file. Optional, default '.jar'. * @param inString the string to use as the suffix. */ public void setSuffix(String inString) { this.jarSuffix = inString; } /** * This controls whether the generic file used as input to * ejbdeploy is retained; optional, default false. * @param inValue either 'true' or 'false'. */ public void setKeepgeneric(boolean inValue) { this.keepGeneric = inValue; } /** * Decide, wether ejbdeploy should be called or not; * optional, default true. * * @param ejbdeploy a boolean value. */ public void setEjbdeploy(boolean ejbdeploy) { this.ejbdeploy = ejbdeploy; } /** * 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 * @ant.attribute ignore="true" * @param oldCMP a boolean value. */ 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. * @param newCMP a boolean value. */ public void setNewCMP(boolean newCMP) { this.newCMP = newCMP; } /** * The directory, where ejbdeploy will write temporary files; * optional, defaults to '_ejbdeploy_temp'. * @param tempdir the directory name to use. */ public void setTempdir(String tempdir) { this.tempdir = tempdir; } /** {@inheritDoc}. */ 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; } /** * Get a description handler. * @param srcDir the source directory. * @return the 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. * @param ejbFiles a hashtable entryname -> file. * @param baseName a prefix to use. */ 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(); } /** * 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) { Java javaTask = new Java(getTask()); // 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"); File libdir = new File(websphereHome, "lib"); var.setValue(libdir.getAbsolutePath()); javaTask.addSysproperty(var); // Set the working directory javaTask.setDir(websphereHome); // Set the Java class name javaTask.setTaskName("ejbdeploy"); javaTask.setClassname("com.greenpepper.shaded.com.ibm.etools.ejbdeploy.EJBDeploy"); javaTask.createArg().setValue(sourceJar.getPath()); javaTask.createArg().setValue(tempdir); javaTask.createArg().setValue(destJar.getPath()); javaTask.createArg().setLine(getOptions()); if (getCombinedClasspath() != null && getCombinedClasspath().toString().length() > 0) { javaTask.createArg().setValue("-cp"); javaTask.createArg().setValue(getCombinedClasspath().toString()); } 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); } } /** {@inheritDoc}. */ 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); } } /** * Called to validate that the tool parameters have been configured. * @throws BuildException if there is an error. */ public void validateConfigured() throws BuildException { super.validateConfigured(); if (ejbdeploy) { String home = getTask().getProject().getProperty("websphere.home"); if (home == null) { throw new BuildException("The 'websphere.home' property must " + "be set when 'ejbdeploy=true'"); } websphereHome = getTask().getProject().resolveFile(home); } } /** * 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 descriptors 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. * @return true if a rebuild is required. */ 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()) || (genericEntry.getSize() != wasEntry.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 doesn't 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[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 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) { // Ignore } } if (wasJar != null) { try { wasJar.close(); } catch (IOException closeException) { // Ignore } } if (newJarStream != null) { try { newJarStream.close(); } catch (IOException closeException) { // Ignore } try { FILE_UTILS.rename(newwasJarFile, websphereJarFile); } catch (IOException renameException) { log(renameException.getMessage(), Project.MSG_WARN); 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. * @return a classloader for the jar file. * @throws IOException if there is an error. */ 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); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy