1 /* nContext.java -- implementation of NamingContext
2    Copyright (C) 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.CORBA.NamingService;
40 
41 import org.omg.CORBA.Object;
42 import org.omg.CosNaming.Binding;
43 import org.omg.CosNaming.BindingIteratorHolder;
44 import org.omg.CosNaming.BindingListHolder;
45 import org.omg.CosNaming.BindingType;
46 import org.omg.CosNaming.NameComponent;
47 import org.omg.CosNaming.NamingContext;
48 import org.omg.CosNaming.NamingContextOperations;
49 import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
50 import org.omg.CosNaming.NamingContextPackage.CannotProceed;
51 import org.omg.CosNaming.NamingContextPackage.InvalidName;
52 import org.omg.CosNaming.NamingContextPackage.NotEmpty;
53 import org.omg.CosNaming.NamingContextPackage.NotFound;
54 import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
55 import org.omg.CosNaming._NamingContextImplBase;
56 
57 import gnu.CORBA.SafeForDirectCalls;
58 
59 import java.util.Iterator;
60 import java.util.Map;
61 
62 /**
63  * This class implements the transient naming service, defined by
64  * {@link NamingContext}. The 'transient' means that the service does
65  * not store its state into the persistent memory. If the service is
66  * restarted, the named objects must be re-registered again.
67  *
68  * TODO Write the persistent naming service.
69  *
70  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
71  */
72 public class TransientContext
73   extends _NamingContextImplBase
74   implements NamingContext, NamingContextOperations, SafeForDirectCalls
75 {
76   /**
77    * Use serial version UID for interoperability.
78    */
79   private static final long serialVersionUID = 2;
80 
81   /**
82    * The already named contexts.
83    */
84   protected final NamingMap named_contexts;
85 
86   /**
87    * The already named objects.
88    */
89   protected final NamingMap named_objects;
90 
91   /**
92    * Create the naming conetxt with default (transient) naming maps.
93    */
TransientContext()94   public TransientContext()
95   {
96     this(new NamingMap(), new NamingMap());
97   }
98 
99   /**
100    * Create the naming conetxt with the two provided naming maps.
101    *
102    * @param context_map the map for contexts
103    * @param object_map the map for objectss
104    */
TransientContext(NamingMap context_map, NamingMap object_map)105   public TransientContext(NamingMap context_map, NamingMap object_map)
106   {
107     named_contexts = context_map;
108     named_objects = object_map;
109   }
110 
111   /**
112    * Gives the object a name, valid in this context.
113    *
114    * @param a_name the name, being given to the object.
115    * @param an_object the object, being named.
116    *
117    * @throws AlreadyBound if the object is already named in this context.
118    * @throws InvalidName if the name has zero length or otherwise invalid.
119    */
bind(NameComponent[] a_name, Object an_object)120   public void bind(NameComponent[] a_name, Object an_object)
121             throws NotFound, CannotProceed, InvalidName, AlreadyBound
122   {
123     if (a_name.length == 1)
124       named_objects.bind(a_name [ 0 ], an_object);
125     else
126       {
127         NamingContext context =
128           (NamingContext) named_contexts.get(a_name [ 0 ]);
129         context.bind(getSuffix(a_name), an_object);
130       }
131   }
132 
133   /**
134    * Gives a child context name, valid in this context.
135    *
136    * @param a_name the name, being given to the child context.
137    * @param a_context the child context being named.
138    *
139    * @throws AlreadyBound if the child context is already named in
140    * the current context.
141    */
bind_context(NameComponent[] a_name, NamingContext a_context)142   public void bind_context(NameComponent[] a_name, NamingContext a_context)
143                     throws NotFound, CannotProceed, InvalidName, AlreadyBound
144   {
145     if (a_name.length == 1)
146       named_contexts.bind(a_name [ 0 ], a_context);
147     else
148       {
149         NamingContext context =
150           (NamingContext) named_contexts.get(a_name [ 0 ]);
151         context.bind_context(getSuffix(a_name), a_context);
152       }
153   }
154 
155   /**
156    * Create a new context and give it a given name (bound it)
157    * in the current context.
158    *
159    * The context being created is returned by calling
160    * {@link #new_context()}.
161    *
162    * @param a_name the name being given to the new context.
163    *
164    * @return the newly created context.
165    *
166    * @throws AlreadyBound if the name is already in use.
167    * @throws InvalidName if the name has zero length or otherwise invalid.
168    */
bind_new_context(NameComponent[] a_name)169   public NamingContext bind_new_context(NameComponent[] a_name)
170                                  throws NotFound, AlreadyBound, CannotProceed,
171                                         InvalidName
172   {
173     if (named_contexts.containsKey(a_name [ 0 ]) ||
174         named_objects.containsKey(a_name [ 0 ])
175        )
176       throw new AlreadyBound();
177 
178     NamingContext child = new_context();
179     bind_context(a_name, child);
180     return child;
181   }
182 
183   /**
184    * Destroy this context (must be empty).
185    * @throws NotEmpty if the context being destroyed is not empty.
186    */
destroy()187   public void destroy()
188                throws NotEmpty
189   {
190     if (named_contexts.size() > 0 || named_objects.size() > 0)
191       throw new NotEmpty();
192   }
193 
194   /**
195    * Iterate over all bindings, defined in this namind context.
196    *
197    * @param amount the maximal number of context to return in the
198    * holder a_list. The remaining bindings are accessible via iterator
199    * an_iter. If the parameter amount is zero, all bindings are accessed only
200    * via this iterator.
201    *
202    * This implementation list contexts first, then objects.
203    *
204    * @param a_list the holder, where the returned bindigs are stored.
205    * @param an_iter the iterator that can be used to access the remaining
206    * bindings.
207    */
list(int amount, BindingListHolder a_list, BindingIteratorHolder an_iter )208   public void list(int amount, BindingListHolder a_list,
209                    BindingIteratorHolder an_iter
210                   )
211   {
212     int nb = named_contexts.size() + named_objects.size();
213     int nl = nb;
214     if (nl > amount)
215       nl = amount;
216 
217     a_list.value = new Binding[ nl ];
218 
219     Iterator contexts = named_contexts.entries().iterator();
220     Iterator objects = named_objects.entries().iterator();
221 
222     // Create a binding list.
223     for (int i = 0; i < nl; i++)
224       {
225         if (contexts.hasNext())
226           a_list.value [ i ] = mkBinding(contexts.next(), BindingType.ncontext);
227         else if (objects.hasNext())
228           a_list.value [ i ] = mkBinding(objects.next(), BindingType.nobject);
229         else
230           throw new InternalError();
231       }
232 
233     // Create an iterator.
234     Binding[] remainder = new Binding[ nb - nl ];
235     int p = 0;
236 
237     while (contexts.hasNext())
238       remainder [ p++ ] = mkBinding(contexts.next(), BindingType.ncontext);
239 
240     while (objects.hasNext())
241       remainder [ p++ ] = mkBinding(objects.next(), BindingType.nobject);
242 
243     Binding_iterator_impl bit = new Binding_iterator_impl(remainder);
244     _orb().connect(bit);
245     an_iter.value = bit;
246   }
247 
248   /**
249    * Creates a new naming context, not bound to any name.
250    */
new_context()251   public NamingContext new_context()
252   {
253     Ext context = new Ext(new TransientContext());
254 
255     // Connect the context to the current ORB:
256     _orb().connect(context);
257     return context;
258   }
259 
260   /**
261    * Names or renames the object.
262    *
263    * @param a_name the new name, being given to the object
264    * in the scope of the current context. If the object is already
265    * named in this context, it is renamed.
266    *
267    * @param an_object the object, being named.
268    *
269    * @throws InvalidName if the name has zero length or otherwise invalid.
270    */
rebind(NameComponent[] a_name, Object an_object)271   public void rebind(NameComponent[] a_name, Object an_object)
272               throws NotFound, CannotProceed, InvalidName
273   {
274     if (a_name.length == 1)
275       named_objects.rebind(a_name [ 0 ], an_object);
276     else
277       {
278         NamingContext context =
279           (NamingContext) named_contexts.get(a_name [ 0 ]);
280         context.rebind(getSuffix(a_name), an_object);
281       }
282   }
283 
284   /**
285    * Names or renames the child context.
286    * If the child context is already named in
287    * the current context, it is renamed. The the name being given is in
288    * use, the old meaning of the name is discarded.
289    *
290    * @param a_name the name, being given to the child context in the scope
291    * of the current context.
292    *
293    * @param a_context the child context being named.
294    *
295    * @throws InvalidName if the name has zero length or otherwise invalid.
296    */
rebind_context(NameComponent[] a_name, NamingContext a_context)297   public void rebind_context(NameComponent[] a_name, NamingContext a_context)
298                       throws NotFound, CannotProceed, InvalidName
299   {
300     if (a_name.length == 1)
301       named_contexts.rebind(a_name [ 0 ], a_context);
302     else
303       {
304         NamingContext context =
305           (NamingContext) named_contexts.get(a_name [ 0 ]);
306         context.rebind_context(getSuffix(a_name), a_context);
307       }
308   }
309 
310   /**
311    * Get the object, bound to the specified name in this
312    * context. The given object must match the bound
313    * name.
314    *
315    * This implementation resolves the names as defined in specification
316    * of the CORBA naming service. This means, if the beginning of the
317    * name can be resolved to some naming context, the request is
318    * forwarded to this context, passing the unresolved name part as a
319    * parameter. In this way, it is possible to have a hierarchy of the
320    * naming services. The central services resolve the the beginning
321    * of the name. The local services resolve the remaining nodes of the
322    * name that may be relevant to some local details. It can be three or
323    * more ranks of the naming services.
324    *
325    * @param a_name the object name.
326    *
327    * @return the object, matching this name. The client
328    * usually casts or narrows (using the helper) the returned value
329    * to the more specific type.
330    *
331    * @throws NotFound if the name cannot be resolved.
332    * @throws InvalidName if the name has zero length or otherwise invalid.
333    */
resolve(NameComponent[] a_name)334   public Object resolve(NameComponent[] a_name)
335                  throws NotFound, CannotProceed, InvalidName
336   {
337     NameValidator.check(a_name);
338 
339     if (a_name.length > 1)
340       return resolveSubContext(a_name);
341     else
342       {
343         // A single node name.
344         org.omg.CORBA.Object object;
345 
346         object = named_objects.get(a_name [ 0 ]);
347         if (object != null)
348           return object;
349 
350         object = named_contexts.get(a_name [ 0 ]);
351         if (object != null)
352           return object;
353       }
354 
355     throw new NotFound(NotFoundReason.missing_node, a_name);
356   }
357 
358   /**
359    * Removes the name from the binding context.
360    *
361    * @param a_name a name to remove.
362    *
363    * @throws InvalidName if the name has zero length or otherwise invalid.
364    */
unbind(NameComponent[] a_name)365   public void unbind(NameComponent[] a_name)
366               throws NotFound, CannotProceed, InvalidName
367   {
368     NameValidator.check(a_name);
369 
370     // Single node name - handle it.
371     if (a_name.length == 1)
372       {
373         if (named_objects.containsKey(a_name [ 0 ]))
374           named_objects.remove(a_name [ 0 ]);
375         else if (named_contexts.containsKey(a_name [ 0 ]))
376           named_contexts.remove(a_name [ 0 ]);
377         else
378           throw new NotFound(NotFoundReason.missing_node, a_name);
379       }
380     else
381       {
382         // Handle the first node and forward the command.
383         NamingContext subcontext =
384           (NamingContext) named_contexts.get(a_name [ 0 ]);
385 
386         if (subcontext == null)
387           throw new NotFound(NotFoundReason.missing_node, a_name);
388 
389         subcontext.unbind(getSuffix(a_name));
390       }
391   }
392 
393   /**
394    * Get the name suffix, discarding the first member.
395    */
getSuffix(NameComponent[] a_name)396   private NameComponent[] getSuffix(NameComponent[] a_name)
397   {
398     NameComponent[] suffix = new NameComponent[ a_name.length - 1 ];
399     System.arraycopy(a_name, 1, suffix, 0, suffix.length);
400     return suffix;
401   }
402 
403   /**
404    * Create a binding.
405    *
406    * @param an_entry the entry, defining the bound object.
407    * @param type the binding type.
408    * @return the created binding.
409    */
mkBinding(java.lang.Object an_entry, BindingType type)410   private Binding mkBinding(java.lang.Object an_entry, BindingType type)
411   {
412     Map.Entry entry = (Map.Entry) an_entry;
413     Binding b = new Binding();
414 
415     // The name component has always only one node (the current context)
416     b.binding_name = new NameComponent[] { (NameComponent) entry.getKey() };
417     b.binding_type = type;
418     return b;
419   }
420 
421   /**
422    * Find the context, bound to the first name of the given
423    * name, and pass the remainder (without the first node)
424    * of the name for that context to resolve.
425    *
426    * @param a_name the name to resolve.
427    *
428    * @return the resolved context
429    */
resolveSubContext(NameComponent[] a_name)430   private Object resolveSubContext(NameComponent[] a_name)
431                             throws NotFound, CannotProceed, InvalidName
432   {
433     // A multiple node name.
434     // This context resolves the first node only.
435     NamingContext context = (NamingContext) named_contexts.get(a_name [ 0 ]);
436     if (context == null)
437       throw new NotFound(NotFoundReason.missing_node, a_name);
438 
439     NameComponent[] suffix = getSuffix(a_name);
440 
441     return context.resolve(suffix);
442   }
443 }
444