001: /*
002: * @(#)WrappedRemote.java 1.14 05/03/12
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package com.sun.xlet.ixc;
029:
030: import java.rmi.Remote;
031: import java.rmi.RemoteException;
032: import java.rmi.UnexpectedException;
033: import java.lang.reflect.Method;
034: import java.lang.reflect.InvocationTargetException;
035: import javax.microedition.xlet.XletContext;
036: import java.security.AccessController;
037: import java.security.AccessControlContext;
038: import java.security.PrivilegedActionException;
039: import java.security.PrivilegedExceptionAction;
040:
041: /**
042: * A remote object that has been wrapped to be safely accessible from
043: * a client. In other words, an instance of WrappedRemote is a stub
044: * object that delegates its calls to the true remote object. The remote
045: * calls are executed in a thread that is in the remote ResourceDomain.
046: * This can be done by transferring the call to a worker thread on the
047: * remote side, or by changing the owner attribute of the thread.
048: */
049:
050: public abstract class WrappedRemote implements Remote {
051: private Remote target;
052: private ImportRegistry registry;
053: private RegistryKey key;
054: private static Method hashCodeMethod;
055: private static Method equalsMethod;
056: private static Method toStringMethod;
057: static {
058: try {
059: Class obj = Object.class;
060: hashCodeMethod = obj.getMethod("hashCode", new Class[0]);
061: equalsMethod = obj.getMethod("equals", new Class[] { obj });
062: toStringMethod = obj.getMethod("toString", new Class[0]);
063: } catch (Exception ex) {
064: // assert(false);
065: ex.printStackTrace();
066: }
067: }
068:
069: protected WrappedRemote(Remote target, ImportRegistry registry,
070: RegistryKey key) {
071: this .target = target;
072: this .registry = registry;
073: this .key = key;
074: }
075:
076: protected void finalize() {
077: registry.unregisterStub(key);
078: }
079:
080: //
081: // Execute a remote method. Note that this Method object must refer
082: // to the method loaded by the target classloader (and not the
083: // classloader of the stub class).
084: //
085: protected final Object com_sun_xlet_execute(
086: final Method remoteMethod, final Object[] args)
087: throws java.lang.Exception {
088: //XletContextImpl localXlet = registry.importer;
089: //XletContextImpl remoteXlet = registry.target;
090: XletContext localXlet = registry.importer;
091: XletContext remoteXlet = registry.target;
092: if (remoteXlet == null) {
093: throw new RemoteException("Remote target killed");
094: }
095: IxcRegistryImpl ixcRegis = IxcRegistryImpl
096: .getIxcRegistryImpl(remoteXlet);
097: ImportRegistry remoteIR = (ImportRegistry) ixcRegis
098: .getImportRegistry(localXlet);
099: final AccessControlContext context = ixcRegis.acc;
100:
101: // Now wrap or copy arguments...
102: for (int i = 0; i < args.length; i++) {
103: args[i] = remoteIR.wrapOrCopy(args[i]);
104: }
105: final Object[] result = new Object[2];
106: final Remote targetNow = target;
107: if (targetNow == null) {
108: // This should never happen, but be conservative
109: throw new RemoteException("Remote target killed");
110: }
111: if (remoteMethod == null) {
112: // Stub has been destroyed in this case, must be reexported object
113: throw new RemoteException("Remote target killed");
114: }
115: ixcRegis.executeForClient(new Runnable() {
116: public void run() {
117: try {
118: AccessController.doPrivileged(
119: new PrivilegedExceptionAction() {
120: public Object run()
121: throws RemoteException {
122: Throwable err = null;
123: try {
124: result[0] = remoteMethod
125: .invoke(targetNow, args);
126: } catch (InvocationTargetException ite) {
127: err = ite.getTargetException();
128: } catch (Throwable t) {
129: err = t;
130: }
131: if (err == null) {
132: try {
133: result[0] = registry
134: .wrapOrCopy(result[0]);
135: } catch (RemoteException ex) {
136: result[1] = ex;
137: }
138: } else {
139: try {
140: result[1] = registry
141: .wrapOrCopy(err);
142: } catch (RemoteException ex) {
143: result[1] = ex;
144: }
145: }
146: return null;
147: }
148: }, context);
149: } catch (PrivilegedActionException pae) {
150: // assert(false)
151: pae.getCause().printStackTrace();
152: }
153: }
154: });
155: if (result[1] != null) {
156: // fix for 4653779, if the exception is checked, throw it
157: // directly, else wrap it in UnsupportedException
158: Class[] exceptions = remoteMethod.getExceptionTypes();
159: for (int i = 0; i < exceptions.length; i++) {
160: if (exceptions[i].isInstance(result[1])) {
161: throw (Exception) result[1];
162: }
163: }
164: // fix for 4641529, just throw if it's a RuntimeException,
165: // else wrap it in RemoteException
166:
167: if (result[1] instanceof RuntimeException) {
168: throw (RuntimeException) result[1];
169: } else if (result[1] instanceof RemoteException) {
170: throw (RemoteException) result[1];
171: } else {
172: throw new UnexpectedException("Non-declared exception",
173: (Exception) result[1]);
174: }
175: }
176: return registry.wrapOrCopy(result[0]);
177: }
178:
179: void destroy() {
180: target = null;
181: }
182:
183: Remote getTarget() {
184: return target;
185: }
186:
187: public int hashCode() {
188: try {
189: Object result = com_sun_xlet_execute(hashCodeMethod,
190: new Object[0]);
191: return ((Integer) result).intValue();
192: //} catch (RemoteException ex) {
193: } catch (Exception ex) {
194: // Client has died. This is the same behavior that
195: // java.rmi.server.RemoteObject gives.
196: return super .hashCode();
197: }
198: }
199:
200: public boolean equals(Object obj) {
201: if (this == obj) {
202: return true;
203: } else if (!(obj instanceof WrappedRemote)) {
204: if (obj == null) {
205: return false;
206: } else {
207: return obj.equals(this );
208: // cf. bug 4099660, and java.rmi.server.RemoteObject.equals().
209: }
210: }
211: try {
212: Object result
213: //= com_sun_tvimpl_execute(equalsMethod, new Object[] { obj });
214: = com_sun_xlet_execute(equalsMethod, new Object[] { obj });
215: return ((Boolean) result).booleanValue();
216: } catch (Exception ex) {
217: // Client has died, or o is an incompatible type.
218: return false;
219: }
220: }
221:
222: public String toString() {
223: try {
224: String classname = this .getClass().getName();
225: Object result
226: //= com_sun_tvimpl_execute(toStringMethod, new Object[0]);
227: = com_sun_xlet_execute(toStringMethod, new Object[0]);
228: return classname + "[" + result + "]";
229: //} catch (RemoteException ex) {
230: } catch (Exception ex) {
231: return super.toString();
232: }
233: }
234: }
|