/* * @(#)ImportRegistry.java 1.20 06/10/10 * * 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.util.Hashtable; import java.util.Enumeration; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.io.Serializable; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import javax.microedition.xlet.XletContext; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.NotBoundException; import java.rmi.AlreadyBoundException; import javax.microedition.xlet.ixc.StubException; /** * Registry for imported objects. This keeps track of objects that have * been imported into our XletContext, called importer, from some other * XletContext, called target. */ public class ImportRegistry { XletContext importer; XletContext target; // Xlet we import from. This gets set null when that Xlet is // killed. private Hashtable importedObjects = new Hashtable(11); // Hashtable<RegistryKey, WrappedRemote> ImportRegistry(XletContext importer, XletContext target) { this.importer = importer; this.target = target; } // Returns the Remote object which might be wrapped as a Stub. // public Remote lookup(Remote rawResult) throws InterruptedException, NotBoundException, RemoteException { XletContext t = target; if (t == null) { throw new RemoteException("Target Xlet has been destroyed"); } if (rawResult == null) { throw new NotBoundException(); } if (rawResult instanceof WrappedRemote) { // re-exporting! rawResult = ((WrappedRemote) rawResult).getTarget(); } return wrapIfImported(rawResult); } private Remote wrapImportedObject(Remote raw) throws RemoteException { Remote result = null; synchronized (importedObjects) { WeakReference ref = (WeakReference) importedObjects.get(raw); if (ref != null) { result = (Remote) ref.get(); if (result == null) { importedObjects.remove(raw); // This makes sure that the old RegistryKey doesn't // get retained in the Hashtable. If it did, it would // be == to the RegistryKey that pretty soon is // going to be removed, when the stub's finalizer // executes. } } if (result == null) { RegistryKey key = new RegistryKey(raw); result = doWrap(raw, key); importedObjects.put(key, new WeakReference(result)); } } return result; } private Remote wrapIfImported(Remote raw) throws RemoteException { if (raw == null) { throw new RemoteException("Target Xlet has been destroyed"); } if (isParentLoader(raw.getClass().getClassLoader(), IxcRegistryImpl.getIxcClassLoader(importer))) { return raw; // No need to wrap if it's from us } else { return wrapImportedObject(raw); } } // // Wraps a remote object that we're sure has never been wrapped // before. // private Remote doWrap(Remote raw, RegistryKey key) throws RemoteException { Remote r; try { // First get the target xlet's IxcClassLoader, to wrap. IxcClassLoader importerLoader = IxcRegistryImpl.getIxcClassLoader(importer); // Then get the stb object wrapped with the importer's CL. // The returned wrappedClass is loaded with importerLoader's // parent classloader, which is xlet's ClassLoader. Class wrappingClass = importerLoader.getStubClass( IxcRegistryImpl.getIxcClassLoader(target), raw.getClass()); // Then instanciate the Remote object and return it. Class[] types = { Remote.class, ImportRegistry.class, RegistryKey.class }; Constructor m = wrappingClass.getConstructor(types); Object[] args = { raw, this, key }; r = (Remote) m.newInstance(args); } catch (RemoteException ex) { throw ex; } catch (Exception ex) { //throw new RemoteException("cannot wrap Remote", ex); throw new StubException("cannot wrap Remote", ex); } return r; } /** * Creates a deep copy of a serializable object. * * @param obj an object which will be copied * * @return a deep copy of its argument * * @see #java.io.Serializable * file does not exist or cannt be downloaded. */ private Serializable copyObject(Serializable o) throws RemoteException { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(o); oos.flush(); oos.close(); byte[] ba = bos.toByteArray(); // Now, we have to de-serialize the object in a method loaded // by the importer's classloader. //Method m = importer.loader.getDeserializeMethod(); Method m = IxcRegistryImpl.getIxcClassLoader(importer).getDeserializeMethod(); return (Serializable) m.invoke(null, new Object[] { ba } ); } catch (RemoteException ex) { throw ex; } catch (Exception ex) { throw new RemoteException("Cannot copy object", ex); } } Object wrapOrCopy(Object o) throws RemoteException { if (o == null) { return null; } else if (o instanceof WrappedRemote) { return wrapIfImported(((WrappedRemote) o).getTarget()); } else if (o instanceof Remote) { return wrapImportedObject((Remote) o); } else if (o instanceof Serializable) { return copyObject((Serializable) o); } else { throw new RemoteException("Object is neither Serializable nor Remote"); } } void unregisterStub(RegistryKey key) { importedObjects.remove(key); } boolean isParentLoader(ClassLoader parent, ClassLoader child) { do { if (child == parent) { return true; } child = child.getParent(); } while (child != null); return false; } // // Called to notify that our target Xlet has been destroyed. This means // that we shouidl destroy all the imported objects we manage. // void targetDestroyed() { try { IxcClassLoader importingLoader = IxcRegistryImpl.getIxcClassLoader(importer); IxcClassLoader targetLoader = IxcRegistryImpl.getIxcClassLoader(target); importingLoader.forgetStubsFor(targetLoader); } catch (Exception e) { e.printStackTrace(); } target = null; synchronized (importedObjects) { for (Enumeration e = importedObjects.elements(); e.hasMoreElements();) { WeakReference value = (WeakReference) e.nextElement(); WrappedRemote r = (WrappedRemote) value.get(); if (r != null) { r.destroy(); } } } } }