| /* RMIC.java -- | |
| Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006 | |
| Free Software Foundation, Inc. | |
| 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. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package gnu.java.rmi.rmic; | |
| import gnu.java.rmi.server.RMIHashes; | |
| import java.io.File; | |
| import java.io.FileWriter; | |
| import java.io.IOException; | |
| import java.io.PrintWriter; | |
| 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.Arrays; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Set; | |
| import java.util.StringTokenizer; | |
| public class RMIC | |
| { | |
| private String[] args; | |
| private int next; | |
| private Exception exception; | |
| private boolean keep = false; | |
| private boolean need11Stubs = true; | |
| private boolean need12Stubs = true; | |
| private boolean compile = true; | |
| private boolean verbose; | |
| private String destination; | |
| private PrintWriter out; | |
| private TabbedWriter ctrl; | |
| private Class clazz; | |
| private String classname; | |
| private String fullclassname; | |
| private String fullstubname; | |
| private String fullskelname; | |
| private MethodRef[] remotemethods; | |
| private String stubname; | |
| private String skelname; | |
| private ClassLoader loader; | |
| private String classpath; | |
| private int errorCount = 0; | |
| private List mRemoteInterfaces; | |
| public RMIC(String[] a) | |
| { | |
| args = a; | |
| } | |
| public static void main(String[] args) | |
| { | |
| RMIC r = new RMIC(args); | |
| if (r.run() == false) | |
| { | |
| Exception e = r.getException(); | |
| if (e != null) | |
| e.printStackTrace(); | |
| else | |
| System.exit(1); | |
| } | |
| } | |
| public boolean run() | |
| { | |
| parseOptions(); | |
| if (next >= args.length) | |
| error("no class names found"); | |
| for (int i = next; i < args.length; i++) | |
| { | |
| try | |
| { | |
| if (verbose) | |
| System.out.println("[Processing class " + args[i] + ".class]"); | |
| processClass(args[i].replace(File.separatorChar, '.')); | |
| } | |
| catch (Exception e) | |
| { | |
| exception = e; | |
| return (false); | |
| } | |
| } | |
| return (true); | |
| } | |
| private boolean processClass(String cls) throws Exception | |
| { | |
| // reset class specific vars | |
| clazz = null; | |
| classname = null; | |
| fullclassname = null; | |
| remotemethods = null; | |
| stubname = null; | |
| fullstubname = null; | |
| skelname = null; | |
| fullskelname = null; | |
| mRemoteInterfaces = new ArrayList(); | |
| errorCount = 0; | |
| analyzeClass(cls); | |
| if (errorCount > 0) | |
| System.exit(1); | |
| generateStub(); | |
| if (need11Stubs) | |
| generateSkel(); | |
| if (compile) | |
| { | |
| compile(fullstubname); | |
| if (need11Stubs) | |
| compile(fullskelname); | |
| } | |
| if (! keep) | |
| { | |
| (new File(fullstubname)).delete(); | |
| if (need11Stubs) | |
| (new File(fullskelname)).delete(); | |
| } | |
| return (true); | |
| } | |
| private void analyzeClass(String cname) throws Exception | |
| { | |
| if (verbose) | |
| System.out.println("[analyze class " + cname + "]"); | |
| int p = cname.lastIndexOf('.'); | |
| if (p != -1) | |
| classname = cname.substring(p + 1); | |
| else | |
| classname = cname; | |
| fullclassname = cname; | |
| findClass(); | |
| findRemoteMethods(); | |
| } | |
| public Exception getException() | |
| { | |
| return (exception); | |
| } | |
| private void findClass() throws ClassNotFoundException | |
| { | |
| try | |
| { | |
| ClassLoader cl = (loader == null | |
| ? ClassLoader.getSystemClassLoader() | |
| : loader); | |
| clazz = Class.forName(fullclassname, false, cl); | |
| } | |
| catch (ClassNotFoundException cnfe) | |
| { | |
| System.err.println(fullclassname + " not found in " + classpath); | |
| throw new RuntimeException(cnfe); | |
| } | |
| if (! Remote.class.isAssignableFrom(clazz)) | |
| { | |
| logError("Class " + clazz.getName() + " is not a remote object. " | |
| + "It does not implement an interface that is a " | |
| + "java.rmi.Remote-interface."); | |
| throw new RuntimeException | |
| ("Class " + clazz.getName() + " is not a remote object. " | |
| + "It does not implement an interface that is a " | |
| + "java.rmi.Remote-interface."); | |
| } | |
| } | |
| private void generateStub() throws IOException | |
| { | |
| stubname = fullclassname + "_Stub"; | |
| String stubclassname = classname + "_Stub"; | |
| fullstubname = (destination == null ? "" : destination + File.separator) | |
| + stubname.replace('.', File.separatorChar) + ".java"; | |
| File file = new File(fullstubname); | |
| if (file.getParentFile() != null) | |
| file.getParentFile().mkdirs(); | |
| ctrl = | |
| new TabbedWriter(new FileWriter(file)); | |
| out = new PrintWriter(ctrl); | |
| if (verbose) | |
| System.out.println("[Generating class " + stubname + ".java]"); | |
| out.println("// Stub class generated by rmic - DO NOT EDIT!"); | |
| out.println(); | |
| if (fullclassname != classname) | |
| { | |
| String pname = | |
| fullclassname.substring(0, fullclassname.lastIndexOf('.')); | |
| out.println("package " + pname + ";"); | |
| out.println(); | |
| } | |
| out.print("public final class " + stubclassname); | |
| ctrl.indent(); | |
| out.println("extends java.rmi.server.RemoteStub"); | |
| // Output interfaces we implement | |
| out.print("implements "); | |
| Iterator iter = mRemoteInterfaces.iterator(); | |
| while (iter.hasNext()) | |
| { | |
| /* Print remote interface. */ | |
| Class iface = (Class) iter.next(); | |
| out.print(iface.getName()); | |
| /* Print ", " if more remote interfaces follow. */ | |
| if (iter.hasNext()) | |
| out.print(", "); | |
| } | |
| ctrl.unindent(); | |
| out.print("{"); | |
| ctrl.indent(); | |
| // UID | |
| if (need12Stubs) | |
| { | |
| out.println("private static final long serialVersionUID = 2L;"); | |
| out.println(); | |
| } | |
| // InterfaceHash - don't know how to calculate this - XXX | |
| if (need11Stubs) | |
| { | |
| out.println("private static final long interfaceHash = " | |
| + RMIHashes.getInterfaceHash(clazz) + "L;"); | |
| out.println(); | |
| if (need12Stubs) | |
| { | |
| out.println("private static boolean useNewInvoke;"); | |
| out.println(); | |
| } | |
| // Operation table | |
| out.print("private static final java.rmi.server.Operation[] operations = {"); | |
| ctrl.indent(); | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| out.print("new java.rmi.server.Operation(\""); | |
| out.print(getPrettyName(m.getReturnType()) + " "); | |
| out.print(m.getName() + "("); | |
| // Output signature | |
| Class[] sig = m.getParameterTypes(); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print(getPrettyName(sig[j])); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.print(")\")"); | |
| if (i + 1 < remotemethods.length) | |
| out.println(","); | |
| } | |
| ctrl.unindent(); | |
| out.println("};"); | |
| out.println(); | |
| } | |
| // Set of method references. | |
| if (need12Stubs) | |
| { | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| out.println("private static java.lang.reflect.Method $method_" | |
| + m.getName() + "_" + i + ";"); | |
| } | |
| // Initialize the methods references. | |
| out.println(); | |
| out.print("static {"); | |
| ctrl.indent(); | |
| out.print("try {"); | |
| ctrl.indent(); | |
| if (need11Stubs) | |
| { | |
| out.println("java.rmi.server.RemoteRef.class.getMethod(\"invoke\", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });"); | |
| out.println("useNewInvoke = true;"); | |
| } | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| out.print("$method_" + m.getName() + "_" + i + " = "); | |
| out.print(m.getDeclaringClass().getName() + ".class.getMethod(\"" | |
| + m.getName() + "\""); | |
| out.print(", new java.lang.Class[] {"); | |
| // Output signature | |
| Class[] sig = m.getParameterTypes(); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print(getPrettyName(sig[j]) + ".class"); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.println("});"); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("catch (java.lang.NoSuchMethodException e) {"); | |
| ctrl.indent(); | |
| if (need11Stubs) | |
| out.print("useNewInvoke = false;"); | |
| else | |
| out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.println(); | |
| } | |
| // Constructors | |
| if (need11Stubs) | |
| { | |
| out.print("public " + stubclassname + "() {"); | |
| ctrl.indent(); | |
| out.print("super();"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| } | |
| if (need12Stubs) | |
| { | |
| out.print("public " + stubclassname | |
| + "(java.rmi.server.RemoteRef ref) {"); | |
| ctrl.indent(); | |
| out.print("super(ref);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| } | |
| // Method implementations | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| Class[] sig = m.getParameterTypes(); | |
| Class returntype = m.getReturnType(); | |
| Class[] except = sortExceptions(m.getExceptionTypes()); | |
| out.println(); | |
| out.print("public " + getPrettyName(returntype) + " " + m.getName() | |
| + "("); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print(getPrettyName(sig[j])); | |
| out.print(" $param_" + j); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.print(") "); | |
| out.print("throws "); | |
| for (int j = 0; j < except.length; j++) | |
| { | |
| out.print(getPrettyName(except[j])); | |
| if (j + 1 < except.length) | |
| out.print(", "); | |
| } | |
| out.print(" {"); | |
| ctrl.indent(); | |
| out.print("try {"); | |
| ctrl.indent(); | |
| if (need12Stubs) | |
| { | |
| if (need11Stubs) | |
| { | |
| out.print("if (useNewInvoke) {"); | |
| ctrl.indent(); | |
| } | |
| if (returntype != Void.TYPE) | |
| out.print("java.lang.Object $result = "); | |
| out.print("ref.invoke(this, $method_" + m.getName() + "_" + i | |
| + ", "); | |
| if (sig.length == 0) | |
| out.print("null, "); | |
| else | |
| { | |
| out.print("new java.lang.Object[] {"); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| if (sig[j] == Boolean.TYPE) | |
| out.print("new java.lang.Boolean($param_" + j + ")"); | |
| else if (sig[j] == Byte.TYPE) | |
| out.print("new java.lang.Byte($param_" + j + ")"); | |
| else if (sig[j] == Character.TYPE) | |
| out.print("new java.lang.Character($param_" + j + ")"); | |
| else if (sig[j] == Short.TYPE) | |
| out.print("new java.lang.Short($param_" + j + ")"); | |
| else if (sig[j] == Integer.TYPE) | |
| out.print("new java.lang.Integer($param_" + j + ")"); | |
| else if (sig[j] == Long.TYPE) | |
| out.print("new java.lang.Long($param_" + j + ")"); | |
| else if (sig[j] == Float.TYPE) | |
| out.print("new java.lang.Float($param_" + j + ")"); | |
| else if (sig[j] == Double.TYPE) | |
| out.print("new java.lang.Double($param_" + j + ")"); | |
| else | |
| out.print("$param_" + j); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.print("}, "); | |
| } | |
| out.print(Long.toString(remotemethods[i].hash) + "L"); | |
| out.print(");"); | |
| if (returntype != Void.TYPE) | |
| { | |
| out.println(); | |
| out.print("return ("); | |
| if (returntype == Boolean.TYPE) | |
| out.print("((java.lang.Boolean)$result).booleanValue()"); | |
| else if (returntype == Byte.TYPE) | |
| out.print("((java.lang.Byte)$result).byteValue()"); | |
| else if (returntype == Character.TYPE) | |
| out.print("((java.lang.Character)$result).charValue()"); | |
| else if (returntype == Short.TYPE) | |
| out.print("((java.lang.Short)$result).shortValue()"); | |
| else if (returntype == Integer.TYPE) | |
| out.print("((java.lang.Integer)$result).intValue()"); | |
| else if (returntype == Long.TYPE) | |
| out.print("((java.lang.Long)$result).longValue()"); | |
| else if (returntype == Float.TYPE) | |
| out.print("((java.lang.Float)$result).floatValue()"); | |
| else if (returntype == Double.TYPE) | |
| out.print("((java.lang.Double)$result).doubleValue()"); | |
| else | |
| out.print("(" + getPrettyName(returntype) + ")$result"); | |
| out.print(");"); | |
| } | |
| if (need11Stubs) | |
| { | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("else {"); | |
| ctrl.indent(); | |
| } | |
| } | |
| if (need11Stubs) | |
| { | |
| out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, " | |
| + i + ", interfaceHash);"); | |
| out.print("try {"); | |
| ctrl.indent(); | |
| out.print("java.io.ObjectOutput out = call.getOutputStream();"); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.println(); | |
| if (sig[j] == Boolean.TYPE) | |
| out.print("out.writeBoolean("); | |
| else if (sig[j] == Byte.TYPE) | |
| out.print("out.writeByte("); | |
| else if (sig[j] == Character.TYPE) | |
| out.print("out.writeChar("); | |
| else if (sig[j] == Short.TYPE) | |
| out.print("out.writeShort("); | |
| else if (sig[j] == Integer.TYPE) | |
| out.print("out.writeInt("); | |
| else if (sig[j] == Long.TYPE) | |
| out.print("out.writeLong("); | |
| else if (sig[j] == Float.TYPE) | |
| out.print("out.writeFloat("); | |
| else if (sig[j] == Double.TYPE) | |
| out.print("out.writeDouble("); | |
| else | |
| out.print("out.writeObject("); | |
| out.print("$param_" + j + ");"); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("catch (java.io.IOException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.println("ref.invoke(call);"); | |
| if (returntype != Void.TYPE) | |
| out.println(getPrettyName(returntype) + " $result;"); | |
| out.print("try {"); | |
| ctrl.indent(); | |
| out.print("java.io.ObjectInput in = call.getInputStream();"); | |
| boolean needcastcheck = false; | |
| if (returntype != Void.TYPE) | |
| { | |
| out.println(); | |
| out.print("$result = "); | |
| if (returntype == Boolean.TYPE) | |
| out.print("in.readBoolean();"); | |
| else if (returntype == Byte.TYPE) | |
| out.print("in.readByte();"); | |
| else if (returntype == Character.TYPE) | |
| out.print("in.readChar();"); | |
| else if (returntype == Short.TYPE) | |
| out.print("in.readShort();"); | |
| else if (returntype == Integer.TYPE) | |
| out.print("in.readInt();"); | |
| else if (returntype == Long.TYPE) | |
| out.print("in.readLong();"); | |
| else if (returntype == Float.TYPE) | |
| out.print("in.readFloat();"); | |
| else if (returntype == Double.TYPE) | |
| out.print("in.readDouble();"); | |
| else | |
| { | |
| if (returntype != Object.class) | |
| out.print("(" + getPrettyName(returntype) + ")"); | |
| else | |
| needcastcheck = true; | |
| out.print("in.readObject();"); | |
| } | |
| out.println(); | |
| out.print("return ($result);"); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("catch (java.io.IOException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| if (needcastcheck) | |
| { | |
| out.print("catch (java.lang.ClassNotFoundException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| } | |
| out.print("finally {"); | |
| ctrl.indent(); | |
| out.print("ref.done(call);"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| if (need12Stubs && need11Stubs) | |
| { | |
| ctrl.unindent(); | |
| out.print("}"); | |
| } | |
| } | |
| ctrl.unindent(); | |
| out.print("}"); | |
| boolean needgeneral = true; | |
| for (int j = 0; j < except.length; j++) | |
| { | |
| out.println(); | |
| out.print("catch (" + getPrettyName(except[j]) + " e) {"); | |
| ctrl.indent(); | |
| out.print("throw e;"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| if (except[j] == Exception.class) | |
| needgeneral = false; | |
| } | |
| if (needgeneral) | |
| { | |
| out.println(); | |
| out.print("catch (java.lang.Exception e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| } | |
| ctrl.unindent(); | |
| out.print("}"); | |
| out.println(); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.close(); | |
| } | |
| private void generateSkel() throws IOException | |
| { | |
| skelname = fullclassname + "_Skel"; | |
| String skelclassname = classname + "_Skel"; | |
| fullskelname = (destination == null ? "" : destination + File.separator) | |
| + skelname.replace('.', File.separatorChar) + ".java"; | |
| File file = new File(fullskelname); | |
| if (file.getParentFile() != null) | |
| file.getParentFile().mkdirs(); | |
| ctrl = | |
| new TabbedWriter(new FileWriter(file)); | |
| out = new PrintWriter(ctrl); | |
| if (verbose) | |
| System.out.println("[Generating class " + skelname + ".java]"); | |
| out.println("// Skel class generated by rmic - DO NOT EDIT!"); | |
| out.println(); | |
| if (fullclassname != classname) | |
| { | |
| String pname = | |
| fullclassname.substring(0, fullclassname.lastIndexOf('.')); | |
| out.println("package " + pname + ";"); | |
| out.println(); | |
| } | |
| out.print("public final class " + skelclassname); | |
| ctrl.indent(); | |
| // Output interfaces we implement | |
| out.print("implements java.rmi.server.Skeleton"); | |
| ctrl.unindent(); | |
| out.print("{"); | |
| ctrl.indent(); | |
| // Interface hash - don't know how to calculate this - XXX | |
| out.println("private static final long interfaceHash = " | |
| + RMIHashes.getInterfaceHash(clazz) + "L;"); | |
| out.println(); | |
| // Operation table | |
| out.print("private static final java.rmi.server.Operation[] operations = {"); | |
| ctrl.indent(); | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| out.print("new java.rmi.server.Operation(\""); | |
| out.print(getPrettyName(m.getReturnType()) + " "); | |
| out.print(m.getName() + "("); | |
| // Output signature | |
| Class[] sig = m.getParameterTypes(); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print(getPrettyName(sig[j])); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.print("\")"); | |
| if (i + 1 < remotemethods.length) | |
| out.println(","); | |
| } | |
| ctrl.unindent(); | |
| out.println("};"); | |
| out.println(); | |
| // getOperations method | |
| out.print("public java.rmi.server.Operation[] getOperations() {"); | |
| ctrl.indent(); | |
| out.print("return ((java.rmi.server.Operation[]) operations.clone());"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.println(); | |
| // Dispatch method | |
| out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {"); | |
| ctrl.indent(); | |
| out.print("if (opnum < 0) {"); | |
| ctrl.indent(); | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| out.print("if (hash == " + Long.toString(remotemethods[i].hash) | |
| + "L) {"); | |
| ctrl.indent(); | |
| out.print("opnum = " + i + ";"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("else "); | |
| } | |
| out.print("{"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("else if (hash != interfaceHash) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.println(); | |
| out.println(fullclassname + " server = (" + fullclassname + ")obj;"); | |
| out.println("switch (opnum) {"); | |
| // Method dispatch | |
| for (int i = 0; i < remotemethods.length; i++) | |
| { | |
| Method m = remotemethods[i].meth; | |
| out.println("case " + i + ":"); | |
| out.print("{"); | |
| ctrl.indent(); | |
| Class[] sig = m.getParameterTypes(); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print(getPrettyName(sig[j])); | |
| out.println(" $param_" + j + ";"); | |
| } | |
| out.print("try {"); | |
| boolean needcastcheck = false; | |
| ctrl.indent(); | |
| out.println("java.io.ObjectInput in = call.getInputStream();"); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print("$param_" + j + " = "); | |
| if (sig[j] == Boolean.TYPE) | |
| out.print("in.readBoolean();"); | |
| else if (sig[j] == Byte.TYPE) | |
| out.print("in.readByte();"); | |
| else if (sig[j] == Character.TYPE) | |
| out.print("in.readChar();"); | |
| else if (sig[j] == Short.TYPE) | |
| out.print("in.readShort();"); | |
| else if (sig[j] == Integer.TYPE) | |
| out.print("in.readInt();"); | |
| else if (sig[j] == Long.TYPE) | |
| out.print("in.readLong();"); | |
| else if (sig[j] == Float.TYPE) | |
| out.print("in.readFloat();"); | |
| else if (sig[j] == Double.TYPE) | |
| out.print("in.readDouble();"); | |
| else | |
| { | |
| if (sig[j] != Object.class) | |
| { | |
| out.print("(" + getPrettyName(sig[j]) + ")"); | |
| needcastcheck = true; | |
| } | |
| out.print("in.readObject();"); | |
| } | |
| out.println(); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("catch (java.io.IOException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| if (needcastcheck) | |
| { | |
| out.print("catch (java.lang.ClassCastException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| } | |
| out.print("finally {"); | |
| ctrl.indent(); | |
| out.print("call.releaseInputStream();"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| Class returntype = m.getReturnType(); | |
| if (returntype != Void.TYPE) | |
| out.print(getPrettyName(returntype) + " $result = "); | |
| out.print("server." + m.getName() + "("); | |
| for (int j = 0; j < sig.length; j++) | |
| { | |
| out.print("$param_" + j); | |
| if (j + 1 < sig.length) | |
| out.print(", "); | |
| } | |
| out.println(");"); | |
| out.print("try {"); | |
| ctrl.indent(); | |
| out.print("java.io.ObjectOutput out = call.getResultStream(true);"); | |
| if (returntype != Void.TYPE) | |
| { | |
| out.println(); | |
| if (returntype == Boolean.TYPE) | |
| out.print("out.writeBoolean($result);"); | |
| else if (returntype == Byte.TYPE) | |
| out.print("out.writeByte($result);"); | |
| else if (returntype == Character.TYPE) | |
| out.print("out.writeChar($result);"); | |
| else if (returntype == Short.TYPE) | |
| out.print("out.writeShort($result);"); | |
| else if (returntype == Integer.TYPE) | |
| out.print("out.writeInt($result);"); | |
| else if (returntype == Long.TYPE) | |
| out.print("out.writeLong($result);"); | |
| else if (returntype == Float.TYPE) | |
| out.print("out.writeFloat($result);"); | |
| else if (returntype == Double.TYPE) | |
| out.print("out.writeDouble($result);"); | |
| else | |
| out.print("out.writeObject($result);"); | |
| } | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("catch (java.io.IOException e) {"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.print("break;"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.println(); | |
| } | |
| out.print("default:"); | |
| ctrl.indent(); | |
| out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| ctrl.unindent(); | |
| out.print("}"); | |
| ctrl.unindent(); | |
| out.println("}"); | |
| out.close(); | |
| } | |
| private void compile(String name) throws Exception | |
| { | |
| Compiler comp = Compiler.getInstance(); | |
| if (verbose) | |
| System.out.println("[Compiling class " + name + "]"); | |
| comp.setDestination(destination); | |
| if (classpath != null) | |
| comp.setClasspath(classpath); | |
| comp.compile(name); | |
| } | |
| private static String getPrettyName(Class cls) | |
| { | |
| StringBuffer str = new StringBuffer(); | |
| for (int count = 0;; count++) | |
| { | |
| if (! cls.isArray()) | |
| { | |
| str.append(cls.getName()); | |
| for (; count > 0; count--) | |
| str.append("[]"); | |
| return (str.toString()); | |
| } | |
| cls = cls.getComponentType(); | |
| } | |
| } | |
| /** | |
| * Sort exceptions so the most general go last. | |
| */ | |
| private Class[] sortExceptions(Class[] except) | |
| { | |
| for (int i = 0; i < except.length; i++) | |
| { | |
| for (int j = i + 1; j < except.length; j++) | |
| { | |
| if (except[i].isAssignableFrom(except[j])) | |
| { | |
| Class tmp = except[i]; | |
| except[i] = except[j]; | |
| except[j] = tmp; | |
| } | |
| } | |
| } | |
| return (except); | |
| } | |
| /** | |
| * Process the options until we find the first argument. | |
| */ | |
| private void parseOptions() | |
| { | |
| for (;;) | |
| { | |
| if (next >= args.length || args[next].charAt(0) != '-') | |
| break; | |
| String arg = args[next]; | |
| next++; | |
| // Accept `--' options if they look long enough. | |
| if (arg.length() > 3 && arg.charAt(0) == '-' && arg.charAt(1) == '-') | |
| arg = arg.substring(1); | |
| if (arg.equals("-keep")) | |
| keep = true; | |
| else if (arg.equals("-keepgenerated")) | |
| keep = true; | |
| else if (arg.equals("-v1.1")) | |
| { | |
| need11Stubs = true; | |
| need12Stubs = false; | |
| } | |
| else if (arg.equals("-vcompat")) | |
| { | |
| need11Stubs = true; | |
| need12Stubs = true; | |
| } | |
| else if (arg.equals("-v1.2")) | |
| { | |
| need11Stubs = false; | |
| need12Stubs = true; | |
| } | |
| else if (arg.equals("-g")) | |
| { | |
| } | |
| else if (arg.equals("-depend")) | |
| { | |
| } | |
| else if (arg.equals("-nowarn")) | |
| { | |
| } | |
| else if (arg.equals("-verbose")) | |
| verbose = true; | |
| else if (arg.equals("-nocompile")) | |
| compile = false; | |
| else if (arg.equals("-classpath")) | |
| { | |
| classpath = args[next]; | |
| next++; | |
| StringTokenizer st = | |
| new StringTokenizer(classpath, File.pathSeparator); | |
| URL[] u = new URL[st.countTokens()]; | |
| for (int i = 0; i < u.length; i++) | |
| { | |
| String path = st.nextToken(); | |
| File f = new File(path); | |
| try | |
| { | |
| u[i] = f.toURL(); | |
| } | |
| catch (MalformedURLException mue) | |
| { | |
| error("malformed classpath component " + path); | |
| } | |
| } | |
| loader = new URLClassLoader(u); | |
| } | |
| else if (arg.equals("-help")) | |
| usage(); | |
| else if (arg.equals("-version")) | |
| { | |
| System.out.println("rmic (" + System.getProperty("java.vm.name") | |
| + ") " + System.getProperty("java.vm.version")); | |
| System.out.println(); | |
| System.out.println("Copyright 2006 Free Software Foundation, Inc."); | |
| System.out.println("This is free software; see the source for copying conditions. There is NO"); | |
| System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); | |
| System.exit(0); | |
| } | |
| else if (arg.equals("-d")) | |
| { | |
| destination = args[next]; | |
| next++; | |
| } | |
| else if (arg.charAt(1) == 'J') | |
| { | |
| } | |
| else | |
| error("unrecognized option `" + arg + "'"); | |
| } | |
| } | |
| private void findRemoteMethods() { | |
| List rmeths = new ArrayList(); | |
| for (Class cur = clazz; cur != null; cur = cur.getSuperclass()) | |
| { | |
| Class[] interfaces = cur.getInterfaces(); | |
| for (int i = 0; i < interfaces.length; i++) | |
| { | |
| if (java.rmi.Remote.class.isAssignableFrom(interfaces[i])) | |
| { | |
| Class remoteInterface = interfaces[i]; | |
| if (verbose) | |
| System.out.println | |
| ("[implements " + remoteInterface.getName() + "]"); | |
| // check if the methods declare RemoteExceptions | |
| Method[] meths = remoteInterface.getMethods(); | |
| for (int j = 0; j < meths.length; j++) | |
| { | |
| Method m = meths[j]; | |
| Class[] exs = m.getExceptionTypes(); | |
| boolean throwsRemote = false; | |
| for (int k = 0; k < exs.length; k++) | |
| { | |
| if (exs[k].isAssignableFrom(RemoteException.class)) | |
| throwsRemote = true; | |
| } | |
| if (! throwsRemote) | |
| { | |
| logError("Method " + m | |
| + " does not throw a RemoteException"); | |
| continue; | |
| } | |
| rmeths.add(m); | |
| } | |
| mRemoteInterfaces.add(remoteInterface); | |
| } | |
| } | |
| } | |
| // intersect exceptions for doubly inherited methods | |
| boolean[] skip = new boolean[rmeths.size()]; | |
| for (int i = 0; i < skip.length; i++) | |
| skip[i] = false; | |
| List methrefs = new ArrayList(); | |
| for (int i = 0; i < rmeths.size(); i++) | |
| { | |
| if (skip[i]) continue; | |
| Method current = (Method) rmeths.get(i); | |
| MethodRef ref = new MethodRef(current); | |
| for (int j = i+1; j < rmeths.size(); j++) | |
| { | |
| Method other = (Method) rmeths.get(j); | |
| if (ref.isMatch(other)) | |
| { | |
| ref.intersectExceptions(other); | |
| skip[j] = true; | |
| } | |
| } | |
| methrefs.add(ref); | |
| } | |
| // Convert into a MethodRef array and sort them | |
| remotemethods = (MethodRef[]) | |
| methrefs.toArray(new MethodRef[methrefs.size()]); | |
| Arrays.sort(remotemethods); | |
| } | |
| /** | |
| * Prints an error to System.err and increases the error count. | |
| * @param theError | |
| */ | |
| private void logError(String theError) | |
| { | |
| errorCount++; | |
| System.err.println("error:" + theError); | |
| } | |
| private static void error(String message) | |
| { | |
| System.err.println("rmic: " + message); | |
| System.err.println("Try `rmic --help' for more information."); | |
| System.exit(1); | |
| } | |
| private static void usage() | |
| { | |
| System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n" | |
| + " -keep Don't delete any intermediate files\n" | |
| + " -keepgenerated Same as -keep\n" | |
| + " -v1.1 Java 1.1 style stubs only\n" | |
| + " -vcompat Java 1.1 & Java 1.2 stubs\n" | |
| + " -v1.2 Java 1.2 style stubs only\n" | |
| + " -g * Generated debugging information\n" | |
| + " -depend * Recompile out-of-date files\n" | |
| + " -nowarn * Suppress warning messages\n" | |
| + " -nocompile Don't compile the generated files\n" | |
| + " -verbose Output what's going on\n" | |
| + " -classpath <path> * Use given path as classpath\n" | |
| + " -d <directory> Specify where to place generated classes\n" | |
| + " -J<flag> * Pass flag to Java\n" | |
| + " -help Print this help, then exit\n" | |
| + " -version Print version number, then exit\n" + "\n" | |
| + " * Option currently ignored\n" | |
| + "Long options can be used with `--option' form as well."); | |
| System.exit(0); | |
| } | |
| private static class MethodRef | |
| implements Comparable | |
| { | |
| Method meth; | |
| long hash; | |
| List exceptions; | |
| private String sig; | |
| MethodRef(Method m) | |
| { | |
| meth = m; | |
| sig = m.getName(); // XXX should be full signature used to compute hash | |
| hash = RMIHashes.getMethodHash(m); | |
| // add exceptions removing subclasses | |
| exceptions = removeSubclasses(m.getExceptionTypes()); | |
| } | |
| public int compareTo(Object obj) | |
| { | |
| MethodRef that = (MethodRef) obj; | |
| int name = this.meth.getName().compareTo(that.meth.getName()); | |
| if (name == 0) { | |
| return this.sig.compareTo(that.sig); | |
| } | |
| return name; | |
| } | |
| public boolean isMatch(Method m) | |
| { | |
| if (!meth.getName().equals(m.getName())) | |
| return false; | |
| Class[] params1 = meth.getParameterTypes(); | |
| Class[] params2 = m.getParameterTypes(); | |
| if (params1.length != params2.length) | |
| return false; | |
| for (int i = 0; i < params1.length; i++) | |
| if (!params1[i].equals(params2[i])) return false; | |
| return true; | |
| } | |
| private static List removeSubclasses(Class[] classes) | |
| { | |
| List list = new ArrayList(); | |
| for (int i = 0; i < classes.length; i++) | |
| { | |
| Class candidate = classes[i]; | |
| boolean add = true; | |
| for (int j = 0; j < classes.length; j++) | |
| { | |
| if (classes[j].equals(candidate)) | |
| continue; | |
| else if (classes[j].isAssignableFrom(candidate)) | |
| add = false; | |
| } | |
| if (add) list.add(candidate); | |
| } | |
| return list; | |
| } | |
| public void intersectExceptions(Method m) | |
| { | |
| List incoming = removeSubclasses(m.getExceptionTypes()); | |
| List updated = new ArrayList(); | |
| for (int i = 0; i < exceptions.size(); i++) | |
| { | |
| Class outer = (Class) exceptions.get(i); | |
| boolean addOuter = false; | |
| for (int j = 0; j < incoming.size(); j++) | |
| { | |
| Class inner = (Class) incoming.get(j); | |
| if (inner.equals(outer) || inner.isAssignableFrom(outer)) | |
| addOuter = true; | |
| else if (outer.isAssignableFrom(inner)) | |
| updated.add(inner); | |
| } | |
| if (addOuter) | |
| updated.add(outer); | |
| } | |
| exceptions = updated; | |
| } | |
| } | |
| } |