1 package nl.tudelft.simulation.naming.context; 2 3 import java.io.Serializable; 4 import java.rmi.RemoteException; 5 import java.util.Collection; 6 import java.util.Map; 7 import java.util.Set; 8 9 import javax.naming.NameAlreadyBoundException; 10 import javax.naming.NameNotFoundException; 11 import javax.naming.NamingException; 12 import javax.naming.NotContextException; 13 14 import org.djutils.event.EventProducer; 15 import org.djutils.event.EventType; 16 import org.djutils.metadata.MetaData; 17 import org.djutils.metadata.ObjectDescriptor; 18 19 /** 20 * ContextInterface is the lightweight and simplified version of the JNDI EventContext interface in the standard Java 21 * distribution. It just contains the services for binding and unbinding of objects, for retrieving objects and Context trees, 22 * and for creating an initial context and creating and removing subcontexts. As it extends the EventProducer, it is 23 * able to fire events for adding and removing of elements in the Context. 24 * <p> 25 * A name for a Context can be compound, i.e. consisting of parts separated by a separator string. Usually the separator string 26 * is the forward slash. As an example, when the name is "sub1/sub2/ref", sub1 and sub2 must be pointing to a Context, whereas 27 * ref can be either another Context, or a regular Object. 28 * </p> 29 * <p> 30 * The context names support <i>absolute</i> addresses that start with a forward slash. For an absolute address, the context 31 * tree is traversed to the root, and the (compound) name is resolved from the root context. For <i>relative</i> addresses that 32 * start with any character but the forward slash, the (compound) name is resolved from the current context. 33 * </p> 34 * <p> 35 * Values that are stored in the context are required to be Serializable. Both the FileContext and the RemoteContext need to 36 * serialize the values when storing them, so serializability of the Context's content is a necessary property. 37 * </p> 38 * <p> 39 * Copyright (c) 2020-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See 40 * for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL 41 * project is distributed under a three-clause BSD-style license, which can be found at 42 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank"> 43 * https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>. 44 * </p> 45 * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a> 46 */ 47 public interface ContextInterface extends EventProducer, Serializable 48 { 49 /** The default root sign for a context. */ 50 public static final String ROOT = "/"; 51 52 /** The default separator sign for a context. */ 53 public static final String SEPARATOR = "/"; 54 55 /** The replacement string for the separator, in case it is part of a name. */ 56 public static final String REPLACE_SEPARATOR = "#"; 57 58 /** 59 * OBJECT_ADDED_EVENT is fired whenever an object is added to the Context. The implementations of the ContextInterface in 60 * the nl.tudelft.simulation.naming.context package take care of firing this event. <br> 61 * Payload: Object[] - the absolute path of the context in which the object was bound, the relative key in the context, and 62 * the bound object. 63 */ 64 public static final EventType OBJECT_ADDED_EVENT = new EventType(new MetaData("OBJECT_ADDED", "Object added to context", 65 new ObjectDescriptor("path", "absolute path in context", String.class), 66 new ObjectDescriptor("key", "relative key in the context", String.class), 67 new ObjectDescriptor("object", "bound object", Object.class))); 68 69 /** 70 * OBJECT_REMOVED_EVENT is fired whenever an object is removed from the Context. The implementations of the ContextInterface 71 * in the nl.tudelft.simulation.naming.context package take care of firing this event. <br> 72 * Payload: Object[] - the absolute path of the context in which the object was bound, the relative key in the context, and 73 * the removed object. 74 */ 75 public static final EventType OBJECT_REMOVED_EVENT = new EventType(new MetaData("OBJECT_REMOVED", 76 "Object removed from context", new ObjectDescriptor("path", "absolute path in context", String.class), 77 new ObjectDescriptor("key", "relative key in the context", String.class), 78 new ObjectDescriptor("object", "bound object", Object.class))); 79 80 /** 81 * OBJECT_CHANGED_EVENT can be fired whenever an object present in the Context is changed. The object making changes has to 82 * fire this Event itself, because the Context has no way of knowing that the content of the object has changed. The method 83 * fireObjectChangedEvent(...) in the ContextInterface can be used to fire this event. <br> 84 * Payload: Object[] - the absolute path of the context in which the object is bound, the relative key in the context, the 85 * object after change. 86 */ 87 public static final EventType OBJECT_CHANGED_EVENT = new EventType(new MetaData("OBJECT_CHANGED", 88 "Object in context changed", new ObjectDescriptor("path", "absolute path in context", String.class), 89 new ObjectDescriptor("key", "relative key in the context", String.class), 90 new ObjectDescriptor("object", "changed object", Object.class))); 91 92 /** 93 * Retrieves the atomic name of this context. 94 * @return String; the atomic name of this context 95 * @throws RemoteException on a network error when the Context is used over RMI 96 */ 97 String getAtomicName() throws RemoteException; 98 99 /** 100 * Retrieves the parent context for this context, or null when this is the root context. 101 * @return ContextInterface; parent context for this context, or null when this is the root context 102 * @throws RemoteException on a network error when the Context is used over RMI 103 */ 104 ContextInterface getParent() throws RemoteException; 105 106 /** 107 * Retrieves the root context for this context, or the current context when this is the root context. 108 * @return ContextInterface; the root context for this context 109 * @throws RemoteException on a network error when the Context is used over RMI 110 */ 111 ContextInterface getRootContext() throws RemoteException; 112 113 /** 114 * Returns the absolute path for this context, or an empty string when this is the root context. 115 * @return String; the absolute path for this context, or an empty string when this is the root context 116 * @throws RemoteException on a network error when the Context is used over RMI 117 */ 118 String getAbsolutePath() throws RemoteException; 119 120 /** 121 * Retrieves the named object from the Context. The name may be a compound name where parts are separated by separation 122 * strings indicating subcontexts. All intermediate subcontexts must exist. When name is the empty String or "/", the 123 * current Context is returned. 124 * @param name String; the name of the object to look up; may be a compound name 125 * @return Object; the Context or Object indicated by the name 126 * @throws NamingException as a placeholder overarching exception 127 * @throws NameNotFoundException if an intermediate context or the reference does not exist 128 * @throws NullPointerException when name is null 129 * @throws RemoteException on a network error when the Context is used over RMI 130 */ 131 Object get(String name) throws NamingException, RemoteException; 132 133 /** 134 * Retrieves the named object from the Context. The key is <b>not</b> compound. Key cannot be empty or contain "/". 135 * @param key String; the name of the object to look up; NOT a compound name 136 * @return Object; the Context or Object indicated by the key 137 * @throws NamingException when key is the empty string or when key contains "/" 138 * @throws NameNotFoundException if the key does not exist in the current context 139 * @throws NullPointerException when key is null 140 * @throws RemoteException on a network error when the Context is used over RMI 141 */ 142 Object getObject(String key) throws NamingException, RemoteException; 143 144 /** 145 * Indicates whether an object with the given name has been registered in the Context. The name may be a compound name where 146 * parts are separated by separation strings indicating subcontexts. All intermediate subcontexts must exist. When name is 147 * the empty String or "/", the method returns true. 148 * @param name String; the name of the object to look up; may be a compound name 149 * @return boolean; whether an object with the given name has been registered 150 * @throws NamingException as a placeholder overarching exception 151 * @throws NameNotFoundException when an intermediate context does not exist 152 * @throws NullPointerException when name is null 153 * @throws RemoteException on a network error when the Context is used over RMI 154 */ 155 boolean exists(String name) throws NamingException, RemoteException; 156 157 /** 158 * Indicates whether the key has been registered in the current Context. The name is <b>not</b> compound. When name is the 159 * empty String or "/", the method returns an exception. 160 * @param key String; the name of the object to look up; NOT compound 161 * @return boolean; whether an object with the given key has been registered in the current context 162 * @throws NamingException when key is the empty string or when key contains "/" 163 * @throws NullPointerException when key is null 164 * @throws RemoteException on a network error when the Context is used over RMI 165 */ 166 boolean hasKey(String key) throws NamingException, RemoteException; 167 168 /** 169 * Indicates whether the object has been registered (once or more) in the current Context. The object may be null. 170 * @param object Object; the object to look up; mey be null 171 * @return boolean; whether an object with the given key has been registered once or more in the current context 172 * @throws RemoteException on a network error when the Context is used over RMI 173 */ 174 boolean hasObject(Object object) throws RemoteException; 175 176 /** 177 * Indicates whether the current context is empty. 178 * @return boolean; whether the current context is empty 179 * @throws RemoteException on a network error when the Context is used over RMI 180 */ 181 boolean isEmpty() throws RemoteException; 182 183 /** 184 * Binds an object into the Context using the name. The name may be a compound name where parts are separated by separation 185 * strings indicating subcontexts. All intermediate subcontexts must already exist. The object will be registered using the 186 * terminal atomic reference in the deepest subcontext provided. Name cannot be empty or "/". An OBJECT_ADDED_EVENT is fired 187 * containing an object array with a pointer to the context, the relative key, and the object when a new binding has taken 188 * place. 189 * @param name String; the name under which the object will be stored; may be a compound name with the terminal reference 190 * indicating the key under which the object will be stored 191 * @param object Object; the Context or Object to be stored into the given context; a null object is allowed 192 * @throws NamingException when the reference is "/" or empty 193 * @throws NameAlreadyBoundException if name is already bound to an object 194 * @throws NameNotFoundException when an intermediate context does not exist 195 * @throws NullPointerException when name is null 196 * @throws RemoteException on a network error when the Context is used over RMI 197 */ 198 void bind(String name, Object object) throws NamingException, RemoteException; 199 200 /** 201 * Binds an object into this Context using the key. The key is <b>not </b> compound. The key cannot be empty or "/". An 202 * OBJECT_ADDED_EVENT is fired containing an object array with a pointer to the context, the relative key, and the object 203 * when a new binding has taken place. 204 * @param key String; the key under which the object will be stored; NOT a compound name 205 * @param object Object; the Context or Object to be stored into this Context using the given name; a null object is allowed 206 * @throws NamingException when key is the empty string or when key contains "/" 207 * @throws NameAlreadyBoundException if key is already bound to an object 208 * @throws NullPointerException when key is null 209 * @throws RemoteException on a network error when the Context is used over RMI 210 */ 211 void bindObject(String key, Object object) throws NamingException, RemoteException; 212 213 /** 214 * Binds an object into the Context using the toString() method of the object as the key. All "/" characters in the 215 * toString() result will be replaced by "#" characters. An OBJECT_ADDED_EVENT is fired containing an object array with a 216 * pointer to the context, the relative key, and the object when a new binding has taken place. 217 * @param object Object; the Context or Object to be stored into this Context using the toString() result as the key; a null 218 * object is not allowed 219 * @throws NamingException when the toString() of the object results in an empty string 220 * @throws NameAlreadyBoundException if key is already bound to an object 221 * @throws NullPointerException when object is null 222 * @throws RemoteException on a network error when the Context is used over RMI 223 */ 224 void bindObject(Object object) throws NamingException, RemoteException; 225 226 /** 227 * Removes the binding for an object in the Context with the given name. The name may be a compound name where parts are 228 * separated by separation strings indicating subcontexts. Name cannot be empty or "/". It is not a problem when there is no 229 * object registered with the given name. An OBJECT_REMOVED_EVENT is fired containing an object array with a pointer to the 230 * context, the relative key, and the removed object when a binding has been removed. 231 * @param name String; the name of the object that has to be removed; may be a compound name with the terminal reference 232 * indicating the key under which the object is stored 233 * @throws NamingException when the reference is "/" or empty 234 * @throws NameNotFoundException when an intermediate context does not exist 235 * @throws NullPointerException when name is null 236 * @throws RemoteException on a network error when the Context is used over RMI 237 */ 238 void unbind(String name) throws NamingException, RemoteException; 239 240 /** 241 * Removes the binding for an object in this Context with the given key. The key is <b>not</b> compound. The key cannot be 242 * empty or "/". It is not a problem when there is no object registered with the given key. An OBJECT_REMOVED_EVENT is fired 243 * containing an object array with a pointer to the context, the relative key, and the removed object when a binding has 244 * been removed. 245 * @param key String; the key of the object that has to be removed; NOT a compound name 246 * @throws NamingException when key is the empty string or when key contains "/" 247 * @throws NullPointerException when key is null 248 * @throws RemoteException on a network error when the Context is used over RMI 249 */ 250 void unbindObject(String key) throws NamingException, RemoteException; 251 252 /** 253 * Replaces an object in the Context with the given name, or registers the object when a registration with the name does not 254 * exist yet. The name may be a compound name where parts are separated by separation strings indicating subcontexts. All 255 * intermediate subcontexts must already exist. The object will be (re)registered using the terminal atomic reference in the 256 * deepest subcontext provided. Name cannot be empty or "/". An OBJECT_REMOVED_EVENT is fired containing an object array 257 * with a pointer to the context, the relative key, and the removed object when a binding had to be removed, followed by an 258 * OBJECT_ADDED_EVENT containing an object array with a pointer to the context, the key, and the new object when a new 259 * binding has taken place. 260 * @param name String; the name of the object to be replaced, or under which the object will be stored; may be a compound 261 * name with the terminal reference indicating the key under which the object will be stored 262 * @param object Object; the Context or Object to be replaced or stored into this Context using the given name; a null 263 * object is allowed 264 * @throws NamingException when the reference is "/" or empty 265 * @throws NameNotFoundException when an intermediate context does not exist 266 * @throws NullPointerException when name is null 267 * @throws RemoteException on a network error when the Context is used over RMI 268 */ 269 void rebind(String name, Object object) throws NamingException, RemoteException; 270 271 /** 272 * Replaces an object in this Context with the given key, or registers the object when a registration with the key does not 273 * exist yet. The key is <b>not</b> a compound name. Name cannot be empty or "/". An OBJECT_REMOVED_EVENT is fired 274 * containing an object array with a pointer to the context, the relative key, and the removed object when a binding had to 275 * be removed, followed by an OBJECT_ADDED_EVENT containing an object array with a pointer to the context, the key, and the 276 * new object when a new binding has taken place. 277 * @param key String; the key of the object to be replaced, or under which the object will be stored; NOT a compound name 278 * @param object Object; the Context or Object to be replaced or stored into this Context using the given name; a null 279 * object is allowed 280 * @throws NamingException when key is the empty string or when key contains "/" 281 * @throws NullPointerException when name is null 282 * @throws RemoteException on a network error when the Context is used over RMI 283 */ 284 void rebindObject(String key, Object object) throws NamingException, RemoteException; 285 286 /** 287 * Replaces the name under which an object has been registered in the Context. Both names are relative to the current 288 * Context, and may be compound names where parts are separated by separation strings indicating subcontexts. All 289 * intermediate subcontexts of the new name must already exist. The object will be deregistered under the old name, and 290 * reregistered using the terminal atomic reference in the deepest subcontext of the newName. Nether the oldName, nor the 291 * newName can be empty or "/". An OBJECT_REMOVED_EVENT is fired containing an object array with a pointer to the old 292 * context, the old relative key, and the object when a binding had to be removed, followed by an OBJECT_ADDED_EVENT 293 * containing an object array with a pointer to the new context, the new relative key, and the object when a new binding has 294 * taken place. When the new name is illegal or occupied, the object will not be renamed. 295 * @param oldName String; the (compound) name of the object to be moved to a new location 296 * @param newName String; the (compound) name with the terminal reference indicating where the object will be stored 297 * @throws NamingException when the reference of oldName or newName is "/" or empty 298 * @throws NameNotFoundException when an intermediate context of oldName or newName does not exist, or when there is no 299 * registration at the oldName reference 300 * @throws NameAlreadyBoundException if newName is already bound to an object 301 * @throws NullPointerException when oldName or newName is null 302 * @throws RemoteException on a network error when the Context is used over RMI 303 */ 304 void rename(String oldName, String newName) throws NamingException, RemoteException; 305 306 /** 307 * Creates and binds a new context into the current Context using the name. The name may be a compound name where parts are 308 * separated by separation strings indicating subcontexts. All intermediate subcontexts that do not yet exist, will be 309 * created. The new context will be registered using the terminal atomic reference in the deepest subcontext provided. Name 310 * cannot be empty or "/". On success, OBJECT_ADDED_EVENTs are fired for the created context and each new intermediate 311 * context, containing an object array with an object array with a pointer to the embedding context, the local key in the 312 * embedding context, and the newly created (intermediate) context. 313 * @param name String; the name under which the new context will be stored; may be a compound name with the terminal 314 * reference indicating the key under which the new context will be stored 315 * @return ContextInterface; a pointer to the newly created subcontext 316 * @throws NamingException when the terminal reference is "/" or empty 317 * @throws NameNotFoundException when an intermediate context does not exist 318 * @throws NameAlreadyBoundException if name is already bound to an object or context 319 * @throws NullPointerException when name is null 320 * @throws RemoteException on a network error when the Context is used over RMI 321 */ 322 ContextInterface createSubcontext(String name) throws NamingException, RemoteException; 323 324 /** 325 * Removes the binding for an existing, empty subcontext with the given name, and recursively unbinds all objects and 326 * contexts in the context indicated by the name. The name may be a compound name where parts are separated by separation 327 * strings indicating subcontexts. Name cannot be empty or "/". A context has to be registered with the given name. For all 328 * removed objects and contexts, OBJECT_REMOVED_EVENT events are fired containing an object array with a pointer to the 329 * context from which content has been removed, the key of the binding that has been removed, and the removed object. The 330 * OBJECT_REMOVED_EVENT events are fired in depth-first order. 331 * @param name String; the name of the object that has to be removed; may be a compound name with the terminal reference 332 * indicating the key under which the object is stored 333 * @throws NamingException when the reference is "/" or empty 334 * @throws NotContextException if the name is bound but does not name a context 335 * @throws NameNotFoundException when an intermediate context does not exist, or when no object is registered with the 336 * terminating atomic reference 337 * @throws NullPointerException when name is null 338 * @throws RemoteException on a network error when the Context is used over RMI 339 */ 340 void destroySubcontext(String name) throws NamingException, RemoteException; 341 342 /** 343 * Fire an OBJECT_CHANGED_EVENT for an object within the current context. Look up if the the object exists using the 344 * toString() method of the object as the key. All "/" characters in the toString() result will be replaced by "#" 345 * characters. When the object does not exist directly in the context, a NameNotFoundException is thrown. 346 * @param object Object; the object that has changed and for which an event should be fired 347 * @throws NamingException on general error in the method, e.g., a problem with remote connections 348 * @throws NameNotFoundException when no object is registered with object.toString() as the key 349 * @throws NullPointerException when object is null 350 * @throws RemoteException on a network error when the Context is used over RMI 351 */ 352 void fireObjectChangedEventValue(final Object object) 353 throws NameNotFoundException, NullPointerException, NamingException, RemoteException; 354 355 /** 356 * Fire an OBJECT_CHANGED_EVENT for an object with the given key in the current context. If the the key does not exist 357 * directly in the context, a NameNotFoundException is thrown. The key should not be the empty String or contain "/" 358 * characters. 359 * @param key String; the key within the context of the object that has changed and for which an event should be fired 360 * @throws NamingException when key is the empty string or when key contains "/", or on a general error in the method, e.g., 361 * a problem with remote connections 362 * @throws NameNotFoundException when no object is registered with the key in the given context 363 * @throws NullPointerException when key is null 364 * @throws RemoteException on a network error when the Context is used over RMI 365 */ 366 void fireObjectChangedEventKey(final String key) 367 throws NameNotFoundException, NullPointerException, NamingException, RemoteException; 368 369 /** 370 * Returns a set of registered keys in the current context. 371 * @return Set<String>; a set of registered keys in the current context 372 * @throws RemoteException on a network error when the Context is used over RMI 373 */ 374 Set<String> keySet() throws RemoteException; 375 376 /** 377 * Returns a (raw) collection of registered values in the current context. 378 * @return Collection<Object>; a raw set of registered objects in the current context 379 * @throws RemoteException on a network error when the Context is used over RMI 380 */ 381 Collection<Object> values() throws RemoteException; 382 383 /** 384 * Returns a (raw) map of bindings in the current context, mapping the name on the registered objects. Both regular objects 385 * and subcontexts are returned. Mappings to null objects can exist. 386 * @return Map<String, Object>; a map of registered names and their bound (possibly null) object in the current 387 * context 388 * @throws RemoteException on a network error when the Context is used over RMI 389 */ 390 Map<String, Object> bindings() throws RemoteException; 391 392 /** 393 * Check whether a circular reference would occur when the object would be inserted into the current context. Insertion 394 * potentially causes a problem when the object to be inserted is a Context. 395 * @param newObject the object to be inserted 396 * @throws NamingException when a circular reference would occur 397 * @throws RemoteException on a network error when the Context is used over RMI 398 */ 399 void checkCircular(Object newObject) throws NamingException, RemoteException; 400 401 /** 402 * Closes the context and removes all content from the context. No events will be fired that the content of the context has 403 * been removed. Some contexts, such as the FileContext could have to be really closed as well. 404 * @throws NamingException when a problem occurs during closing (e.g., of a FileContext) 405 * @throws RemoteException on a network error when the Context is used over RMI 406 */ 407 void close() throws NamingException, RemoteException; 408 409 /** 410 * Return a String with the hierarchical content of the Context in case verbose is true; otherwise return the atomic name. 411 * @param verbose boolean; whether the information is exhaustive or very brief 412 * @return String; formatted content of the context when verbose is true; otherwise the atomic name 413 * @throws RemoteException on a network error when the Context is used over RMI 414 */ 415 String toString(final boolean verbose) throws RemoteException; 416 }