View Javadoc
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&lt;String&gt;; 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&lt;Object&gt;; 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&lt;String, Object&gt;; 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 }