KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jegg > impl > PortRegistry


1 /*
2  * Copyright (c) 2004, Bruce Lowery
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * - Neither the name of GOSSIP nor the names of its contributors may be used
14  * to endorse or promote products derived from this software without
15  * specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */

29 package jegg.impl;
30
31 import java.util.HashMap JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Vector JavaDoc;
36
37 import jegg.EggBase;
38 import jegg.Port;
39 import jegg.PortException;
40
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43
44 /**
45  *
46  *
47  * @author Bruce Lowery
48  */

49 public class PortRegistry extends EggBase
50 {
51     private static final Log LOG = LogFactory.getLog(PortRegistry.class);
52     /** The name separator used to compose the path name of a registry. */
53     public static final String JavaDoc SEPARATOR = "/";
54     /** Registry contexts */
55     private static final Map JavaDoc _contexts_ = new HashMap JavaDoc();
56     /** My egg */
57     private String JavaDoc _name;
58     private PortRegistry _parent;
59     /** The ports that have subscribed with this service */
60     private Map JavaDoc _ports = new HashMap JavaDoc();
61     /** Child contexts */
62     private Map JavaDoc _children = new HashMap JavaDoc();
63     /** Outstanding port requests */
64     private List JavaDoc _outstanding = new Vector JavaDoc();
65     /** List of queued requests that have been serviced */
66     private List JavaDoc _doneList = new Vector JavaDoc();
67
68     /**
69      * Return the default registry.
70      * @return the default registry.
71      */

72     public static final PortRegistry getInstance()
73     {
74         return getInstance(".");
75     }
76
77     /**
78      * Get a named registry. If the named registry doesn't
79      * exist, it will be created.
80      * @param name the name of the context to find or create.
81      * @return a registry.
82      */

83     public static final PortRegistry getInstance(final String JavaDoc name)
84     {
85         PortRegistry registry = null;
86         synchronized (_contexts_)
87         {
88             registry = (PortRegistry) _contexts_.get(name);
89             if (null == registry)
90             {
91                 try
92                 {
93                     EggInfo info = HenHouse.getHenHouse().hatch(name,PortRegistry.class.getName(),null,true, true);
94                     registry = (PortRegistry) info.getEgg().getHandler();
95                     registry.setName(name);
96                     _contexts_.put(name, registry);
97                 }
98                 catch (HatchException e)
99                 {
100                     LOG.error("Failed to hatch port registry "+name);
101                 }
102             }
103         }
104         return registry;
105     }
106     
107     PortRegistry()
108     {
109         super();
110     }
111     
112     PortRegistry(final String JavaDoc name)
113     {
114         this(name,null);
115     }
116     
117     PortRegistry(final String JavaDoc name, final PortRegistry parent)
118     {
119         super();
120         _name = name;
121         _parent = parent;
122     }
123
124     void setName(final String JavaDoc n) {_name = n;}
125     
126     public Port getPort()
127     {
128         return getContext().getPort();
129     }
130     
131     /* (non-Javadoc)
132      * @see egg.Egg#handle(java.lang.Object)
133      */

134     public void handle(Object JavaDoc message)
135     {
136         LOG.warn("PortRegistry: got unexpected 'Object' message: "+message);
137     }
138     
139     /**
140      * Handle a lookup request from a client egg.
141      * @param message the lookup details.
142      */

143     public void handle(LocatePortMessage message)
144     {
145         LOG.debug("PortRegistry: got LocateMessage");
146         
147         String JavaDoc name = message.getName();
148         Port p = find(name);
149         if (null != p)
150         {
151             getContext().respond(p);
152         }
153         else
154         {
155             _outstanding.add(new QueuedRequest(name,getContext().getFromPort()));
156         }
157     }
158     
159     
160     /**
161      * Inner class used to hold the details of a lookup request that
162      * can't be serviced yet.
163      */

164     private class QueuedRequest
165     {
166         public String JavaDoc name;
167         public Port requestor;
168         public QueuedRequest(String JavaDoc n,Port r)
169         {
170             name = n;
171             requestor = r;
172         }
173     }
174     
175     /**
176      * Handle a request to publish a named port in the registry.
177      * @param message the message containing the details.
178      */

179     public void handle(PublishPortMessage message)
180     {
181         //System.err.println("PortRegistery: got PublishMessage");
182

183         String JavaDoc name = message.getName();
184         Port p = message.getPort();
185         try
186         {
187             register(name, p);
188             _doneList.clear();
189             if (!_outstanding.isEmpty())
190             {
191                 MessageImpl msg = new MessageImpl(p,getContext().getPort(),Priority.MEDIUM);
192                 for (Iterator JavaDoc it=_outstanding.iterator(); it.hasNext(); )
193                 {
194                     QueuedRequest qr = (QueuedRequest) it.next();
195                     if (qr.name.equals(name))
196                     {
197                         try
198                         {
199                             qr.requestor.send(msg);
200                         }
201                         catch (PortException e1)
202                         {
203                             LOG.error("Failed to send locate port response "+msg+": ", e1);
204                         }
205                         _doneList.add(qr);
206                     }
207                 }
208                 for (Iterator JavaDoc it=_doneList.iterator(); it.hasNext(); )
209                 {
210                     QueuedRequest qr = (QueuedRequest) it.next();
211                     _outstanding.remove(qr);
212                 }
213                 _doneList.clear();
214             }
215         }
216         catch (DuplicatePortException e)
217         {
218             try
219             {
220                 //System.err.println("sending duplicate-name-exception");
221
getContext().getFromPort().send(getContext().createMessage(e));
222             }
223             catch (PortException e1)
224             {
225                 LOG.error("Failed to send duplicate-name-exception "+e.getMessage(), e1);
226             }
227         }
228     }
229     
230     /**
231      * Create a child registry of this registry.
232      * @param name the name to assign to the child registry
233      * @return the new child registry.
234      * @throws DuplicatePortException if the name already exists in
235      * this context.
236      */

237     public final PortRegistry createRegistry(final String JavaDoc name)
238         throws DuplicatePortException
239     {
240         if (_children.containsKey(name))
241         {
242             throw new DuplicatePortException(name);
243         }
244         PortRegistry registry = new PortRegistry(name, this);
245         _children.put(name, registry);
246         return registry;
247     }
248     
249     /**
250      * Search this registry context for a port registered
251      * using the specified name. Child contexts, if any, or
252      * also searched.
253      * @param name the name of the port to search for.
254      * @return the port, or null if not found.
255      */

256     Port find(final String JavaDoc name)
257     {
258         List JavaDoc stack = new Vector JavaDoc();
259         stack.add(this);
260         while (!stack.isEmpty())
261         {
262             PortRegistry registry = (PortRegistry) stack.remove(0);
263             if (registry.isRegistered(name))
264             {
265                 return registry.getPort(name);
266             }
267
268             PortRegistry[] children = registry.getChildren();
269             for (int i = 0; i < children.length; ++i)
270             {
271                 stack.add(children[i]);
272             }
273         }
274
275         return null;
276     }
277
278     /**
279      * Return the subcontext registries of this registry.
280      * @return arrray of PortRegistry instances, which may
281      * be empty.
282      */

283     PortRegistry[] getChildren()
284     {
285         return (PortRegistry[]) _children.values().toArray(
286             new PortRegistry[_children.size()]);
287     }
288
289     /**
290      * Register a port with this service.
291      * @param name The name to publish the port under.
292      * @param port The port to publish.
293      * @throws DuplicatePortException if an attempt is made to
294      * publish a port under a name that already exists in the registry.
295      */

296     private void register(final String JavaDoc name, final Port port)
297         throws DuplicatePortException
298     {
299         //System.err.println("register("+name+")");
300

301         if (_ports.containsKey(name))
302         {
303             //System.err.println("duplicate name: "+name);
304
throw new DuplicatePortException("already registered: " + name);
305         }
306
307         _ports.put(name, port);
308     }
309
310     /**
311      * Determine if this registry contains an entry for the
312      * specified name.
313      * @param name the entry name to search for.
314      * @return true if the name is registered; otherwise, false;
315      */

316     boolean isRegistered(final String JavaDoc name)
317     {
318         return _ports.containsKey(name);
319     }
320
321     /**
322      * Return the port registered under a specified name. If the port is
323      * not registered in this context, then the parent context is searched
324      * (recursively).
325      * @param name the name of the port to return;
326      * @return the port registered under the specified name, or null if none
327      * is found in this context or the parent's.
328      */

329     Port getPort(final String JavaDoc name)
330     {
331         if (isRegistered(name))
332         {
333             return (Port) _ports.get(name);
334         }
335         else if (null != _parent)
336         {
337             return _parent.getPort(name);
338         }
339         else
340         {
341             return null;
342         }
343     }
344
345     /**
346      * Return the parent context of this registry, if any.
347      * @return the parent context, or null if none.
348      */

349     PortRegistry getParent()
350     {
351         return _parent;
352     }
353
354     /**
355      * Return the name of this registry.
356      * @return the registry name.
357      */

358     String JavaDoc getName()
359     {
360         return _name;
361     }
362
363     /**
364      * Get the full name of this registry. The full name of
365      * the registry is composed of the names of it's parent and
366      * all ancestors concantenated using the SEPARATOR character.
367      * If the registry is a singleton (has no parent), then the
368      * full name is identical to the value returned by the
369      * <code>getName()</code> method.
370      * @return the full name of the registry.
371      */

372     String JavaDoc getFullName()
373     {
374         if (null == _parent)
375         {
376             return getName();
377         }
378         else
379         {
380             return getParent().getFullName() + PortRegistry.SEPARATOR + getName();
381         }
382     }
383
384 }
385
Popular Tags