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