📄 stubclassgenerator.java
字号:
/* * @(#)StubClassGenerator.java 1.5 06/08/10 * * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program 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 version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */package com.sun.jumpimpl.ixc;import javax.microedition.xlet.ixc.StubException;import java.lang.reflect.Method;import java.lang.reflect.AccessibleObject;import java.security.AccessController;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.IOException;import java.security.AccessController;import java.security.PrivilegedAction;import java.rmi.RemoteException;import java.util.Arrays;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;/** * Instances of this class generate stub classes. They do this * by creating a byte[], and then passing it to the xlet's * ClassLoader. The method on ClassLoader is protected, so * we use reflection wrapped in a doPrivileged block to call it. * <p> * To give an example, suppose that a user class implemens a remote * interface UserIF, * and that interface contains two methods, void frob(Something), and * int glorp(float). This class will automatically generate * a remote stub. The stub will be equivalent to the following class: * <pre> * * package com.sun.jumpimpl.ixc; * * import java.rmi.RemoteException; * * public final class StubClass_stub42 * extends com.sun.jumpimpl.ixc.StubObject * implements UserIF { * * public StubClass_stub42(Object registry, * Object target) { * // Arguments are of type ImportedObjectRegistry and RemoteHandle * super(registry, target); * } * * public void frob(Something arg1) throws RemoteException { * com_sun_xlet_execute("frob", new Object[] { arg1 }); * } * * public int glorp(float arg1) throws RemoteException { * Object r = com_sun_xlet_execute("glorb",new Object[] { new Float(arg1) }); * return ((Integer) r).intValue(); * } * } * * </pre> **/ // @@ Add the synthetic attribute // @@ Do this with a security manager installed // @@ Make exception handling consistent with 1.2 behavior. Specifically, // RemoteExceptions should be cloned and wrapped, RuntimeExceptions // should be cloned and re-thrown, checked exception that appear in the // interface method's signature should be cloned and re-thrown (probably // with our deprecated friend, Thread.stop(Throwable)), and unexpected // checked exceptions should be cloned and wrapped (there's some exception // under java.rmi specifically for this).public class StubClassGenerator { private ClassLoader xletClassLoader; private static int nextStubNumber = 1; // This could be non-static, because xlets aren't permitted // to share classloaders. However, if for some reason two // xlets ever to share a classloader (due to a bug or a // spec change), then this being static will prevent // a collision. public StubClassGenerator(ClassLoader xletClassLoader) { this.xletClassLoader = xletClassLoader; } //Class generate(RemoteRef remoteRef) throws StubException { Class generate(RemoteObjectType remoteRef) throws StubException { final String stubName = "StubClass_stub" + (nextStubNumber++); byte[] tmp = null; try { tmp = generateClassBytes(stubName, remoteRef); } catch (IOException ex) { throw new StubException("error generating stub", ex); } final byte[] classBytes = tmp; java.lang.reflect.Method tmp2 = null; try { tmp2 = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, classBytes.getClass(), int.class, int.class }); } catch (NoSuchMethodException ex) { throw new StubException("internal error", ex); } final java.lang.reflect.Method m = tmp2; // We need a privileged block, so that we can call the // protected defineClass method. Since we're doing that // anyway, we define the stub class in our package namespace, // to guarantee there won't be any name collisions. Object result = AccessController.doPrivileged(new PrivilegedAction() { public Object run() { m.setAccessible(new AccessibleObject[]{m}, true); // Tempolary disable the security manager here, as it can // error in loadClass for RuntimePermission // accessClassInPackage.sun.mtask.xlet.ixc // (Yes, even in the privileged block) //SecurityManager sm = System.getSecurityManager(); //if (sm != null) // System.setSecurityManager(null); Object result = null; try { Object[] args = new Object[] { stubName.replace('/', '.'), classBytes, new Integer(0), new Integer(classBytes.length) }; result = m.invoke(xletClassLoader, args); } catch (Throwable t) { result = t; } //if (sm != null) // Set the SecurityManager back // System.setSecurityManager(sm); return result; } }); if (result instanceof Class) { return (Class) result; } else if (result instanceof StubException) { throw (StubException) result; } else if (result instanceof NoClassDefFoundError) { Throwable err = (NoClassDefFoundError) result; throw new StubException("Cannot find a class definition", err); } else if (result instanceof Exception) { throw new StubException("getStub() failed", (Exception) result); } else { throw new StubException("getStub() failed: " + result); } } private String descriptorFor(Method m) { String descriptor = "("; Class[] params = m.getParameterTypes(); for (int j = 0; j < params.length; j++) { descriptor += TypeInfo.descriptorFor(params[j]); } descriptor += ")"; descriptor += TypeInfo.descriptorFor(m.getReturnType()); return descriptor; } // // The stub includes methods defined in 'remote interface', // which is an interface that directly or indirectly extends // java.rmi.Remote. In other words, // interface BaseInterface extends java.rmi.Remote // interface ExtendedInterface extends java.rmi.Remote, Xlet // class TestXlet implements ExtendedInterface // then, ExtendedInterface is a 'remote interface' for TestXlet // and methods declared in BaseInterface, ExtendedInterface // and Xlet interface are treated as remote methods. // private byte[] generateClassBytes(String stubName, RemoteObjectType type) throws IOException, StubException { ConstantPool cp = new ConstantPool(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); cp.addString("Code"); // For the code attribute cp.addString("Exceptions"); // For the exceptoins attribute String importedObject = "com/sun/jumpimpl/ixc/StubObject"; //String importedObject = "sun/mtask/xlet/ixc/StubObject"; String constructorDescriptor = "(Ljava/lang/Object;Ljava/lang/Object;)V"; String executeDescriptor = "(J[Ljava/lang/Object;)Ljava/lang/Object;"; // Add constant pool entries for names derived from the stuff // we're implementing. cp.addClass(importedObject); cp.addClass(stubName); // @@ Need this: cp.addClass("com/sun/xlet/mvmixc/Utils"); cp.addClass("java/lang/Object"); cp.addClass("java/lang/Exception"); cp.addClass("java/rmi/RemoteException"); cp.addClass("java/lang/RuntimeException"); cp.addClass("java/rmi/UnexpectedException"); String[] remoteInterfaces = type.getRemoteInterfaceNames(); Long[] methodIDs = (Long[])type.methodsByID.keySet().toArray(new Long[]{}); Method[] remoteMethods = new Method[methodIDs.length]; for (int i = 0; i < remoteInterfaces.length; i++) { cp.addClass(remoteInterfaces[i].replace('.', '/')); } HashMap primArgsDone = new HashMap(); HashMap primRetsDone = new HashMap(); for (int i = 0; i < methodIDs.length; i++) { remoteMethods[i] = (Method)type.methodsByID.get(methodIDs[i]); Method m = remoteMethods[i]; cp.addStringConstant(m.getName()); cp.addLong(methodIDs[i]); cp.addIfMethodReference(m.getDeclaringClass().getName().replace('.', '/'), m.getName(), descriptorFor(m)); cp.addStringConstant(m.getDeclaringClass().getName()); Class rt = m.getReturnType(); if (Void.TYPE.equals(rt)) { // do nothing } else if (rt.isPrimitive()) { TypeInfo info = TypeInfo.get(rt); String rtNm = info.primitiveWrapper.getName().replace('.', '/'); cp.addClass(rtNm); cp.addMethodReference(rtNm, info.valueMethod, "()" + info.typeDescriptor); } else { cp.addClass(rt.getName().replace('.', '/')); } Class[] params = m.getParameterTypes(); for (int j = 0; j < params.length; j++) { if (params[j].isPrimitive()) { // Don't need to worry about void here TypeInfo info = TypeInfo.get(params[j]); Class p = info.primitiveWrapper; String nm = p.getName().replace('.', '/'); if (primArgsDone.get(nm) == null) { primArgsDone.put(nm, nm); cp.addClass(nm); // The constructor for the wrapper class: cp.addMethodReference(nm, "<init>", "(" + TypeInfo.descriptorFor(params[j]) + ")V"); // The TYPE field cp.addField(nm, "TYPE", "Ljava/lang/Class;"); } } else { cp.addStringConstant(params[j].getName()); } } // Adding exception types Class[] exceptions = m.getExceptionTypes();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -