blob: fb7822f151cb4e96fd7e083b6cb1a987810093ff [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2004 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 */
25
26package com.sun.jndi.toolkit.url;
27
28import javax.naming.*;
29import javax.naming.spi.ResolveResult;
30import javax.naming.spi.NamingManager;
31
32import java.util.Hashtable;
33import java.net.MalformedURLException;
34
35/**
36 * This abstract class is a generic URL context that accepts as the
37 * name argument either a string URL or a Name whose first component
38 * is a URL. It resolves the URL to a target context and then continues
39 * the operation using the remaining name in the target context as if
40 * the first component names a junction.
41 *
42 * A subclass must define getRootURLContext()
43 * to process the URL into head/tail pieces. If it wants to control how
44 * URL strings are parsed and compared for the rename() operation, then
45 * it should override getNonRootURLSuffixes() and urlEquals().
46 *
47 * @author Scott Seligman
48 * @author Rosanna Lee
49 */
50abstract public class GenericURLContext implements Context {
51 protected Hashtable myEnv = null;
52
53 public GenericURLContext(Hashtable env) {
54 // context that is not tied to any specific URL
55 myEnv = env; // copied on write
56 }
57
58 public void close() throws NamingException {
59 myEnv = null;
60 }
61
62 public String getNameInNamespace() throws NamingException {
63 return ""; // %%% check this out: A URL context's name is ""
64 }
65
66 /**
67 * Resolves 'name' into a target context with remaining name.
68 * For example, with a JNDI URL "jndi://dnsname/rest_name",
69 * this method resolves "jndi://dnsname/" to a target context,
70 * and returns the target context with "rest_name".
71 * The definition of "root URL" and how much of the URL to
72 * consume is implementation specific.
73 * If rename() is supported for a particular URL scheme,
74 * getRootURLContext(), getURLPrefix(), and getURLSuffix()
75 * must be in sync wrt how URLs are parsed and returned.
76 */
77 abstract protected ResolveResult getRootURLContext(String url,
78 Hashtable env) throws NamingException;
79
80 /**
81 * Returns the suffix of the url. The result should be identical to
82 * that of calling getRootURLContext().getRemainingName(), but
83 * without the overhead of doing anything with the prefix like
84 * creating a context.
85 *<p>
86 * This method returns a Name instead of a String because to give
87 * the provider an opportunity to return a Name (for example,
88 * for weakly separated naming systems like COS naming).
89 *<p>
90 * The default implementation uses skips 'prefix', calls
91 * UrlUtil.decode() on it, and returns the result as a single component
92 * CompositeName.
93 * Subclass should override if this is not appropriate.
94 * This method is used only by rename().
95 * If rename() is supported for a particular URL scheme,
96 * getRootURLContext(), getURLPrefix(), and getURLSuffix()
97 * must be in sync wrt how URLs are parsed and returned.
98 *<p>
99 * For many URL schemes, this method is very similar to URL.getFile(),
100 * except getFile() will return a leading slash in the
101 * 2nd, 3rd, and 4th cases. For schemes like "ldap" and "iiop",
102 * the leading slash must be skipped before the name is an acceptable
103 * format for operation by the Context methods. For schemes that treat the
104 * leading slash as significant (such as "file"),
105 * the subclass must override getURLSuffix() to get the correct behavior.
106 * Remember, the behavior must match getRootURLContext().
107 *
108 * URL Suffix
109 * foo://host:port <empty string>
110 * foo://host:port/rest/of/name rest/of/name
111 * foo:///rest/of/name rest/of/name
112 * foo:/rest/of/name rest/of/name
113 * foo:rest/of/name rest/of/name
114 */
115 protected Name getURLSuffix(String prefix, String url) throws NamingException {
116 String suffix = url.substring(prefix.length());
117 if (suffix.length() == 0) {
118 return new CompositeName();
119 }
120
121 if (suffix.charAt(0) == '/') {
122 suffix = suffix.substring(1); // skip leading slash
123 }
124
125 try {
126 return new CompositeName().add(UrlUtil.decode(suffix));
127 } catch (MalformedURLException e) {
128 throw new InvalidNameException(e.getMessage());
129 }
130 }
131
132 /**
133 * Finds the prefix of a URL.
134 * Default implementation looks for slashes and then extracts
135 * prefixes using String.substring().
136 * Subclass should override if this is not appropriate.
137 * This method is used only by rename().
138 * If rename() is supported for a particular URL scheme,
139 * getRootURLContext(), getURLPrefix(), and getURLSuffix()
140 * must be in sync wrt how URLs are parsed and returned.
141 *<p>
142 * URL Prefix
143 * foo://host:port foo://host:port
144 * foo://host:port/rest/of/name foo://host:port
145 * foo:///rest/of/name foo://
146 * foo:/rest/of/name foo:
147 * foo:rest/of/name foo:
148 */
149 protected String getURLPrefix(String url) throws NamingException {
150 int start = url.indexOf(":");
151
152 if (start < 0) {
153 throw new OperationNotSupportedException("Invalid URL: " + url);
154 }
155 ++start; // skip ':'
156
157 if (url.startsWith("//", start)) {
158 start += 2; // skip double slash
159
160 // find last slash
161 int posn = url.indexOf("/", start);
162 if (posn >= 0) {
163 start = posn;
164 } else {
165 start = url.length(); // rest of URL
166 }
167 }
168
169 // else 0 or 1 iniitial slashes; start is unchanged
170 return url.substring(0, start);
171 }
172
173 /**
174 * Determines whether two URLs are the same.
175 * Default implementation uses String.equals().
176 * Subclass should override if this is not appropriate.
177 * This method is used by rename().
178 */
179 protected boolean urlEquals(String url1, String url2) {
180 return url1.equals(url2);
181 }
182
183 /**
184 * Gets the context in which to continue the operation. This method
185 * is called when this context is asked to process a multicomponent
186 * Name in which the first component is a URL.
187 * Treat the first component like a junction: resolve it and then use
188 * NamingManager.getContinuationContext() to get the target context in
189 * which to operate on the remainder of the name (n.getSuffix(1)).
190 */
191 protected Context getContinuationContext(Name n) throws NamingException {
192 Object obj = lookup(n.get(0));
193 CannotProceedException cpe = new CannotProceedException();
194 cpe.setResolvedObj(obj);
195 cpe.setEnvironment(myEnv);
196 return NamingManager.getContinuationContext(cpe);
197 }
198
199 public Object lookup(String name) throws NamingException {
200 ResolveResult res = getRootURLContext(name, myEnv);
201 Context ctx = (Context)res.getResolvedObj();
202 try {
203 return ctx.lookup(res.getRemainingName());
204 } finally {
205 ctx.close();
206 }
207 }
208
209 public Object lookup(Name name) throws NamingException {
210 if (name.size() == 1) {
211 return lookup(name.get(0));
212 } else {
213 Context ctx = getContinuationContext(name);
214 try {
215 return ctx.lookup(name.getSuffix(1));
216 } finally {
217 ctx.close();
218 }
219 }
220 }
221
222 public void bind(String name, Object obj) throws NamingException {
223 ResolveResult res = getRootURLContext(name, myEnv);
224 Context ctx = (Context)res.getResolvedObj();
225 try {
226 ctx.bind(res.getRemainingName(), obj);
227 } finally {
228 ctx.close();
229 }
230 }
231
232 public void bind(Name name, Object obj) throws NamingException {
233 if (name.size() == 1) {
234 bind(name.get(0), obj);
235 } else {
236 Context ctx = getContinuationContext(name);
237 try {
238 ctx.bind(name.getSuffix(1), obj);
239 } finally {
240 ctx.close();
241 }
242 }
243 }
244
245 public void rebind(String name, Object obj) throws NamingException {
246 ResolveResult res = getRootURLContext(name, myEnv);
247 Context ctx = (Context)res.getResolvedObj();
248 try {
249 ctx.rebind(res.getRemainingName(), obj);
250 } finally {
251 ctx.close();
252 }
253 }
254
255 public void rebind(Name name, Object obj) throws NamingException {
256 if (name.size() == 1) {
257 rebind(name.get(0), obj);
258 } else {
259 Context ctx = getContinuationContext(name);
260 try {
261 ctx.rebind(name.getSuffix(1), obj);
262 } finally {
263 ctx.close();
264 }
265 }
266 }
267
268 public void unbind(String name) throws NamingException {
269 ResolveResult res = getRootURLContext(name, myEnv);
270 Context ctx = (Context)res.getResolvedObj();
271 try {
272 ctx.unbind(res.getRemainingName());
273 } finally {
274 ctx.close();
275 }
276 }
277
278 public void unbind(Name name) throws NamingException {
279 if (name.size() == 1) {
280 unbind(name.get(0));
281 } else {
282 Context ctx = getContinuationContext(name);
283 try {
284 ctx.unbind(name.getSuffix(1));
285 } finally {
286 ctx.close();
287 }
288 }
289 }
290
291 public void rename(String oldName, String newName) throws NamingException {
292 String oldPrefix = getURLPrefix(oldName);
293 String newPrefix = getURLPrefix(newName);
294 if (!urlEquals(oldPrefix, newPrefix)) {
295 throw new OperationNotSupportedException(
296 "Renaming using different URL prefixes not supported : " +
297 oldName + " " + newName);
298 }
299
300 ResolveResult res = getRootURLContext(oldName, myEnv);
301 Context ctx = (Context)res.getResolvedObj();
302 try {
303 ctx.rename(res.getRemainingName(), getURLSuffix(newPrefix, newName));
304 } finally {
305 ctx.close();
306 }
307 }
308
309 public void rename(Name name, Name newName) throws NamingException {
310 if (name.size() == 1) {
311 if (newName.size() != 1) {
312 throw new OperationNotSupportedException(
313 "Renaming to a Name with more components not supported: " + newName);
314 }
315 rename(name.get(0), newName.get(0));
316 } else {
317 // > 1 component with 1st one being URL
318 // URLs must be identical; cannot deal with diff URLs
319 if (!urlEquals(name.get(0), newName.get(0))) {
320 throw new OperationNotSupportedException(
321 "Renaming using different URLs as first components not supported: " +
322 name + " " + newName);
323 }
324
325 Context ctx = getContinuationContext(name);
326 try {
327 ctx.rename(name.getSuffix(1), newName.getSuffix(1));
328 } finally {
329 ctx.close();
330 }
331 }
332 }
333
334 public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
335 ResolveResult res = getRootURLContext(name, myEnv);
336 Context ctx = (Context)res.getResolvedObj();
337 try {
338 return ctx.list(res.getRemainingName());
339 } finally {
340 ctx.close();
341 }
342 }
343
344 public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
345 if (name.size() == 1) {
346 return list(name.get(0));
347 } else {
348 Context ctx = getContinuationContext(name);
349 try {
350 return ctx.list(name.getSuffix(1));
351 } finally {
352 ctx.close();
353 }
354 }
355 }
356
357 public NamingEnumeration<Binding> listBindings(String name)
358 throws NamingException {
359 ResolveResult res = getRootURLContext(name, myEnv);
360 Context ctx = (Context)res.getResolvedObj();
361 try {
362 return ctx.listBindings(res.getRemainingName());
363 } finally {
364 ctx.close();
365 }
366 }
367
368 public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
369 if (name.size() == 1) {
370 return listBindings(name.get(0));
371 } else {
372 Context ctx = getContinuationContext(name);
373 try {
374 return ctx.listBindings(name.getSuffix(1));
375 } finally {
376 ctx.close();
377 }
378 }
379 }
380
381 public void destroySubcontext(String name) throws NamingException {
382 ResolveResult res = getRootURLContext(name, myEnv);
383 Context ctx = (Context)res.getResolvedObj();
384 try {
385 ctx.destroySubcontext(res.getRemainingName());
386 } finally {
387 ctx.close();
388 }
389 }
390
391 public void destroySubcontext(Name name) throws NamingException {
392 if (name.size() == 1) {
393 destroySubcontext(name.get(0));
394 } else {
395 Context ctx = getContinuationContext(name);
396 try {
397 ctx.destroySubcontext(name.getSuffix(1));
398 } finally {
399 ctx.close();
400 }
401 }
402 }
403
404 public Context createSubcontext(String name) throws NamingException {
405 ResolveResult res = getRootURLContext(name, myEnv);
406 Context ctx = (Context)res.getResolvedObj();
407 try {
408 return ctx.createSubcontext(res.getRemainingName());
409 } finally {
410 ctx.close();
411 }
412 }
413
414 public Context createSubcontext(Name name) throws NamingException {
415 if (name.size() == 1) {
416 return createSubcontext(name.get(0));
417 } else {
418 Context ctx = getContinuationContext(name);
419 try {
420 return ctx.createSubcontext(name.getSuffix(1));
421 } finally {
422 ctx.close();
423 }
424 }
425 }
426
427 public Object lookupLink(String name) throws NamingException {
428 ResolveResult res = getRootURLContext(name, myEnv);
429 Context ctx = (Context)res.getResolvedObj();
430 try {
431 return ctx.lookupLink(res.getRemainingName());
432 } finally {
433 ctx.close();
434 }
435 }
436
437 public Object lookupLink(Name name) throws NamingException {
438 if (name.size() == 1) {
439 return lookupLink(name.get(0));
440 } else {
441 Context ctx = getContinuationContext(name);
442 try {
443 return ctx.lookupLink(name.getSuffix(1));
444 } finally {
445 ctx.close();
446 }
447 }
448 }
449
450 public NameParser getNameParser(String name) throws NamingException {
451 ResolveResult res = getRootURLContext(name, myEnv);
452 Context ctx = (Context)res.getResolvedObj();
453 try {
454 return ctx.getNameParser(res.getRemainingName());
455 } finally {
456 ctx.close();
457 }
458 }
459
460 public NameParser getNameParser(Name name) throws NamingException {
461 if (name.size() == 1) {
462 return getNameParser(name.get(0));
463 } else {
464 Context ctx = getContinuationContext(name);
465 try {
466 return ctx.getNameParser(name.getSuffix(1));
467 } finally {
468 ctx.close();
469 }
470 }
471 }
472
473 public String composeName(String name, String prefix)
474 throws NamingException {
475 if (prefix.equals("")) {
476 return name;
477 } else if (name.equals("")) {
478 return prefix;
479 } else {
480 return (prefix + "/" + name);
481 }
482 }
483
484 public Name composeName(Name name, Name prefix) throws NamingException {
485 Name result = (Name)prefix.clone();
486 result.addAll(name);
487 return result;
488 }
489
490 public Object removeFromEnvironment(String propName)
491 throws NamingException {
492 if (myEnv == null) {
493 return null;
494 }
495 myEnv = (Hashtable)myEnv.clone();
496 return myEnv.remove(propName);
497 }
498
499 public Object addToEnvironment(String propName, Object propVal)
500 throws NamingException {
501 myEnv = (myEnv == null) ?
502 new Hashtable(11, 0.75f) : (Hashtable)myEnv.clone();
503 return myEnv.put(propName, propVal);
504 }
505
506 public Hashtable getEnvironment() throws NamingException {
507 if (myEnv == null) {
508 return new Hashtable(5, 0.75f);
509 } else {
510 return (Hashtable)myEnv.clone();
511 }
512 }
513
514/*
515// To test, declare getURLPrefix and getURLSuffix static.
516
517 public static void main(String[] args) throws Exception {
518 String[] tests = {"file://host:port",
519 "file:///rest/of/name",
520 "file://host:port/rest/of/name",
521 "file:/rest/of/name",
522 "file:rest/of/name"};
523 for (int i = 0; i < tests.length; i++) {
524 String pre = getURLPrefix(tests[i]);
525 System.out.println(pre);
526 System.out.println(getURLSuffix(pre, tests[i]));
527 }
528 }
529*/
530}