001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs.optional.ejb;
020:
021: import java.io.BufferedReader;
022: import java.io.File;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.InputStreamReader;
026: import java.io.OutputStream;
027: import java.util.Hashtable;
028: import java.util.Iterator;
029: import java.util.Vector;
030: import org.apache.tools.ant.BuildException;
031: import org.apache.tools.ant.Project;
032: import org.apache.tools.ant.taskdefs.ExecTask;
033: import org.apache.tools.ant.taskdefs.Execute;
034: import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
035: import org.apache.tools.ant.taskdefs.Java;
036: import org.apache.tools.ant.types.Commandline;
037: import org.apache.tools.ant.types.Path;
038:
039: /**
040: * BorlandDeploymentTool is dedicated to the Borland Application Server 4.5 and 4.5.1
041: * This task generates and compiles the stubs and skeletons for all ejb described into the
042: * Deployment Descriptor, builds the jar file including the support files and verify
043: * whether the produced jar is valid or not.
044: * The supported options are:
045: * <ul>
046: * <li>debug (boolean) : turn on the debug mode for generation of
047: * stubs and skeletons (default:false)</li>
048: * <li>verify (boolean) : turn on the verification at the end of the jar
049: * production (default:true) </li>
050: * <li>verifyargs (String) : add optional argument to verify command
051: * (see vbj com.inprise.ejb.util.Verify)</li>
052: * <li>basdtd (String) : location of the BAS DTD </li>
053: * <li>generateclient (boolean) : turn on the client jar file generation </li>
054: * <li>version (int) : tell what is the Borland appserver version 4 or 5 </li>
055: * </ul>
056: *
057: *<PRE>
058: *
059: * <ejbjar srcdir="${build.classes}"
060: * basejarname="vsmp"
061: * descriptordir="${rsc.dir}/hrmanager">
062: * <borland destdir="tstlib">
063: * <classpath refid="classpath" />
064: * </borland>
065: * <include name="**\ejb-jar.xml"/>
066: * <support dir="${build.classes}">
067: * <include name="demo\smp\*.class"/>
068: * <include name="demo\helper\*.class"/>
069: * </support>
070: * </ejbjar>
071: *</PRE>
072: *
073: */
074: public class BorlandDeploymentTool extends GenericDeploymentTool
075: implements ExecuteStreamHandler {
076: /** Borland 1.1 ejb id */
077: public static final String PUBLICID_BORLAND_EJB = "-//Inprise Corporation//DTD Enterprise JavaBeans 1.1//EN";
078:
079: protected static final String DEFAULT_BAS45_EJB11_DTD_LOCATION = "/com/inprise/j2ee/xml/dtds/ejb-jar.dtd";
080:
081: protected static final String DEFAULT_BAS_DTD_LOCATION = "/com/inprise/j2ee/xml/dtds/ejb-inprise.dtd";
082:
083: protected static final String BAS_DD = "ejb-inprise.xml";
084: protected static final String BES_DD = "ejb-borland.xml";
085:
086: /** Java2iiop executable **/
087: protected static final String JAVA2IIOP = "java2iiop";
088:
089: /** Verify class */
090: protected static final String VERIFY = "com.inprise.ejb.util.Verify";
091:
092: /** Instance variable that stores the suffix for the borland jarfile. */
093: private String jarSuffix = "-ejb.jar";
094:
095: /** Instance variable that stores the location of the borland DTD file. */
096: private String borlandDTD;
097:
098: /** Instance variable that determines whether the debug mode is on */
099: private boolean java2iiopdebug = false;
100:
101: /** store additional param for java2iiop command used to build EJB Stubs */
102: private String java2iioparams = null;
103:
104: /** Instance variable that determines whether the client jar file is generated */
105: private boolean generateclient = false;
106:
107: /** Borland Enterprise Server = version 5 */
108: static final int BES = 5;
109: /** Borland Application Server or Inprise Application Server = version 4 */
110: static final int BAS = 4;
111:
112: /** borland appserver version 4 or 5 */
113: private int version = BAS;
114:
115: /**
116: * Instance variable that determines whether it is necessary to verify the
117: * produced jar
118: */
119: private boolean verify = true;
120: private String verifyArgs = "";
121:
122: private Hashtable genfiles = new Hashtable();
123:
124: /**
125: * set the debug mode for java2iiop (default false)
126: * @param debug the setting to use.
127: **/
128: public void setDebug(boolean debug) {
129: this .java2iiopdebug = debug;
130: }
131:
132: /**
133: * set the verify mode for the produced jar (default true)
134: * @param verify the setting to use.
135: **/
136: public void setVerify(boolean verify) {
137: this .verify = verify;
138: }
139:
140: /**
141: * Setter used to store the suffix for the generated borland jar file.
142: * @param inString the string to use as the suffix.
143: */
144: public void setSuffix(String inString) {
145: this .jarSuffix = inString;
146: }
147:
148: /**
149: * sets some additional args to send to verify command
150: * @param args additional command line parameters
151: */
152: public void setVerifyArgs(String args) {
153: this .verifyArgs = args;
154: }
155:
156: /**
157: * Setter used to store the location of the borland DTD. This can be a file on the system
158: * or a resource on the classpath.
159: * @param inString the string to use as the DTD location.
160: */
161: public void setBASdtd(String inString) {
162: this .borlandDTD = inString;
163: }
164:
165: /**
166: * setter used to store whether the task will include the generate client task.
167: * (see : BorlandGenerateClient task)
168: * @param b if true generate the client task.
169: */
170: public void setGenerateclient(boolean b) {
171: this .generateclient = b;
172: }
173:
174: /**
175: * setter used to store the borland appserver version [4 or 5]
176: * @param version app server version 4 or 5
177: */
178: public void setVersion(int version) {
179: this .version = version;
180: }
181:
182: /**
183: * If filled, the params are added to the java2iiop command.
184: * (ex: -no_warn_missing_define)
185: * @param params additional params for java2iiop
186: */
187: public void setJava2iiopParams(String params) {
188: this .java2iioparams = params;
189: }
190:
191: /**
192: * Get the borland descriptor handler.
193: * @param srcDir the source directory.
194: * @return the descriptor.
195: */
196: protected DescriptorHandler getBorlandDescriptorHandler(
197: final File srcDir) {
198: DescriptorHandler handler = new DescriptorHandler(getTask(),
199: srcDir) {
200: protected void processElement() {
201: if (currentElement.equals("type-storage")) {
202: // Get the filename of vendor specific descriptor
203: String fileNameWithMETA = currentText;
204: //trim the META_INF\ off of the file name
205: String fileName = fileNameWithMETA.substring(
206: META_DIR.length(), fileNameWithMETA
207: .length());
208: File descriptorFile = new File(srcDir, fileName);
209:
210: ejbFiles.put(fileNameWithMETA, descriptorFile);
211: }
212: }
213: };
214: handler.registerDTD(PUBLICID_BORLAND_EJB,
215: borlandDTD == null ? DEFAULT_BAS_DTD_LOCATION
216: : borlandDTD);
217:
218: for (Iterator i = getConfig().dtdLocations.iterator(); i
219: .hasNext();) {
220: EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i
221: .next();
222: handler.registerDTD(dtdLocation.getPublicId(), dtdLocation
223: .getLocation());
224: }
225: return handler;
226: }
227:
228: /**
229: * Add any vendor specific files which should be included in the
230: * EJB Jar.
231: * @param ejbFiles the map to add the files to.
232: * @param ddPrefix the prefix to use.
233: */
234: protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
235:
236: //choose the right vendor DD
237: if (!(version == BES || version == BAS)) {
238: throw new BuildException("version " + version
239: + " is not supported");
240: }
241:
242: String dd = (version == BES ? BES_DD : BAS_DD);
243:
244: log("vendor file : " + ddPrefix + dd, Project.MSG_DEBUG);
245:
246: File borlandDD = new File(getConfig().descriptorDir, ddPrefix
247: + dd);
248: if (borlandDD.exists()) {
249: log("Borland specific file found " + borlandDD,
250: Project.MSG_VERBOSE);
251: ejbFiles.put(META_DIR + dd, borlandDD);
252: } else {
253: log(
254: "Unable to locate borland deployment descriptor. "
255: + "It was expected to be in "
256: + borlandDD.getPath(), Project.MSG_WARN);
257: return;
258: }
259: }
260:
261: /**
262: * Get the vendor specific name of the Jar that will be output. The modification date
263: * of this jar will be checked against the dependent bean classes.
264: */
265: File getVendorOutputJarFile(String baseName) {
266: return new File(getDestDir(), baseName + jarSuffix);
267: }
268:
269: /**
270: * Verify the produced jar file by invoking the Borland verify tool
271: * @param sourceJar java.io.File representing the produced jar file
272: */
273: private void verifyBorlandJar(File sourceJar) {
274: if (version == BAS) {
275: verifyBorlandJarV4(sourceJar);
276: return;
277: }
278: if (version == BES) {
279: verifyBorlandJarV5(sourceJar);
280: return;
281: }
282: log("verify jar skipped because the version is invalid ["
283: + version + "]", Project.MSG_WARN);
284: }
285:
286: /**
287: * Verify the produced jar file by invoking the Borland iastool tool
288: * @param sourceJar java.io.File representing the produced jar file
289: */
290: private void verifyBorlandJarV5(File sourceJar) {
291: log("verify BES " + sourceJar, Project.MSG_INFO);
292: try {
293: ExecTask execTask = null;
294: execTask = new ExecTask(getTask());
295: execTask.setDir(new File("."));
296: execTask.setExecutable("iastool");
297: //classpath
298: if (getCombinedClasspath() != null) {
299: execTask.createArg().setValue("-VBJclasspath");
300: execTask.createArg().setValue(
301: getCombinedClasspath().toString());
302: }
303:
304: if (java2iiopdebug) {
305: execTask.createArg().setValue("-debug");
306: }
307: execTask.createArg().setValue("-verify");
308: execTask.createArg().setValue("-src");
309: // ejb jar file to verify
310: execTask.createArg().setValue(sourceJar.getPath());
311: log("Calling iastool", Project.MSG_VERBOSE);
312: execTask.execute();
313: } catch (Exception e) {
314: // Have to catch this because of the semantics of calling main()
315: String msg = "Exception while calling generateclient Details: "
316: + e.toString();
317: throw new BuildException(msg, e);
318: }
319: }
320:
321: /**
322: * Verify the produced jar file by invoking the Borland verify tool
323: * @param sourceJar java.io.File representing the produced jar file
324: */
325: private void verifyBorlandJarV4(File sourceJar) {
326: org.apache.tools.ant.taskdefs.Java javaTask = null;
327: log("verify BAS " + sourceJar, Project.MSG_INFO);
328: try {
329: String args = verifyArgs;
330: args += " " + sourceJar.getPath();
331:
332: javaTask = new Java(getTask());
333: javaTask.setTaskName("verify");
334: javaTask.setClassname(VERIFY);
335: Commandline.Argument arguments = javaTask.createArg();
336: arguments.setLine(args);
337: Path classpath = getCombinedClasspath();
338: if (classpath != null) {
339: javaTask.setClasspath(classpath);
340: javaTask.setFork(true);
341: }
342:
343: log("Calling " + VERIFY + " for " + sourceJar.toString(),
344: Project.MSG_VERBOSE);
345: javaTask.execute();
346: } catch (Exception e) {
347: //TO DO : delete the file if it is not a valid file.
348: String msg = "Exception while calling " + VERIFY
349: + " Details: " + e.toString();
350: throw new BuildException(msg, e);
351: }
352: }
353:
354: /**
355: * Generate the client jar corresponding to the jar file passed as parameter
356: * the method uses the BorlandGenerateClient task.
357: * @param sourceJar java.io.File representing the produced jar file
358: */
359: private void generateClient(File sourceJar) {
360: getTask()
361: .getProject()
362: .addTaskDefinition(
363: "internal_bas_generateclient",
364: org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient.class);
365:
366: org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient gentask = null;
367: log("generate client for " + sourceJar, Project.MSG_INFO);
368: try {
369: Project project = getTask().getProject();
370: gentask = (BorlandGenerateClient) project
371: .createTask("internal_bas_generateclient");
372: gentask.setEjbjar(sourceJar);
373: gentask.setDebug(java2iiopdebug);
374: Path classpath = getCombinedClasspath();
375: if (classpath != null) {
376: gentask.setClasspath(classpath);
377: }
378: gentask.setVersion(version);
379: gentask.setTaskName("generate client");
380: gentask.execute();
381: } catch (Exception e) {
382: //TO DO : delete the file if it is not a valid file.
383: String msg = "Exception while calling " + VERIFY
384: + " Details: " + e.toString();
385: throw new BuildException(msg, e);
386: }
387: }
388:
389: /**
390: * Generate stubs & skeleton for each home found into the DD
391: * Add all the generate class file into the ejb files
392: * @param ithomes : iterator on home class
393: */
394: private void buildBorlandStubs(Iterator ithomes) {
395: Execute execTask = null;
396:
397: execTask = new Execute(this );
398: Project project = getTask().getProject();
399: execTask.setAntRun(project);
400: execTask.setWorkingDirectory(project.getBaseDir());
401:
402: Commandline commandline = new Commandline();
403: commandline.setExecutable(JAVA2IIOP);
404: //debug ?
405: if (java2iiopdebug) {
406: commandline.createArgument().setValue("-VBJdebug");
407: }
408: //set the classpath
409: commandline.createArgument().setValue("-VBJclasspath");
410: commandline.createArgument().setPath(getCombinedClasspath());
411: //list file
412: commandline.createArgument().setValue("-list_files");
413: //no TIE classes
414: commandline.createArgument().setValue("-no_tie");
415:
416: if (java2iioparams != null) {
417: log("additional " + java2iioparams + " to java2iiop ", 0);
418: commandline.createArgument().setValue(java2iioparams);
419: }
420:
421: //root dir
422: commandline.createArgument().setValue("-root_dir");
423: commandline.createArgument().setValue(
424: getConfig().srcDir.getAbsolutePath());
425: //compiling order
426: commandline.createArgument().setValue("-compile");
427: //add the home class
428: while (ithomes.hasNext()) {
429: commandline.createArgument().setValue(
430: ithomes.next().toString());
431: }
432:
433: try {
434: log("Calling java2iiop", Project.MSG_VERBOSE);
435: log(commandline.describeCommand(), Project.MSG_DEBUG);
436: execTask.setCommandline(commandline.getCommandline());
437: int result = execTask.execute();
438: if (Execute.isFailure(result)) {
439: String msg = "Failed executing java2iiop (ret code is "
440: + result + ")";
441: throw new BuildException(msg, getTask().getLocation());
442: }
443: } catch (java.io.IOException e) {
444: log("java2iiop exception :" + e.getMessage(),
445: Project.MSG_ERR);
446: throw new BuildException(e, getTask().getLocation());
447: }
448: }
449:
450: /**
451: * Method used to encapsulate the writing of the JAR file. Iterates over the
452: * filenames/java.io.Files in the Hashtable stored on the instance variable
453: * ejbFiles.
454: * @param baseName the base name.
455: * @param jarFile the jar file to write to.
456: * @param files the files to write to the jar.
457: * @param publicId the id to use.
458: * @throws BuildException if there is an error.
459: */
460: protected void writeJar(String baseName, File jarFile,
461: Hashtable files, String publicId) throws BuildException {
462: //build the home classes list.
463: Vector homes = new Vector();
464: Iterator it = files.keySet().iterator();
465: while (it.hasNext()) {
466: String clazz = (String) it.next();
467: if (clazz.endsWith("Home.class")) {
468: //remove .class extension
469: String home = toClass(clazz);
470: homes.add(home);
471: log(" Home " + home, Project.MSG_VERBOSE);
472: }
473: }
474:
475: buildBorlandStubs(homes.iterator());
476:
477: //add the gen files to the collection
478: files.putAll(genfiles);
479:
480: super .writeJar(baseName, jarFile, files, publicId);
481:
482: if (verify) {
483: verifyBorlandJar(jarFile);
484: }
485:
486: if (generateclient) {
487: generateClient(jarFile);
488: }
489: }
490:
491: /**
492: * convert a class file name : A/B/C/toto.class
493: * into a class name: A.B.C.toto
494: */
495: private String toClass(String filename) {
496: //remove the .class
497: String classname = filename.substring(0, filename
498: .lastIndexOf(".class"));
499: classname = classname.replace('\\', '.');
500: return classname;
501: }
502:
503: /**
504: * convert a file name : A/B/C/toto.java
505: * into a class name: A/B/C/toto.class
506: */
507: private String toClassFile(String filename) {
508: //remove the .class
509: String classfile = filename.substring(0, filename
510: .lastIndexOf(".java"));
511: classfile = classfile + ".class";
512: return classfile;
513: }
514:
515: // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
516:
517: /** {@inheritDoc}. */
518: public void start() throws IOException {
519: }
520:
521: /** {@inheritDoc}. */
522: public void stop() {
523: }
524:
525: /** {@inheritDoc}. */
526: public void setProcessInputStream(OutputStream param1)
527: throws IOException {
528: }
529:
530: /**
531: * Set the output stream of the process.
532: * @param is the input stream.
533: * @throws IOException if there is an error.
534: */
535: public void setProcessOutputStream(InputStream is)
536: throws IOException {
537: try {
538: BufferedReader reader = new BufferedReader(
539: new InputStreamReader(is));
540: String javafile;
541: while ((javafile = reader.readLine()) != null) {
542: if (javafile.endsWith(".java")) {
543: String classfile = toClassFile(javafile);
544: String key = classfile.substring(getConfig().srcDir
545: .getAbsolutePath().length() + 1);
546: genfiles.put(key, new File(classfile));
547: }
548: }
549: reader.close();
550: } catch (Exception e) {
551: String msg = "Exception while parsing java2iiop output. Details: "
552: + e.toString();
553: throw new BuildException(msg, e);
554: }
555: }
556:
557: /**
558: * Set the error stream of the process.
559: * @param is the input stream.
560: * @throws IOException if there is an error.
561: */
562: public void setProcessErrorStream(InputStream is)
563: throws IOException {
564: BufferedReader reader = new BufferedReader(
565: new InputStreamReader(is));
566: String s = reader.readLine();
567: if (s != null) {
568: log("[java2iiop] " + s, Project.MSG_ERR);
569: }
570: }
571: }
|