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-2023 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 }