source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/Rmic.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 23.2 KB
Line 
1/*
2 * Copyright 2000-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
18package org.apache.tools.ant.taskdefs;
19
20import java.io.File;
21import java.io.IOException;
22import java.rmi.Remote;
23import java.util.Vector;
24import org.apache.tools.ant.BuildException;
25import org.apache.tools.ant.DirectoryScanner;
26import org.apache.tools.ant.Project;
27import org.apache.tools.ant.taskdefs.rmic.RmicAdapter;
28import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory;
29import org.apache.tools.ant.types.FilterSetCollection;
30import org.apache.tools.ant.types.Path;
31import org.apache.tools.ant.types.Reference;
32import org.apache.tools.ant.util.FileNameMapper;
33import org.apache.tools.ant.util.FileUtils;
34import org.apache.tools.ant.util.SourceFileScanner;
35import org.apache.tools.ant.util.facade.FacadeTaskHelper;
36
37/**
38 * Runs the rmic compiler against classes.</p>
39 * <p>Rmic can be run on a single class (as specified with the classname
40 * attribute) or a number of classes at once (all classes below base that
41 * are neither _Stub nor _Skel classes). If you want to rmic a single
42 * class and this class is a class nested into another class, you have to
43 * specify the classname in the form <code>Outer$$Inner</code> instead of
44 * <code>Outer.Inner</code>.</p>
45 * <p>It is possible to refine the set of files that are being rmiced. This can
46 * be done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>,
47 * <i>excludesfile</i> and <i>defaultexcludes</i>
48 * attributes. With the <i>includes</i> or <i>includesfile</i> attribute you
49 * specify the files you want to have included by using patterns. The
50 * <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
51 * the files you want to have excluded. This is also done with patterns. And
52 * finally with the <i>defaultexcludes</i> attribute, you can specify whether
53 * you want to use default exclusions or not. See the section on
54 * directory based tasks</a>, on how the
55 * inclusion/exclusion of files works, and how to write patterns.</p>
56 * <p>This task forms an implicit FileSet and
57 * supports all attributes of <code>&lt;fileset&gt;</code>
58 * (<code>dir</code> becomes <code>base</code>) as well as the nested
59 * <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
60 * <code>&lt;patternset&gt;</code> elements.</p>
61 * <p>It is possible to use different compilers. This can be selected
62 * with the &quot;build.rmic&quot; property or the <code>compiler</code>
63 * attribute. <a name="compilervalues">There are three choices</a>:</p>
64 * <ul>
65 * <li>sun (the standard compiler of the JDK)</li>
66 * <li>kaffe (the standard compiler of
67 * {@link <a href="http://www.kaffe.org">Kaffe</a>})</li>
68 * <li>weblogic</li>
69 * </ul>
70 *
71 * <p> The <a href="http://dione.zcu.cz/~toman40/miniRMI/">miniRMI</a>
72 * project contains a compiler implementation for this task as well,
73 * please consult miniRMI's documentation to learn how to use it.</p>
74 *
75 * @since Ant 1.1
76 *
77 * @ant.task category="java"
78 */
79
80public class Rmic extends MatchingTask {
81
82 private static final String FAIL_MSG
83 = "Rmic failed; see the compiler error output for details.";
84
85 private File baseDir;
86 private String classname;
87 private File sourceBase;
88 private String stubVersion;
89 private Path compileClasspath;
90 private Path extDirs;
91 private boolean verify = false;
92 private boolean filtering = false;
93
94 private boolean iiop = false;
95 private String iiopOpts;
96 private boolean idl = false;
97 private String idlOpts;
98 private boolean debug = false;
99 private boolean includeAntRuntime = true;
100 private boolean includeJavaRuntime = false;
101
102 private Vector compileList = new Vector();
103
104 private ClassLoader loader = null;
105
106 private FileUtils fileUtils = FileUtils.newFileUtils();
107
108 private FacadeTaskHelper facade;
109
110 /**
111 * Constructor for Rmic.
112 */
113 public Rmic() {
114 try {
115 Class.forName("kaffe.rmi.rmic.RMIC");
116 facade = new FacadeTaskHelper("kaffe");
117 } catch (ClassNotFoundException cnfe) {
118 facade = new FacadeTaskHelper("sun");
119 }
120 }
121
122 /**
123 * Sets the location to store the compiled files; required
124 * @param base the location to store the compiled files
125 */
126 public void setBase(File base) {
127 this.baseDir = base;
128 }
129
130 /**
131 * Gets the base directory to output generated class.
132 * @return the location of the compiled files
133 */
134
135 public File getBase() {
136 return this.baseDir;
137 }
138
139 /**
140 * Sets the class to run <code>rmic</code> against;
141 * optional
142 * @param classname the name of the class for rmic to create code for
143 */
144 public void setClassname(String classname) {
145 this.classname = classname;
146 }
147
148 /**
149 * Gets the class name to compile.
150 * @return the name of the class to compile
151 */
152 public String getClassname() {
153 return classname;
154 }
155
156 /**
157 * optional directory to save generated source files to.
158 * @param sourceBase the directory to save source files to.
159 */
160 public void setSourceBase(File sourceBase) {
161 this.sourceBase = sourceBase;
162 }
163
164 /**
165 * Gets the source dirs to find the source java files.
166 * @return sourceBase the directory containing the source files.
167 */
168 public File getSourceBase() {
169 return sourceBase;
170 }
171
172 /**
173 * Specify the JDK version for the generated stub code.
174 * Specify &quot;1.1&quot; to pass the &quot;-v1.1&quot; option to rmic.</td>
175 * @param stubVersion the JDK version
176 */
177 public void setStubVersion(String stubVersion) {
178 this.stubVersion = stubVersion;
179 }
180
181 /**
182 * Gets the JDK version for the generated stub code.
183 * @return stubVersion
184 */
185 public String getStubVersion() {
186 return stubVersion;
187 }
188
189 /**
190 * Sets token filtering [optional], default=false
191 * @param filter turn on token filtering
192 */
193 public void setFiltering(boolean filter) {
194 this.filtering = filter;
195 }
196
197 /**
198 * Gets whether token filtering is set
199 * @return filtering
200 */
201 public boolean getFiltering() {
202 return filtering;
203 }
204
205 /**
206 * Generate debug info (passes -g to rmic);
207 * optional, defaults to false
208 * @param debug turn on debug info
209 */
210 public void setDebug(boolean debug) {
211 this.debug = debug;
212 }
213
214 /**
215 * Gets the debug flag.
216 * @return debug
217 */
218 public boolean getDebug() {
219 return debug;
220 }
221
222 /**
223 * Set the classpath to be used for this compilation.
224 * @param classpath the classpath used for this compilation
225 */
226 public void setClasspath(Path classpath) {
227 if (compileClasspath == null) {
228 compileClasspath = classpath;
229 } else {
230 compileClasspath.append(classpath);
231 }
232 }
233
234 /**
235 * Creates a nested classpath element.
236 * @return classpath
237 */
238 public Path createClasspath() {
239 if (compileClasspath == null) {
240 compileClasspath = new Path(getProject());
241 }
242 return compileClasspath.createPath();
243 }
244
245 /**
246 * Adds to the classpath a reference to
247 * a &lt;path&gt; defined elsewhere.
248 * @param pathRef the reference to add to the classpath
249 */
250 public void setClasspathRef(Reference pathRef) {
251 createClasspath().setRefid(pathRef);
252 }
253
254 /**
255 * Gets the classpath.
256 * @return the classpath
257 */
258 public Path getClasspath() {
259 return compileClasspath;
260 }
261
262 /**
263 * Flag to enable verification so that the classes
264 * found by the directory match are
265 * checked to see if they implement java.rmi.Remote.
266 * optional; This defaults to false if not set.
267 * @param verify turn on verification for classes
268 */
269
270 public void setVerify(boolean verify) {
271 this.verify = verify;
272 }
273
274 /**
275 * Get verify flag.
276 * @return verify
277 */
278 public boolean getVerify() {
279 return verify;
280 }
281
282 /**
283 * Indicates that IIOP compatible stubs should
284 * be generated; optional, defaults to false
285 * if not set.
286 * @param iiop generate IIOP compatible stubs
287 */
288 public void setIiop(boolean iiop) {
289 this.iiop = iiop;
290 }
291
292 /**
293 * Gets iiop flags.
294 * @return iiop
295 */
296 public boolean getIiop() {
297 return iiop;
298 }
299
300 /**
301 * Set additional arguments for iiop
302 * @param iiopOpts additional arguments for iiop
303 */
304 public void setIiopopts(String iiopOpts) {
305 this.iiopOpts = iiopOpts;
306 }
307
308 /**
309 * Gets additional arguments for iiop.
310 * @return iiopOpts
311 */
312 public String getIiopopts() {
313 return iiopOpts;
314 }
315
316 /**
317 * Indicates that IDL output should be
318 * generated. This defaults to false
319 * if not set.
320 * @param idl generate IDL output
321 */
322 public void setIdl(boolean idl) {
323 this.idl = idl;
324 }
325
326 /**
327 * Gets IDL flags.
328 * @return the idl flag
329 */
330 public boolean getIdl() {
331 return idl;
332 }
333
334 /**
335 * pass additional arguments for IDL compile
336 * @param idlOpts additional IDL arguments
337 */
338 public void setIdlopts(String idlOpts) {
339 this.idlOpts = idlOpts;
340 }
341
342 /**
343 * Gets additional arguments for idl compile.
344 * @return the idl options
345 */
346 public String getIdlopts() {
347 return idlOpts;
348 }
349
350 /**
351 * Gets file list to compile.
352 * @return the list of files to compile.
353 */
354 public Vector getFileList() {
355 return compileList;
356 }
357
358 /**
359 * Sets whether or not to include ant's own classpath in this task's
360 * classpath.
361 * Optional; default is <code>true</code>.
362 * @param include if true include ant's classpath
363 */
364 public void setIncludeantruntime(boolean include) {
365 includeAntRuntime = include;
366 }
367
368 /**
369 * Gets whether or not the ant classpath is to be included in the
370 * task's classpath.
371 * @return true if ant's classpath is to be included
372 */
373 public boolean getIncludeantruntime() {
374 return includeAntRuntime;
375 }
376
377 /**
378 * task's classpath.
379 * Enables or disables including the default run-time
380 * libraries from the executing VM; optional,
381 * defaults to false
382 * @param include if true include default run-time libraries
383 */
384 public void setIncludejavaruntime(boolean include) {
385 includeJavaRuntime = include;
386 }
387
388 /**
389 * Gets whether or not the java runtime should be included in this
390 * task's classpath.
391 * @return true if default run-time libraries are included
392 */
393 public boolean getIncludejavaruntime() {
394 return includeJavaRuntime;
395 }
396
397 /**
398 * Sets the extension directories that will be used during the
399 * compilation; optional.
400 * @param extDirs the extension directories to be used
401 */
402 public void setExtdirs(Path extDirs) {
403 if (this.extDirs == null) {
404 this.extDirs = extDirs;
405 } else {
406 this.extDirs.append(extDirs);
407 }
408 }
409
410 /**
411 * Maybe creates a nested extdirs element.
412 * @return path object to be configured with the extension directories
413 */
414 public Path createExtdirs() {
415 if (extDirs == null) {
416 extDirs = new Path(getProject());
417 }
418 return extDirs.createPath();
419 }
420
421 /**
422 * Gets the extension directories that will be used during the
423 * compilation.
424 * @return the extension directories to be used
425 */
426 public Path getExtdirs() {
427 return extDirs;
428 }
429
430 /**
431 * @return the compile list.
432 */
433 public Vector getCompileList() {
434 return compileList;
435 }
436
437 /**
438 * Sets the compiler implementation to use; optional,
439 * defaults to the value of the <code>build.rmic</code> property,
440 * or failing that, default compiler for the current VM
441 * @param compiler the compiler implemention to use
442 * @since Ant 1.5
443 */
444 public void setCompiler(String compiler) {
445 if (compiler.length() > 0) {
446 facade.setImplementation(compiler);
447 }
448 }
449
450 /**
451 * get the name of the current compiler
452 * @return the name of the compiler
453 * @since Ant 1.5
454 */
455 public String getCompiler() {
456 facade.setMagicValue(getProject().getProperty("build.rmic"));
457 return facade.getImplementation();
458 }
459
460 /**
461 * Adds an implementation specific command line argument.
462 * @return an object to be configured with a command line argument
463 * @since Ant 1.5
464 */
465 public ImplementationSpecificArgument createCompilerArg() {
466 ImplementationSpecificArgument arg =
467 new ImplementationSpecificArgument();
468 facade.addImplementationArgument(arg);
469 return arg;
470 }
471
472 /**
473 * Get the additional implementation specific command line arguments.
474 * @return array of command line arguments, guaranteed to be non-null.
475 * @since Ant 1.5
476 */
477 public String[] getCurrentCompilerArgs() {
478 getCompiler();
479 return facade.getArgs();
480 }
481
482 /**
483 * execute by creating an instance of an implementation
484 * class and getting to do the work
485 */
486 public void execute() throws BuildException {
487 if (baseDir == null) {
488 throw new BuildException("base attribute must be set!", getLocation());
489 }
490 if (!baseDir.exists()) {
491 throw new BuildException("base does not exist!", getLocation());
492 }
493
494 if (verify) {
495 log("Verify has been turned on.", Project.MSG_VERBOSE);
496 }
497
498 RmicAdapter adapter = RmicAdapterFactory.getRmic(getCompiler(), this);
499
500 // now we need to populate the compiler adapter
501 adapter.setRmic(this);
502
503 Path classpath = adapter.getClasspath();
504 loader = getProject().createClassLoader(classpath);
505
506 try {
507 // scan base dirs to build up compile lists only if a
508 // specific classname is not given
509 if (classname == null) {
510 DirectoryScanner ds = this.getDirectoryScanner(baseDir);
511 String[] files = ds.getIncludedFiles();
512 scanDir(baseDir, files, adapter.getMapper());
513 } else {
514 // otherwise perform a timestamp comparison - at least
515 scanDir(baseDir,
516 new String[] {classname.replace('.',
517 File.separatorChar)
518 + ".class"},
519 adapter.getMapper());
520 }
521
522 int fileCount = compileList.size();
523 if (fileCount > 0) {
524 log("RMI Compiling " + fileCount
525 + " class" + (fileCount > 1 ? "es" : "") + " to " + baseDir,
526 Project.MSG_INFO);
527
528 // finally, lets execute the compiler!!
529 if (!adapter.execute()) {
530 throw new BuildException(FAIL_MSG, getLocation());
531 }
532 }
533
534 /*
535 * Move the generated source file to the base directory. If
536 * base directory and sourcebase are the same, the generated
537 * sources are already in place.
538 */
539 if (null != sourceBase && !baseDir.equals(sourceBase)
540 && fileCount > 0) {
541 if (idl) {
542 log("Cannot determine sourcefiles in idl mode, ",
543 Project.MSG_WARN);
544 log("sourcebase attribute will be ignored.",
545 Project.MSG_WARN);
546 } else {
547 for (int j = 0; j < fileCount; j++) {
548 moveGeneratedFile(baseDir, sourceBase,
549 (String) compileList.elementAt(j),
550 adapter);
551 }
552 }
553 }
554 } finally {
555 compileList.removeAllElements();
556 }
557 }
558
559 /**
560 * Move the generated source file(s) to the base directory
561 *
562 * @throws org.apache.tools.ant.BuildException When error
563 * copying/removing files.
564 */
565 private void moveGeneratedFile (File baseDir, File sourceBaseFile,
566 String classname,
567 RmicAdapter adapter)
568 throws BuildException {
569
570 String classFileName =
571 classname.replace('.', File.separatorChar) + ".class";
572 String[] generatedFiles =
573 adapter.getMapper().mapFileName(classFileName);
574
575 for (int i = 0; i < generatedFiles.length; i++) {
576 final String generatedFile = generatedFiles[i];
577 if (!generatedFile.endsWith(".class")) {
578 // don't know how to handle that - a IDL file doesn't
579 // have a corresponding Java source for example.
580 continue;
581 }
582
583 final int pos = generatedFile.length() - ".class".length();
584 String sourceFileName =
585 generatedFile.substring(0, pos) + ".java";
586
587 File oldFile = new File(baseDir, sourceFileName);
588 if (!oldFile.exists()) {
589 // no source file generated, nothing to move
590 continue;
591 }
592
593 File newFile = new File(sourceBaseFile, sourceFileName);
594 try {
595 if (filtering) {
596 fileUtils.copyFile(oldFile, newFile,
597 new FilterSetCollection(getProject()
598 .getGlobalFilterSet()));
599 } else {
600 fileUtils.copyFile(oldFile, newFile);
601 }
602 oldFile.delete();
603 } catch (IOException ioe) {
604 String msg = "Failed to copy " + oldFile + " to "
605 + newFile + " due to " + ioe.getMessage();
606 throw new BuildException(msg, ioe, getLocation());
607 }
608 }
609 }
610
611 /**
612 * Scans the directory looking for class files to be compiled.
613 * The result is returned in the class variable compileList.
614 * @param baseDir the base direction
615 * @param files the list of files to scan
616 * @param mapper the mapper of files to target files
617 */
618 protected void scanDir(File baseDir, String[] files,
619 FileNameMapper mapper) {
620
621 String[] newFiles = files;
622 if (idl) {
623 log("will leave uptodate test to rmic implementation in idl mode.",
624 Project.MSG_VERBOSE);
625 } else if (iiop
626 && iiopOpts != null && iiopOpts.indexOf("-always") > -1) {
627 log("no uptodate test as -always option has been specified",
628 Project.MSG_VERBOSE);
629 } else {
630 SourceFileScanner sfs = new SourceFileScanner(this);
631 newFiles = sfs.restrict(files, baseDir, baseDir, mapper);
632 }
633
634 for (int i = 0; i < newFiles.length; i++) {
635 String classname = newFiles[i].replace(File.separatorChar, '.');
636 classname = classname.substring(0, classname.lastIndexOf(".class"));
637 compileList.addElement(classname);
638 }
639 }
640
641 /**
642 * Load named class and test whether it can be rmic'ed
643 * @param classname the name of the class to be tested
644 * @return true if the class can be rmic'ed
645 */
646 public boolean isValidRmiRemote(String classname) {
647 try {
648 Class testClass = loader.loadClass(classname);
649 // One cannot RMIC an interface for "classic" RMI (JRMP)
650 if (testClass.isInterface() && !iiop && !idl) {
651 return false;
652 }
653 return isValidRmiRemote(testClass);
654 } catch (ClassNotFoundException e) {
655 log("Unable to verify class " + classname
656 + ". It could not be found.", Project.MSG_WARN);
657 } catch (NoClassDefFoundError e) {
658 log("Unable to verify class " + classname
659 + ". It is not defined.", Project.MSG_WARN);
660 } catch (Throwable t) {
661 log("Unable to verify class " + classname
662 + ". Loading caused Exception: "
663 + t.getMessage(), Project.MSG_WARN);
664 }
665 // we only get here if an exception has been thrown
666 return false;
667 }
668
669 /**
670 * Returns the topmost interface that extends Remote for a given
671 * class - if one exists.
672 * @param testClass the class to be tested
673 * @return the topmost interface that extends Remote, or null if there
674 * is none.
675 */
676 public Class getRemoteInterface(Class testClass) {
677 if (Remote.class.isAssignableFrom(testClass)) {
678 Class [] interfaces = testClass.getInterfaces();
679 if (interfaces != null) {
680 for (int i = 0; i < interfaces.length; i++) {
681 if (Remote.class.isAssignableFrom(interfaces[i])) {
682 return interfaces[i];
683 }
684 }
685 }
686 }
687 return null;
688 }
689
690 /**
691 * Check to see if the class or (super)interfaces implement
692 * java.rmi.Remote.
693 */
694 private boolean isValidRmiRemote (Class testClass) {
695 return getRemoteInterface(testClass) != null;
696 }
697
698 /**
699 * Classloader for the user-specified classpath.
700 * @return the classloader
701 */
702 public ClassLoader getLoader() {
703 return loader;
704 }
705
706 /**
707 * Adds an "compiler" attribute to Commandline$Attribute used to
708 * filter command line attributes based on the current
709 * implementation.
710 */
711 public class ImplementationSpecificArgument extends
712 org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
713
714 /**
715 * Only pass the specified argument if the
716 * chosen compiler implementation matches the
717 * value of this attribute. Legal values are
718 * the same as those in the above list of
719 * valid compilers.)
720 * @param impl the compiler to be used.
721 */
722 public void setCompiler(String impl) {
723 super.setImplementation(impl);
724 }
725 }
726
727}
728
Note: See TracBrowser for help on using the repository browser.