KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > ubik > rmi > naming > remote > RemoteInitialContextFactory


1 package org.sapia.ubik.rmi.naming.remote;
2
3 import java.io.IOException JavaDoc;
4 import java.rmi.RemoteException JavaDoc;
5 import java.util.Hashtable JavaDoc;
6
7 import javax.naming.Context JavaDoc;
8 import javax.naming.InitialContext JavaDoc;
9 import javax.naming.NamingException JavaDoc;
10 import javax.naming.spi.InitialContextFactory JavaDoc;
11
12 import org.sapia.ubik.mcast.AsyncEventListener;
13 import org.sapia.ubik.mcast.EventChannel;
14 import org.sapia.ubik.mcast.RemoteEvent;
15 import org.sapia.ubik.net.TCPAddress;
16 import org.sapia.ubik.net.Uri;
17 import org.sapia.ubik.net.UriSyntaxException;
18 import org.sapia.ubik.rmi.naming.ServiceLocator;
19 import org.sapia.ubik.rmi.naming.remote.proxy.ContextResolver;
20 import org.sapia.ubik.rmi.naming.remote.proxy.DefaultContextResolver;
21 import org.sapia.ubik.rmi.naming.remote.proxy.ReliableLocalContext;
22 import org.sapia.ubik.rmi.server.Log;
23
24
25 /**
26  * Implements a factory that allows to register <code>ServiceDiscoveryListener</code>s
27  * that are notified when a service is bound to the JNDI servers.
28  *
29  * <p>
30  * Usage:
31  * <p>
32  * <pre>
33  * Properties props = new Properties();
34  *
35  * // IMPORTANT: the following line of code sets the domain name
36  * // to which this client (or rather, to which the JNDI context
37  * // thereafter acquired) belongs. Service discovery notifications
38  * // will only be received from the JNDI servers that belong to the
39  * // same domain as the thus acquired JNDI context.
40  *
41  * props.setProperty("ubik.jndi.domain", "someDomain");
42  *
43  * // If the above is not specified, the domain will be 'default'.
44  *
45  *
46  * props.setProperty(InitialContext.PROVIDER_URL, "ubik://localhost:1098/");
47  *
48  * // IMPORTANT: do not set the wrong factory, otherwise the code
49  * // further below will break...
50  *
51  * props.setProperty(InitialContext.INITIAL_CONTEXT_FACTORY,
52  * RemoteInitialContextFactory.class.getName());
53  *
54  * InitialContext ctx = new InitialContext(props);
55  *
56  * MyServiceDiscoveryListener listener = new MyServiceDiscoveryListener();
57  *
58  * ReliableLocalContext rctx = ReliableLocalContext.currentContext();
59  * rctx.addServiceDiscoListener(listener);
60  *
61  * // IMPORTANT: from then on, the listener will be notified if a new service
62  * // is bound to the domain, for AS LONG AS THE close() METHOD IS NOT CALLED
63  * // ON THE CONTEXT!!!
64  *
65  * // ... So do the following only when the acquired initial context must
66  * // be disposed of - the added listeners will not receive notifications
67  * // anymore:
68  * ctx.close();
69  * </pre>
70  *
71  * An instance of this class instantiates an <code>EventChannel</code> to receive
72  * notifications from the Ubik JNDI servers on the network, through UDP multicast.
73  * The multicast address and port can be specified through the following properties:
74  *
75  * <ul>
76  * <li>ubik.rmi.naming.mcast.address
77  * <li>ubik.rmi.naming.mcast.port
78  * </ul>
79  *
80  * These properties must be specified (and passed to an instance of this class) as
81  * demonstrated below:
82  *
83  * <pre>
84  * Properties props = new Properties();
85  *
86  * props.setProperty("ubik.rmi.naming.mcast.address", "224.0.0.10");
87  *
88  * props.setProperty("ubik.rmi.naming.mcast.port", "6565");
89  *
90  * props.setProperty(InitialContext.PROVIDER_URL, "ubik://localhost:1098/");
91  *
92  * props.setProperty(InitialContext.INITIAL_CONTEXT_FACTORY,
93  * ReliableInitialContextFactory.class.getName());
94  *
95  * props.setProperty(
96  *
97  * InitialContext ctx = new InitialContext(props);
98  * </pre>
99  *
100  * If not specified, the following are used for multicast address and port, respectively:
101  *
102  * <ul>
103  * <li>224.0.0.1
104  * <li>5454
105  * </ul>
106  *
107  *
108  * @see org.sapia.ubik.rmi.naming.remote.proxy.ReliableLocalContext
109  *
110  * @author Yanick Duchesne
111  * <dl>
112  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2003 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
113  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
114  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
115  * </dl>
116  */

