/*
* @(#)WrappedRemote.java 1.14 05/03/12
*
* Copyright 1990-2008 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.xlet.ixc;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.UnexpectedException;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import javax.microedition.xlet.XletContext;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
/**
* A remote object that has been wrapped to be safely accessible from
* a client. In other words, an instance of WrappedRemote is a stub
* object that delegates its calls to the true remote object. The remote
* calls are executed in a thread that is in the remote ResourceDomain.
* This can be done by transferring the call to a worker thread on the
* remote side, or by changing the owner attribute of the thread.
*/
public abstract class WrappedRemote implements Remote {
private Remote target;
private ImportRegistry registry;
private RegistryKey key;
private static Method hashCodeMethod;
private static Method equalsMethod;
private static Method toStringMethod;
static {
try {
Class obj = Object.class;
hashCodeMethod = obj.getMethod("hashCode", new Class[0]);
equalsMethod = obj.getMethod("equals", new Class[] { obj }
);
toStringMethod = obj.getMethod("toString", new Class[0]);
} catch (Exception ex) {
// assert(false);
ex.printStackTrace();
}
}
protected WrappedRemote(Remote target, ImportRegistry registry,
RegistryKey key) {
this.target = target;
this.registry = registry;
this.key = key;
}
protected void finalize() {
registry.unregisterStub(key);
}
//
// Execute a remote method. Note that this Method object must refer
// to the method loaded by the target classloader (and not the
// classloader of the stub class).
//
protected final Object
com_sun_xlet_execute(final Method remoteMethod, final Object[] args)
throws java.lang.Exception {
//XletContextImpl localXlet = registry.importer;
//XletContextImpl remoteXlet = registry.target;
XletContext localXlet = registry.importer;
XletContext remoteXlet = registry.target;
if (remoteXlet == null) {
throw new RemoteException("Remote target killed");
}
IxcRegistryImpl ixcRegis =
IxcRegistryImpl.getIxcRegistryImpl(remoteXlet);
ImportRegistry remoteIR = (ImportRegistry)
ixcRegis.getImportRegistry(localXlet);
final AccessControlContext context = ixcRegis.acc;
// Now wrap or copy arguments...
for (int i = 0; i < args.length; i++) {
args[i] = remoteIR.wrapOrCopy(args[i]);
}
final Object[] result = new Object[2];
final Remote targetNow = target;
if (targetNow == null) {
// This should never happen, but be conservative
throw new RemoteException("Remote target killed");
}
if (remoteMethod == null) {
// Stub has been destroyed in this case, must be reexported object
throw new RemoteException("Remote target killed");
}
ixcRegis.executeForClient(new Runnable() {
public void run() {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws RemoteException {
Throwable err = null;
try {
result[0] = remoteMethod.invoke(targetNow, args);
} catch (InvocationTargetException ite) {
err = ite.getTargetException();
} catch (Throwable t) {
err = t;
}
if (err == null) {
try {
result[0] = registry.wrapOrCopy(result[0]);
} catch (RemoteException ex) {
result[1] = ex;
}
} else {
try {
result[1] = registry.wrapOrCopy(err);
} catch (RemoteException ex) {
result[1] = ex;
}
}
return null;
}
}
, context);
} catch (PrivilegedActionException pae) {
// assert(false)
pae.getCause().printStackTrace();
}
}
}
);
if (result[1] != null) {
// fix for 4653779, if the exception is checked, throw it
// directly, else wrap it in UnsupportedException
Class[] exceptions = remoteMethod.getExceptionTypes();
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i].isInstance(result[1])) {
throw (Exception) result[1];
}
}
// fix for 4641529, just throw if it's a RuntimeException,
// else wrap it in RemoteException
if (result[1] instanceof RuntimeException) {
throw (RuntimeException) result[1];
} else if (result[1] instanceof RemoteException) {
throw (RemoteException) result[1];
} else {
throw new UnexpectedException("Non-declared exception", (Exception) result[1]);
}
}
return registry.wrapOrCopy(result[0]);
}
void destroy() {
target = null;
}
Remote getTarget() {
return target;
}
public int hashCode() {
try {
Object result
= com_sun_xlet_execute(hashCodeMethod, new Object[0]);
return ((Integer) result).intValue();
//} catch (RemoteException ex) {
} catch (Exception ex) {
// Client has died. This is the same behavior that
// java.rmi.server.RemoteObject gives.
return super.hashCode();
}
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof WrappedRemote)) {
if (obj == null) {
return false;
} else {
return obj.equals(this);
// cf. bug 4099660, and java.rmi.server.RemoteObject.equals().
}
}
try {
Object result
//= com_sun_tvimpl_execute(equalsMethod, new Object[] { obj });
= com_sun_xlet_execute(equalsMethod, new Object[] { obj }
);
return ((Boolean) result).booleanValue();
} catch (Exception ex) {
// Client has died, or o is an incompatible type.
return false;
}
}
public String toString() {
try {
String classname = this.getClass().getName();
Object result
//= com_sun_tvimpl_execute(toStringMethod, new Object[0]);
= com_sun_xlet_execute(toStringMethod, new Object[0]);
return classname + "[" + result + "]";
//} catch (RemoteException ex) {
} catch (Exception ex) {
return super.toString();
}
}
}