]> git.ipfire.org Git - thirdparty/gcc.git/blame - libjava/classpath/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java
re PR libgcj/32198 (rmic fails if remote method throws superclass of RemoteException)
[thirdparty/gcc.git] / libjava / classpath / tools / gnu / classpath / tools / rmic / SourceGiopRmicCompiler.java
CommitLineData
97b8365c 1/* SourceGiopRmicCompiler -- Central GIOP-based RMI stub and tie compiler class.
2e10f49b 2 Copyright (C) 2006, 2008 Free Software Foundation
8aa540d2
MW
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1902110-1301 USA.
4f9533c7 20*/
8aa540d2 21
97b8365c 22package gnu.classpath.tools.rmic;
8aa540d2 23
97b8365c 24import gnu.classpath.tools.rmic.AbstractMethodGenerator;
8aa540d2 25
02440ca4 26import java.io.File;
97b8365c
TT
27import java.io.FileOutputStream;
28import java.io.IOException;
29import java.io.OutputStream;
8aa540d2 30import java.lang.reflect.Method;
02440ca4
TF
31import java.net.MalformedURLException;
32import java.net.URL;
33import java.net.URLClassLoader;
8aa540d2
MW
34import java.rmi.Remote;
35import java.rmi.RemoteException;
36import java.util.ArrayList;
37import java.util.Collection;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.HashSet;
41import java.util.Iterator;
42import java.util.Properties;
02440ca4 43import java.util.StringTokenizer;
8aa540d2
MW
44import java.util.TreeSet;
45
46/**
47 * Provides the extended rmic functionality to generate the POA - based classes
48 * for GIOP (javax.rmi.CORBA package).
49 *
50 * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
51 */
97b8365c
TT
52public class SourceGiopRmicCompiler
53 extends Generator implements Comparator, RmicBackend
8aa540d2
MW
54{
55 /** The package name. */
56 protected String packag;
57
58 /**
59 * The "basic" name (normally, the interface name, unless several Remote -
60 * derived interfaces are implemented.
61 */
62 protected String name;
63
64 /**
65 * The name (without package) of the class, passed as the parameter.
66 */
67 protected String implName;
68
69 /**
70 * The proposed name for the stub.
71 */
72 protected String stubName;
73
74 /**
75 * The Remote's, implemented by this class.
76 */
77 protected Collection implementedRemotes = new HashSet();
78
79 /**
80 * The extra classes that must be imported.
81 */
82 protected Collection extraImports = new HashSet();
83
84 /**
85 * The methods we must implement.
86 */
87 protected Collection methods = new HashSet();
88
89 /**
90 * The map of all code generator variables.
91 */
92 public Properties vars = new Properties();
93
94 /**
95 * If this flag is set (true by default), the compiler generates the Servant
96 * based classes. If set to false, the compiler generates the old style
97 * ObjectImpl based classes.
98 */
99 protected boolean poaMode = true;
100
101 /**
102 * If this flag is set (true by default), the compiler emits warnings.
103 */
104 protected boolean warnings = true;
105
97b8365c
TT
106 /**
107 * If this flag is set (false by default), the compiler does not
108 * write output files.
109 */
110 protected boolean noWrite = false;
111
112 /**
113 * If this flag is set (false by default), the compiler keeps source
114 * output files. For SourceGiopRmicCompiler this overrides
115 * -nowrite, since -nowrite doesn't apply to sources kept with
116 * -keep.
117 */
118 protected boolean keep = false;
119
8aa540d2
MW
120 /**
121 * Verbose output
122 */
123 protected boolean verbose = false;
4f9533c7
MW
124
125 /**
126 * Force mode - do not check the exceptions
127 */
128 protected boolean force = false;
97b8365c
TT
129
130 /**
131 * The output directory for generated files.
132 */
133 protected String outputDirectory;
134
02440ca4
TF
135 /**
136 * The class loader to load the class being compiled.
137 */
138 ClassLoader classLoader;
8aa540d2
MW
139
140 /**
141 * Clear data, preparing for the next compilation.
142 */
143 public void reset()
144 {
145 packag = name = implName = stubName = null;
146 implementedRemotes.clear();
147 extraImports.clear();
148 methods.clear();
149 vars.clear();
150 }
02440ca4
TF
151
152 /**
153 * Set the class path (handle the -classpath key)
154 *
155 * @param classPath the class path to set.
156 */
157 public void setClassPath(String classPath)
158 {
159 classLoader = Thread.currentThread().getContextClassLoader();
160 StringTokenizer tok = new StringTokenizer(classPath, File.pathSeparator,
161 true);
162 ArrayList urls = new ArrayList(tok.countTokens());
163 String s = null;
164 try
165 {
166 while (tok.hasMoreTokens())
167 {
168 s = tok.nextToken();
169 if (s.equals(File.pathSeparator))
170 urls.add(new File(".").toURL());
171 else
172 {
173 urls.add(new File(s).toURL());
174 if (tok.hasMoreTokens())
175 {
176 // Skip the separator.
177 tok.nextToken();
178 // If the classpath ended with a separator,
179 // append the current directory.
180 if (! tok.hasMoreTokens())
181 urls.add(new File(".").toURL());
182 }
183 }
184 }
185 }
186 catch (MalformedURLException ex)
187 {
188 System.err.println("Malformed path '" + s + "' in classpath '"
189 + classPath + "'");
190 System.exit(1);
191 }
192 URL[] u = new URL[urls.size()];
193 for (int i = 0; i < u.length; i++)
194 {
195 u[i] = (URL) urls.get(i);
196 }
197
198 classLoader = new URLClassLoader(u, classLoader);
199 }
200
201 /**
202 * Loads the class with the given name (uses class path, if applicable)
203 *
204 * @param name the name of the class.
205 */
206 public Class loadClass(String name)
207 {
208 ClassLoader loader = classLoader;
209 if (loader == null)
210 loader = Thread.currentThread().getContextClassLoader();
211 try
212 {
213 return loader.loadClass(name);
214 }
215 catch (ClassNotFoundException e)
216 {
217 System.err.println(name+" not found on "+loader);
218 System.exit(1);
219 // Unreacheable code.
220 return null;
221 }
222 }
8aa540d2
MW
223
224 /**
225 * Compile the given class (the instance of Remote), generating the stub and
226 * tie for it.
227 *
228 * @param remote
229 * the class to compile.
230 */
231 public synchronized void compile(Class remote)
232 {
233 reset();
234 String s;
235
236 // Get the package.
237 s = remote.getName();
238 int p = s.lastIndexOf('.');
239 if (p < 0)
240 {
241 // Root package.
242 packag = "";
243 implName = name = s;
244 }
245 else
246 {
247 packag = s.substring(0, p);
248 implName = name = s.substring(p + 1);
249 }
250
251 name = convertStubName(name);
252
253 stubName = name;
254
255 vars.put("#name", name);
256 vars.put("#package", packag);
257 vars.put("#implName", implName);
258
259 if (verbose)
260 System.out.println("Package " + packag + ", name " + name + " impl "
261 + implName);
262
263 // Get the implemented remotes.
264 Class[] interfaces = remote.getInterfaces();
265
266 for (int i = 0; i < interfaces.length; i++)
267 {
268 if (Remote.class.isAssignableFrom(interfaces[i]))
269 {
270 if (! interfaces[i].equals(Remote.class))
271 {
272 implementedRemotes.add(interfaces[i]);
273 }
274 }
275 }
276
277 vars.put("#idList", getIdList(implementedRemotes));
278
279 // Collect and process methods.
280 Iterator iter = implementedRemotes.iterator();
281
282 while (iter.hasNext())
283 {
284 Class c = (Class) iter.next();
285 Method[] m = c.getMethods();
286
287 // Check if throws RemoteException.
288 for (int i = 0; i < m.length; i++)
289 {
290 Class[] exc = m[i].getExceptionTypes();
291 boolean remEx = false;
292
293 for (int j = 0; j < exc.length; j++)
294 {
2e10f49b 295 if (exc[j].isAssignableFrom(RemoteException.class))
8aa540d2
MW
296 {
297 remEx = true;
298 break;
299 }
02440ca4
TF
300 }
301 if (! remEx && !force)
302 throw new CompilationError(m[i].getName() + ", defined in "
303 + c.getName()
304 + ", does not throw "
305 + RemoteException.class.getName());
8aa540d2
MW
306 AbstractMethodGenerator mm = createMethodGenerator(m[i]);
307 methods.add(mm);
308 }
309 }
310 }
311
312 /**
313 * Create the method generator for the given method.
314 *
315 * @param m the method
316 *
317 * @return the created method generator
318 */
319 protected AbstractMethodGenerator createMethodGenerator(Method m)
320 {
321 return new MethodGenerator(m, this);
322 }
323
324 /**
325 * Get the name of the given class. The class is added to imports, if not
326 * already present and not from java.lang and not from the current package.
327 *
328 * @param nameIt
329 * the class to name
330 * @return the name of class as it should appear in java language
331 */
332 public String name(Class nameIt)
333 {
334 if (nameIt.isArray())
335 {
336 // Mesure dimensions:
337 int dimension = 0;
338 Class finalComponent = nameIt;
339 while (finalComponent.isArray())
340 {
341 finalComponent = finalComponent.getComponentType();
342 dimension++;
343 }
344
345 StringBuffer brackets = new StringBuffer();
346
347 for (int i = 0; i < dimension; i++)
348 {
349 brackets.append("[]");
350 }
351
352 return name(finalComponent) + " " + brackets;
353 }
354 else
355 {
356 String n = nameIt.getName();
357 if (! nameIt.isArray() && ! nameIt.isPrimitive())
358 if (! n.startsWith("java.lang")
359 && ! (packag != null && n.startsWith(packag)))
360 extraImports.add(n);
361
362 int p = n.lastIndexOf('.');
363 if (p < 0)
364 return n;
365 else
366 return n.substring(p + 1);
367 }
368 }
369
370 /**
371 * Get the RMI-style repository Id for the given class.
372 *
373 * @param c
374 * the interface, for that the repository Id must be created.
375 * @return the repository id
376 */
377 public String getId(Class c)
378 {
379 return "RMI:" + c.getName() + ":0000000000000000";
380 }
381
382 /**
383 * Get repository Id string array declaration.
384 *
385 * @param remotes
386 * the collection of interfaces
387 * @return the fully formatted string array.
388 */
389 public String getIdList(Collection remotes)
390 {
391 StringBuffer b = new StringBuffer();
392
393 // Keep the Ids sorted, ensuring, that the same order will be preserved
394 // between compilations.
395 TreeSet sortedIds = new TreeSet();
396
397 Iterator iter = remotes.iterator();
398 while (iter.hasNext())
399 {
400 sortedIds.add(getId((Class) iter.next()));
401 }
402
403 iter = sortedIds.iterator();
404 while (iter.hasNext())
405 {
406 b.append(" \"" + iter.next() + "\"");
407 if (iter.hasNext())
408 b.append(", \n");
409 }
410 return b.toString();
411 }
412
413 /**
414 * Generate stub. Can only be called from {@link #compile}.
415 *
416 * @return the string, containing the text of the generated stub.
417 */
418 public String generateStub()
419 {
420 String template = getResource("Stub.jav");
421
422 // Generate methods.
423 StringBuffer b = new StringBuffer();
424 Iterator iter = methods.iterator();
425 while (iter.hasNext())
426 {
427 AbstractMethodGenerator m = (AbstractMethodGenerator) iter.next();
428 b.append(m.generateStubMethod());
429 }
430
431 vars.put("#stub_methods", b.toString());
432 vars.put("#imports", getImportStatements());
433 vars.put("#interfaces", getAllInterfaces());
434
435 String output = replaceAll(template, vars);
436 return output;
437 }
438
439 /**
440 * Get the list of all interfaces, implemented by the class, that are
441 * derived from Remote.
442 *
443 * @return the string - all interfaces.
444 */
445 public String getAllInterfaces()
446 {
447 StringBuffer b = new StringBuffer();
448 Iterator iter = implementedRemotes.iterator();
449
450 while (iter.hasNext())
451 {
452 b.append(name((Class) iter.next()));
453 if (iter.hasNext())
454 b.append(", ");
455 }
456
457 return b.toString();
458 }
459
460 /**
461 * Generate Tie. Can only be called from {@link #compile}.
462 *
463 * @return the string, containing the text of the generated Tie.
464 */
465 public String generateTie()
466 {
467 String template;
468 if (poaMode)
469 template = getResource("Tie.jav");
470 else
471 template = getResource("ImplTie.jav");
472
473 // Generate methods.
474 HashFinder hashFinder = new HashFinder();
475
476 // Find the hash character position:
477 Iterator iter = methods.iterator();
478 String[] names = new String[methods.size()];
479 int p = 0;
480
481 for (int i = 0; i < names.length; i++)
482 names[i] = ((MethodGenerator) iter.next()).getGiopMethodName();
483
484 int hashCharPosition = hashFinder.findHashCharPosition(names);
485
486 iter = methods.iterator();
487 while (iter.hasNext())
488 ((MethodGenerator) iter.next()).hashCharPosition = hashCharPosition;
489
490 vars.put("#hashCharPos", Integer.toString(hashCharPosition));
491
492 ArrayList sortedMethods = new ArrayList(methods);
493 Collections.sort(sortedMethods, this);
494
495 iter = sortedMethods.iterator();
496
497 StringBuffer b = new StringBuffer();
498
499 MethodGenerator prev = null;
500
501 while (iter.hasNext())
502 {
503 MethodGenerator m = (MethodGenerator) iter.next();
504 m.previous = prev;
505 m.hashCharPosition = hashCharPosition;
506 prev = m;
507 b.append(m.generateTieMethod());
508 }
509
510 vars.put("#tie_methods", b.toString());
511
512 vars.put("#imports", getImportStatements());
513
514 String output = replaceAll(template, vars);
515 return output;
516 }
517
518 public int compare(Object a, Object b)
519 {
520 MethodGenerator g1 = (MethodGenerator) a;
521 MethodGenerator g2 = (MethodGenerator) b;
522
523 return g1.getHashChar() - g2.getHashChar();
524 }
525
526 /**
527 * Import the extra classes, used as the method parameters and return values.
528 *
529 * @return the additional import block.
530 */
531 protected String getImportStatements()
532 {
533 TreeSet imp = new TreeSet();
534
535 Iterator it = extraImports.iterator();
536 while (it.hasNext())
537 {
538 String ic = it.next().toString();
539 imp.add("import " + ic + ";\n");
540 }
541
542 StringBuffer b = new StringBuffer();
543 it = imp.iterator();
544
545 while (it.hasNext())
546 {
547 b.append(it.next());
548 }
549 return b.toString();
550 }
551
552 /**
553 * If this flag is set (true by default), the compiler generates the Servant
554 * based classes. If set to false, the compiler generates the old style
555 * ObjectImpl based classes.
556 */
557 public void setPoaMode(boolean mode)
558 {
559 poaMode = mode;
560 }
561
562 /**
563 * Set the verbose output mode (false by default)
564 *
565 * @param isVerbose the verbose output mode
566 */
567 public void setVerbose(boolean isVerbose)
568 {
569 verbose = isVerbose;
570 }
571
572 /**
573 * If this flag is set (true by default), the compiler emits warnings.
574 */
575 public void setWarnings(boolean warn)
576 {
577 warnings = warn;
578 }
4f9533c7
MW
579
580 /**
581 * Set the error ignore mode.
582 */
583 public void setForce(boolean isforce)
584 {
585 force = isforce;
586 }
8aa540d2
MW
587
588 /**
589 * Get the package name.
590 */
591 public String getPackageName()
592 {
593 return packag;
594 }
595
596 /**
597 * Get the proposed stub name
598 */
599 public String getStubName()
600 {
601 return stubName;
602 }
603
604 /**
605 * Additional processing of the stub name.
606 */
607 public String convertStubName(String name)
608 {
609 // Drop the Impl suffix, if one exists.
610 if (name.endsWith("Impl"))
611 return name.substring(0, name.length() - "Impl".length());
612 else
613 return name;
614 }
97b8365c
TT
615
616 /**
617 * Assumes that output directory is already created.
618 */
619 protected boolean outputTie(File fw, Class c)
620 {
621 try
622 {
623 String tie = generateTie();
624 String tieName = "_" + name(c) + "_Tie.java";
625
626 OutputStream out = new FileOutputStream(new File(fw, tieName));
627 out.write(tie.getBytes());
628 out.close();
629 }
630 catch (IOException ioex)
631 {
632 System.err.println("Output path not accessible");
633 ioex.printStackTrace();
634 return false;
635 }
636 return true;
637 }
638
639 public void setup(boolean keep, boolean need11Stubs, boolean need12Stubs,
640 boolean iiop, boolean poa, boolean debug, boolean warnings,
641 boolean noWrite, boolean verbose, boolean force, String classpath,
642 String bootclasspath, String extdirs, String outputDirectory)
643 {
644 setWarnings(warnings);
645 setVerbose(verbose);
646 setForce(force);
647 setClassPath(classpath);
648 setPoaMode(poa);
649 this.outputDirectory = outputDirectory;
650 this.noWrite = noWrite;
651 this.keep = keep;
652 }
653
654 public boolean run(String[] inputFiles)
655 {
656 for (int i = 0; i < inputFiles.length; i++)
657 {
658 reset();
659 Class c = loadClass(inputFiles[i]);
660
661 compile(c);
662 String packag = getPackageName().replace('.', '/');
663 File fw = new File(outputDirectory, packag);
664
665 // Generate stub.
666 String stub = generateStub();
667 String subName = getStubName() + "_Stub.java";
668
669 // -keep overrides -nowrite for sources.
670 if (!noWrite || keep)
671 {
672 try
673 {
674 fw.mkdirs();
675 OutputStream out = new FileOutputStream(new File(fw,
676 subName));
677 out.write(stub.getBytes());
678 out.close();
679
680 // Generate tie
681 if (!outputTie(fw, c))
682 return false;
683 }
684 catch (IOException ioex)
685 {
686 System.err.println("Output path not accessible");
687 ioex.printStackTrace();
688 return false;
689 }
690 }
691 }
692 return true;
693 }
8aa540d2 694}