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)
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
22 package gnu
.classpath
.tools
.rmic
;
24 import gnu
.classpath
.tools
.rmic
.AbstractMethodGenerator
;
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
;
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
;
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
;
59 * The "basic" name (normally, the interface name, unless several Remote -
60 * derived interfaces are implemented.
62 protected String name
;
65 * The name (without package) of the class, passed as the parameter.
67 protected String implName
;
70 * The proposed name for the stub.
72 protected String stubName
;
75 * The Remote's, implemented by this class.
77 protected Collection implementedRemotes
= new HashSet();
80 * The extra classes that must be imported.
82 protected Collection extraImports
= new HashSet();
85 * The methods we must implement.
87 protected Collection methods
= new HashSet();
90 * The map of all code generator variables.
92 public Properties vars
= new Properties();
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
118 protected boolean keep
= false;
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();
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
,
162 ArrayList urls
= new ArrayList(tok
.countTokens());
166 while (tok
.hasMoreTokens())
169 if (s
.equals(File
.pathSeparator
))
170 urls
.add(new File(".").toURL());
173 urls
.add(new File(s
).toURL());
174 if (tok
.hasMoreTokens())
176 // Skip the separator.
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 '"
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
;
210 loader
= Thread
.currentThread().getContextClassLoader();
213 return loader
.loadClass(name
);
215 catch (ClassNotFoundException e
)
217 System
.err
.println(name
+" not found on "+loader
);
219 // Unreacheable code.
225 * Compile the given class (the instance of Remote), generating the stub and
229 * the class to compile.
231 public synchronized void compile(Class remote
)
237 s
= remote
.getName();
238 int p
= s
.lastIndexOf('.');
247 packag
= s
.substring(0, p
);
248 implName
= name
= s
.substring(p
+ 1);
251 name
= convertStubName(name
);
255 vars
.put("#name", name
);
256 vars
.put("#package", packag
);
257 vars
.put("#implName", implName
);
260 System
.out
.println("Package " + packag
+ ", name " + name
+ " impl "
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))
301 if (! remEx
&& !force
)
302 throw new CompilationError(m
[i
].getName() + ", defined in "
304 + ", does not throw "
305 + RemoteException
.class.getName());
306 AbstractMethodGenerator mm
= createMethodGenerator(m
[i
]);
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.
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:
338 Class finalComponent
= nameIt
;
339 while (finalComponent
.isArray())
341 finalComponent
= finalComponent
.getComponentType();
345 StringBuilder brackets
= new StringBuilder();
347 for (int i
= 0; i
< dimension
; i
++)
349 brackets
.append("[]");
352 return name(finalComponent
) + " " + brackets
;
356 String n
= nameIt
.getName();
357 if (! nameIt
.isArray() && ! nameIt
.isPrimitive())
358 if (! n
.startsWith("java.lang")
359 && ! (packag
!= null && n
.startsWith(packag
)))
362 int p
= n
.lastIndexOf('.');
366 return n
.substring(p
+ 1);
371 * Get the RMI-style repository Id for the given class.
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.
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() + "\"");
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");
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
);
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()));
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()
469 template
= getResource("Tie.jav");
471 template
= getResource("ImplTie.jav");
474 HashFinder hashFinder
= new HashFinder();
476 // Find the hash character position:
477 Iterator iter
= methods
.iterator();
478 String
[] names
= new String
[methods
.size()];
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();
505 m
.hashCharPosition
= hashCharPosition
;
507 b
.append(m
.generateTieMethod());
510 vars
.put("#tie_methods", b
.toString());
512 vars
.put("#imports", getImportStatements());
514 String output
= replaceAll(template
, vars
);
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();
538 String ic
= it
.next().toString();
539 imp
.add("import " + ic
+ ";\n");
542 StringBuilder b
= new StringBuilder();
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
)
563 * Set the verbose output mode (false by default)
565 * @param isVerbose the verbose output mode
567 public void setVerbose(boolean isVerbose
)
573 * If this flag is set (true by default), the compiler emits warnings.
575 public void setWarnings(boolean warn
)
581 * Set the error ignore mode.
583 public void setForce(boolean isforce
)
589 * Get the package name.
591 public String
getPackageName()
597 * Get the proposed stub name
599 public String
getStubName()
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());
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());
630 catch (IOException ioex
)
632 System
.err
.println("Output path not accessible");
633 ioex
.printStackTrace();
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
);
647 setClassPath(classpath
);
649 this.outputDirectory
= outputDirectory
;
650 this.noWrite
= noWrite
;
654 public boolean run(String
[] inputFiles
)
656 for (int i
= 0; i
< inputFiles
.length
; i
++)
659 Class c
= loadClass(inputFiles
[i
]);
662 String packag
= getPackageName().replace('.', '/');
663 File fw
= new File(outputDirectory
, packag
);
666 String stub
= generateStub();
667 String subName
= getStubName() + "_Stub.java";
669 // -keep overrides -nowrite for sources.
670 if (!noWrite
|| keep
)
675 OutputStream out
= new FileOutputStream(new File(fw
,
677 out
.write(stub
.getBytes());
681 if (!outputTie(fw
, c
))
684 catch (IOException ioex
)
686 System
.err
.println("Output path not accessible");
687 ioex
.printStackTrace();