1. /*
  2. * Copyright 2000-2002,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.FileInputStream;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.io.ObjectInputStream;
  23. import java.io.PrintWriter;
  24. import java.util.Vector;
  25. import javax.ejb.deployment.DeploymentDescriptor;
  26. import javax.ejb.deployment.EntityDescriptor;
  27. /**
  28. * A helper class which performs the actual work of the ejbc task.
  29. *
  30. * This class is run with a classpath which includes the weblogic tools and the home and remote
  31. * interface class files referenced in the deployment descriptors being processed.
  32. *
  33. */
  34. public class EjbcHelper {
  35. /**
  36. * The root directory of the tree containing the serialised deployment desciptors.
  37. */
  38. private File descriptorDirectory;
  39. /**
  40. * The directory where generated files are placed.
  41. */
  42. private File generatedFilesDirectory;
  43. /**
  44. * The name of the manifest file generated for the EJB jar.
  45. */
  46. private File manifestFile;
  47. /**
  48. * The source directory for the home and remote interfaces. This is used to determine if
  49. * the generated deployment classes are out of date.
  50. */
  51. private File sourceDirectory;
  52. /**
  53. * The names of the serialised deployment descriptors
  54. */
  55. String[] descriptors;
  56. private boolean keepGenerated;
  57. /**
  58. * Command line interface for the ejbc helper task.
  59. */
  60. public static void main(String[] args) throws Exception {
  61. EjbcHelper helper = new EjbcHelper(args);
  62. helper.process();
  63. }
  64. /**
  65. * Initialise the EjbcHelper by reading the command arguments.
  66. */
  67. private EjbcHelper(String[] args) {
  68. int index = 0;
  69. descriptorDirectory = new File(args[index++]);
  70. generatedFilesDirectory = new File(args[index++]);
  71. sourceDirectory = new File(args[index++]);
  72. manifestFile = new File(args[index++]);
  73. keepGenerated = Boolean.valueOf(args[index++]).booleanValue();
  74. descriptors = new String[args.length - index];
  75. for (int i = 0; index < args.length; ++i) {
  76. descriptors[i] = args[index++];
  77. }
  78. }
  79. private String[] getCommandLine(boolean debug, File descriptorFile) {
  80. Vector v = new Vector();
  81. if (!debug) {
  82. v.addElement("-noexit");
  83. }
  84. if (keepGenerated) {
  85. v.addElement("-keepgenerated");
  86. }
  87. v.addElement("-d");
  88. v.addElement(generatedFilesDirectory.getPath());
  89. v.addElement(descriptorFile.getPath());
  90. String[] args = new String[v.size()];
  91. v.copyInto(args);
  92. return args;
  93. }
  94. /**
  95. * Determine if the weblogic EJB support classes need to be regenerated
  96. * for a given deployment descriptor.
  97. *
  98. * This process attempts to determine if the support classes need to be
  99. * rebuilt. It does this by examining only some of the support classes
  100. * which are typically generated. If the ejbc task is interrupted generating
  101. * the support classes for a bean, all of the support classes should be removed
  102. * to force regeneration of the support classes.
  103. *
  104. * @param descriptorFile the serialised deployment descriptor
  105. *
  106. * @return true if the support classes need to be regenerated.
  107. *
  108. * @throws IOException if the descriptor file cannot be closed.
  109. */
  110. private boolean isRegenRequired(File descriptorFile) throws IOException {
  111. // read in the descriptor. Under weblogic, the descriptor is a weblogic
  112. // specific subclass which has references to the implementation classes.
  113. // These classes must, therefore, be in the classpath when the deployment
  114. // descriptor is loaded from the .ser file
  115. FileInputStream fis = null;
  116. try {
  117. fis = new FileInputStream(descriptorFile);
  118. ObjectInputStream ois = new ObjectInputStream(fis);
  119. DeploymentDescriptor dd = (DeploymentDescriptor) ois.readObject();
  120. fis.close();
  121. String homeInterfacePath
  122. = dd.getHomeInterfaceClassName().replace('.', '/') + ".java";
  123. String remoteInterfacePath
  124. = dd.getRemoteInterfaceClassName().replace('.', '/') + ".java";
  125. String primaryKeyClassPath = null;
  126. if (dd instanceof EntityDescriptor) {
  127. primaryKeyClassPath
  128. = ((EntityDescriptor) dd).getPrimaryKeyClassName();
  129. primaryKeyClassPath
  130. = primaryKeyClassPath.replace('.', '/') + ".java";;
  131. }
  132. File homeInterfaceSource = new File(sourceDirectory, homeInterfacePath);
  133. File remoteInterfaceSource = new File(sourceDirectory, remoteInterfacePath);
  134. File primaryKeyClassSource = null;
  135. if (primaryKeyClassPath != null) {
  136. primaryKeyClassSource = new File(sourceDirectory, remoteInterfacePath);
  137. }
  138. // are any of the above out of date.
  139. // we find the implementation classes and see if they are older than any
  140. // of the above or the .ser file itself.
  141. String beanClassBase = dd.getEnterpriseBeanClassName().replace('.', '/');
  142. File ejbImplentationClass
  143. = new File(generatedFilesDirectory, beanClassBase + "EOImpl.class");
  144. File homeImplementationClass
  145. = new File(generatedFilesDirectory, beanClassBase + "HomeImpl.class");
  146. File beanStubClass
  147. = new File(generatedFilesDirectory, beanClassBase + "EOImpl_WLStub.class");
  148. // if the implementation classes don;t exist regenerate
  149. if (!ejbImplentationClass.exists()
  150. || !homeImplementationClass.exists()
  151. || !beanStubClass.exists()) {
  152. return true;
  153. }
  154. // Is the ser file or any of the source files newer then the class files.
  155. // firstly find the oldest of the two class files.
  156. long classModificationTime = ejbImplentationClass.lastModified();
  157. if (homeImplementationClass.lastModified() < classModificationTime) {
  158. classModificationTime = homeImplementationClass.lastModified();
  159. }
  160. if (beanStubClass.lastModified() < classModificationTime) {
  161. classModificationTime = beanStubClass.lastModified();
  162. }
  163. if (descriptorFile.lastModified() > classModificationTime
  164. || homeInterfaceSource.lastModified() > classModificationTime
  165. || remoteInterfaceSource.lastModified() > classModificationTime) {
  166. return true;
  167. }
  168. if (primaryKeyClassSource != null
  169. && primaryKeyClassSource.lastModified() > classModificationTime) {
  170. return true;
  171. }
  172. } catch (Throwable descriptorLoadException) {
  173. System.out.println("Exception occurred reading "
  174. + descriptorFile.getName() + " - continuing");
  175. // any problems - just regenerate
  176. return true;
  177. } finally {
  178. if (fis != null) {
  179. fis.close();
  180. }
  181. }
  182. return false;
  183. }
  184. /**
  185. * Process the descriptors in turn generating support classes for each and a manifest
  186. * file for all of the beans.
  187. */
  188. private void process() throws Exception {
  189. String manifest = "Manifest-Version: 1.0\n\n";
  190. for (int i = 0; i < descriptors.length; ++i) {
  191. String descriptorName = descriptors[i];
  192. File descriptorFile = new File(descriptorDirectory, descriptorName);
  193. if (isRegenRequired(descriptorFile)) {
  194. System.out.println("Running ejbc for " + descriptorFile.getName());
  195. regenerateSupportClasses(descriptorFile);
  196. } else {
  197. System.out.println(descriptorFile.getName() + " is up to date");
  198. }
  199. manifest += "Name: " + descriptorName.replace('\\', '/')
  200. + "\nEnterprise-Bean: True\n\n";
  201. }
  202. FileWriter fw = new FileWriter(manifestFile);
  203. PrintWriter pw = new PrintWriter(fw);
  204. pw.print(manifest);
  205. fw.flush();
  206. fw.close();
  207. }
  208. /**
  209. * Perform the weblogic.ejbc call to regenerate the support classes.
  210. *
  211. * Note that this method relies on an undocumented -noexit option to the
  212. * ejbc tool to stop the ejbc tool exiting the VM altogether.
  213. */
  214. private void regenerateSupportClasses(File descriptorFile) throws Exception {
  215. // create a Java task to do the rebuild
  216. String[] args = getCommandLine(false, descriptorFile);
  217. try {
  218. weblogic.ejbc.main(args);
  219. } catch (Exception e) {
  220. // run with no exit for better reporting
  221. String[] newArgs = getCommandLine(true, descriptorFile);
  222. weblogic.ejbc.main(newArgs);
  223. }
  224. }
  225. }