| /* 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; |
| } |
| } |
| } |