29 import java.util.Hashtable; 30 import java.util.Properties; 31 import java.rmi.*; 32 import java.rmi.server.*; 33 import java.rmi.registry.Registry; 34 import java.rmi.registry.LocateRegistry; 35 36 import javax.naming.*; 37 import javax.naming.spi.NamingManager; 38 39 40 /** 41 * A RegistryContext is a context representing a remote RMI registry. 42 * 43 * @author Scott Seligman 44 */ 45 46 47 public class RegistryContext implements Context, Referenceable { 48 49 private Hashtable environment; 50 private Registry registry; 51 private String host; 52 private int port; 53 private static final NameParser nameParser = new AtomicNameParser(); 54 private static final String SOCKET_FACTORY = "com.sun.jndi.rmi.factory.socket"; 55 56 Reference reference = null; // ref used to create this context, if any 57 58 // Environment property that, if set, indicates that a security 59 // manager should be installed (if none is already in place). 60 public static final String SECURITY_MGR = 61 "java.naming.rmi.security.manager"; 62 63 /** 64 * Returns a context for the registry at a given host and port. 65 * If "host" is null, uses default host. 66 * If "port" is non-positive, uses default port. 67 * Cloning of "env" is handled by caller; see comments within 68 * RegistryContextFactory.getObjectInstance(), for example. 69 */ 70 public RegistryContext(String host, int port, Hashtable env) 71 throws NamingException 72 { 73 environment = ((env == null) ? new Hashtable(5) : env); 74 if (environment.get(SECURITY_MGR) != null) { 75 installSecurityMgr(); 76 } 77 78 // chop off '[' and ']' in an IPv6 literal address 79 if ((host != null) && (host.charAt(0) == '[')) { 80 host = host.substring(1, host.length() - 1); 81 } 82 83 RMIClientSocketFactory socketFactory = 84 (RMIClientSocketFactory) environment.get(SOCKET_FACTORY); 85 registry = getRegistry(host, port, socketFactory); 86 this.host = host; 87 this.port = port; 88 } 89 90 /** 91 * Returns a clone of a registry context. The context's private state 92 * is independent of the original's (so closing one context, for example, 93 * won't close the other). 94 */ 95 // %%% Alternatively, this could be done with a clone() method. 96 RegistryContext(RegistryContext ctx) { 97 environment = (Hashtable)ctx.environment.clone(); 98 registry = ctx.registry; 99 host = ctx.host; 100 port = ctx.port; 101 reference = ctx.reference; 102 } 103 104 protected void finalize() { 105 close(); 106 } 107 108 public Object lookup(Name name) throws NamingException { 109 if (name.isEmpty()) { 110 return (new RegistryContext(this)); 111 } 112 Remote obj; 113 try { 114 obj = registry.lookup(name.get(0)); 115 } catch (NotBoundException e) { 116 throw (new NameNotFoundException(name.get(0))); 117 } catch (RemoteException e) { 178 } 179 } 180 181 public void unbind(String name) throws NamingException { 182 unbind(new CompositeName(name)); 183 } 184 185 /** 186 * Rename is implemented by this sequence of operations: 187 * lookup, bind, unbind. The sequence is not performed atomically. 188 */ 189 public void rename(Name oldName, Name newName) throws NamingException { 190 bind(newName, lookup(oldName)); 191 unbind(oldName); 192 } 193 194 public void rename(String name, String newName) throws NamingException { 195 rename(new CompositeName(name), new CompositeName(newName)); 196 } 197 198 public NamingEnumeration list(Name name) throws NamingException { 199 if (!name.isEmpty()) { 200 throw (new InvalidNameException( 201 "RegistryContext: can only list \"\"")); 202 } 203 try { 204 String[] names = registry.list(); 205 return (new NameClassPairEnumeration(names)); 206 } catch (RemoteException e) { 207 throw (NamingException)wrapRemoteException(e).fillInStackTrace(); 208 } 209 } 210 211 public NamingEnumeration list(String name) throws NamingException { 212 return list(new CompositeName(name)); 213 } 214 215 public NamingEnumeration listBindings(Name name) 216 throws NamingException 217 { 218 if (!name.isEmpty()) { 219 throw (new InvalidNameException( 220 "RegistryContext: can only list \"\"")); 221 } 222 try { 223 String[] names = registry.list(); 224 return (new BindingEnumeration(this, names)); 225 } catch (RemoteException e) { 226 throw (NamingException)wrapRemoteException(e).fillInStackTrace(); 227 } 228 } 229 230 public NamingEnumeration listBindings(String name) throws NamingException { 231 return listBindings(new CompositeName(name)); 232 } 233 234 public void destroySubcontext(Name name) throws NamingException { 235 throw (new OperationNotSupportedException()); 236 } 237 238 public void destroySubcontext(String name) throws NamingException { 239 throw (new OperationNotSupportedException()); 240 } 241 242 public Context createSubcontext(Name name) throws NamingException { 243 throw (new OperationNotSupportedException()); 244 } 245 246 public Context createSubcontext(String name) throws NamingException { 247 throw (new OperationNotSupportedException()); 248 } 249 250 public Object lookupLink(Name name) throws NamingException { 273 { 274 return composeName(new CompositeName(name), 275 new CompositeName(prefix)).toString(); 276 } 277 278 public Object removeFromEnvironment(String propName) 279 throws NamingException 280 { 281 return environment.remove(propName); 282 } 283 284 public Object addToEnvironment(String propName, Object propVal) 285 throws NamingException 286 { 287 if (propName.equals(SECURITY_MGR)) { 288 installSecurityMgr(); 289 } 290 return environment.put(propName, propVal); 291 } 292 293 public Hashtable getEnvironment() throws NamingException { 294 return (Hashtable)environment.clone(); 295 } 296 297 public void close() { 298 environment = null; 299 registry = null; 300 // &&& If we were caching registry connections, we would probably 301 // uncache this one now. 302 } 303 304 public String getNameInNamespace() { 305 return ""; // Registry has an empty name 306 } 307 308 /** 309 * Returns an RMI registry reference for this context. 310 *<p> 311 * If this context was created from a reference, that reference is 312 * returned. Otherwise, an exception is thrown if the registry's 313 * host is "localhost" or the default (null). Although this could 314 * possibly make for a valid reference, it's far more likely to be 466 throw ne; 467 } 468 } 469 470 } 471 472 473 /** 474 * A name parser for case-sensitive atomic names. 475 */ 476 class AtomicNameParser implements NameParser { 477 private static final Properties syntax = new Properties(); 478 479 public Name parse(String name) throws NamingException { 480 return (new CompoundName(name, syntax)); 481 } 482 } 483 484 485 /** 486 * An enumeration of name / class-name pairs. Since we don't know anything 487 * about the classes, each class name is returned as the generic 488 * "java.lang.Object". 489 */ 490 class NameClassPairEnumeration implements NamingEnumeration { 491 private final String[] names; 492 private int nextName; // index into "names" 493 494 NameClassPairEnumeration(String[] names) { 495 this.names = names; 496 nextName = 0; 497 } 498 499 public boolean hasMore() { 500 return (nextName < names.length); 501 } 502 503 public Object next() throws NamingException { 504 if (!hasMore()) { 505 throw (new java.util.NoSuchElementException()); 506 } 507 // Convert name to a one-element composite name, so embedded 508 // meta-characters are properly escaped. 509 String name = names[nextName++]; 510 Name cname = (new CompositeName()).add(name); 511 NameClassPair ncp = new NameClassPair(cname.toString(), 512 "java.lang.Object"); 513 ncp.setNameInNamespace(name); 514 return ncp; 515 } 516 517 public boolean hasMoreElements() { 518 return hasMore(); 519 } 520 521 public Object nextElement() { 522 try { 523 return next(); 524 } catch (NamingException e) { // should never happen 525 throw (new java.util.NoSuchElementException( 526 "javax.naming.NamingException was thrown")); 527 } 528 } 529 530 public void close() { 531 nextName = names.length; 532 } 533 } 534 535 536 /** 537 * An enumeration of Bindings. 538 * 539 * The actual registry lookups are performed when next() is called. It would 540 * be nicer to defer this until the object (or its class name) is actually 541 * requested. The problem with that approach is that Binding.getObject() 542 * cannot throw NamingException. 543 */ 544 class BindingEnumeration implements NamingEnumeration { 545 private RegistryContext ctx; 546 private final String[] names; 547 private int nextName; // index into "names" 548 549 BindingEnumeration(RegistryContext ctx, String[] names) { 550 // Clone ctx in case someone closes it before we're through. 551 this.ctx = new RegistryContext(ctx); 552 this.names = names; 553 nextName = 0; 554 } 555 556 protected void finalize() { 557 ctx.close(); 558 } 559 560 public boolean hasMore() { 561 if (nextName >= names.length) { 562 ctx.close(); 563 } 564 return (nextName < names.length); 565 } 566 567 public Object next() throws NamingException { 568 if (!hasMore()) { 569 throw (new java.util.NoSuchElementException()); 570 } 571 // Convert name to a one-element composite name, so embedded 572 // meta-characters are properly escaped. 573 String name = names[nextName++]; 574 Name cname = (new CompositeName()).add(name); 575 576 Object obj = ctx.lookup(cname); 577 String cnameStr = cname.toString(); 578 Binding binding = new Binding(cnameStr, obj); 579 binding.setNameInNamespace(cnameStr); 580 return binding; 581 } 582 583 public boolean hasMoreElements() { 584 return hasMore(); 585 } 586 587 public Object nextElement() { 588 try { 589 return next(); 590 } catch (NamingException e) { 591 throw (new java.util.NoSuchElementException( 592 "javax.naming.NamingException was thrown")); 593 } 594 } 595 596 public void close () { 597 finalize(); 598 } 599 } | 29 import java.util.Hashtable; 30 import java.util.Properties; 31 import java.rmi.*; 32 import java.rmi.server.*; 33 import java.rmi.registry.Registry; 34 import java.rmi.registry.LocateRegistry; 35 36 import javax.naming.*; 37 import javax.naming.spi.NamingManager; 38 39 40 /** 41 * A RegistryContext is a context representing a remote RMI registry. 42 * 43 * @author Scott Seligman 44 */ 45 46 47 public class RegistryContext implements Context, Referenceable { 48 49 private Hashtable<String, Object> environment; 50 private Registry registry; 51 private String host; 52 private int port; 53 private static final NameParser nameParser = new AtomicNameParser(); 54 private static final String SOCKET_FACTORY = "com.sun.jndi.rmi.factory.socket"; 55 56 Reference reference = null; // ref used to create this context, if any 57 58 // Environment property that, if set, indicates that a security 59 // manager should be installed (if none is already in place). 60 public static final String SECURITY_MGR = 61 "java.naming.rmi.security.manager"; 62 63 /** 64 * Returns a context for the registry at a given host and port. 65 * If "host" is null, uses default host. 66 * If "port" is non-positive, uses default port. 67 * Cloning of "env" is handled by caller; see comments within 68 * RegistryContextFactory.getObjectInstance(), for example. 69 */ 70 @SuppressWarnings("unchecked") 71 public RegistryContext(String host, int port, Hashtable<?, ?> env) 72 throws NamingException 73 { 74 environment = (env == null) 75 ? new Hashtable<String, Object>(5) 76 : (Hashtable<String, Object>) env; 77 if (environment.get(SECURITY_MGR) != null) { 78 installSecurityMgr(); 79 } 80 81 // chop off '[' and ']' in an IPv6 literal address 82 if ((host != null) && (host.charAt(0) == '[')) { 83 host = host.substring(1, host.length() - 1); 84 } 85 86 RMIClientSocketFactory socketFactory = 87 (RMIClientSocketFactory) environment.get(SOCKET_FACTORY); 88 registry = getRegistry(host, port, socketFactory); 89 this.host = host; 90 this.port = port; 91 } 92 93 /** 94 * Returns a clone of a registry context. The context's private state 95 * is independent of the original's (so closing one context, for example, 96 * won't close the other). 97 */ 98 // %%% Alternatively, this could be done with a clone() method. 99 @SuppressWarnings("unchecked") // clone() 100 RegistryContext(RegistryContext ctx) { 101 environment = (Hashtable<String, Object>)ctx.environment.clone(); 102 registry = ctx.registry; 103 host = ctx.host; 104 port = ctx.port; 105 reference = ctx.reference; 106 } 107 108 protected void finalize() { 109 close(); 110 } 111 112 public Object lookup(Name name) throws NamingException { 113 if (name.isEmpty()) { 114 return (new RegistryContext(this)); 115 } 116 Remote obj; 117 try { 118 obj = registry.lookup(name.get(0)); 119 } catch (NotBoundException e) { 120 throw (new NameNotFoundException(name.get(0))); 121 } catch (RemoteException e) { 182 } 183 } 184 185 public void unbind(String name) throws NamingException { 186 unbind(new CompositeName(name)); 187 } 188 189 /** 190 * Rename is implemented by this sequence of operations: 191 * lookup, bind, unbind. The sequence is not performed atomically. 192 */ 193 public void rename(Name oldName, Name newName) throws NamingException { 194 bind(newName, lookup(oldName)); 195 unbind(oldName); 196 } 197 198 public void rename(String name, String newName) throws NamingException { 199 rename(new CompositeName(name), new CompositeName(newName)); 200 } 201 202 public NamingEnumeration<NameClassPair> list(Name name) throws 203 NamingException { 204 if (!name.isEmpty()) { 205 throw (new InvalidNameException( 206 "RegistryContext: can only list \"\"")); 207 } 208 try { 209 String[] names = registry.list(); 210 return (new NameClassPairEnumeration(names)); 211 } catch (RemoteException e) { 212 throw (NamingException)wrapRemoteException(e).fillInStackTrace(); 213 } 214 } 215 216 public NamingEnumeration<NameClassPair> list(String name) throws 217 NamingException { 218 return list(new CompositeName(name)); 219 } 220 221 public NamingEnumeration<Binding> listBindings(Name name) 222 throws NamingException 223 { 224 if (!name.isEmpty()) { 225 throw (new InvalidNameException( 226 "RegistryContext: can only list \"\"")); 227 } 228 try { 229 String[] names = registry.list(); 230 return (new BindingEnumeration(this, names)); 231 } catch (RemoteException e) { 232 throw (NamingException)wrapRemoteException(e).fillInStackTrace(); 233 } 234 } 235 236 public NamingEnumeration<Binding> listBindings(String name) throws 237 NamingException { 238 return listBindings(new CompositeName(name)); 239 } 240 241 public void destroySubcontext(Name name) throws NamingException { 242 throw (new OperationNotSupportedException()); 243 } 244 245 public void destroySubcontext(String name) throws NamingException { 246 throw (new OperationNotSupportedException()); 247 } 248 249 public Context createSubcontext(Name name) throws NamingException { 250 throw (new OperationNotSupportedException()); 251 } 252 253 public Context createSubcontext(String name) throws NamingException { 254 throw (new OperationNotSupportedException()); 255 } 256 257 public Object lookupLink(Name name) throws NamingException { 280 { 281 return composeName(new CompositeName(name), 282 new CompositeName(prefix)).toString(); 283 } 284 285 public Object removeFromEnvironment(String propName) 286 throws NamingException 287 { 288 return environment.remove(propName); 289 } 290 291 public Object addToEnvironment(String propName, Object propVal) 292 throws NamingException 293 { 294 if (propName.equals(SECURITY_MGR)) { 295 installSecurityMgr(); 296 } 297 return environment.put(propName, propVal); 298 } 299 300 @SuppressWarnings("unchecked") // clone() 301 public Hashtable<String, Object> getEnvironment() throws NamingException { 302 return (Hashtable<String, Object>)environment.clone(); 303 } 304 305 public void close() { 306 environment = null; 307 registry = null; 308 // &&& If we were caching registry connections, we would probably 309 // uncache this one now. 310 } 311 312 public String getNameInNamespace() { 313 return ""; // Registry has an empty name 314 } 315 316 /** 317 * Returns an RMI registry reference for this context. 318 *<p> 319 * If this context was created from a reference, that reference is 320 * returned. Otherwise, an exception is thrown if the registry's 321 * host is "localhost" or the default (null). Although this could 322 * possibly make for a valid reference, it's far more likely to be 474 throw ne; 475 } 476 } 477 478 } 479 480 481 /** 482 * A name parser for case-sensitive atomic names. 483 */ 484 class AtomicNameParser implements NameParser { 485 private static final Properties syntax = new Properties(); 486 487 public Name parse(String name) throws NamingException { 488 return (new CompoundName(name, syntax)); 489 } 490 } 491 492 493 /** 494 * An enumeration of name / class-name pairs. 495 */ 496 class NameClassPairEnumeration implements NamingEnumeration<NameClassPair> { 497 private final String[] names; 498 private int nextName; // index into "names" 499 500 NameClassPairEnumeration(String[] names) { 501 this.names = names; 502 nextName = 0; 503 } 504 505 public boolean hasMore() { 506 return (nextName < names.length); 507 } 508 509 public NameClassPair next() throws NamingException { 510 if (!hasMore()) { 511 throw (new java.util.NoSuchElementException()); 512 } 513 // Convert name to a one-element composite name, so embedded 514 // meta-characters are properly escaped. 515 String name = names[nextName++]; 516 Name cname = (new CompositeName()).add(name); 517 NameClassPair ncp = new NameClassPair(cname.toString(), 518 "java.lang.Object"); 519 ncp.setNameInNamespace(name); 520 return ncp; 521 } 522 523 public boolean hasMoreElements() { 524 return hasMore(); 525 } 526 527 public NameClassPair nextElement() { 528 try { 529 return next(); 530 } catch (NamingException e) { // should never happen 531 throw (new java.util.NoSuchElementException( 532 "javax.naming.NamingException was thrown")); 533 } 534 } 535 536 public void close() { 537 nextName = names.length; 538 } 539 } 540 541 542 /** 543 * An enumeration of Bindings. 544 * 545 * The actual registry lookups are performed when next() is called. It would 546 * be nicer to defer this until the object (or its class name) is actually 547 * requested. The problem with that approach is that Binding.getObject() 548 * cannot throw NamingException. 549 */ 550 class BindingEnumeration implements NamingEnumeration<Binding> { 551 private RegistryContext ctx; 552 private final String[] names; 553 private int nextName; // index into "names" 554 555 BindingEnumeration(RegistryContext ctx, String[] names) { 556 // Clone ctx in case someone closes it before we're through. 557 this.ctx = new RegistryContext(ctx); 558 this.names = names; 559 nextName = 0; 560 } 561 562 protected void finalize() { 563 ctx.close(); 564 } 565 566 public boolean hasMore() { 567 if (nextName >= names.length) { 568 ctx.close(); 569 } 570 return (nextName < names.length); 571 } 572 573 public Binding next() throws NamingException { 574 if (!hasMore()) { 575 throw (new java.util.NoSuchElementException()); 576 } 577 // Convert name to a one-element composite name, so embedded 578 // meta-characters are properly escaped. 579 String name = names[nextName++]; 580 Name cname = (new CompositeName()).add(name); 581 582 Object obj = ctx.lookup(cname); 583 String cnameStr = cname.toString(); 584 Binding binding = new Binding(cnameStr, obj); 585 binding.setNameInNamespace(cnameStr); 586 return binding; 587 } 588 589 public boolean hasMoreElements() { 590 return hasMore(); 591 } 592 593 public Binding nextElement() { 594 try { 595 return next(); 596 } catch (NamingException e) { 597 throw (new java.util.NoSuchElementException( 598 "javax.naming.NamingException was thrown")); 599 } 600 } 601 602 public void close () { 603 finalize(); 604 } 605 } |