1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.ejb;
  18. import java.io.File;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.util.Enumeration;
  23. import java.util.Hashtable;
  24. import java.util.Iterator;
  25. import java.util.jar.JarEntry;
  26. import java.util.jar.JarFile;
  27. import java.util.jar.JarOutputStream;
  28. import org.apache.tools.ant.BuildException;
  29. import org.apache.tools.ant.Project;
  30. import org.apache.tools.ant.taskdefs.Java;
  31. import org.apache.tools.ant.types.EnumeratedAttribute;
  32. import org.apache.tools.ant.types.Environment;
  33. import org.apache.tools.ant.types.Path;
  34. import org.apache.tools.ant.util.FileUtils;
  35. /**
  36. * Websphere deployment tool that augments the ejbjar task.
  37. * Searches for the websphere specific deployment descriptors and
  38. * adds them to the final ejb jar file. Websphere has two specific descriptors for session
  39. * beans:
  40. * <ul>
  41. * <li>ibm-ejb-jar-bnd.xmi</li>
  42. * <li>ibm-ejb-jar-ext.xmi</li>
  43. * </ul>
  44. * and another two for container managed entity beans:
  45. * <ul>
  46. * <li>Map.mapxmi</li>
  47. * <li>Schema.dbxmi</li>
  48. * </ul>
  49. * In terms of WebSphere, the generation of container code and stubs is
  50. * called <code>deployment</code>. This step can be performed by the websphere
  51. * element as part of the jar generation process. If the switch
  52. * <code>ejbdeploy</code> is on, the ejbdeploy tool from the websphere toolset
  53. * is called for every ejb-jar. Unfortunately, this step only works, if you
  54. * use the ibm jdk. Otherwise, the rmic (called by ejbdeploy) throws a
  55. * ClassFormatError. Be sure to switch ejbdeploy off, if run ant with
  56. * sun jdk.
  57. *
  58. */
  59. public class WebsphereDeploymentTool extends GenericDeploymentTool {
  60. /**
  61. * Enumerated attribute with the values for the database vendor types
  62. *
  63. */
  64. public static class DBVendor extends EnumeratedAttribute {
  65. public String[] getValues() {
  66. return new String[]{
  67. "SQL92", "SQL99", "DB2UDBWIN_V71", "DB2UDBOS390_V6", "DB2UDBAS400_V4R5",
  68. "ORACLE_V8", "INFORMIX_V92", "SYBASE_V1192", "MSSQLSERVER_V7", "MYSQL_V323"
  69. };
  70. }
  71. }
  72. public static final String PUBLICID_EJB11
  73. = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
  74. public static final String PUBLICID_EJB20
  75. = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
  76. protected static final String SCHEMA_DIR = "Schema/";
  77. protected static final String WAS_EXT = "ibm-ejb-jar-ext.xmi";
  78. protected static final String WAS_BND = "ibm-ejb-jar-bnd.xmi";
  79. protected static final String WAS_CMP_MAP = "Map.mapxmi";
  80. protected static final String WAS_CMP_SCHEMA = "Schema.dbxmi";
  81. /** Instance variable that stores the suffix for the websphere jarfile. */
  82. private String jarSuffix = ".jar";
  83. /** Instance variable that stores the location of the ejb 1.1 DTD file. */
  84. private String ejb11DTD;
  85. /** Instance variable that determines whether generic ejb jars are kept. */
  86. private boolean keepGeneric = false;
  87. private boolean alwaysRebuild = true;
  88. private boolean ejbdeploy = true;
  89. /** Indicates if the old CMP location convention is to be used. */
  90. private boolean newCMP = false;
  91. /** The classpath to the websphere classes. */
  92. private Path wasClasspath = null;
  93. /** The DB Vendor name, the EJB is persisted against */
  94. private String dbVendor;
  95. /** The name of the database to create. (For top-down mapping only) */
  96. private String dbName;
  97. /** The name of the schema to create. (For top-down mappings only) */
  98. private String dbSchema;
  99. /** true - Only generate the deployment code, do not run RMIC or Javac */
  100. private boolean codegen;
  101. /** true - Only output error messages, suppress informational messages */
  102. private boolean quiet = true;
  103. /** true - Disable the validation steps */
  104. private boolean novalidate;
  105. /** true - Disable warning and informational messages */
  106. private boolean nowarn;
  107. /** true - Disable informational messages */
  108. private boolean noinform;
  109. /** true - Enable internal tracing */
  110. private boolean trace;
  111. /** Additional options for RMIC */
  112. private String rmicOptions;
  113. /** true- Use the WebSphere 3.5 compatible mapping rules */
  114. private boolean use35MappingRules;
  115. /** the scratchdir for the ejbdeploy operation */
  116. private String tempdir = "_ejbdeploy_temp";
  117. /** the home directory for websphere */
  118. private File websphereHome;
  119. /** Get the classpath to the websphere classpaths */
  120. public Path createWASClasspath() {
  121. if (wasClasspath == null) {
  122. wasClasspath = new Path(getTask().getProject());
  123. }
  124. return wasClasspath.createPath();
  125. }
  126. public void setWASClasspath(Path wasClasspath) {
  127. this.wasClasspath = wasClasspath;
  128. }
  129. /** Sets the DB Vendor for the Entity Bean mapping ; optional.
  130. * Valid options are for example:
  131. * <ul>
  132. * <li>SQL92</li> <li>SQL99</li> <li>DB2UDBWIN_V71</li>
  133. * <li>DB2UDBOS390_V6</li> <li>DB2UDBAS400_V4R5</li> <li>ORACLE_V8</li>
  134. * <li>INFORMIX_V92</li> <li>SYBASE_V1192</li> <li>MYSQL_V323</li>
  135. * </ul>
  136. * This is also used to determine the name of the Map.mapxmi and
  137. * Schema.dbxmi files, for example Account-DB2UDBWIN_V71-Map.mapxmi
  138. * and Account-DB2UDBWIN_V71-Schema.dbxmi.
  139. */
  140. public void setDbvendor(DBVendor dbvendor) {
  141. this.dbVendor = dbvendor.getValue();
  142. }
  143. /**
  144. * Sets the name of the Database to create; optional.
  145. *
  146. * @param dbName name of the database
  147. */
  148. public void setDbname(String dbName) {
  149. this.dbName = dbName;
  150. }
  151. /**
  152. * Sets the name of the schema to create; optional.
  153. *
  154. * @param dbSchema name of the schema
  155. */
  156. public void setDbschema(String dbSchema) {
  157. this.dbSchema = dbSchema;
  158. }
  159. /**
  160. * Flag, default false, to only generate the deployment
  161. * code, do not run RMIC or Javac
  162. *
  163. * @param codegen option
  164. */
  165. public void setCodegen(boolean codegen) {
  166. this.codegen = codegen;
  167. }
  168. /**
  169. * Flag, default true, to only output error messages.
  170. *
  171. * @param quiet option
  172. */
  173. public void setQuiet(boolean quiet) {
  174. this.quiet = quiet;
  175. }
  176. /**
  177. * Flag to disable the validation steps; optional, default false.
  178. *
  179. * @param novalidate option
  180. */
  181. public void setNovalidate(boolean novalidate) {
  182. this.novalidate = novalidate;
  183. }
  184. /**
  185. * Flag to disable warning and informational messages; optional, default false.
  186. *
  187. * @param nowarn option
  188. */
  189. public void setNowarn(boolean nowarn) {
  190. this.nowarn = nowarn;
  191. }
  192. /**
  193. * Flag to disable informational messages; optional, default false.
  194. *
  195. * @param noinform if true disables informational messages
  196. */
  197. public void setNoinform(boolean noinform) {
  198. this.noinform = noinform;
  199. }
  200. /**
  201. * Flag to enable internal tracing when set, optional, default false.
  202. *
  203. * @param trace
  204. */
  205. public void setTrace(boolean trace) {
  206. this.trace = trace;
  207. }
  208. /**
  209. * Set the rmic options.
  210. *
  211. * @param options
  212. */
  213. public void setRmicoptions(String options) {
  214. this.rmicOptions = options;
  215. }
  216. /**
  217. * Flag to use the WebSphere 3.5 compatible mapping rules ; optional, default false.
  218. *
  219. * @param attr
  220. */
  221. public void setUse35(boolean attr) {
  222. use35MappingRules = attr;
  223. }
  224. /**
  225. * Set the rebuild flag to false to only update changes in the jar rather
  226. * than rerunning ejbdeploy; optional, default true.
  227. */
  228. public void setRebuild(boolean rebuild) {
  229. this.alwaysRebuild = rebuild;
  230. }
  231. /**
  232. * String value appended to the basename of the deployment
  233. * descriptor to create the filename of the WebLogic EJB
  234. * jar file. Optional, default '.jar'.
  235. * @param inString the string to use as the suffix.
  236. */
  237. public void setSuffix(String inString) {
  238. this.jarSuffix = inString;
  239. }
  240. /**
  241. * This controls whether the generic file used as input to
  242. * ejbdeploy is retained; optional, default false.
  243. * @param inValue either 'true' or 'false'.
  244. */
  245. public void setKeepgeneric(boolean inValue) {
  246. this.keepGeneric = inValue;
  247. }
  248. /**
  249. * Decide, wether ejbdeploy should be called or not;
  250. * optional, default true.
  251. *
  252. * @param ejbdeploy
  253. */
  254. public void setEjbdeploy(boolean ejbdeploy) {
  255. this.ejbdeploy = ejbdeploy;
  256. }
  257. /**
  258. * Setter used to store the location of the Sun's Generic EJB DTD. This
  259. * can be a file on the system or a resource on the classpath.
  260. *
  261. * @param inString the string to use as the DTD location.
  262. */
  263. public void setEJBdtd(String inString) {
  264. this.ejb11DTD = inString;
  265. }
  266. /**
  267. * Set the value of the oldCMP scheme. This is an antonym for newCMP
  268. * @ant.attribute ignore="true"
  269. */
  270. public void setOldCMP(boolean oldCMP) {
  271. this.newCMP = !oldCMP;
  272. }
  273. /**
  274. * Set the value of the newCMP scheme. The old CMP scheme locates the
  275. * websphere CMP descriptor based on the naming convention where the
  276. * websphere CMP file is expected to be named with the bean name as the
  277. * prefix. Under this scheme the name of the CMP descriptor does not match
  278. * the name actually used in the main websphere EJB descriptor. Also,
  279. * descriptors which contain multiple CMP references could not be used.
  280. */
  281. public void setNewCMP(boolean newCMP) {
  282. this.newCMP = newCMP;
  283. }
  284. /**
  285. * The directory, where ejbdeploy will write temporary files;
  286. * optional, defaults to '_ejbdeploy_temp'.
  287. */
  288. public void setTempdir(String tempdir) {
  289. this.tempdir = tempdir;
  290. }
  291. protected DescriptorHandler getDescriptorHandler(File srcDir) {
  292. DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir);
  293. // register all the DTDs, both the ones that are known and
  294. // any supplied by the user
  295. handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
  296. for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
  297. EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
  298. handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
  299. }
  300. return handler;
  301. }
  302. protected DescriptorHandler getWebsphereDescriptorHandler(final File srcDir) {
  303. DescriptorHandler handler =
  304. new DescriptorHandler(getTask(), srcDir) {
  305. protected void processElement() {
  306. }
  307. };
  308. for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
  309. EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
  310. handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
  311. }
  312. return handler;
  313. }
  314. /**
  315. * Add any vendor specific files which should be included in the EJB Jar.
  316. */
  317. protected void addVendorFiles(Hashtable ejbFiles, String baseName) {
  318. String ddPrefix = (usingBaseJarName() ? "" : baseName);
  319. String dbPrefix = (dbVendor == null) ? "" : dbVendor + "-";
  320. // Get the Extensions document
  321. File websphereEXT = new File(getConfig().descriptorDir, ddPrefix + WAS_EXT);
  322. if (websphereEXT.exists()) {
  323. ejbFiles.put(META_DIR + WAS_EXT,
  324. websphereEXT);
  325. } else {
  326. log("Unable to locate websphere extensions. "
  327. + "It was expected to be in "
  328. + websphereEXT.getPath(), Project.MSG_VERBOSE);
  329. }
  330. File websphereBND = new File(getConfig().descriptorDir, ddPrefix + WAS_BND);
  331. if (websphereBND.exists()) {
  332. ejbFiles.put(META_DIR + WAS_BND,
  333. websphereBND);
  334. } else {
  335. log("Unable to locate websphere bindings. "
  336. + "It was expected to be in "
  337. + websphereBND.getPath(), Project.MSG_VERBOSE);
  338. }
  339. if (!newCMP) {
  340. log("The old method for locating CMP files has been DEPRECATED.",
  341. Project.MSG_VERBOSE);
  342. log("Please adjust your websphere descriptor and set "
  343. + "newCMP=\"true\" to use the new CMP descriptor "
  344. + "inclusion mechanism. ", Project.MSG_VERBOSE);
  345. } else {
  346. // We attempt to put in the MAP and Schema files of CMP beans
  347. try {
  348. // Add the Map file
  349. File websphereMAP = new File(getConfig().descriptorDir,
  350. ddPrefix + dbPrefix + WAS_CMP_MAP);
  351. if (websphereMAP.exists()) {
  352. ejbFiles.put(META_DIR + WAS_CMP_MAP,
  353. websphereMAP);
  354. } else {
  355. log("Unable to locate the websphere Map: "
  356. + websphereMAP.getPath(), Project.MSG_VERBOSE);
  357. }
  358. File websphereSchema = new File(getConfig().descriptorDir,
  359. ddPrefix + dbPrefix + WAS_CMP_SCHEMA);
  360. if (websphereSchema.exists()) {
  361. ejbFiles.put(META_DIR + SCHEMA_DIR + WAS_CMP_SCHEMA,
  362. websphereSchema);
  363. } else {
  364. log("Unable to locate the websphere Schema: "
  365. + websphereSchema.getPath(), Project.MSG_VERBOSE);
  366. }
  367. // Theres nothing else to see here...keep moving sonny
  368. } catch (Exception e) {
  369. String msg = "Exception while adding Vendor specific files: "
  370. + e.toString();
  371. throw new BuildException(msg, e);
  372. }
  373. }
  374. }
  375. /**
  376. * Get the vendor specific name of the Jar that will be output. The
  377. * modification date of this jar will be checked against the dependent
  378. * bean classes.
  379. */
  380. File getVendorOutputJarFile(String baseName) {
  381. return new File(getDestDir(), baseName + jarSuffix);
  382. }
  383. /**
  384. * Gets the options for the EJB Deploy operation
  385. *
  386. * @return String
  387. */
  388. protected String getOptions() {
  389. // Set the options
  390. StringBuffer options = new StringBuffer();
  391. if (dbVendor != null) {
  392. options.append(" -dbvendor ").append(dbVendor);
  393. }
  394. if (dbName != null) {
  395. options.append(" -dbname \"").append(dbName).append("\"");
  396. }
  397. if (dbSchema != null) {
  398. options.append(" -dbschema \"").append(dbSchema).append("\"");
  399. }
  400. if (codegen) {
  401. options.append(" -codegen");
  402. }
  403. if (quiet) {
  404. options.append(" -quiet");
  405. }
  406. if (novalidate) {
  407. options.append(" -novalidate");
  408. }
  409. if (nowarn) {
  410. options.append(" -nowarn");
  411. }
  412. if (noinform) {
  413. options.append(" -noinform");
  414. }
  415. if (trace) {
  416. options.append(" -trace");
  417. }
  418. if (use35MappingRules) {
  419. options.append(" -35");
  420. }
  421. if (rmicOptions != null) {
  422. options.append(" -rmic \"").append(rmicOptions).append("\"");
  423. }
  424. return options.toString();
  425. }
  426. /**
  427. * Helper method invoked by execute() for each websphere jar to be built.
  428. * Encapsulates the logic of constructing a java task for calling
  429. * websphere.ejbdeploy and executing it.
  430. *
  431. * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
  432. * @param destJar java.io.File representing the destination, websphere
  433. * jarfile.
  434. */
  435. private void buildWebsphereJar(File sourceJar, File destJar) {
  436. try {
  437. if (ejbdeploy) {
  438. Java javaTask = (Java) getTask().getProject().createTask("java");
  439. // Set the JvmArgs
  440. javaTask.createJvmarg().setValue("-Xms64m");
  441. javaTask.createJvmarg().setValue("-Xmx128m");
  442. // Set the Environment variable
  443. Environment.Variable var = new Environment.Variable();
  444. var.setKey("websphere.lib.dir");
  445. File libdir = new File(websphereHome, "lib");
  446. var.setValue(libdir.getAbsolutePath());
  447. javaTask.addSysproperty(var);
  448. // Set the working directory
  449. javaTask.setDir(websphereHome);
  450. // Set the Java class name
  451. javaTask.setTaskName("ejbdeploy");
  452. javaTask.setClassname("com.ibm.etools.ejbdeploy.EJBDeploy");
  453. javaTask.createArg().setValue(sourceJar.getPath());
  454. javaTask.createArg().setValue(tempdir);
  455. javaTask.createArg().setValue(destJar.getPath());
  456. javaTask.createArg().setLine(getOptions());
  457. if (getCombinedClasspath() != null
  458. && getCombinedClasspath().toString().length() > 0) {
  459. javaTask.createArg().setValue("-cp");
  460. javaTask.createArg().setValue(getCombinedClasspath().toString());
  461. }
  462. Path classpath = wasClasspath;
  463. if (classpath == null) {
  464. classpath = getCombinedClasspath();
  465. }
  466. if (classpath != null) {
  467. javaTask.setClasspath(classpath);
  468. javaTask.setFork(true);
  469. } else {
  470. javaTask.setFork(true);
  471. }
  472. log("Calling websphere.ejbdeploy for " + sourceJar.toString(),
  473. Project.MSG_VERBOSE);
  474. javaTask.execute();
  475. }
  476. } catch (Exception e) {
  477. // Have to catch this because of the semantics of calling main()
  478. String msg = "Exception while calling ejbdeploy. Details: " + e.toString();
  479. throw new BuildException(msg, e);
  480. }
  481. }
  482. /**
  483. * Method used to encapsulate the writing of the JAR file. Iterates over
  484. * the filenames/java.io.Files in the Hashtable stored on the instance
  485. * variable ejbFiles.
  486. */
  487. protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
  488. throws BuildException {
  489. if (ejbdeploy) {
  490. // create the -generic.jar, if required
  491. File genericJarFile = super.getVendorOutputJarFile(baseName);
  492. super.writeJar(baseName, genericJarFile, files, publicId);
  493. // create the output .jar, if required
  494. if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
  495. buildWebsphereJar(genericJarFile, jarFile);
  496. }
  497. if (!keepGeneric) {
  498. log("deleting generic jar " + genericJarFile.toString(),
  499. Project.MSG_VERBOSE);
  500. genericJarFile.delete();
  501. }
  502. } else {
  503. // create the "undeployed" output .jar, if required
  504. super.writeJar(baseName, jarFile, files, publicId);
  505. }
  506. }
  507. /**
  508. * Called to validate that the tool parameters have been configured.
  509. */
  510. public void validateConfigured() throws BuildException {
  511. super.validateConfigured();
  512. if (ejbdeploy) {
  513. String home = getTask().getProject().getProperty("websphere.home");
  514. if (home == null) {
  515. throw new BuildException("The 'websphere.home' property must "
  516. + "be set when 'ejbdeploy=true'");
  517. }
  518. websphereHome = getTask().getProject().resolveFile(home);
  519. }
  520. }
  521. /**
  522. * Helper method to check to see if a websphere EBJ1.1 jar needs to be
  523. * rebuilt using ejbdeploy. Called from writeJar it sees if the "Bean"
  524. * classes are the only thing that needs to be updated and either updates
  525. * the Jar with the Bean classfile or returns true, saying that the whole
  526. * websphere jar needs to be regened with ejbdeploy. This allows faster
  527. * build times for working developers. <p>
  528. *
  529. * The way websphere ejbdeploy works is it creates wrappers for the
  530. * publicly defined methods as they are exposed in the remote interface.
  531. * If the actual bean changes without changing the the method signatures
  532. * then only the bean classfile needs to be updated and the rest of the
  533. * websphere jar file can remain the same. If the Interfaces, ie. the
  534. * method signatures change or if the xml deployment descriptors changed,
  535. * the whole jar needs to be rebuilt with ejbdeploy. This is not strictly
  536. * true for the xml files. If the JNDI name changes then the jar doesnt
  537. * have to be rebuild, but if the resources references change then it
  538. * does. At this point the websphere jar gets rebuilt if the xml files
  539. * change at all.
  540. *
  541. * @param genericJarFile java.io.File The generic jar file.
  542. * @param websphereJarFile java.io.File The websphere jar file to check to
  543. * see if it needs to be rebuilt.
  544. */
  545. protected boolean isRebuildRequired(File genericJarFile, File websphereJarFile) {
  546. boolean rebuild = false;
  547. JarFile genericJar = null;
  548. JarFile wasJar = null;
  549. File newwasJarFile = null;
  550. JarOutputStream newJarStream = null;
  551. try {
  552. log("Checking if websphere Jar needs to be rebuilt for jar "
  553. + websphereJarFile.getName(), Project.MSG_VERBOSE);
  554. // Only go forward if the generic and the websphere file both exist
  555. if (genericJarFile.exists() && genericJarFile.isFile()
  556. && websphereJarFile.exists() && websphereJarFile.isFile()) {
  557. //open jar files
  558. genericJar = new JarFile(genericJarFile);
  559. wasJar = new JarFile(websphereJarFile);
  560. Hashtable genericEntries = new Hashtable();
  561. Hashtable wasEntries = new Hashtable();
  562. Hashtable replaceEntries = new Hashtable();
  563. //get the list of generic jar entries
  564. for (Enumeration e = genericJar.entries(); e.hasMoreElements();) {
  565. JarEntry je = (JarEntry) e.nextElement();
  566. genericEntries.put(je.getName().replace('\\', '/'), je);
  567. }
  568. //get the list of websphere jar entries
  569. for (Enumeration e = wasJar.entries(); e.hasMoreElements();) {
  570. JarEntry je = (JarEntry) e.nextElement();
  571. wasEntries.put(je.getName(), je);
  572. }
  573. //Cycle Through generic and make sure its in websphere
  574. ClassLoader genericLoader = getClassLoaderFromJar(genericJarFile);
  575. for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) {
  576. String filepath = (String) e.nextElement();
  577. if (wasEntries.containsKey(filepath)) {
  578. // File name/path match
  579. // Check files see if same
  580. JarEntry genericEntry = (JarEntry) genericEntries.get(filepath);
  581. JarEntry wasEntry = (JarEntry) wasEntries.get(filepath);
  582. if ((genericEntry.getCrc() != wasEntry.getCrc())
  583. || (genericEntry.getSize() != wasEntry.getSize())) {
  584. if (genericEntry.getName().endsWith(".class")) {
  585. //File are different see if its an object or an interface
  586. String classname
  587. = genericEntry.getName().replace(File.separatorChar, '.');
  588. classname = classname.substring(0, classname.lastIndexOf(".class"));
  589. Class genclass = genericLoader.loadClass(classname);
  590. if (genclass.isInterface()) {
  591. //Interface changed rebuild jar.
  592. log("Interface " + genclass.getName()
  593. + " has changed", Project.MSG_VERBOSE);
  594. rebuild = true;
  595. break;
  596. } else {
  597. //Object class Changed update it.
  598. replaceEntries.put(filepath, genericEntry);
  599. }
  600. } else {
  601. // is it the manifest. If so ignore it
  602. if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) {
  603. //File other then class changed rebuild
  604. log("Non class file " + genericEntry.getName()
  605. + " has changed", Project.MSG_VERBOSE);
  606. rebuild = true;
  607. }
  608. break;
  609. }
  610. }
  611. } else {
  612. // a file doesn't exist rebuild
  613. log("File " + filepath + " not present in websphere jar",
  614. Project.MSG_VERBOSE);
  615. rebuild = true;
  616. break;
  617. }
  618. }
  619. if (!rebuild) {
  620. log("No rebuild needed - updating jar", Project.MSG_VERBOSE);
  621. newwasJarFile = new File(websphereJarFile.getAbsolutePath() + ".temp");
  622. if (newwasJarFile.exists()) {
  623. newwasJarFile.delete();
  624. }
  625. newJarStream = new JarOutputStream(new FileOutputStream(newwasJarFile));
  626. newJarStream.setLevel(0);
  627. //Copy files from old websphere jar
  628. for (Enumeration e = wasEntries.elements(); e.hasMoreElements();) {
  629. byte[] buffer = new byte[1024];
  630. int bytesRead;
  631. InputStream is;
  632. JarEntry je = (JarEntry) e.nextElement();
  633. if (je.getCompressedSize() == -1
  634. || je.getCompressedSize() == je.getSize()) {
  635. newJarStream.setLevel(0);
  636. } else {
  637. newJarStream.setLevel(9);
  638. }
  639. // Update with changed Bean class
  640. if (replaceEntries.containsKey(je.getName())) {
  641. log("Updating Bean class from generic Jar " + je.getName(),
  642. Project.MSG_VERBOSE);
  643. // Use the entry from the generic jar
  644. je = (JarEntry) replaceEntries.get(je.getName());
  645. is = genericJar.getInputStream(je);
  646. } else {
  647. //use fle from original websphere jar
  648. is = wasJar.getInputStream(je);
  649. }
  650. newJarStream.putNextEntry(new JarEntry(je.getName()));
  651. while ((bytesRead = is.read(buffer)) != -1) {
  652. newJarStream.write(buffer, 0, bytesRead);
  653. }
  654. is.close();
  655. }
  656. } else {
  657. log("websphere Jar rebuild needed due to changed "
  658. + "interface or XML", Project.MSG_VERBOSE);
  659. }
  660. } else {
  661. rebuild = true;
  662. }
  663. } catch (ClassNotFoundException cnfe) {
  664. String cnfmsg = "ClassNotFoundException while processing ejb-jar file"
  665. + ". Details: "
  666. + cnfe.getMessage();
  667. throw new BuildException(cnfmsg, cnfe);
  668. } catch (IOException ioe) {
  669. String msg = "IOException while processing ejb-jar file "
  670. + ". Details: "
  671. + ioe.getMessage();
  672. throw new BuildException(msg, ioe);
  673. } finally {
  674. // need to close files and perhaps rename output
  675. if (genericJar != null) {
  676. try {
  677. genericJar.close();
  678. } catch (IOException closeException) {
  679. }
  680. }
  681. if (wasJar != null) {
  682. try {
  683. wasJar.close();
  684. } catch (IOException closeException) {
  685. }
  686. }
  687. if (newJarStream != null) {
  688. try {
  689. newJarStream.close();
  690. } catch (IOException closeException) {
  691. }
  692. try {
  693. FileUtils.newFileUtils().rename(newwasJarFile,
  694. websphereJarFile);
  695. } catch (IOException renameException) {
  696. log(renameException.getMessage(), Project.MSG_WARN);
  697. rebuild = true;
  698. }
  699. }
  700. }
  701. return rebuild;
  702. }
  703. /**
  704. * Helper method invoked by isRebuildRequired to get a ClassLoader for a
  705. * Jar File passed to it.
  706. *
  707. * @param classjar java.io.File representing jar file to get classes from.
  708. */
  709. protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException {
  710. Path lookupPath = new Path(getTask().getProject());
  711. lookupPath.setLocation(classjar);
  712. Path classpath = getCombinedClasspath();
  713. if (classpath != null) {
  714. lookupPath.append(classpath);
  715. }
  716. return getTask().getProject().createClassLoader(lookupPath);
  717. }
  718. }