diff options
Diffstat (limited to 'tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java')
-rw-r--r-- | tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java | 694 |
1 files changed, 694 insertions, 0 deletions
diff --git a/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java b/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java new file mode 100644 index 000000000..e9b7bff0b --- /dev/null +++ b/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java @@ -0,0 +1,694 @@ +/* SourceGiopRmicCompiler -- Central GIOP-based RMI stub and tie compiler class. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. +*/ + +package gnu.classpath.tools.rmic; + +import gnu.classpath.tools.rmic.AbstractMethodGenerator; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.TreeSet; + +/** + * Provides the extended rmic functionality to generate the POA - based classes + * for GIOP (javax.rmi.CORBA package). + * + * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org) + */ +public class SourceGiopRmicCompiler + extends Generator implements Comparator, RmicBackend +{ + /** The package name. */ + protected String packag; + + /** + * The "basic" name (normally, the interface name, unless several Remote - + * derived interfaces are implemented. + */ + protected String name; + + /** + * The name (without package) of the class, passed as the parameter. + */ + protected String implName; + + /** + * The proposed name for the stub. + */ + protected String stubName; + + /** + * The Remote's, implemented by this class. + */ + protected Collection implementedRemotes = new HashSet(); + + /** + * The extra classes that must be imported. + */ + protected Collection extraImports = new HashSet(); + + /** + * The methods we must implement. + */ + protected Collection methods = new HashSet(); + + /** + * The map of all code generator variables. + */ + public Properties vars = new Properties(); + + /** + * If this flag is set (true by default), the compiler generates the Servant + * based classes. If set to false, the compiler generates the old style + * ObjectImpl based classes. + */ + protected boolean poaMode = true; + + /** + * If this flag is set (true by default), the compiler emits warnings. + */ + protected boolean warnings = true; + + /** + * If this flag is set (false by default), the compiler does not + * write output files. + */ + protected boolean noWrite = false; + + /** + * If this flag is set (false by default), the compiler keeps source + * output files. For SourceGiopRmicCompiler this overrides + * -nowrite, since -nowrite doesn't apply to sources kept with + * -keep. + */ + protected boolean keep = false; + + /** + * Verbose output + */ + protected boolean verbose = false; + + /** + * Force mode - do not check the exceptions + */ + protected boolean force = false; + + /** + * The output directory for generated files. + */ + protected String outputDirectory; + + /** + * The class loader to load the class being compiled. + */ + ClassLoader classLoader; + + /** + * Clear data, preparing for the next compilation. + */ + public void reset() + { + packag = name = implName = stubName = null; + implementedRemotes.clear(); + extraImports.clear(); + methods.clear(); + vars.clear(); + } + + /** + * Set the class path (handle the -classpath key) + * + * @param classPath the class path to set. + */ + public void setClassPath(String classPath) + { + classLoader = Thread.currentThread().getContextClassLoader(); + StringTokenizer tok = new StringTokenizer(classPath, File.pathSeparator, + true); + ArrayList urls = new ArrayList(tok.countTokens()); + String s = null; + try + { + while (tok.hasMoreTokens()) + { + s = tok.nextToken(); + if (s.equals(File.pathSeparator)) + urls.add(new File(".").toURL()); + else + { + urls.add(new File(s).toURL()); + if (tok.hasMoreTokens()) + { + // Skip the separator. + tok.nextToken(); + // If the classpath ended with a separator, + // append the current directory. + if (! tok.hasMoreTokens()) + urls.add(new File(".").toURL()); + } + } + } + } + catch (MalformedURLException ex) + { + System.err.println("Malformed path '" + s + "' in classpath '" + + classPath + "'"); + System.exit(1); + } + URL[] u = new URL[urls.size()]; + for (int i = 0; i < u.length; i++) + { + u[i] = (URL) urls.get(i); + } + + classLoader = new URLClassLoader(u, classLoader); + } + + /** + * Loads the class with the given name (uses class path, if applicable) + * + * @param name the name of the class. + */ + public Class loadClass(String name) + { + ClassLoader loader = classLoader; + if (loader == null) + loader = Thread.currentThread().getContextClassLoader(); + try + { + return loader.loadClass(name); + } + catch (ClassNotFoundException e) + { + System.err.println(name+" not found on "+loader); + System.exit(1); + // Unreacheable code. + return null; + } + } + + /** + * Compile the given class (the instance of Remote), generating the stub and + * tie for it. + * + * @param remote + * the class to compile. + */ + public synchronized void compile(Class remote) + { + reset(); + String s; + + // Get the package. + s = remote.getName(); + int p = s.lastIndexOf('.'); + if (p < 0) + { + // Root package. + packag = ""; + implName = name = s; + } + else + { + packag = s.substring(0, p); + implName = name = s.substring(p + 1); + } + + name = convertStubName(name); + + stubName = name; + + vars.put("#name", name); + vars.put("#package", packag); + vars.put("#implName", implName); + + if (verbose) + System.out.println("Package " + packag + ", name " + name + " impl " + + implName); + + // Get the implemented remotes. + Class[] interfaces = remote.getInterfaces(); + + for (int i = 0; i < interfaces.length; i++) + { + if (Remote.class.isAssignableFrom(interfaces[i])) + { + if (! interfaces[i].equals(Remote.class)) + { + implementedRemotes.add(interfaces[i]); + } + } + } + + vars.put("#idList", getIdList(implementedRemotes)); + + // Collect and process methods. + Iterator iter = implementedRemotes.iterator(); + + while (iter.hasNext()) + { + Class c = (Class) iter.next(); + Method[] m = c.getMethods(); + + // Check if throws RemoteException. + for (int i = 0; i < m.length; i++) + { + Class[] exc = m[i].getExceptionTypes(); + boolean remEx = false; + + for (int j = 0; j < exc.length; j++) + { + if (RemoteException.class.isAssignableFrom(exc[j])) + { + remEx = true; + break; + } + } + if (! remEx && !force) + throw new CompilationError(m[i].getName() + ", defined in " + + c.getName() + + ", does not throw " + + RemoteException.class.getName()); + AbstractMethodGenerator mm = createMethodGenerator(m[i]); + methods.add(mm); + } + } + } + + /** + * Create the method generator for the given method. + * + * @param m the method + * + * @return the created method generator + */ + protected AbstractMethodGenerator createMethodGenerator(Method m) + { + return new MethodGenerator(m, this); + } + + /** + * Get the name of the given class. The class is added to imports, if not + * already present and not from java.lang and not from the current package. + * + * @param nameIt + * the class to name + * @return the name of class as it should appear in java language + */ + public String name(Class nameIt) + { + if (nameIt.isArray()) + { + // Mesure dimensions: + int dimension = 0; + Class finalComponent = nameIt; + while (finalComponent.isArray()) + { + finalComponent = finalComponent.getComponentType(); + dimension++; + } + + StringBuffer brackets = new StringBuffer(); + + for (int i = 0; i < dimension; i++) + { + brackets.append("[]"); + } + + return name(finalComponent) + " " + brackets; + } + else + { + String n = nameIt.getName(); + if (! nameIt.isArray() && ! nameIt.isPrimitive()) + if (! n.startsWith("java.lang") + && ! (packag != null && n.startsWith(packag))) + extraImports.add(n); + + int p = n.lastIndexOf('.'); + if (p < 0) + return n; + else + return n.substring(p + 1); + } + } + + /** + * Get the RMI-style repository Id for the given class. + * + * @param c + * the interface, for that the repository Id must be created. + * @return the repository id + */ + public String getId(Class c) + { + return "RMI:" + c.getName() + ":0000000000000000"; + } + + /** + * Get repository Id string array declaration. + * + * @param remotes + * the collection of interfaces + * @return the fully formatted string array. + */ + public String getIdList(Collection remotes) + { + StringBuffer b = new StringBuffer(); + + // Keep the Ids sorted, ensuring, that the same order will be preserved + // between compilations. + TreeSet sortedIds = new TreeSet(); + + Iterator iter = remotes.iterator(); + while (iter.hasNext()) + { + sortedIds.add(getId((Class) iter.next())); + } + + iter = sortedIds.iterator(); + while (iter.hasNext()) + { + b.append(" \"" + iter.next() + "\""); + if (iter.hasNext()) + b.append(", \n"); + } + return b.toString(); + } + + /** + * Generate stub. Can only be called from {@link #compile}. + * + * @return the string, containing the text of the generated stub. + */ + public String generateStub() + { + String template = getResource("Stub.jav"); + + // Generate methods. + StringBuffer b = new StringBuffer(); + Iterator iter = methods.iterator(); + while (iter.hasNext()) + { + AbstractMethodGenerator m = (AbstractMethodGenerator) iter.next(); + b.append(m.generateStubMethod()); + } + + vars.put("#stub_methods", b.toString()); + vars.put("#imports", getImportStatements()); + vars.put("#interfaces", getAllInterfaces()); + + String output = replaceAll(template, vars); + return output; + } + + /** + * Get the list of all interfaces, implemented by the class, that are + * derived from Remote. + * + * @return the string - all interfaces. + */ + public String getAllInterfaces() + { + StringBuffer b = new StringBuffer(); + Iterator iter = implementedRemotes.iterator(); + + while (iter.hasNext()) + { + b.append(name((Class) iter.next())); + if (iter.hasNext()) + b.append(", "); + } + + return b.toString(); + } + + /** + * Generate Tie. Can only be called from {@link #compile}. + * + * @return the string, containing the text of the generated Tie. + */ + public String generateTie() + { + String template; + if (poaMode) + template = getResource("Tie.jav"); + else + template = getResource("ImplTie.jav"); + + // Generate methods. + HashFinder hashFinder = new HashFinder(); + + // Find the hash character position: + Iterator iter = methods.iterator(); + String[] names = new String[methods.size()]; + int p = 0; + + for (int i = 0; i < names.length; i++) + names[i] = ((MethodGenerator) iter.next()).getGiopMethodName(); + + int hashCharPosition = hashFinder.findHashCharPosition(names); + + iter = methods.iterator(); + while (iter.hasNext()) + ((MethodGenerator) iter.next()).hashCharPosition = hashCharPosition; + + vars.put("#hashCharPos", Integer.toString(hashCharPosition)); + + ArrayList sortedMethods = new ArrayList(methods); + Collections.sort(sortedMethods, this); + + iter = sortedMethods.iterator(); + + StringBuffer b = new StringBuffer(); + + MethodGenerator prev = null; + + while (iter.hasNext()) + { + MethodGenerator m = (MethodGenerator) iter.next(); + m.previous = prev; + m.hashCharPosition = hashCharPosition; + prev = m; + b.append(m.generateTieMethod()); + } + + vars.put("#tie_methods", b.toString()); + + vars.put("#imports", getImportStatements()); + + String output = replaceAll(template, vars); + return output; + } + + public int compare(Object a, Object b) + { + MethodGenerator g1 = (MethodGenerator) a; + MethodGenerator g2 = (MethodGenerator) b; + + return g1.getHashChar() - g2.getHashChar(); + } + + /** + * Import the extra classes, used as the method parameters and return values. + * + * @return the additional import block. + */ + protected String getImportStatements() + { + TreeSet imp = new TreeSet(); + + Iterator it = extraImports.iterator(); + while (it.hasNext()) + { + String ic = it.next().toString(); + imp.add("import " + ic + ";\n"); + } + + StringBuffer b = new StringBuffer(); + it = imp.iterator(); + + while (it.hasNext()) + { + b.append(it.next()); + } + return b.toString(); + } + + /** + * If this flag is set (true by default), the compiler generates the Servant + * based classes. If set to false, the compiler generates the old style + * ObjectImpl based classes. + */ + public void setPoaMode(boolean mode) + { + poaMode = mode; + } + + /** + * Set the verbose output mode (false by default) + * + * @param isVerbose the verbose output mode + */ + public void setVerbose(boolean isVerbose) + { + verbose = isVerbose; + } + + /** + * If this flag is set (true by default), the compiler emits warnings. + */ + public void setWarnings(boolean warn) + { + warnings = warn; + } + + /** + * Set the error ignore mode. + */ + public void setForce(boolean isforce) + { + force = isforce; + } + + /** + * Get the package name. + */ + public String getPackageName() + { + return packag; + } + + /** + * Get the proposed stub name + */ + public String getStubName() + { + return stubName; + } + + /** + * Additional processing of the stub name. + */ + public String convertStubName(String name) + { + // Drop the Impl suffix, if one exists. + if (name.endsWith("Impl")) + return name.substring(0, name.length() - "Impl".length()); + else + return name; + } + + /** + * Assumes that output directory is already created. + */ + protected boolean outputTie(File fw, Class c) + { + try + { + String tie = generateTie(); + String tieName = "_" + name(c) + "_Tie.java"; + + OutputStream out = new FileOutputStream(new File(fw, tieName)); + out.write(tie.getBytes()); + out.close(); + } + catch (IOException ioex) + { + System.err.println("Output path not accessible"); + ioex.printStackTrace(); + return false; + } + return true; + } + + public void setup(boolean keep, boolean need11Stubs, boolean need12Stubs, + boolean iiop, boolean poa, boolean debug, boolean warnings, + boolean noWrite, boolean verbose, boolean force, String classpath, + String bootclasspath, String extdirs, String outputDirectory) + { + setWarnings(warnings); + setVerbose(verbose); + setForce(force); + setClassPath(classpath); + setPoaMode(poa); + this.outputDirectory = outputDirectory; + this.noWrite = noWrite; + this.keep = keep; + } + + public boolean run(String[] inputFiles) + { + for (int i = 0; i < inputFiles.length; i++) + { + reset(); + Class c = loadClass(inputFiles[i]); + + compile(c); + String packag = getPackageName().replace('.', '/'); + File fw = new File(outputDirectory, packag); + + // Generate stub. + String stub = generateStub(); + String subName = getStubName() + "_Stub.java"; + + // -keep overrides -nowrite for sources. + if (!noWrite || keep) + { + try + { + fw.mkdirs(); + OutputStream out = new FileOutputStream(new File(fw, + subName)); + out.write(stub.getBytes()); + out.close(); + + // Generate tie + if (!outputTie(fw, c)) + return false; + } + catch (IOException ioex) + { + System.err.println("Output path not accessible"); + ioex.printStackTrace(); + return false; + } + } + } + return true; + } +} |