1 /* 2 * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.rmi; 26 27 import java.rmi.registry.*; 28 import java.net.MalformedURLException; 29 import java.net.URI; 30 import java.net.URISyntaxException; 31 32 /** 33 * The <code>Naming</code> class provides methods for storing and obtaining 34 * references to remote objects in a remote object registry. Each method of 35 * the <code>Naming</code> class takes as one of its arguments a name that 36 * is a <code>java.lang.String</code> in URL format (without the 37 * scheme component) of the form: 38 * 39 * <PRE> 40 * //host:port/name 41 * </PRE> 42 * 43 * <P>where <code>host</code> is the host (remote or local) where the registry 44 * is located, <code>port</code> is the port number on which the registry 45 * accepts calls, and where <code>name</code> is a simple string uninterpreted 46 * by the registry. Both <code>host</code> and <code>port</code> are optional. 47 * If <code>host</code> is omitted, the host defaults to the local host. If 48 * <code>port</code> is omitted, then the port defaults to 1099, the 49 * "well-known" port that RMI's registry, <code>rmiregistry</code>, uses. 50 * 51 * <P><em>Binding</em> a name for a remote object is associating or 52 * registering a name for a remote object that can be used at a later time to 53 * look up that remote object. A remote object can be associated with a name 54 * using the <code>Naming</code> class's <code>bind</code> or 55 * <code>rebind</code> methods. 56 * 57 * <P>Once a remote object is registered (bound) with the RMI registry on the 58 * local host, callers on a remote (or local) host can lookup the remote 59 * object by name, obtain its reference, and then invoke remote methods on the 60 * object. A registry may be shared by all servers running on a host or an 61 * individual server process may create and use its own registry if desired 62 * (see <code>java.rmi.registry.LocateRegistry.createRegistry</code> method 63 * for details). 64 * 65 * @author Ann Wollrath 66 * @author Roger Riggs 67 * @since 1.1 68 * @see java.rmi.registry.Registry 69 * @see java.rmi.registry.LocateRegistry 70 * @see java.rmi.registry.LocateRegistry#createRegistry(int) 71 */ 72 public final class Naming { 73 /** 74 * Disallow anyone from creating one of these 75 */ 76 private Naming() {} 77 78 /** 79 * Returns a reference, a stub, for the remote object associated 80 * with the specified <code>name</code>. 81 * 82 * @param name a name in URL format (without the scheme component) 83 * @return a reference for a remote object 84 * @exception NotBoundException if name is not currently bound 85 * @exception RemoteException if registry could not be contacted 86 * @exception AccessException if this operation is not permitted 87 * @exception MalformedURLException if the name is not an appropriately 88 * formatted URL 89 * @since 1.1 90 */ 91 public static Remote lookup(String name) 92 throws NotBoundException, 93 java.net.MalformedURLException, 94 RemoteException 95 { 96 ParsedNamingURL parsed = parseURL(name); 97 Registry registry = getRegistry(parsed); 98 99 if (parsed.name == null) 100 return registry; 101 return registry.lookup(parsed.name); 102 } 103 104 /** 105 * Binds the specified <code>name</code> to a remote object. 106 * 107 * @param name a name in URL format (without the scheme component) 108 * @param obj a reference for the remote object (usually a stub) 109 * @exception AlreadyBoundException if name is already bound 110 * @exception MalformedURLException if the name is not an appropriately 111 * formatted URL 112 * @exception RemoteException if registry could not be contacted 113 * @exception AccessException if this operation is not permitted (if 114 * originating from a non-local host, for example) 115 * @since 1.1 116 */ 117 public static void bind(String name, Remote obj) 118 throws AlreadyBoundException, 119 java.net.MalformedURLException, 120 RemoteException 121 { 122 ParsedNamingURL parsed = parseURL(name); 123 Registry registry = getRegistry(parsed); 124 125 if (obj == null) 126 throw new NullPointerException("cannot bind to null"); 127 128 registry.bind(parsed.name, obj); 129 } 130 131 /** 132 * Destroys the binding for the specified name that is associated 133 * with a remote object. 134 * 135 * @param name a name in URL format (without the scheme component) 136 * @exception NotBoundException if name is not currently bound 137 * @exception MalformedURLException if the name is not an appropriately 138 * formatted URL 139 * @exception RemoteException if registry could not be contacted 140 * @exception AccessException if this operation is not permitted (if 141 * originating from a non-local host, for example) 142 * @since 1.1 143 */ 144 public static void unbind(String name) 145 throws RemoteException, 146 NotBoundException, 147 java.net.MalformedURLException 148 { 149 ParsedNamingURL parsed = parseURL(name); 150 Registry registry = getRegistry(parsed); 151 152 registry.unbind(parsed.name); 153 } 154 155 /** 156 * Rebinds the specified name to a new remote object. Any existing 157 * binding for the name is replaced. 158 * 159 * @param name a name in URL format (without the scheme component) 160 * @param obj new remote object to associate with the name 161 * @exception MalformedURLException if the name is not an appropriately 162 * formatted URL 163 * @exception RemoteException if registry could not be contacted 164 * @exception AccessException if this operation is not permitted (if 165 * originating from a non-local host, for example) 166 * @since 1.1 167 */ 168 public static void rebind(String name, Remote obj) 169 throws RemoteException, java.net.MalformedURLException 170 { 171 ParsedNamingURL parsed = parseURL(name); 172 Registry registry = getRegistry(parsed); 173 174 if (obj == null) 175 throw new NullPointerException("cannot bind to null"); 176 177 registry.rebind(parsed.name, obj); 178 } 179 180 /** 181 * Returns an array of the names bound in the registry. The names are 182 * URL-formatted (without the scheme component) strings. The array contains 183 * a snapshot of the names present in the registry at the time of the 184 * call. 185 * 186 * @param name a registry name in URL format (without the scheme 187 * component) 188 * @return an array of names (in the appropriate format) bound 189 * in the registry 190 * @exception MalformedURLException if the name is not an appropriately 191 * formatted URL 192 * @exception RemoteException if registry could not be contacted. 193 * @since 1.1 194 */ 195 public static String[] list(String name) 196 throws RemoteException, java.net.MalformedURLException 197 { 198 ParsedNamingURL parsed = parseURL(name); 199 Registry registry = getRegistry(parsed); 200 201 String prefix = ""; 202 if (parsed.port > 0 || !parsed.host.isEmpty()) 203 prefix += "//" + parsed.host; 204 if (parsed.port > 0) 205 prefix += ":" + parsed.port; 206 prefix += "/"; 207 208 String[] names = registry.list(); 209 for (int i = 0; i < names.length; i++) { 210 names[i] = prefix + names[i]; 211 } 212 return names; 213 } 214 215 /** 216 * Returns a registry reference obtained from information in the URL. 217 */ 218 private static Registry getRegistry(ParsedNamingURL parsed) 219 throws RemoteException 220 { 221 return LocateRegistry.getRegistry(parsed.host, parsed.port); 222 } 223 224 /** 225 * Dissect Naming URL strings to obtain referenced host, port and 226 * object name. 227 * 228 * @return an object which contains each of the above 229 * components. 230 * 231 * @exception MalformedURLException if given url string is malformed 232 */ 233 private static ParsedNamingURL parseURL(String str) 234 throws MalformedURLException 235 { 236 try { 237 return intParseURL(str); 238 } catch (URISyntaxException ex) { 239 /* With RFC 3986 URI handling, 'rmi://:<port>' and 240 * '//:<port>' forms will result in a URI syntax exception 241 * Convert the authority to a localhost:<port> form 242 */ 243 MalformedURLException mue = new MalformedURLException( 244 "invalid URL String: " + str); 245 mue.initCause(ex); 246 int indexSchemeEnd = str.indexOf(':'); 247 int indexAuthorityBegin = str.indexOf("//:"); 248 if (indexAuthorityBegin < 0) { 249 throw mue; 250 } 251 if ((indexAuthorityBegin == 0) || 252 ((indexSchemeEnd > 0) && 253 (indexAuthorityBegin == indexSchemeEnd + 1))) { 254 int indexHostBegin = indexAuthorityBegin + 2; 255 String newStr = str.substring(0, indexHostBegin) + 256 "localhost" + 257 str.substring(indexHostBegin); 258 try { 259 return intParseURL(newStr); 260 } catch (URISyntaxException inte) { 261 throw mue; 262 } catch (MalformedURLException inte) { 263 throw inte; 264 } 265 } 266 throw mue; 267 } 268 } 269 270 private static ParsedNamingURL intParseURL(String str) 271 throws MalformedURLException, URISyntaxException 272 { 273 URI uri = new URI(str); 274 if (uri.isOpaque()) { 275 throw new MalformedURLException( 276 "not a hierarchical URL: " + str); 277 } 278 if (uri.getFragment() != null) { 279 throw new MalformedURLException( 280 "invalid character, '#', in URL name: " + str); 281 } else if (uri.getQuery() != null) { 282 throw new MalformedURLException( 283 "invalid character, '?', in URL name: " + str); 284 } else if (uri.getUserInfo() != null) { 285 throw new MalformedURLException( 286 "invalid character, '@', in URL host: " + str); 287 } 288 String scheme = uri.getScheme(); 289 if (scheme != null && !scheme.equals("rmi")) { 290 throw new MalformedURLException("invalid URL scheme: " + str); 291 } 292 293 String name = uri.getPath(); 294 if (name != null) { 295 if (name.startsWith("/")) { 296 name = name.substring(1); 297 } 298 if (name.length() == 0) { 299 name = null; 300 } 301 } 302 303 String host = uri.getHost(); 304 if (host == null) { 305 host = ""; 306 try { 307 /* 308 * With 2396 URI handling, forms such as 'rmi://host:bar' 309 * or 'rmi://:<port>' are parsed into a registry based 310 * authority. We only want to allow server based naming 311 * authorities. 312 */ 313 uri.parseServerAuthority(); 314 } catch (URISyntaxException use) { 315 // Check if the authority is of form ':<port>' 316 String authority = uri.getAuthority(); 317 if (authority != null && authority.startsWith(":")) { 318 // Convert the authority to 'localhost:<port>' form 319 authority = "localhost" + authority; 320 try { 321 uri = new URI(null, authority, null, null, null); 322 // Make sure it now parses to a valid server based 323 // naming authority 324 uri.parseServerAuthority(); 325 } catch (URISyntaxException use2) { 326 throw new 327 MalformedURLException("invalid authority: " + str); 328 } 329 } else { 330 throw new 331 MalformedURLException("invalid authority: " + str); 332 } 333 } 334 } 335 int port = uri.getPort(); 336 if (port == -1) { 337 port = Registry.REGISTRY_PORT; 338 } 339 return new ParsedNamingURL(host, port, name); 340 } 341 342 /** 343 * Simple class to enable multiple URL return values. 344 */ 345 private static class ParsedNamingURL { 346 String host; 347 int port; 348 String name; 349 350 ParsedNamingURL(String host, int port, String name) { 351 this.host = host; 352 this.port = port; 353 this.name = name; 354 } 355 } 356 }