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 JEGG 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.registry;
30
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Vector;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 import jegg.Egg;
41 import jegg.Message;
42 import jegg.Port;
43 import jegg.Priority;
44
45 /***
46 * Provides a naming service for eggs. Eggs indirectly communicate
47 * with the registry, to publish or request ports, via jegg.Egg
48 * base class methods: {@link jegg.Egg.publishPort() Egg.publishPort}
49 * and {@link jegg.Egg.requestPort(String) Egg.requestPort}.
50 * <p>
51 * The Registry can be directly communicated with by sending either a
52 * {@link jegg.registry.LocatePortMessage LocatePortMessage} message or
53 * a {@link jegg.registry.PublishPortMessage PublishPortMessage}.
54 */
55 public final class PortRegistry extends Egg
56 {
57 // The current implementation can allow a hierarchy
58 // of registries, but that feature isn't used, yet.
59
60 public final static Log LOG = LogFactory.getLog(PortRegistry.class);
61
62 /*** The name separator used to compose the path name of a registry. */
63 public static final String SEPARATOR = "/";
64 /*** Registry contexts */
65 private static final Map _contexts_ = new HashMap();
66 /*** The name of this service instance */
67 private String _name;
68 /*** The parent context of this service instance */
69 private PortRegistry _parent;
70 /*** The ports that have subscribed with this service */
71 private Map _ports;
72 /*** Child contexts */
73 private Map _children = new HashMap();
74 /*** Outstanding port requests */
75 private List _outstanding = new Vector();
76 /*** List of queued requests that have been serviced */
77 private List _doneList = new Vector();
78
79 /***
80 * Return the default registry.
81 * @return the default registry.
82 */
83 public static final PortRegistry getInstance()
84 {
85 return getInstance(".");
86 }
87
88 /***
89 * Get a named registry. If the named registry doesn't
90 * exist, it will be created.
91 * @param name the name of the context to find or create.
92 * @return a registry.
93 */
94 public static final PortRegistry getInstance(final String name)
95 {
96 PortRegistry registry = null;
97 synchronized (_contexts_)
98 {
99 registry = (PortRegistry) _contexts_.get(name);
100 if (null == registry)
101 {
102 registry = new PortRegistry(name);
103 _contexts_.put(name, registry);
104 }
105 }
106 return registry;
107 }
108
109 /***
110 * Construct a port service.
111 * @param name the name to associate with this service instance.
112 */
113 private PortRegistry(final String name)
114 {
115 this(name, null);
116 }
117
118 /***
119 * Construct a port service as a child of a parent
120 * context.
121 * @param name the name to associate with this service instance.
122 * @param parent the parent context of this instance.
123 */
124 private PortRegistry(final String name, final PortRegistry parent)
125 {
126 super(PortRegistry.class.getName());
127 this._name = name;
128 this._parent = parent;
129 this._ports = new HashMap();
130 }
131
132 /***
133 * Create a child registry of this registry.
134 * @param name the name to assign to the child registry
135 * @return the new child registry.
136 * @throws DuplicateNameException if the name already exists in
137 * this context.
138 */
139 public final PortRegistry createRegistry(final String name)
140 throws DuplicateNameException
141 {
142 if (_children.containsKey(name))
143 {
144 throw new DuplicateNameException("already exists: " + name);
145 }
146 PortRegistry registry = new PortRegistry(name, this);
147 _children.put(name, registry);
148 return registry;
149 }
150
151 /***
152 * Register a port with this service.
153 * @param name The name to publish the port under.
154 * @param port The port to publish.
155 * @throws DuplicateNameException if an attempt is made to
156 * publish a port under a name that already exists in the registry.
157 */
158 private void register(final String name, final Port port)
159 throws DuplicateNameException
160 {
161 if (_ports.containsKey(name))
162 {
163 throw new DuplicateNameException("already registered: " + name);
164 }
165
166 _ports.put(name, port);
167 }
168
169 /***
170 * Determine if this registry contains an entry for the
171 * specified name.
172 * @param name the entry name to search for.
173 * @return true if the name is registered; otherwise, false;
174 */
175 boolean isRegistered(final String name)
176 {
177 return _ports.containsKey(name);
178 }
179
180 /***
181 * Return the port registered under a specified name. If the port is
182 * not registered in this context, then the parent context is searched
183 * (recursively).
184 * @param name the name of the port to return;
185 * @return the port registered under the specified name, or null if none
186 * is found in this context or the parent's.
187 */
188 Port getPort(final String name)
189 {
190 if (isRegistered(name))
191 {
192 return (Port) _ports.get(name);
193 }
194 else if (null != _parent)
195 {
196 return _parent.getPort(name);
197 }
198 else
199 {
200 return null;
201 }
202 }
203
204 /***
205 * Return the parent context of this registry, if any.
206 * @return the parent context, or null if none.
207 */
208 PortRegistry getParent()
209 {
210 return _parent;
211 }
212
213 /***
214 * Return the name of this registry.
215 * @return the registry name.
216 */
217 String getName()
218 {
219 return _name;
220 }
221
222 /***
223 * Get the full name of this registry. The full name of
224 * the registry is composed of the names of it's parent and
225 * all ancestors concantenated using the SEPARATOR character.
226 * If the registry is a singleton (has no parent), then the
227 * full name is identical to the value returned by the
228 * <code>getName()</code> method.
229 * @return the full name of the registry.
230 */
231 String getFullName()
232 {
233 if (null == _parent)
234 {
235 return getName();
236 }
237 else
238 {
239 return getParent().getFullName() + SEPARATOR + getName();
240 }
241 }
242
243 /***
244 * Search this registry context for a port registered
245 * using the specified name. Child contexts, if any, or
246 * also searched.
247 * @param name the name of the port to search for.
248 * @return the port, or null if not found.
249 */
250 Port find(final String name)
251 {
252 List stack = new Vector();
253 stack.add(this);
254 while (!stack.isEmpty())
255 {
256 PortRegistry registry = (PortRegistry) stack.remove(0);
257 if (registry.isRegistered(name))
258 {
259 return registry.getPort(name);
260 }
261
262 PortRegistry[] children = registry.getChildren();
263 for (int i = 0; i < children.length; ++i)
264 {
265 stack.add(children[i]);
266 }
267 }
268
269 return null;
270 }
271
272 /***
273 * Return the subcontext registries of this registry.
274 * @return arrray of PortRegistry instances, which may
275 * be empty.
276 */
277 PortRegistry[] getChildren()
278 {
279 return (PortRegistry[]) _children.values().toArray(
280 new PortRegistry[_children.size()]);
281 }
282
283 /* (non-Javadoc)
284 * @see egg.Egg#handle(java.lang.Object)
285 */
286 public void handle(Object message)
287 {
288 LOG.debug("PortRegistry: got unexpected 'Object' message");
289 }
290
291 /***
292 * Handle a lookup request from a client egg.
293 * @param message the lookup details.
294 */
295 public void handle(LocatePortMessage message)
296 {
297 LOG.debug("PortRegistry: got LocateMessage");
298
299 String name = message.getName();
300 Port p = find(name);
301 if (null != p)
302 {
303 respond(new LocatePortResponse(name,p));
304 }
305 else
306 {
307 _outstanding.add(new QueuedRequest(name,getFromPort()));
308 }
309 }
310
311
312 /***
313 * Inner class used to hold the details of a lookup request that
314 * can't be serviced yet.
315 */
316 private class QueuedRequest
317 {
318 public String name;
319 public Port requestor;
320 public QueuedRequest(String n,Port r)
321 {
322 name = n;
323 requestor = r;
324 }
325 }
326
327 /***
328 * Handle a request to publish a named port in the registry.
329 * @param message the message containing the details.
330 */
331 public void handle(PublishPortMessage message)
332 {
333 System.err.println("PortRegistery: got PublishMessage");
334
335 String name = message.getName();
336 Port p = message.getPort();
337 try
338 {
339 register(name, p);
340 _doneList.clear();
341 if (!_outstanding.isEmpty())
342 {
343 Message msg = new Message(new LocatePortResponse(name,p),getPort(),Priority.MEDIUM);
344 for (Iterator it=_outstanding.iterator(); it.hasNext(); )
345 {
346 QueuedRequest qr = (QueuedRequest) it.next();
347 if (qr.name.equals(name))
348 {
349 qr.requestor.send(msg);
350 _doneList.add(qr);
351 }
352 }
353 for (Iterator it=_doneList.iterator(); it.hasNext(); )
354 {
355 QueuedRequest qr = (QueuedRequest) it.next();
356 _outstanding.remove(qr);
357 }
358 _doneList.clear();
359 }
360 }
361 catch (DuplicateNameException e)
362 {
363 getFromPort().send(createMessage(e));
364 }
365 }
366 }
This page was automatically generated by Maven