blob: 633950bb3fe6a8259c8097696706274522a61740 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package java.rmi;
26
27import java.rmi.registry.*;
28import java.net.MalformedURLException;
29import java.net.URI;
30import 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 JDK1.1
68 * @see java.rmi.registry.Registry
69 * @see java.rmi.registry.LocateRegistry
70 * @see java.rmi.registry.LocateRegistry#createRegistry(int)
71 */
72public 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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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.equals(""))
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}