001: /*
002: * @(#)IxcRegistryImpl.java 1.25 05/05/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 javax.microedition.xlet.ixc.*;
031:
032: import java.rmi.Remote;
033: import java.rmi.RemoteException;
034: import java.rmi.AccessException;
035: import java.rmi.NotBoundException;
036: import java.rmi.AlreadyBoundException;
037: import java.rmi.registry.Registry;
038: import javax.microedition.xlet.XletContext;
039: import java.util.Hashtable;
040: import java.util.Enumeration;
041: import java.util.Vector;
042:
043: import java.security.AccessController;
044: import java.security.AccessControlContext;
045: import java.security.PrivilegedAction;
046: import java.security.PrivilegedExceptionAction;
047: import java.security.PrivilegedActionException;
048:
049: /**
050: * <code>IXCRegistry</code> is the bootstrap mechanism for obtaining
051: * references to remote objects residing in other Xlets executing on
052: * the same machine, but in separate classloaders.
053: * * <p>
054: * Instances of <code>IXCRegistry</code> are never accessible via
055: * <code>java.rmi.Naming</code> or
056: * <code>java.rmi.registry.LocateRegistry</code> if RMI functionality
057: * is implemented.
058: *
059: * @see java.rmi.Registry
060: */
061:
062: public class IxcRegistryImpl extends IxcRegistry {
063: // Hashtable<XletContext, IxcRegistry>
064: static Hashtable registries = new Hashtable(11);
065:
066: // Hashtable<Name, XletContext>, who exported what names.
067: static Hashtable xletContextMap = new Hashtable(11);
068: // Hashtable<Name, RemoteObject>, who exported what Remote objects.
069: static Hashtable remoteObjectMap = new Hashtable(11);
070:
071: // Lock object to synchronize access to
072: // remoteObjectMap and xletContextMap.
073: // We don't want Name to be appearing in one but not in another.
074: static private Object lock = new Object();
075:
076: /* A thread for Remote method invocation */
077: private static Worker worker;
078:
079: /* Xlet which this IxcRegistry belongs to*/
080: private XletContext context;
081: /* IxcClassLoader for this xlet */
082: IxcClassLoader ixcClassLoader;
083: /* ImportRegistries for this xlet.
084: <target xlet's XletContext, ImportRegis> */
085: Hashtable importRegistries = new Hashtable(11);
086:
087: AccessControlContext acc;
088:
089: /**
090: * Creates a IxcRegistry instance.
091: */
092: protected IxcRegistryImpl(XletContext ctxt) {
093: context = ctxt;
094:
095: final ClassLoader finalLoader = ctxt.getClassLoader();
096: ixcClassLoader = (IxcClassLoader) AccessController
097: .doPrivileged(new PrivilegedAction() {
098: public Object run() {
099: return new IxcClassLoader(finalLoader);
100: }
101: });
102:
103: acc = AccessController.getContext();
104:
105: synchronized (registries) {
106: if (worker == null) // first time caller!
107: worker = new Worker(
108: "Remote invocation thread for IxcRegistry");
109: }
110: }
111:
112: /**
113: * Gets the IxcRegistry
114: */
115: public static IxcRegistryImpl getIxcRegistryImpl(XletContext ctxt) {
116:
117: IxcRegistryImpl regis = (IxcRegistryImpl) registries.get(ctxt);
118:
119: if (regis == null) {
120: IxcRegistryImpl newRegis = new IxcRegistryImpl(ctxt);
121:
122: registries.put(ctxt, newRegis);
123: regis = newRegis;
124: }
125:
126: return regis;
127: }
128:
129: /**
130: * Returns a reference, a stub, for the remote object associated
131: * with the specified <code>name</code>.
132: *
133: * @param name a URL-formatted name for the remote object
134: * @return a reference for a remote object
135: * @exception NotBoundException if name is not currently bound
136: * @exception RemoteException if registry could not be contacted
137: * @exception AccessException if this operation is not permitted (if
138: * originating from a non-local host, for example)
139: */
140: public Remote lookup(String name) throws StubException,
141: NotBoundException {
142:
143: SecurityManager sm = System.getSecurityManager();
144: if (sm != null)
145: sm.checkPermission(new IxcPermission(name, "lookup"));
146:
147: /* if not in the global hash, forget it */
148: if (!xletContextMap.containsKey(name)) {
149: throw new NotBoundException();
150: }
151: /* find out who exported this name */
152: XletContext targetXlet = (XletContext) xletContextMap.get(name);
153:
154: /* When the xlet who exported the object is found,
155: we can consult appropriate ImportRegistry to make a stub*/
156: if (targetXlet != null) {
157: try {
158: Remote origRemoteObj = (Remote) remoteObjectMap
159: .get(name);
160:
161: /* Returns the object wrapped as a 'stub' in the context
162: of this method's caller */
163: return getImportRegistry(targetXlet).lookup(
164: origRemoteObj);
165: } catch (StubException se) {
166: throw se;
167: } catch (RemoteException re) {
168: // shouldn't happen, but just in case...
169: throw new StubException("lookup failed", re);
170: } catch (InterruptedException ie) {
171: throw new StubException("Can't lookup", ie);
172: }
173: }
174: return null;
175: }
176:
177: /**
178: * Binds the specified <code>name</code> to a remote object.
179: *
180: * @param name a URL-formatted name for the remote object
181: * @param obj a reference for the remote object (usually a stub)
182: * @exception AlreadyBoundException if name is already bound
183: * @exception MalformedURLException if the name is not an appropriately
184: * formatted URL
185: * @exception RemoteException if registry could not be contacted
186: * @exception AccessException if this operation is not permitted (if
187: * originating from a non-local host, for example)
188: */
189: public void bind(String name, Remote obj) throws StubException,
190: AlreadyBoundException {
191:
192: SecurityManager sm = System.getSecurityManager();
193: if (sm != null)
194: sm.checkPermission(new IxcPermission(name, "bind"));
195:
196: synchronized (lock) {
197: if (remoteObjectMap.get(name) != null) {
198: throw new AlreadyBoundException();
199: }
200: try {
201: rebind(name, obj);
202: } catch (AccessException e) {
203: // can't happen, but just in case,
204: throw new AlreadyBoundException();
205: }
206: }
207: }
208:
209: /**
210: * Destroys the binding for the specified name that is associated
211: * with a remote object.
212: *
213: * @param name a URL-formatted name associated with a remote object
214: * @exception NotBoundException if name is not currently bound
215: * @exception MalformedURLException if the name is not an appropriately
216: * formatted URL
217: * @exception RemoteException if registry could not be contacted
218: * @exception AccessException if this operation is not permitted (if
219: * originating from a non-local host, for example)
220: */
221: public void unbind(String name) throws NotBoundException,
222: AccessException {
223:
224: /* 6254044, Exception checking - there are three cases.
225: * 1) The name was never bound (binderCtxt == null)
226: * 2) The name was binded by the same xlet as the caller
227: * of this method. (binderCtxt == this.context)
228: * 3) The name was binded by a different xlet.
229: * (binderCtxt != this.context && binderCtxt != null)
230: * Permission check is needed for (1) and (3) but not for (2).
231: */
232: XletContext binderCtxt = (XletContext) xletContextMap.get(name);
233: if (binderCtxt != context) {
234: // Either case (1) or (3), Security check first.
235: SecurityManager sm = System.getSecurityManager();
236: if (sm != null) {
237: sm.checkPermission(new IxcPermission(name, "bind"));
238: }
239:
240: // The caller has the right permission, so just throw
241: // exceptions based on the condition.
242:
243: if (binderCtxt == null) { // case (1)
244: throw new NotBoundException("Object not bound");
245: } else { // case (3)
246: throw new AccessException(
247: "Cannot unbind objects bound by other xlets");
248: }
249: }
250:
251: // Case (2), proceed.
252: synchronized (lock) {
253: remoteObjectMap.remove(name);
254: xletContextMap.remove(name);
255: }
256: }
257:
258: /**
259: * Rebinds the specified name to a new remote object. Any existing
260: * binding for the name is replaced.
261: *
262: * @param name a URL-formatted name associated with the remote object
263: * @param obj new remote object to associate with the name
264: * @exception MalformedURLException if the name is not an appropriately
265: * formatted URL
266: * @exception RemoteException if registry could not be contacted
267: * @exception AccessException if this operation is not permitted (if
268: * originating from a non-local host, for example)
269: */
270: public void rebind(String name, Remote obj) throws StubException,
271: AccessException {
272:
273: SecurityManager sm = System.getSecurityManager();
274: if (sm != null)
275: sm.checkPermission(new IxcPermission(name, "bind"));
276:
277: /* first check if the remote interface is valid */
278: try {
279: ixcClassLoader.getStubClass(ixcClassLoader, obj.getClass());
280: } catch (RemoteException e) {
281: if (e instanceof StubException)
282: throw (StubException) e;
283: else
284: throw new StubException("Cannot bind", e);
285: }
286: /* validity check is done here */
287: synchronized (lock) {
288: Object ctxt = xletContextMap.get(name);
289: if (ctxt == null) {
290: xletContextMap.put(name, context);
291: } else if (ctxt != context) {
292: throw new AccessException(
293: "Cannot rebind an object of another xlet");
294: }
295: remoteObjectMap.put(name, obj);
296: }
297: }
298:
299: /**
300: * Returns an array of the names bound in the registry. The names are
301: * URL-formatted strings. The array contains a snapshot of the names
302: * present in the registry at the time of the call.
303: *
304: * @return an array of names (in the appropriate URL format) bound
305: * in the registry
306: * @exception RemoteException if registry could not be contacted
307: * @exception AccessException if this operation is not permitted (if
308: * originating from a non-local host, for example)
309: */
310: public String[] list() {
311:
312: SecurityManager sm = System.getSecurityManager();
313: if (sm == null) {
314: synchronized (lock) {
315: return (String[]) remoteObjectMap.keySet().toArray(
316: new String[remoteObjectMap.size()]);
317: }
318: }
319:
320: // SecurityManager is installed, return the names
321: // which the caller has the permission to lookup.
322: Vector v = new Vector();
323: synchronized (lock) {
324: String name;
325: for (Enumeration enumeration = remoteObjectMap.keys(); enumeration
326: .hasMoreElements();) {
327: name = (String) enumeration.nextElement();
328: try {
329: sm
330: .checkPermission(new IxcPermission(name,
331: "lookup"));
332: v.add(name);
333: } catch (SecurityException e) {
334: }
335: }
336: }
337:
338: return (String[]) v.toArray(new String[v.size()]);
339: }
340:
341: /**
342: * Removes the bindings for all remote objects currently exported by
343: * the calling Xlet.
344: */
345: public void unbindAll() {
346: for (Enumeration e = xletContextMap.keys(); e.hasMoreElements();) {
347: String key = (String) e.nextElement();
348: XletContext other = (XletContext) xletContextMap.get(key);
349: if (other == context) {
350: // Cleanup xletContextMap and remoteObjectMap
351: synchronized (lock) {
352: xletContextMap.remove(key);
353: remoteObjectMap.remove(key);
354: }
355: } else {
356: // Clean up ImportRegistry for the other (alive) xlet
357: // which imported objects from this destroyed xlet
358:
359: IxcRegistryImpl regis = (IxcRegistryImpl) registries
360: .get(other);
361: ImportRegistry ir = null;
362: synchronized (regis.importRegistries) {
363: ir = (ImportRegistry) regis.importRegistries
364: .get(context);
365: if (ir != null) {
366: regis.importRegistries.remove(context);
367: }
368: }
369: if (ir != null) {
370: // This means that we have imported objects from other,
371: // so we need to unhook them.
372: ir.targetDestroyed();
373: }
374: }
375: }
376: // finally remove entry from IxcRegistry Hash itself
377: registries.remove(context);
378: return;
379: }
380:
381: /**
382: * Returns an ImportRegistry of the target xlet which the xlet
383: * belonging to this IxcRegistry is trying to import an object
384: * from.
385: */
386: ImportRegistry getImportRegistry(XletContext targetXlet) {
387: if (targetXlet == null)
388: return null;
389: ImportRegistry result;
390: synchronized (importRegistries) {
391: result = (ImportRegistry) importRegistries.get(targetXlet);
392: if (result == null) {
393: result = new ImportRegistry(context, targetXlet);
394: importRegistries.put(targetXlet, result);
395: }
396: }
397: return (ImportRegistry) result;
398: }
399:
400: void executeForClient(Runnable r) throws RemoteException {
401: worker.execute(r);
402: }
403:
404: // Convenience method to access IxcClassLoader based on XletContext
405: static IxcClassLoader getIxcClassLoader(XletContext ctxt) {
406: return getIxcRegistryImpl(ctxt).ixcClassLoader;
407: }
408: }
|