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.BufferedReader;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.InputStreamReader;
  23. import java.io.OutputStream;
  24. import java.util.Hashtable;
  25. import java.util.Iterator;
  26. import java.util.Vector;
  27. import org.apache.tools.ant.BuildException;
  28. import org.apache.tools.ant.Project;
  29. import org.apache.tools.ant.taskdefs.ExecTask;
  30. import org.apache.tools.ant.taskdefs.Execute;
  31. import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
  32. import org.apache.tools.ant.taskdefs.Java;
  33. import org.apache.tools.ant.types.Commandline;
  34. import org.apache.tools.ant.types.Path;
  35. /**
  36. * BorlandDeploymentTool is dedicated to the Borland Application Server 4.5 and 4.5.1
  37. * This task generates and compiles the stubs and skeletons for all ejb described into the
  38. * Deployment Descriptor, builds the jar file including the support files and verify
  39. * whether the produced jar is valid or not.
  40. * The supported options are:
  41. * <ul>
  42. * <li>debug (boolean) : turn on the debug mode for generation of
  43. * stubs and skeletons (default:false)</li>
  44. * <li>verify (boolean) : turn on the verification at the end of the jar
  45. * production (default:true) </li>
  46. * <li>verifyargs (String) : add optional argument to verify command
  47. * (see vbj com.inprise.ejb.util.Verify)</li>
  48. * <li>basdtd (String) : location of the BAS DTD </li>
  49. * <li>generateclient (boolean) : turn on the client jar file generation </li>
  50. * <li>version (int) : tell what is the Borland appserver version 4 or 5 </li>
  51. * </ul>
  52. *
  53. *<PRE>
  54. *
  55. * <ejbjar srcdir="${build.classes}"
  56. * basejarname="vsmp"
  57. * descriptordir="${rsc.dir}/hrmanager">
  58. * <borland destdir="tstlib">
  59. * <classpath refid="classpath" />
  60. * </borland>
  61. * <include name="**\ejb-jar.xml"/>
  62. * <support dir="${build.classes}">
  63. * <include name="demo\smp\*.class"/>
  64. * <include name="demo\helper\*.class"/>
  65. * </support>
  66. * </ejbjar>
  67. *</PRE>
  68. *
  69. */
  70. public class BorlandDeploymentTool extends GenericDeploymentTool
  71. implements ExecuteStreamHandler {
  72. public static final String PUBLICID_BORLAND_EJB
  73. = "-//Inprise Corporation//DTD Enterprise JavaBeans 1.1//EN";
  74. protected static final String DEFAULT_BAS45_EJB11_DTD_LOCATION
  75. = "/com/inprise/j2ee/xml/dtds/ejb-jar.dtd";
  76. protected static final String DEFAULT_BAS_DTD_LOCATION
  77. = "/com/inprise/j2ee/xml/dtds/ejb-inprise.dtd";
  78. protected static final String BAS_DD = "ejb-inprise.xml";
  79. protected static final String BES_DD = "ejb-borland.xml";
  80. /** Java2iiop executable **/
  81. protected static final String JAVA2IIOP = "java2iiop";
  82. /** Verify class */
  83. protected static final String VERIFY = "com.inprise.ejb.util.Verify";
  84. /** Instance variable that stores the suffix for the borland jarfile. */
  85. private String jarSuffix = "-ejb.jar";
  86. /** Instance variable that stores the location of the borland DTD file. */
  87. private String borlandDTD;
  88. /** Instance variable that determines whether the debug mode is on */
  89. private boolean java2iiopdebug = false;
  90. /** store additional param for java2iiop command used to build EJB Stubs */
  91. private String java2iioparams = null;
  92. /** Instance variable that determines whether the client jar file is generated */
  93. private boolean generateclient = false;
  94. /** Borland Enterprise Server = version 5 */
  95. static final int BES = 5;
  96. /** Borland Application Server or Inprise Application Server = version 4 */
  97. static final int BAS = 4;
  98. /** borland appserver version 4 or 5 */
  99. private int version = BAS;
  100. /**
  101. * Instance variable that determines whether it is necessary to verify the
  102. * produced jar
  103. */
  104. private boolean verify = true;
  105. private String verifyArgs = "";
  106. private Hashtable _genfiles = new Hashtable();
  107. /**
  108. * set the debug mode for java2iiop (default false)
  109. **/
  110. public void setDebug(boolean debug) {
  111. this.java2iiopdebug = debug;
  112. }
  113. /**
  114. * set the verify mode for the produced jar (default true)
  115. **/
  116. public void setVerify(boolean verify) {
  117. this.verify = verify;
  118. }
  119. /**
  120. * Setter used to store the suffix for the generated borland jar file.
  121. * @param inString the string to use as the suffix.
  122. */
  123. public void setSuffix(String inString) {
  124. this.jarSuffix = inString;
  125. }
  126. /**
  127. * sets some additional args to send to verify command
  128. * @param args additional command line parameters
  129. */
  130. public void setVerifyArgs(String args) {
  131. this.verifyArgs = args;
  132. }
  133. /**
  134. * Setter used to store the location of the borland DTD. This can be a file on the system
  135. * or a resource on the classpath.
  136. * @param inString the string to use as the DTD location.
  137. */
  138. public void setBASdtd(String inString) {
  139. this.borlandDTD = inString;
  140. }
  141. /**
  142. * setter used to store whether the task will include the generate client task.
  143. * (see : BorlandGenerateClient task)
  144. */
  145. public void setGenerateclient(boolean b) {
  146. this.generateclient = b;
  147. }
  148. /**
  149. * setter used to store the borland appserver version [4 or 5]
  150. * @param version app server version 4 or 5
  151. */
  152. public void setVersion(int version) {
  153. this.version = version;
  154. }
  155. /**
  156. * If filled, the params are added to the java2iiop command.
  157. * (ex: -no_warn_missing_define)
  158. * @param params additional params for java2iiop
  159. */
  160. public void setJava2iiopParams(String params) {
  161. this.java2iioparams = params;
  162. }
  163. protected DescriptorHandler getBorlandDescriptorHandler(final File srcDir) {
  164. DescriptorHandler handler =
  165. new DescriptorHandler(getTask(), srcDir) {
  166. protected void processElement() {
  167. if (currentElement.equals("type-storage")) {
  168. // Get the filename of vendor specific descriptor
  169. String fileNameWithMETA = currentText;
  170. //trim the META_INF\ off of the file name
  171. String fileName
  172. = fileNameWithMETA.substring(META_DIR.length(),
  173. fileNameWithMETA.length());
  174. File descriptorFile = new File(srcDir, fileName);
  175. ejbFiles.put(fileNameWithMETA, descriptorFile);
  176. }
  177. }
  178. };
  179. handler.registerDTD(PUBLICID_BORLAND_EJB,
  180. borlandDTD == null ? DEFAULT_BAS_DTD_LOCATION : borlandDTD);
  181. for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
  182. EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
  183. handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
  184. }
  185. return handler;
  186. }
  187. /**
  188. * Add any vendor specific files which should be included in the
  189. * EJB Jar.
  190. */
  191. protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
  192. //choose the right vendor DD
  193. if (!(version == BES || version == BAS)) {
  194. throw new BuildException("version " + version + " is not supported");
  195. }
  196. String dd = (version == BES ? BES_DD : BAS_DD);
  197. log("vendor file : " + ddPrefix + dd, Project.MSG_DEBUG);
  198. File borlandDD = new File(getConfig().descriptorDir, ddPrefix + dd);
  199. if (borlandDD.exists()) {
  200. log("Borland specific file found " + borlandDD, Project.MSG_VERBOSE);
  201. ejbFiles.put(META_DIR + dd , borlandDD);
  202. } else {
  203. log("Unable to locate borland deployment descriptor. "
  204. + "It was expected to be in "
  205. + borlandDD.getPath(), Project.MSG_WARN);
  206. return;
  207. }
  208. }
  209. /**
  210. * Get the vendor specific name of the Jar that will be output. The modification date
  211. * of this jar will be checked against the dependent bean classes.
  212. */
  213. File getVendorOutputJarFile(String baseName) {
  214. return new File(getDestDir(), baseName + jarSuffix);
  215. }
  216. /**
  217. * Verify the produced jar file by invoking the Borland verify tool
  218. * @param sourceJar java.io.File representing the produced jar file
  219. */
  220. private void verifyBorlandJar(File sourceJar) {
  221. if (version == BAS) {
  222. verifyBorlandJarV4(sourceJar);
  223. return;
  224. }
  225. if (version == BES) {
  226. verifyBorlandJarV5(sourceJar);
  227. return;
  228. }
  229. log("verify jar skipped because the version is invalid ["
  230. + version + "]", Project.MSG_WARN);
  231. }
  232. /**
  233. * Verify the produced jar file by invoking the Borland iastool tool
  234. * @param sourceJar java.io.File representing the produced jar file
  235. */
  236. private void verifyBorlandJarV5(File sourceJar) {
  237. log("verify BES " + sourceJar, Project.MSG_INFO);
  238. try {
  239. org.apache.tools.ant.taskdefs.ExecTask execTask = null;
  240. execTask = (ExecTask) getTask().getProject().createTask("exec");
  241. execTask.setDir(new File("."));
  242. execTask.setExecutable("iastool");
  243. //classpath
  244. if (getCombinedClasspath() != null) {
  245. execTask.createArg().setValue("-VBJclasspath");
  246. execTask.createArg().setValue(getCombinedClasspath().toString());
  247. }
  248. if (java2iiopdebug) {
  249. execTask.createArg().setValue("-debug");
  250. }
  251. execTask.createArg().setValue("-verify");
  252. execTask.createArg().setValue("-src");
  253. // ejb jar file to verify
  254. execTask.createArg().setValue(sourceJar.getPath());
  255. log("Calling iastool", Project.MSG_VERBOSE);
  256. execTask.execute();
  257. } catch (Exception e) {
  258. // Have to catch this because of the semantics of calling main()
  259. String msg = "Exception while calling generateclient Details: "
  260. + e.toString();
  261. throw new BuildException(msg, e);
  262. }
  263. }
  264. /**
  265. * Verify the produced jar file by invoking the Borland verify tool
  266. * @param sourceJar java.io.File representing the produced jar file
  267. */
  268. private void verifyBorlandJarV4(File sourceJar) {
  269. org.apache.tools.ant.taskdefs.Java javaTask = null;
  270. log("verify BAS " + sourceJar, Project.MSG_INFO);
  271. try {
  272. String args = verifyArgs;
  273. args += " " + sourceJar.getPath();
  274. javaTask = (Java) getTask().getProject().createTask("java");
  275. javaTask.setTaskName("verify");
  276. javaTask.setClassname(VERIFY);
  277. Commandline.Argument arguments = javaTask.createArg();
  278. arguments.setLine(args);
  279. Path classpath = getCombinedClasspath();
  280. if (classpath != null) {
  281. javaTask.setClasspath(classpath);
  282. javaTask.setFork(true);
  283. }
  284. log("Calling " + VERIFY + " for " + sourceJar.toString(),
  285. Project.MSG_VERBOSE);
  286. javaTask.execute();
  287. } catch (Exception e) {
  288. //TO DO : delete the file if it is not a valid file.
  289. String msg = "Exception while calling " + VERIFY + " Details: "
  290. + e.toString();
  291. throw new BuildException(msg, e);
  292. }
  293. }
  294. /**
  295. * Generate the client jar corresponding to the jar file passed as parameter
  296. * the method uses the BorlandGenerateClient task.
  297. * @param sourceJar java.io.File representing the produced jar file
  298. */
  299. private void generateClient(File sourceJar) {
  300. getTask().getProject().addTaskDefinition("internal_bas_generateclient",
  301. org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient.class);
  302. org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient gentask = null;
  303. log("generate client for " + sourceJar, Project.MSG_INFO);
  304. try {
  305. Project project = getTask().getProject();
  306. gentask
  307. = (BorlandGenerateClient) project.createTask("internal_bas_generateclient");
  308. gentask.setEjbjar(sourceJar);
  309. gentask.setDebug(java2iiopdebug);
  310. Path classpath = getCombinedClasspath();
  311. if (classpath != null) {
  312. gentask.setClasspath(classpath);
  313. }
  314. gentask.setVersion(version);
  315. gentask.setTaskName("generate client");
  316. gentask.execute();
  317. } catch (Exception e) {
  318. //TO DO : delete the file if it is not a valid file.
  319. String msg = "Exception while calling " + VERIFY + " Details: "
  320. + e.toString();
  321. throw new BuildException(msg, e);
  322. }
  323. }
  324. /**
  325. * Generate stubs & skeleton for each home found into the DD
  326. * Add all the generate class file into the ejb files
  327. * @param ithomes : iterator on home class
  328. */
  329. private void buildBorlandStubs(Iterator ithomes) {
  330. Execute execTask = null;
  331. execTask = new Execute(this);
  332. Project project = getTask().getProject();
  333. execTask.setAntRun(project);
  334. execTask.setWorkingDirectory(project.getBaseDir());
  335. Commandline commandline = new Commandline();
  336. commandline.setExecutable(JAVA2IIOP);
  337. //debug ?
  338. if (java2iiopdebug) {
  339. commandline.createArgument().setValue("-VBJdebug");
  340. }
  341. //set the classpath
  342. commandline.createArgument().setValue("-VBJclasspath");
  343. commandline.createArgument().setPath(getCombinedClasspath());
  344. //list file
  345. commandline.createArgument().setValue("-list_files");
  346. //no TIE classes
  347. commandline.createArgument().setValue("-no_tie");
  348. if (java2iioparams != null) {
  349. log("additional " + java2iioparams + " to java2iiop ", 0);
  350. commandline.createArgument().setValue(java2iioparams);
  351. }
  352. //root dir
  353. commandline.createArgument().setValue("-root_dir");
  354. commandline.createArgument().setValue(getConfig().srcDir.getAbsolutePath());
  355. //compiling order
  356. commandline.createArgument().setValue("-compile");
  357. //add the home class
  358. while (ithomes.hasNext()) {
  359. commandline.createArgument().setValue(ithomes.next().toString());
  360. }
  361. try {
  362. log("Calling java2iiop", Project.MSG_VERBOSE);
  363. log(commandline.describeCommand(), Project.MSG_DEBUG);
  364. execTask.setCommandline(commandline.getCommandline());
  365. int result = execTask.execute();
  366. if (Execute.isFailure(result)) {
  367. String msg = "Failed executing java2iiop (ret code is "
  368. + result + ")";
  369. throw new BuildException(msg, getTask().getLocation());
  370. }
  371. } catch (java.io.IOException e) {
  372. log("java2iiop exception :" + e.getMessage(), Project.MSG_ERR);
  373. throw new BuildException(e, getTask().getLocation());
  374. }
  375. }
  376. /**
  377. * Method used to encapsulate the writing of the JAR file. Iterates over the
  378. * filenames/java.io.Files in the Hashtable stored on the instance variable
  379. * ejbFiles.
  380. */
  381. protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
  382. throws BuildException {
  383. //build the home classes list.
  384. Vector homes = new Vector();
  385. Iterator it = files.keySet().iterator();
  386. while (it.hasNext()) {
  387. String clazz = (String) it.next();
  388. if (clazz.endsWith("Home.class")) {
  389. //remove .class extension
  390. String home = toClass(clazz);
  391. homes.add(home);
  392. log(" Home " + home, Project.MSG_VERBOSE);
  393. }
  394. }
  395. buildBorlandStubs(homes.iterator());
  396. //add the gen files to the collection
  397. files.putAll(_genfiles);
  398. super.writeJar(baseName, jarFile, files, publicId);
  399. if (verify) {
  400. verifyBorlandJar(jarFile);
  401. }
  402. if (generateclient) {
  403. generateClient(jarFile);
  404. }
  405. }
  406. /**
  407. * convert a class file name : A/B/C/toto.class
  408. * into a class name: A.B.C.toto
  409. */
  410. private String toClass(String filename) {
  411. //remove the .class
  412. String classname = filename.substring(0, filename.lastIndexOf(".class"));
  413. classname = classname.replace('\\', '.');
  414. return classname;
  415. }
  416. /**
  417. * convert a file name : A/B/C/toto.java
  418. * into a class name: A/B/C/toto.class
  419. */
  420. private String toClassFile(String filename) {
  421. //remove the .class
  422. String classfile = filename.substring(0, filename.lastIndexOf(".java"));
  423. classfile = classfile + ".class";
  424. return classfile;
  425. }
  426. // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
  427. public void start() throws IOException { }
  428. public void stop() { }
  429. public void setProcessInputStream(OutputStream param1) throws IOException { }
  430. /**
  431. *
  432. * @param is
  433. * @exception java.io.IOException
  434. */
  435. public void setProcessOutputStream(InputStream is) throws IOException {
  436. try {
  437. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  438. String javafile;
  439. while ((javafile = reader.readLine()) != null) {
  440. if (javafile.endsWith(".java")) {
  441. String classfile = toClassFile(javafile);
  442. String key = classfile.substring(getConfig().srcDir.getAbsolutePath().length() + 1);
  443. _genfiles.put(key, new File(classfile));
  444. }
  445. }
  446. reader.close();
  447. } catch (Exception e) {
  448. String msg = "Exception while parsing java2iiop output. Details: " + e.toString();
  449. throw new BuildException(msg, e);
  450. }
  451. }
  452. public void setProcessErrorStream(InputStream is) throws IOException {
  453. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  454. String s = reader.readLine();
  455. if (s != null) {
  456. log("[java2iiop] " + s, Project.MSG_ERR);
  457. }
  458. }
  459. }