001: /*
002: * @(#)ImportRegistry.java 1.20 06/10/10
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.util.Hashtable;
031: import java.util.Enumeration;
032: import java.lang.ref.WeakReference;
033: import java.lang.reflect.Constructor;
034: import java.lang.reflect.Method;
035: import java.io.Serializable;
036: import java.io.ByteArrayOutputStream;
037: import java.io.ObjectOutputStream;
038: import javax.microedition.xlet.XletContext;
039: import java.rmi.Remote;
040: import java.rmi.RemoteException;
041: import java.rmi.NotBoundException;
042: import java.rmi.AlreadyBoundException;
043: import javax.microedition.xlet.ixc.StubException;
044:
045: /**
046: * Registry for imported objects. This keeps track of objects that have
047: * been imported into our XletContext, called importer, from some other
048: * XletContext, called target.
049: */
050:
051: public class ImportRegistry {
052: XletContext importer;
053: XletContext target;
054: // Xlet we import from. This gets set null when that Xlet is
055: // killed.
056: private Hashtable importedObjects = new Hashtable(11);
057:
058: // Hashtable<RegistryKey, WrappedRemote>
059:
060: ImportRegistry(XletContext importer, XletContext target) {
061: this .importer = importer;
062: this .target = target;
063: }
064:
065: // Returns the Remote object which might be wrapped as a Stub.
066: //
067: public Remote lookup(Remote rawResult) throws InterruptedException,
068: NotBoundException, RemoteException {
069: XletContext t = target;
070: if (t == null) {
071: throw new RemoteException("Target Xlet has been destroyed");
072: }
073: if (rawResult == null) {
074: throw new NotBoundException();
075: }
076: if (rawResult instanceof WrappedRemote) { // re-exporting!
077: rawResult = ((WrappedRemote) rawResult).getTarget();
078: }
079: return wrapIfImported(rawResult);
080: }
081:
082: private Remote wrapImportedObject(Remote raw)
083: throws RemoteException {
084: Remote result = null;
085: synchronized (importedObjects) {
086: WeakReference ref = (WeakReference) importedObjects
087: .get(raw);
088: if (ref != null) {
089: result = (Remote) ref.get();
090: if (result == null) {
091: importedObjects.remove(raw);
092: // This makes sure that the old RegistryKey doesn't
093: // get retained in the Hashtable. If it did, it would
094: // be == to the RegistryKey that pretty soon is
095: // going to be removed, when the stub's finalizer
096: // executes.
097: }
098: }
099: if (result == null) {
100: RegistryKey key = new RegistryKey(raw);
101: result = doWrap(raw, key);
102: importedObjects.put(key, new WeakReference(result));
103: }
104: }
105: return result;
106: }
107:
108: private Remote wrapIfImported(Remote raw) throws RemoteException {
109: if (raw == null) {
110: throw new RemoteException("Target Xlet has been destroyed");
111: }
112: if (isParentLoader(raw.getClass().getClassLoader(),
113: IxcRegistryImpl.getIxcClassLoader(importer))) {
114: return raw; // No need to wrap if it's from us
115: } else {
116: return wrapImportedObject(raw);
117: }
118: }
119:
120: //
121: // Wraps a remote object that we're sure has never been wrapped
122: // before.
123: //
124: private Remote doWrap(Remote raw, RegistryKey key)
125: throws RemoteException {
126: Remote r;
127: try {
128: // First get the target xlet's IxcClassLoader, to wrap.
129: IxcClassLoader importerLoader = IxcRegistryImpl
130: .getIxcClassLoader(importer);
131:
132: // Then get the stb object wrapped with the importer's CL.
133: // The returned wrappedClass is loaded with importerLoader's
134: // parent classloader, which is xlet's ClassLoader.
135: Class wrappingClass = importerLoader.getStubClass(
136: IxcRegistryImpl.getIxcClassLoader(target), raw
137: .getClass());
138:
139: // Then instanciate the Remote object and return it.
140: Class[] types = { Remote.class, ImportRegistry.class,
141: RegistryKey.class };
142: Constructor m = wrappingClass.getConstructor(types);
143: Object[] args = { raw, this , key };
144:
145: r = (Remote) m.newInstance(args);
146:
147: } catch (RemoteException ex) {
148: throw ex;
149: } catch (Exception ex) {
150: //throw new RemoteException("cannot wrap Remote", ex);
151: throw new StubException("cannot wrap Remote", ex);
152: }
153:
154: return r;
155: }
156:
157: /**
158: * Creates a deep copy of a serializable object.
159: *
160: * @param obj an object which will be copied
161: *
162: * @return a deep copy of its argument
163: *
164: * @see #java.io.Serializable
165: * file does not exist or cannt be downloaded.
166: */
167: private Serializable copyObject(Serializable o)
168: throws RemoteException {
169: try {
170: ByteArrayOutputStream bos = new ByteArrayOutputStream();
171: ObjectOutputStream oos = new ObjectOutputStream(bos);
172: oos.writeObject(o);
173: oos.flush();
174: oos.close();
175: byte[] ba = bos.toByteArray();
176: // Now, we have to de-serialize the object in a method loaded
177: // by the importer's classloader.
178: //Method m = importer.loader.getDeserializeMethod();
179: Method m = IxcRegistryImpl.getIxcClassLoader(importer)
180: .getDeserializeMethod();
181: return (Serializable) m.invoke(null, new Object[] { ba });
182: } catch (RemoteException ex) {
183: throw ex;
184: } catch (Exception ex) {
185: throw new RemoteException("Cannot copy object", ex);
186: }
187: }
188:
189: Object wrapOrCopy(Object o) throws RemoteException {
190: if (o == null) {
191: return null;
192: } else if (o instanceof WrappedRemote) {
193: return wrapIfImported(((WrappedRemote) o).getTarget());
194: } else if (o instanceof Remote) {
195: return wrapImportedObject((Remote) o);
196: } else if (o instanceof Serializable) {
197: return copyObject((Serializable) o);
198: } else {
199: throw new RemoteException(
200: "Object is neither Serializable nor Remote");
201: }
202: }
203:
204: void unregisterStub(RegistryKey key) {
205: importedObjects.remove(key);
206: }
207:
208: boolean isParentLoader(ClassLoader parent, ClassLoader child) {
209: do {
210: if (child == parent) {
211: return true;
212: }
213: child = child.getParent();
214: } while (child != null);
215: return false;
216: }
217:
218: //
219: // Called to notify that our target Xlet has been destroyed. This means
220: // that we shouidl destroy all the imported objects we manage.
221: //
222: void targetDestroyed() {
223: try {
224: IxcClassLoader importingLoader = IxcRegistryImpl
225: .getIxcClassLoader(importer);
226: IxcClassLoader targetLoader = IxcRegistryImpl
227: .getIxcClassLoader(target);
228: importingLoader.forgetStubsFor(targetLoader);
229: } catch (Exception e) {
230: e.printStackTrace();
231: }
232: target = null;
233: synchronized (importedObjects) {
234: for (Enumeration e = importedObjects.elements(); e
235: .hasMoreElements();) {
236: WeakReference value = (WeakReference) e.nextElement();
237: WrappedRemote r = (WrappedRemote) value.get();
238: if (r != null) {
239: r.destroy();
240: }
241: }
242: }
243: }
244: }
|