View Javadoc
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