libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / rmic / SourceGiopRmicCompiler.java
blobb7ad7f440a5fd9dd37e754c782cc8c83391ed74e
1 /* SourceGiopRmicCompiler -- Central GIOP-based RMI stub and tie compiler class.
2 Copyright (C) 2006, 2008 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
22 package gnu.classpath.tools.rmic;
24 import gnu.classpath.tools.rmic.AbstractMethodGenerator;
26 import java.io.File;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.lang.reflect.Method;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.net.URLClassLoader;
34 import java.rmi.Remote;
35 import java.rmi.RemoteException;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.Comparator;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.Properties;
43 import java.util.StringTokenizer;
44 import java.util.TreeSet;
46 /**
47 * Provides the extended rmic functionality to generate the POA - based classes
48 * for GIOP (javax.rmi.CORBA package).
50 * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
52 public class SourceGiopRmicCompiler
53 extends Generator implements Comparator, RmicBackend
55 /** The package name. */
56 protected String packag;
58 /**
59 * The "basic" name (normally, the interface name, unless several Remote -
60 * derived interfaces are implemented.
62 protected String name;
64 /**
65 * The name (without package) of the class, passed as the parameter.
67 protected String implName;
69 /**
70 * The proposed name for the stub.
72 protected String stubName;
74 /**
75 * The Remote's, implemented by this class.
77 protected Collection implementedRemotes = new HashSet();
79 /**
80 * The extra classes that must be imported.
82 protected Collection extraImports = new HashSet();
84 /**
85 * The methods we must implement.
87 protected Collection methods = new HashSet();
89 /**
90 * The map of all code generator variables.
92 public Properties vars = new Properties();
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.
99 protected boolean poaMode = true;
102 * If this flag is set (true by default), the compiler emits warnings.
104 protected boolean warnings = true;
107 * If this flag is set (false by default), the compiler does not
108 * write output files.
110 protected boolean noWrite = false;
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.
118 protected boolean keep = false;
121 * Verbose output
123 protected boolean verbose = false;
126 * Force mode - do not check the exceptions
128 protected boolean force = false;
131 * The output directory for generated files.
133 protected String outputDirectory;
136 * The class loader to load the class being compiled.
138 ClassLoader classLoader;
141 * Clear data, preparing for the next compilation.
143 public synchronized void reset()
145 packag = name = implName = stubName = null;
146 implementedRemotes.clear();
147 extraImports.clear();
148 methods.clear();
149 vars.clear();
153 * Set the class path (handle the -classpath key)
155 * @param classPath the class path to set.
157 public void setClassPath(String classPath)
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;
166 while (tok.hasMoreTokens())
168 s = tok.nextToken();
169 if (s.equals(File.pathSeparator))
170 urls.add(new File(".").toURL());
171 else
173 urls.add(new File(s).toURL());
174 if (tok.hasMoreTokens())
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());
186 catch (MalformedURLException ex)
188 System.err.println("Malformed path '" + s + "' in classpath '"
189 + classPath + "'");
190 System.exit(1);
192 URL[] u = new URL[urls.size()];
193 for (int i = 0; i < u.length; i++)
195 u[i] = (URL) urls.get(i);
198 classLoader = new URLClassLoader(u, classLoader);
202 * Loads the class with the given name (uses class path, if applicable)
204 * @param name the name of the class.
206 public Class loadClass(String name)
208 ClassLoader loader = classLoader;
209 if (loader == null)
210 loader = Thread.currentThread().getContextClassLoader();
213 return loader.loadClass(name);
215 catch (ClassNotFoundException e)
217 System.err.println(name+" not found on "+loader);
218 System.exit(1);
219 // Unreacheable code.
220 return null;
225 * Compile the given class (the instance of Remote), generating the stub and
226 * tie for it.
228 * @param remote
229 * the class to compile.
231 public synchronized void compile(Class remote)
233 reset();
234 String s;
236 // Get the package.
237 s = remote.getName();
238 int p = s.lastIndexOf('.');
239 if (p < 0)
241 // Root package.
242 packag = "";
243 implName = name = s;
245 else
247 packag = s.substring(0, p);
248 implName = name = s.substring(p + 1);
251 name = convertStubName(name);
253 stubName = name;
255 vars.put("#name", name);
256 vars.put("#package", packag);
257 vars.put("#implName", implName);
259 if (verbose)
260 System.out.println("Package " + packag + ", name " + name + " impl "
261 + implName);
263 // Get the implemented remotes.
264 Class[] interfaces = remote.getInterfaces();
266 for (int i = 0; i < interfaces.length; i++)
268 if (Remote.class.isAssignableFrom(interfaces[i]))
270 if (! interfaces[i].equals(Remote.class))
272 implementedRemotes.add(interfaces[i]);
277 vars.put("#idList", getIdList(implementedRemotes));
279 // Collect and process methods.
280 Iterator iter = implementedRemotes.iterator();
282 while (iter.hasNext())
284 Class c = (Class) iter.next();
285 Method[] m = c.getMethods();
287 // Check if throws RemoteException.
288 for (int i = 0; i < m.length; i++)
290 Class[] exc = m[i].getExceptionTypes();
291 boolean remEx = false;
293 for (int j = 0; j < exc.length; j++)
295 if (exc[j].isAssignableFrom(RemoteException.class))
297 remEx = true;
298 break;
301 if (! remEx && !force)
302 throw new CompilationError(m[i].getName() + ", defined in "
303 + c.getName()
304 + ", does not throw "
305 + RemoteException.class.getName());
306 AbstractMethodGenerator mm = createMethodGenerator(m[i]);
307 methods.add(mm);
313 * Create the method generator for the given method.
315 * @param m the method
317 * @return the created method generator
319 protected AbstractMethodGenerator createMethodGenerator(Method m)
321 return new MethodGenerator(m, this);
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.
328 * @param nameIt
329 * the class to name
330 * @return the name of class as it should appear in java language
332 public synchronized String name(Class nameIt)
334 if (nameIt.isArray())
336 // Mesure dimensions:
337 int dimension = 0;
338 Class finalComponent = nameIt;
339 while (finalComponent.isArray())
341 finalComponent = finalComponent.getComponentType();
342 dimension++;
345 StringBuilder brackets = new StringBuilder();
347 for (int i = 0; i < dimension; i++)
349 brackets.append("[]");
352 return name(finalComponent) + " " + brackets;
354 else
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);
362 int p = n.lastIndexOf('.');
363 if (p < 0)
364 return n;
365 else
366 return n.substring(p + 1);
371 * Get the RMI-style repository Id for the given class.
373 * @param c
374 * the interface, for that the repository Id must be created.
375 * @return the repository id
377 public String getId(Class c)
379 return "RMI:" + c.getName() + ":0000000000000000";
383 * Get repository Id string array declaration.
385 * @param remotes
386 * the collection of interfaces
387 * @return the fully formatted string array.
389 public String getIdList(Collection remotes)
391 StringBuilder b = new StringBuilder();
393 // Keep the Ids sorted, ensuring, that the same order will be preserved
394 // between compilations.
395 TreeSet sortedIds = new TreeSet();
397 Iterator iter = remotes.iterator();
398 while (iter.hasNext())
400 sortedIds.add(getId((Class) iter.next()));
403 iter = sortedIds.iterator();
404 while (iter.hasNext())
406 b.append(" \"" + iter.next() + "\"");
407 if (iter.hasNext())
408 b.append(", \n");
410 return b.toString();
414 * Generate stub. Can only be called from {@link #compile}.
416 * @return the string, containing the text of the generated stub.
418 public String generateStub()
420 String template = getResource("Stub.jav");
422 // Generate methods.
423 StringBuilder b = new StringBuilder();
424 Iterator iter = methods.iterator();
425 while (iter.hasNext())
427 AbstractMethodGenerator m = (AbstractMethodGenerator) iter.next();
428 b.append(m.generateStubMethod());
431 vars.put("#stub_methods", b.toString());
432 vars.put("#imports", getImportStatements());
433 vars.put("#interfaces", getAllInterfaces());
435 String output = replaceAll(template, vars);
436 return output;
440 * Get the list of all interfaces, implemented by the class, that are
441 * derived from Remote.
443 * @return the string - all interfaces.
445 public String getAllInterfaces()
447 StringBuilder b = new StringBuilder();
448 Iterator iter = implementedRemotes.iterator();
450 while (iter.hasNext())
452 b.append(name((Class) iter.next()));
453 if (iter.hasNext())
454 b.append(", ");
457 return b.toString();
461 * Generate Tie. Can only be called from {@link #compile}.
463 * @return the string, containing the text of the generated Tie.
465 public String generateTie()
467 String template;
468 if (poaMode)
469 template = getResource("Tie.jav");
470 else
471 template = getResource("ImplTie.jav");
473 // Generate methods.
474 HashFinder hashFinder = new HashFinder();
476 // Find the hash character position:
477 Iterator iter = methods.iterator();
478 String[] names = new String[methods.size()];
479 int p = 0;
481 for (int i = 0; i < names.length; i++)
482 names[i] = ((MethodGenerator) iter.next()).getGiopMethodName();
484 int hashCharPosition = hashFinder.findHashCharPosition(names);
486 iter = methods.iterator();
487 while (iter.hasNext())
488 ((MethodGenerator) iter.next()).hashCharPosition = hashCharPosition;
490 vars.put("#hashCharPos", Integer.toString(hashCharPosition));
492 ArrayList sortedMethods = new ArrayList(methods);
493 Collections.sort(sortedMethods, this);
495 iter = sortedMethods.iterator();
497 StringBuilder b = new StringBuilder();
499 MethodGenerator prev = null;
501 while (iter.hasNext())
503 MethodGenerator m = (MethodGenerator) iter.next();
504 m.previous = prev;
505 m.hashCharPosition = hashCharPosition;
506 prev = m;
507 b.append(m.generateTieMethod());
510 vars.put("#tie_methods", b.toString());
512 vars.put("#imports", getImportStatements());
514 String output = replaceAll(template, vars);
515 return output;
518 public int compare(Object a, Object b)
520 MethodGenerator g1 = (MethodGenerator) a;
521 MethodGenerator g2 = (MethodGenerator) b;
523 return g1.getHashChar() - g2.getHashChar();
527 * Import the extra classes, used as the method parameters and return values.
529 * @return the additional import block.
531 protected String getImportStatements()
533 TreeSet imp = new TreeSet();
535 Iterator it = extraImports.iterator();
536 while (it.hasNext())
538 String ic = it.next().toString();
539 imp.add("import " + ic + ";\n");
542 StringBuilder b = new StringBuilder();
543 it = imp.iterator();
545 while (it.hasNext())
547 b.append(it.next());
549 return b.toString();
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.
557 public void setPoaMode(boolean mode)
559 poaMode = mode;
563 * Set the verbose output mode (false by default)
565 * @param isVerbose the verbose output mode
567 public void setVerbose(boolean isVerbose)
569 verbose = isVerbose;
573 * If this flag is set (true by default), the compiler emits warnings.
575 public void setWarnings(boolean warn)
577 warnings = warn;
581 * Set the error ignore mode.
583 public void setForce(boolean isforce)
585 force = isforce;
589 * Get the package name.
591 public String getPackageName()
593 return packag;
597 * Get the proposed stub name
599 public String getStubName()
601 return stubName;
605 * Additional processing of the stub name.
607 public String convertStubName(String name)
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;
617 * Assumes that output directory is already created.
619 protected boolean outputTie(File fw, Class c)
623 String tie = generateTie();
624 String tieName = "_" + name(c) + "_Tie.java";
626 OutputStream out = new FileOutputStream(new File(fw, tieName));
627 out.write(tie.getBytes());
628 out.close();
630 catch (IOException ioex)
632 System.err.println("Output path not accessible");
633 ioex.printStackTrace();
634 return false;
636 return true;
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)
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;
654 public boolean run(String[] inputFiles)
656 for (int i = 0; i < inputFiles.length; i++)
658 reset();
659 Class c = loadClass(inputFiles[i]);
661 compile(c);
662 String packag = getPackageName().replace('.', '/');
663 File fw = new File(outputDirectory, packag);
665 // Generate stub.
666 String stub = generateStub();
667 String subName = getStubName() + "_Stub.java";
669 // -keep overrides -nowrite for sources.
670 if (!noWrite || keep)
674 fw.mkdirs();
675 OutputStream out = new FileOutputStream(new File(fw,
676 subName));
677 out.write(stub.getBytes());
678 out.close();
680 // Generate tie
681 if (!outputTie(fw, c))
682 return false;
684 catch (IOException ioex)
686 System.err.println("Output path not accessible");
687 ioex.printStackTrace();
688 return false;
692 return true;