001: /*
002: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: *
024: */
025:
026: package com.sun.jumpimpl.ixc.executive;
027:
028: import java.rmi.*;
029: import java.net.ServerSocket;
030: import java.net.Socket;
031: import java.io.ObjectInputStream;
032: import java.io.ObjectOutputStream;
033: import java.util.ArrayList;
034: import java.util.HashMap;
035: import java.util.HashSet;
036: import java.util.Iterator;
037: import java.util.Set;
038:
039: import javax.microedition.xlet.XletContext;
040: import javax.microedition.xlet.ixc.IxcRegistry;
041: import javax.microedition.xlet.ixc.StubException;
042:
043: import com.sun.jumpimpl.ixc.JUMPExecIxcRegistryRemote;
044:
045: import com.sun.jumpimpl.ixc.ConnectionReceiver;
046: import com.sun.jumpimpl.ixc.ExportedObject;
047: import com.sun.jumpimpl.ixc.RemoteRef;
048: import com.sun.jumpimpl.ixc.Utils;
049: import com.sun.jumpimpl.ixc.XletContextFactory;
050:
051: /*
052: * This is the main, master IxcRegistry that is created in the Executive VM and
053: * exported as a Remote service itself. The client VMs use JUMPIxcRegistryImpl
054: * as it's IxcRegistry class and invokes methods essential for IXC, such as bind,
055: * lookup, list, etc. Underneath the cover, JUMPIxcRegistryImpl has a stub to
056: * this JUMPExecIxcRegistry and invokes those method calls as a remote method
057: * invocation to this JUMPExecIxcRegistry. Therefore this class serves as a single
058: * database of all the registered Remote objects among the Executive VM and all the
059: * client VMs.
060: *
061: * The remote methods in this class (the methods defined in
062: * JUMPExecIxcRegistryRemote and it's superinterface, java.rmi.registry.Registry)
063: * is expected to be called remotely and should not be invoked directly on this class.
064: * If you need to use these remote methods in the executive VM, call them through
065: * JUMPExecIxcRegistryWrapper to avoid false import/export of the remote object.
066: */
067: public class JUMPExecIxcRegistry extends IxcRegistry implements
068: JUMPExecIxcRegistryRemote {
069:
070: private int jumpExecMasterAppId;
071: private int portNumber;
072:
073: // <name, RemoteRef>
074: private HashMap registeredObjects = new HashMap();
075:
076: // <RemoteRef, HashSet of imported xlet IDs>
077: private HashMap importedObjects = new HashMap();
078:
079: private static JUMPExecIxcRegistry registry;
080:
081: /*
082: * Creats and starts the JUMPExecIxcRegistry to be used for the Client VMs.
083: */
084: private JUMPExecIxcRegistry() {
085:
086: try {
087: /*
088: * Use the system classloader to mark this registry. This classloader
089: * would later be used for loading the stub classes for the remote objects.
090: */
091: ClassLoader loader = ClassLoader.getSystemClassLoader();
092: XletContext context = XletContextFactory
093: .getXletContext(loader);
094:
095: /* Automatically export this registry to be available for the client VMs */
096: ExportedObject.registerExportedObject(this , context);
097:
098: /* Now let's start listening to the incoming requests. */
099: ConnectionReceiver.startExecVMService();
100:
101: /*
102: * Remember the Exec VM's process ID. This number would be used
103: * to keep track of the stubs the Executive VM imports,
104: * which is needed to count the number of references left for the
105: * exported objects for cleanup.
106: */
107: jumpExecMasterAppId = Utils.getMtaskServerID();
108:
109: } catch (Exception e) {
110: System.out.println("Cannot export JUMPExecIxcRegistry!!"
111: + e);
112: return;
113: }
114: }
115:
116: public static synchronized void startExecVMService() {
117: if (registry != null) {
118: throw new InternalError(
119: "JUMPExecIxcRegistry has already been created.");
120: }
121: registry = new JUMPExecIxcRegistry();
122: }
123:
124: public static synchronized JUMPExecIxcRegistry getJUMPExecIxcRegistry() {
125: if (registry == null) {
126: throw new InternalError(
127: "JUMPExecIxcRegistry hasn't been created.");
128: }
129:
130: return registry;
131: }
132:
133: public Remote lookup(String name) throws StubException,
134: NotBoundException {
135: synchronized (registeredObjects) {
136: if (!registeredObjects.containsKey(name)) {
137: throw new NotBoundException("Name not bound: " + name);
138: }
139:
140: return (Remote) registeredObjects.get(name);
141: }
142: }
143:
144: public void bind(String name, Remote obj) throws StubException,
145: AlreadyBoundException {
146: synchronized (registeredObjects) {
147: if (registeredObjects.containsKey(name)) {
148: throw new AlreadyBoundException("Name already bound: "
149: + name);
150: }
151: registeredObjects.put(name, obj);
152: }
153:
154: notifyObjectImport(jumpExecMasterAppId, obj);
155: }
156:
157: public void unbind(String name) throws NotBoundException,
158: AccessException {
159:
160: Remote r;
161: synchronized (registeredObjects) {
162: if (!registeredObjects.containsKey(name)) {
163: throw new NotBoundException("Name not bound: " + name);
164: }
165: r = (Remote) registeredObjects.remove(name);
166: }
167:
168: // If noone else is binding this remote object to the IxcRegistry
169: // using another name, then remove the MasterApp's ID from the
170: // importedObjects list also.
171: if (!registeredObjects.containsValue(r)) {
172: synchronized (importedObjects) {
173: Set set = (Set) importedObjects.get(r);
174: if (set != null)
175: set.remove(new Integer(jumpExecMasterAppId));
176: }
177: }
178: }
179:
180: public void rebind(String name, Remote obj) throws StubException,
181: AccessException {
182: // Unbind, bind.
183: try {
184: unbind(name);
185: bind(name, obj);
186: } catch (NotBoundException e) {// forget it
187: } catch (AlreadyBoundException e) { // can't happen
188: throw new StubException("Error in rebind", e);
189: }
190: }
191:
192: public String[] list() {
193: String[] list;
194: synchronized (registeredObjects) {
195: list = (String[]) registeredObjects.keySet().toArray(
196: new String[] {});
197: }
198: return list;
199: }
200:
201: public void unbindAll() {
202: // Unbind all the objects exported by this guy.
203: System.out
204: .println("@@@JUMPExecIxcRegistry.unbindAll() not implemented");
205: }
206:
207: public void notifyObjectImport(int importingXletID, Remote ref) {
208:
209: synchronized (importedObjects) {
210: Set set = (Set) importedObjects.get(ref);
211: if (set == null) {
212: set = new HashSet();
213: importedObjects.put(ref, set);
214: }
215: set.add(new Integer(importingXletID));
216: }
217: }
218:
219: public Remote lookupWithXletID(String name, int importingXletID)
220: throws RemoteException, NotBoundException, AccessException {
221:
222: Remote r = lookup(name);
223:
224: if (importingXletID != ((RemoteRef) r).getXletID()) {
225: notifyObjectImport(importingXletID, r);
226: }
227:
228: return r;
229: }
230:
231: // JUMPExecAppControllerListener's handler for
232: // AppManager's task_killed events.
233: public void taskEvent(String appID, int what) {
234: //Need to implement using JUMP APIs
235: //if (what == TaskListener.CDCAMS_TASK_KILLED) {
236: // updater.addAppID(appID);
237: //}
238: }
239:
240: /*
241: * A thread that updates JUMPExecAppRegistry's
242: * imported remote object data structure in response to the
243: * client died notification from the master mvm VM.
244: */
245: class RegistryListUpdater implements Runnable {
246:
247: private ArrayList appIDs = new ArrayList();
248:
249: public synchronized void addAppID(int id) {
250: appIDs.add(new Integer(id));
251: }
252:
253: public synchronized int getNextAppID() {
254: while (appIDs.isEmpty()) {
255: try {
256: wait(1000);
257: } catch (InterruptedException e) {
258: }
259: }
260:
261: return ((Integer) appIDs.remove(0)).intValue();
262: }
263:
264: public void run() {
265: for (;;) {
266: iterateLists(getNextAppID());
267: }
268: }
269:
270: public void iterateLists(int appID) {
271:
272: String name;
273: RemoteRef ref;
274: ArrayList nameList = new ArrayList();
275:
276: // Remove objects bound by this dying xlet from this
277: // IxcRegistry.
278: synchronized (registeredObjects) {
279: Iterator iterator = registeredObjects.keySet()
280: .iterator();
281: while (iterator.hasNext()) {
282: name = (String) iterator.next();
283: ref = (RemoteRef) registeredObjects.get(name);
284: if (ref.getXletID() == appID) {
285: nameList.add(name);
286: }
287: }
288: for (int i = 0; i < nameList.size(); i++) {
289: registeredObjects.remove(nameList.get(i));
290: }
291: }
292:
293: Set set;
294: ArrayList refList = new ArrayList();
295: synchronized (importedObjects) {
296:
297: // First, need to remove all RemoteRefs exported by this dying
298: // xlet from the importedObjects hash.
299: // Second, need to iterate other RemoteRefs, and remove
300: // the ID recorded for this dying xlet.
301: // Finally, if this dying xlet's ID is the last item of
302: // the other RemoteRefs' set, then remove that RemoteRef
303: // from the hash too, and notify the RemoteRef owner
304: // that nobody holds an reference to that RemoteObject so
305: // it can safely be discarded for GC.
306:
307: Iterator iterator = importedObjects.keySet().iterator();
308: while (iterator.hasNext()) {
309: ref = (RemoteRef) iterator.next();
310:
311: if (ref.getXletID() == appID) {
312: // Need to remove this RemoteRef.
313: refList.add(ref);
314: } else {
315: // Need to update this RemoteRef's Set.
316: set = (Set) importedObjects.get(ref);
317: set.remove(new Integer(appID));
318:
319: if (set.isEmpty()) {
320: refList.add(ref);
321: notifyReferenceRemoval(ref);
322: }
323: }
324: }
325:
326: for (int i = 0; i < refList.size(); i++) {
327: importedObjects.remove(refList.get(i));
328: }
329: }
330: }
331:
332: private void notifyReferenceRemoval(RemoteRef ref) {
333: // ToDo: Need to implement
334: System.out.println("@@@notifyReferenceRemoval: " + ref);
335: }
336: }
337:
338: }
|