117 public class RemoteInitialContextFactory implements InitialContextFactory JavaDoc, Consts {
118   private String JavaDoc _scheme = ServiceLocator.UBIK_SCHEME;
119   
120   public RemoteInitialContextFactory() {
121   }
122   
123   public RemoteInitialContextFactory(String JavaDoc serviceLocatorScheme) {
124     _scheme = serviceLocatorScheme;
125   }
126   
127   /**
128    * @see javax.naming.spi.InitialContextFactory#getInitialContext(Hashtable)
129    */

130   public Context JavaDoc getInitialContext(Hashtable JavaDoc props) throws NamingException JavaDoc {
131     String JavaDoc url = (String JavaDoc) props.get(InitialContext.PROVIDER_URL);
132     
133     if (url == null) {
134       throw new NamingException JavaDoc(InitialContext.PROVIDER_URL +
135         " property not specified");
136     }
137     
138     Uri uri = null;
139     try{
140       uri = Uri.parse(url);
141     }catch(UriSyntaxException e){
142       NamingException JavaDoc ne = new NamingException JavaDoc("Invalid URL:" + url);
143       ne.setRootCause(e);
144       throw ne;
145     }
146     
147     uri.setScheme(_scheme);
148     
149     String JavaDoc domain;
150     
151     if (props.get(UBIK_DOMAIN_NAME) == null) {
152       domain = JNDIServerHelper.DEFAULT_DOMAIN;
153     } else {
154       domain = (String JavaDoc) props.get(UBIK_DOMAIN_NAME);
155     }
156     
157     String JavaDoc mcastAddr = org.sapia.ubik.rmi.Consts.DEFAULT_MCAST_ADDR;
158     int mcastPort = org.sapia.ubik.rmi.Consts.DEFAULT_MCAST_PORT;
159     
160     if (props.get(Consts.MCAST_ADDR_KEY) != null) {
161       mcastAddr = (String JavaDoc) props.get(MCAST_ADDR_KEY);
162     }
163     
164     if (props.get(MCAST_PORT_KEY) != null) {
165       try {
166         mcastPort = Integer.parseInt((String JavaDoc) props.get(MCAST_PORT_KEY));
167       } catch (NumberFormatException JavaDoc e) {
168         throw new NamingException JavaDoc("Invalid multicast port: " + mcastPort);
169       }
170     }
171     
172     EventChannel ec = null;
173     RemoteContext ctx = null;
174     ContextResolver resolver = doGetResolver();
175     
176     try{
177       ec = new EventChannel(domain, mcastAddr, mcastPort);
178       ec.start();
179     }catch(IOException JavaDoc e){
180       NamingException JavaDoc ne = new NamingException JavaDoc("Could not start event channel");
181       ne.setRootCause(e);
182       throw ne;
183     }
184     
185     try {
186       ctx = doGetResolver().resolve(uri.getHost(), uri.getPort());
187     } catch (RemoteException JavaDoc e) {
188       
189       Log.warning(getClass(), "Could not find JNDI server for : " + uri.toString() + "; trying to discover");
190       BlockingEventListener listener = new BlockingEventListener();
191       ec.registerAsyncListener(JNDI_SERVER_DISCO, listener);
192       TCPAddress addr = null;
193       try{
194         ec.dispatch(JNDI_CLIENT_PUBLISH, "");
195         
196         RemoteEvent evt = listener.waitForEvent(10000);
197         ec.unregisterListener(listener);
198         
199         if (evt == null) {
200           NamingException JavaDoc ne = new NamingException JavaDoc(
201             "could not connect to JNDI server");
202           ne.setRootCause(e);
203           throw ne;
204         }
205         
206         addr = (TCPAddress) evt.getData();
207         
208         Log.warning(getClass(), "Disovered JNDI server at : " + addr);
209         ctx = resolver.resolve(addr);
210         return new ReliableLocalContext(ec, uri.toString(), ctx, false, resolver);
211       }catch(Exception JavaDoc e2){
212         NamingException JavaDoc ne = new NamingException JavaDoc("Could not connect to remote JNDI server: " + addr);
213         ne.setRootCause(e2);
214         throw ne;
215       }
216     }
217     try{
218       return new ReliableLocalContext(ec, uri.toString(), ctx, true, resolver);
219     }catch(IOException JavaDoc e){
220       NamingException JavaDoc ne = new NamingException JavaDoc("Could not instantiate local context");
221       ne.setRootCause(e);
222       throw ne;
223     }
224     
225   }
226   
227   protected ContextResolver doGetResolver(){
228     return new DefaultContextResolver();
229   }
230   /*
231   protected RemoteContext doGetRemoteContext(String host, int port)
232   throws RemoteException {
233     return (RemoteContext) Hub.connect(host, port);
234   }*/

235   
236   static final class BlockingEventListener implements AsyncEventListener {
237     private RemoteEvent _evt;
238     
239     BlockingEventListener() {
240     }
241     
242     /**
243      * @see org.sapia.ubik.mcast.AsyncEventListener#onAsyncEvent(RemoteEvent)
244      */

245     public synchronized void onAsyncEvent(RemoteEvent evt) {
246       _evt = evt;
247       notify();
248     }
249     
250     public synchronized RemoteEvent waitForEvent(long timeout) {
251       long start = System.currentTimeMillis();
252       
253       try {
254         while (((System.currentTimeMillis() - start) < timeout) &&
255           (_evt == null)) {
256           wait(timeout);
257         }
258       } catch (InterruptedException JavaDoc e) {
259         return null;
260       }
261       
262       return _evt;
263     }
264   }
265 }
266
Popular Tags