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