001 /*
002 * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package java.rmi;
026
027 import java.rmi.registry.*;
028 import java.net.MalformedURLException;
029 import java.net.URI;
030 import java.net.URISyntaxException;
031
032 /**
033 * The <code>Naming</code> class provides methods for storing and obtaining
034 * references to remote objects in a remote object registry. Each method of
035 * the <code>Naming</code> class takes as one of its arguments a name that
036 * is a <code>java.lang.String</code> in URL format (without the
037 * scheme component) of the form:
038 *
039 * <PRE>
040 * //host:port/name
041 * </PRE>
042 *
043 * <P>where <code>host</code> is the host (remote or local) where the registry
044 * is located, <code>port</code> is the port number on which the registry
045 * accepts calls, and where <code>name</code> is a simple string uninterpreted
046 * by the registry. Both <code>host</code> and <code>port</code> are optional.
047 * If <code>host</code> is omitted, the host defaults to the local host. If
048 * <code>port</code> is omitted, then the port defaults to 1099, the
049 * "well-known" port that RMI's registry, <code>rmiregistry</code>, uses.
050 *
051 * <P><em>Binding</em> a name for a remote object is associating or
052 * registering a name for a remote object that can be used at a later time to
053 * look up that remote object. A remote object can be associated with a name
054 * using the <code>Naming</code> class's <code>bind</code> or
055 * <code>rebind</code> methods.
056 *
057 * <P>Once a remote object is registered (bound) with the RMI registry on the
058 * local host, callers on a remote (or local) host can lookup the remote
059 * object by name, obtain its reference, and then invoke remote methods on the
060 * object. A registry may be shared by all servers running on a host or an
061 * individual server process may create and use its own registry if desired
062 * (see <code>java.rmi.registry.LocateRegistry.createRegistry</code> method
063 * for details).
064 *
065 * @version 1.13, 09/05/99
066 * @author Ann Wollrath
067 * @author Roger Riggs
068 * @since JDK1.1
069 * @see java.rmi.registry.Registry
070 * @see java.rmi.registry.LocateRegistry
071 * @see java.rmi.registry.LocateRegistry#createRegistry(int)
072 */
073 public final class Naming {
074 /**
075 * Disallow anyone from creating one of these
076 */
077 private Naming() {
078 }
079
080 /**
081 * Returns a reference, a stub, for the remote object associated
082 * with the specified <code>name</code>.
083 *
084 * @param name a name in URL format (without the scheme component)
085 * @return a reference for a remote object
086 * @exception NotBoundException if name is not currently bound
087 * @exception RemoteException if registry could not be contacted
088 * @exception AccessException if this operation is not permitted
089 * @exception MalformedURLException if the name is not an appropriately
090 * formatted URL
091 * @since JDK1.1
092 */
093 public static Remote lookup(String name) throws NotBoundException,
094 java.net.MalformedURLException, RemoteException {
095 ParsedNamingURL parsed = parseURL(name);
096 Registry registry = getRegistry(parsed);
097
098 if (parsed.name == null)
099 return registry;
100 return registry.lookup(parsed.name);
101 }
102
103 /**
104 * Binds the specified <code>name</code> to a remote object.
105 *
106 * @param name a name in URL format (without the scheme component)
107 * @param obj a reference for the remote object (usually a stub)
108 * @exception AlreadyBoundException if name is already bound
109 * @exception MalformedURLException if the name is not an appropriately
110 * formatted URL
111 * @exception RemoteException if registry could not be contacted
112 * @exception AccessException if this operation is not permitted (if
113 * originating from a non-local host, for example)
114 * @since JDK1.1
115 */
116 public static void bind(String name, Remote obj)
117 throws AlreadyBoundException,
118 java.net.MalformedURLException, RemoteException {
119 ParsedNamingURL parsed = parseURL(name);
120 Registry registry = getRegistry(parsed);
121
122 if (obj == null)
123 throw new NullPointerException("cannot bind to null");
124
125 registry.bind(parsed.name, obj);
126 }
127
128 /**
129 * Destroys the binding for the specified name that is associated
130 * with a remote object.
131 *
132 * @param name a name in URL format (without the scheme component)
133 * @exception NotBoundException if name is not currently bound
134 * @exception MalformedURLException if the name is not an appropriately
135 * formatted URL
136 * @exception RemoteException if registry could not be contacted
137 * @exception AccessException if this operation is not permitted (if
138 * originating from a non-local host, for example)
139 * @since JDK1.1
140 */
141 public static void unbind(String name) throws RemoteException,
142 NotBoundException, java.net.MalformedURLException {
143 ParsedNamingURL parsed = parseURL(name);
144 Registry registry = getRegistry(parsed);
145
146 registry.unbind(parsed.name);
147 }
148
149 /**
150 * Rebinds the specified name to a new remote object. Any existing
151 * binding for the name is replaced.
152 *
153 * @param name a name in URL format (without the scheme component)
154 * @param obj new remote object to associate with the name
155 * @exception MalformedURLException if the name is not an appropriately
156 * formatted URL
157 * @exception RemoteException if registry could not be contacted
158 * @exception AccessException if this operation is not permitted (if
159 * originating from a non-local host, for example)
160 * @since JDK1.1
161 */
162 public static void rebind(String name, Remote obj)
163 throws RemoteException, java.net.MalformedURLException {
164 ParsedNamingURL parsed = parseURL(name);
165 Registry registry = getRegistry(parsed);
166
167 if (obj == null)
168 throw new NullPointerException("cannot bind to null");
169
170 registry.rebind(parsed.name, obj);
171 }
172
173 /**
174 * Returns an array of the names bound in the registry. The names are
175 * URL-formatted (without the scheme component) strings. The array contains
176 * a snapshot of the names present in the registry at the time of the
177 * call.
178 *
179 * @param name a registry name in URL format (without the scheme
180 * component)
181 * @return an array of names (in the appropriate format) bound
182 * in the registry
183 * @exception MalformedURLException if the name is not an appropriately
184 * formatted URL
185 * @exception RemoteException if registry could not be contacted.
186 * @since JDK1.1
187 */
188 public static String[] list(String name) throws RemoteException,
189 java.net.MalformedURLException {
190 ParsedNamingURL parsed = parseURL(name);
191 Registry registry = getRegistry(parsed);
192
193 String prefix = "";
194 if (parsed.port > 0 || !parsed.host.equals(""))
195 prefix += "//" + parsed.host;
196 if (parsed.port > 0)
197 prefix += ":" + parsed.port;
198 prefix += "/";
199
200 String[] names = registry.list();
201 for (int i = 0; i < names.length; i++) {
202 names[i] = prefix + names[i];
203 }
204 return names;
205 }
206
207 /**
208 * Returns a registry reference obtained from information in the URL.
209 */
210 private static Registry getRegistry(ParsedNamingURL parsed)
211 throws RemoteException {
212 return LocateRegistry.getRegistry(parsed.host, parsed.port);
213 }
214
215 /**
216 * Dissect Naming URL strings to obtain referenced host, port and
217 * object name.
218 *
219 * @return an object which contains each of the above
220 * components.
221 *
222 * @exception MalformedURLException if given url string is malformed
223 */
224 private static ParsedNamingURL parseURL(String str)
225 throws MalformedURLException {
226 try {
227 return intParseURL(str);
228 } catch (URISyntaxException ex) {
229 /* With RFC 3986 URI handling, 'rmi://:<port>' and
230 * '//:<port>' forms will result in a URI syntax exception
231 * Convert the authority to a localhost:<port> form
232 */
233 MalformedURLException mue = new MalformedURLException(
234 "invalid URL String: " + str);
235 mue.initCause(ex);
236 int indexSchemeEnd = str.indexOf(':');
237 int indexAuthorityBegin = str.indexOf("//:");
238 if (indexAuthorityBegin < 0) {
239 throw mue;
240 }
241 if ((indexAuthorityBegin == 0)
242 || ((indexSchemeEnd > 0) && (indexAuthorityBegin == indexSchemeEnd + 1))) {
243 int indexHostBegin = indexAuthorityBegin + 2;
244 String newStr = str.substring(0, indexHostBegin)
245 + "localhost" + str.substring(indexHostBegin);
246 try {
247 return intParseURL(newStr);
248 } catch (URISyntaxException inte) {
249 throw mue;
250 } catch (MalformedURLException inte) {
251 throw inte;
252 }
253 }
254 throw mue;
255 }
256 }
257
258 private static ParsedNamingURL intParseURL(String str)
259 throws MalformedURLException, URISyntaxException {
260 URI uri = new URI(str);
261 if (uri.isOpaque()) {
262 throw new MalformedURLException("not a hierarchical URL: "
263 + str);
264 }
265 if (uri.getFragment() != null) {
266 throw new MalformedURLException(
267 "invalid character, '#', in URL name: " + str);
268 } else if (uri.getQuery() != null) {
269 throw new MalformedURLException(
270 "invalid character, '?', in URL name: " + str);
271 } else if (uri.getUserInfo() != null) {
272 throw new MalformedURLException(
273 "invalid character, '@', in URL host: " + str);
274 }
275 String scheme = uri.getScheme();
276 if (scheme != null && !scheme.equals("rmi")) {
277 throw new MalformedURLException("invalid URL scheme: "
278 + str);
279 }
280
281 String name = uri.getPath();
282 if (name != null) {
283 if (name.startsWith("/")) {
284 name = name.substring(1);
285 }
286 if (name.length() == 0) {
287 name = null;
288 }
289 }
290
291 String host = uri.getHost();
292 if (host == null) {
293 host = "";
294 try {
295 /*
296 * With 2396 URI handling, forms such as 'rmi://host:bar'
297 * or 'rmi://:<port>' are parsed into a registry based
298 * authority. We only want to allow server based naming
299 * authorities.
300 */
301 uri.parseServerAuthority();
302 } catch (URISyntaxException use) {
303 // Check if the authority is of form ':<port>'
304 String authority = uri.getAuthority();
305 if (authority != null && authority.startsWith(":")) {
306 // Convert the authority to 'localhost:<port>' form
307 authority = "localhost" + authority;
308 try {
309 uri = new URI(null, authority, null, null, null);
310 // Make sure it now parses to a valid server based
311 // naming authority
312 uri.parseServerAuthority();
313 } catch (URISyntaxException use2) {
314 throw new MalformedURLException(
315 "invalid authority: " + str);
316 }
317 } else {
318 throw new MalformedURLException(
319 "invalid authority: " + str);
320 }
321 }
322 }
323 int port = uri.getPort();
324 if (port == -1) {
325 port = Registry.REGISTRY_PORT;
326 }
327 return new ParsedNamingURL(host, port, name);
328 }
329
330 /**
331 * Simple class to enable multiple URL return values.
332 */
333 private static class ParsedNamingURL {
334 String host;
335 int port;
336 String name;
337
338 ParsedNamingURL(String host, int port, String name) {
339 this.host = host;
340 this.port = port;
341 this.name = name;
342 }
343 }
344 }
|