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