001 /* 002 * NodeNameRegistrar.java 003 * 004 * Developed for the "Rethinking CS101" project. See http://www.cs101.org, the 005 * CS101 homepage or email las@olin.edu. 006 * 007 * Created on February 19, 2003, 2:32 PM 008 */ 009 010 package nodenet.registrar; 011 012 import nodenet.Node; 013 import nodenet.NodeConfigurationBean; 014 015 import java.io.Serializable; 016 import java.io.ObjectStreamException; 017 import java.util.List; 018 import java.util.Vector; 019 import java.beans.VetoableChangeListener; 020 import java.beans.PropertyChangeEvent; 021 import java.beans.PropertyVetoException; 022 023 /** 024 * Tracks all nodes and ensures that they have legal names. Besides providing 025 * legal names via the {@link #nameAndRegister} method it listens for changes to 026 * node names and vetos any attempt to create am illegal node name. To avoid 027 * multiple registry problems, this class is uses the sigleton pattern, and 028 * the one true <code>NodeNameRegistrar</code> can be obtained via the 029 * static method {@link #getInstance()}. 030 * 031 * <p>This implementation only checks for uniquenes of names, and 032 * accomodates up to Integer.MAX_VALUE nodes, wich is 033 * limited by the Vector class used to store node references. There is also 034 * a limit of Integer.MAX_VALUE name requests during the lifetime of this 035 * registrar object, as unique names are generated in the format "Node X" 036 * where X is replaced by an integer. <strong>If a node name is changed to 037 * "Node Y" where Y is an integer. 038 * 039 * @author Patrick G. Heck, gus.heck@olin.edu 040 * @version $Id: NodeNameRegistry.java,v 1.5 2004/01/14 21:04:16 gus Exp $ 041 */ 042 public final class NodeNameRegistry implements NodeNameRegistrar { 043 044 private static final NodeNameRegistry SINGLETON = new NodeNameRegistry(); 045 046 private NodeNameRegistrar policy; 047 048 /** Prevent independant instantiation */ 049 private NodeNameRegistry() { 050 } 051 052 /** 053 * Factory method to get the one true <code>NodeNameRegistrar</code>. 054 * 055 * @return the registrar object. 056 */ 057 public static NodeNameRegistry getInstance() { 058 return SINGLETON; 059 } 060 061 /** 062 * Set the registrartion policy one time only. This method may not be 063 * invoked more than once. Subsequent invocations will throw an 064 * <code>IllegalStateException</code>. This is necessary to prevent 065 * the registered nodes from being lost. In the future a changePolicy 066 * method may be provided for "graceful" transition between policies. 067 * Note that "graceful" may include deletion of existing nodes. 068 * 069 * @param policy An naming policy implemented as a NodeNameRegistrar. 070 */ 071 public void setPolicy(NodeNameRegistrar policy) { 072 if (!isPolicySet()) { 073 this.policy = policy; 074 } else { 075 throw new IllegalStateException("Policy already set!"); 076 } 077 } 078 079 /** 080 * Check to see if the policy has been set for this registry. 081 * 082 * @return <code>true</code> if the policy has been set, <code>false</code> 083 * otherwise 084 */ 085 086 public boolean isPolicySet() { 087 return (policy == null) ? false : true; 088 } 089 090 // This allows us to deserialize objects containing a reference to the 091 // NodeNameRegistry and never cause duplicate registries. This technique 092 // means that when nodes are deserialized they need to re-register 093 // with the existing registry. 094 private Object readResolve() throws ObjectStreamException { 095 return SINGLETON; 096 } 097 098 public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { 099 if (!isPolicySet()) { 100 throw new IllegalStateException("Policy not set! (method:vetoableChange)"); 101 } 102 103 if (pce.getPropertyName().equals(NodeConfigurationBean.PROP_NODE_NAME)) { 104 this.policy.vetoableChange(pce); 105 } 106 } 107 108 /* (Copy of original doc. Generated version is inherited) 109 * 110 * Provides a name that is currently legal. The legality of the name is 111 * not guaranteed to remain legal for all time. This is particularly true 112 * if the policy implemented by the <code>Registrar</code> requires names 113 * to be unique. The implementation of this method should make a reasonable 114 * attempt not to give out names that will become illegal quickly, either 115 * due to temporal relevance of the name, or due to copetition between 116 * names given out to the clients. For example, this method should not 117 * give out the same node name on consecutive invocations if uniqueness is 118 * a qualification for legality. 119 * 120 * @returns A name that is currently legal, and should remain legal for a 121 * reasonable period of time, if possible. 122 */ 123 public String getLegalName() { 124 if (!isPolicySet()) { 125 throw new IllegalStateException("Policy not set!(method:getLegalName)"); 126 } 127 return this.policy.getLegalName(); 128 } 129 130 /* (Copy of original doc. Generated version is inherited) 131 * 132 * Provides access to nodes via their registred name. This method is 133 * optional, but if it is not implemented it should throw an 134 * <code>UnsupportedOperationException</code> rather than returning 135 * a bogus node or null. 136 * 137 * @param aName The name of the node to look for. 138 * @return A reference to the node if found, null otherwise. 139 */ 140 public Node getNode(String aName) throws UnsupportedOperationException { 141 if (!isPolicySet()) { 142 throw new IllegalStateException("Policy not set!(method:getNode(String))"); 143 } 144 return this.policy.getNode(aName); 145 } 146 147 /* (Copy of original doc. Generated version is inherited) 148 * 149 * Provides a list of currently registered node names. This method is 150 * optional, but if it is not implemented it should throw an 151 * <code>UnsupportedOperationException</code> rather than returning 152 * a bogus list or null. 153 * 154 * @returns An array of node names currently in use. 155 */ 156 public String[] getRegisteredNames() throws UnsupportedOperationException { 157 if (!isPolicySet()) { 158 throw new IllegalStateException("Policy not set!(method:getRegisteredNames)"); 159 } 160 return this.policy.getRegisteredNames(); 161 } 162 163 /* (Copy of original doc. Generated version is inherited) 164 * 165 * Tests a name to see if it is currently legal. The legality of the name is 166 * not guaranteed to remain invariant for all time. This is particularly 167 * true if the policy implemented by the <code>Registrar</code> requires 168 * names to be unique. 169 * 170 * @param aName The node name to be tested. 171 * @returns <code>true</code> if the name is legal, <code>false</code> 172 * otherwise. 173 */ 174 public boolean isLegalName(String aName) { 175 if (!isPolicySet()) { 176 throw new IllegalStateException("Policy not set!(method:isLegalName)"); 177 } 178 return this.policy.isLegalName(aName); 179 } 180 181 /* (Copy of original doc. Generated version is inherited) 182 * 183 * Tests to see if a name belongs to a registered node. For obvious reasons 184 * the results of this test are only valid while the client has a lock 185 * on the registry. 186 * 187 * @param The node name to test 188 * @return <code>true</code> if the name is registered <code>false</code> 189 * otherwise. 190 */ 191 public boolean isRegistered(String aName) { 192 if (!isPolicySet()) { 193 throw new IllegalStateException("Policy not set!(method:isRegistered)"); 194 } 195 return this.policy.isRegistered(aName); 196 } 197 198 /* (Copy of original doc. Generated version is inherited) 199 * 200 * Tests to see if a node has been registered. 201 * 202 * @param The node to test 203 * @return <code>true</code> if the node is registered <code>false</code> 204 * otherwise. 205 */ 206 public boolean isRegistered(Node aNode) { 207 if (!isPolicySet()) { 208 throw new IllegalStateException("Policy not set!(method:isRegistered)"); 209 } 210 return this.policy.isRegistered(aNode); 211 } 212 213 /* (Copy of original doc. Generated version is inherited) 214 * 215 * Gives the node a legal name and registers the node in one step. This 216 * method guarantees that the node will be registered, and no exceptions 217 * should be thrown. The node to be registered must expose a method 218 * with the signature setName(String). 219 */ 220 public void nameAndRegister(Node aNode) { 221 if (!isPolicySet()) { 222 throw new IllegalStateException("Policy not set!(method:nameAndRegister)"); 223 } 224 this.policy.nameAndRegister(aNode); 225 } 226 227 /* (Copy of original doc. Generated version is inherited) 228 * 229 * Attempt to register a node. This method proposes to register a node 230 * with an existing name. The node will be rejected if and only if it 231 * contains a name that would currently generate a false response 232 * from {@link #isLegalName(String)}. If the name contained in the node 233 * is rejected, The node is not registered or tracked in any way and an 234 * <code>IllegalArgumentException</code> will be thrown. 235 * 236 * @param aNode The node that wishes to register itself. 237 */ 238 public void register(Node aNode) throws IllegalArgumentException { 239 if (!isPolicySet()) { 240 throw new IllegalStateException("Policy not set!(method:register)"); 241 } 242 this.policy.register(aNode); 243 } 244 245 /* (Copy of original doc. Generated version is inherited) 246 * 247 * Ensures that the specified node is nolonger registered. If the node 248 * was never registred, it simply returns with no side effects. 249 * 250 * @param aNode the node to unregister 251 */ 252 public void unregister(Node aNode) { 253 if (!isPolicySet()) { 254 throw new IllegalStateException("Policy not set!(method:unregister)"); 255 } 256 this.policy.unregister(aNode); 257 } 258 259 } 260 261 /* 262 * $Log: NodeNameRegistry.java,v $ 263 * Revision 1.5 2004/01/14 21:04:16 gus 264 * More javadoc fixes 265 * 266 * Revision 1.4 2004/01/14 20:23:21 gus 267 * Javadoc and comment cleanup 268 * 269 * Revision 1.3 2003/02/25 21:42:31 gus 270 * Improve error messages to specify which method generated them 271 * 272 * Revision 1.2 2003/02/24 15:54:01 gus 273 * Add support for configuring the destination of generated packets 274 * 275 * Revision 1.1 2003/02/21 17:47:06 gus 276 * A set of classes to support name checking and generation schemes for nodes. 277 * 278 */