1 22 23 package org.xquark.schema.datatypes; 24 25 import java.io.Serializable ; 26 27 31 32 public class URI implements Serializable { 33 private static final String RCSRevision = "$Revision: 1.1 $"; 34 private static final String RCSName = "$Name: $"; 35 36 41 public static class MalformedURIException extends Exception { 42 private static final String RCSRevision = "$Revision: 1.1 $"; 43 private static final String RCSName = "$Name: $"; 44 45 48 public MalformedURIException() { 49 super(); 50 } 51 52 57 public MalformedURIException(String msg) { 58 super(msg); 59 } 60 } 61 62 63 private static final String RESERVED_CHARACTERS = ";/?:@&=+$,"; 64 65 67 private static final String MARK_CHARACTERS = "-_.!~*'()"; 68 69 71 private static final String SCHEME_CHARACTERS = "+-."; 72 73 private String scheme = null; 74 private String authority = null; 75 private String path = ""; 76 private String query = null; 77 private String fragment = null; 78 79 92 public URI(String uri) throws MalformedURIException { 93 if (uri == null) 94 throw new MalformedURIException("uri parameter cannot be empty."); 95 uri = uri.trim(); 96 if (uri.length() == 0) 97 throw new MalformedURIException("uri parameter cannot be empty."); 98 parseURI(uri); 99 } 100 101 109 public URI(URI base, String uri) throws MalformedURIException { 110 if (uri == null || uri.trim().length() == 0) { 111 if (base != null) { 112 copy(base); 113 return; 114 } else { 115 throw new MalformedURIException("base and uri parameters cannot be both empty."); 116 } 117 } 118 parseURI(uri); 119 if (base != null) 120 resolve(base); 121 } 122 123 128 public URI(URI orig) { 129 copy(orig); 130 } 131 132 137 private void copy(URI orig) { 138 scheme = orig.getScheme(); 139 authority = orig.getAuthority(); 140 path = orig.getPath(); 141 query = orig.getQuery(); 142 fragment = orig.getFragment(); 143 } 144 145 153 private void parseURI(String uri) throws MalformedURIException { 154 int len = uri.length(); 155 int index = 0; 156 int colonIndex = uri.indexOf(':', index); 157 int slashIndex = uri.indexOf('/', index); 158 if (colonIndex != -1 && (slashIndex == -1 || colonIndex < slashIndex)) { 159 index = parseScheme(uri); 162 if (index < len && uri.charAt(index) != '/') { 163 index = parseOpaque(uri, index); 165 } else { 166 if (index + 1 < len && uri.charAt(index + 1) == '/') { 168 index = parseAuthority(uri, index + 2); 170 } 171 index = parseAbsolutePath(uri, index); 173 index = parseQuery(uri, index); 175 } 176 } else { 177 if (index < len && uri.charAt(index) != '/') { 179 index = parseRelativeSegment(uri, index); 181 } else if (index + 1 < len && uri.charAt(index + 1) == '/') { 182 index = parseAuthority(uri, index + 2); 184 } 185 index = parseAbsolutePath(uri, index); 187 index = parseQuery(uri, index); 189 } 190 index = parseFragment(uri, index); 191 } 192 193 202 private int parseScheme(String uri) throws MalformedURIException { 203 int len = uri.length(); 204 int index = 0; 205 if (index >= len) 206 throw new MalformedURIException("Scheme cannot be empty in: " + uri + "."); 207 if (!isAlpha(uri.charAt(0))) 208 throw new MalformedURIException("Illegal character in scheme part of " + uri + " at position 0."); 209 index++; 210 while (index < len) { 211 char schemeChar = uri.charAt(index); 212 if (":".indexOf(schemeChar) != -1) 213 break; 214 if (!isAlphanum(schemeChar) && SCHEME_CHARACTERS.indexOf(schemeChar) == -1) 215 throw new MalformedURIException( 216 "Illegal character in scheme part of " + uri + " at position " + index + "."); 217 index++; 218 } 219 scheme = uri.substring(0, index).toLowerCase(); 220 return index + 1; 221 } 222 223 235 private int parseAuthority(String uri, int start) throws MalformedURIException { 236 int len = uri.length(); 237 if (start >= len) 238 return start; 239 StringBuffer buffer = new StringBuffer (len-start); 240 int result = processURIPart(uri, start, "/?#", buffer); 241 authority = buffer.toString(); 242 return result; 243 } 244 245 256 private int parseOpaque(String uri, int start) throws MalformedURIException { 257 int len = uri.length(); 258 StringBuffer buffer = new StringBuffer (len-start); 259 int result = processURIPart(uri, start, "#", buffer); 260 path = buffer.toString(); 261 return result; 262 } 263 264 274 private int parseAbsolutePath(String uri, int start) throws MalformedURIException { 275 int len = uri.length(); 276 if (start >= len) { 277 return start; 278 } 279 StringBuffer buffer = new StringBuffer (len-start); 280 int result = processURIPart(uri, start, "?#", buffer); 281 path += buffer.toString(); 282 return result; 283 } 284 285 295 private int parseRelativeSegment(String uri, int start) throws MalformedURIException { 296 int len = uri.length(); 297 if (start >= len) 298 throw new MalformedURIException("Relative path cannot be empty in: " + uri + "."); 299 StringBuffer buffer = new StringBuffer (len-start); 300 int result = processURIPart(uri, start, "/?#", buffer); 301 path = buffer.toString(); 302 return result; 303 } 304 305 315 private int parseQuery(String uri, int start) throws MalformedURIException { 316 int len = uri.length(); 317 if (start >= len) 318 return start; 319 if (uri.charAt(start) != '?') 320 return start; 321 StringBuffer buffer = new StringBuffer (len-start-1); 322 int result = processURIPart(uri, start+1, "#", buffer); 323 query = buffer.toString(); 324 return result; 325 } 326 327 337 private int parseFragment(String uri, int start) throws MalformedURIException { 338 int len = uri.length(); 339 if (start >= len) 340 return start; 341 if (uri.charAt(start) != '#') 342 return start; 343 StringBuffer buffer = new StringBuffer (len-start-1); 344 int result = processURIPart(uri, start+1, "", buffer); 345 query = buffer.toString(); 346 return result; 347 } 348 349 357 private int processURIPart(String uri, int start, String stopChars, StringBuffer result) throws MalformedURIException { 358 int len = uri.length(); 359 int index = start; 360 if (index >= len) 361 return index; 362 while (index < len) { 363 char c = uri.charAt(index); 364 if (stopChars.indexOf(c) != -1) 365 break; 366 if (!isUnreservedCharacter(c) && !isReservedCharacter(c)) { 367 if (c == '%' && index + 2 < len && isHex(uri.charAt(index + 1)) && isHex(uri.charAt(index + 2))) { 368 result.append((char)Integer.parseInt(uri.substring(index+1, index+3), 16)); 369 index += 3; 370 } else { 371 throw new MalformedURIException("Illegal character in " + uri + " at position " + index + "."); 372 } 373 } else { 374 result.append(c); 375 index++; 376 } 377 } 378 return index; 379 } 380 381 386 private void escapePart(String part, StringBuffer result) { 387 for (int i = 0; i < part.length(); i++) { 388 char c = part.charAt(i); 389 if (!isUnreservedCharacter(c) && !isReservedCharacter(c)) { 390 result.append('%'); 391 result.append(Integer.toHexString((int)c)); 392 } else { 393 result.append(c); 394 } 395 } 396 } 397 398 403 private void resolve(URI base) throws MalformedURIException { 404 if (!base.isHierarchical()) 405 throw new MalformedURIException("Cannot resolve a relative URI to a non-hierarchical base"); 406 if (base.isRelative()) 407 throw new MalformedURIException("Cannot resolve a relative URI to a relative base"); 408 if (scheme != null) 409 return; 410 setScheme(base.getScheme()); 411 if (authority != null) 412 return; 413 setAuthority(base.getAuthority()); 414 if (path.length() == 0) { 415 setPath(base.getPath()); 416 } else if (path.charAt(0) == '/') { 417 return; 418 } else { 419 StringBuffer absPath = new StringBuffer (base.getPath()); 420 int lastSlash = base.getPath().lastIndexOf('/'); 421 if (lastSlash != -1) { 422 absPath.setLength(lastSlash + 1); 423 } 424 absPath.append(path); 425 String rawPath = absPath.toString(); 426 int index = -1; 427 int delta = 0; 428 while ((index = rawPath.indexOf("/./", index + 1)) != -1) { 429 absPath.delete(index + 1 - delta, index + 3 - delta); 430 delta += 2; 431 } 432 if (rawPath.endsWith("/.")) { 433 absPath.setLength(absPath.length() - 1); 434 delta += 1; 435 } 436 if (delta > 0) { 437 rawPath = absPath.toString(); 438 } 439 while ((index = rawPath.indexOf("/../")) > 0) { 440 int prevIndex = rawPath.lastIndexOf('/', index - 1); 441 if (prevIndex != -1) { 442 rawPath = rawPath.substring(0, prevIndex+1).concat(rawPath.substring(index+4)); 443 } 444 } 445 if (rawPath.endsWith("/..")) { 446 int prevIndex = rawPath.lastIndexOf('/', rawPath.length() - 4); 447 if (prevIndex != -1 && !"..".equals(rawPath.substring(prevIndex + 1, prevIndex + 3))) { 448 rawPath = rawPath.substring(0, prevIndex+1); 449 } 450 } 451 path = rawPath; 452 } 453 } 454 455 460 public String getScheme() { 461 return scheme; 462 } 463 464 469 public String getAuthority() { 470 return authority; 471 } 472 473 479 public String getPath() { 480 return path; 481 } 482 483 490 public String getQuery() { 491 return query; 492 } 493 494 501 public String getFragment() { 502 return fragment; 503 } 504 505 510 private void setScheme(String scheme) { 511 this.scheme = scheme; 512 } 513 514 519 private void setAuthority(String auth) { 520 this.authority = auth; 521 } 522 523 528 private void setPath(String path) { 529 this.path = path; 530 } 531 532 538 public void setQuery(String query) { 539 this.query = query; 540 } 541 542 548 public void setFragment(String fragment) throws MalformedURIException { 549 this.fragment = fragment; 550 } 551 552 560 public boolean equals(Object obj) { 561 if (this == obj) return true; 562 if (obj instanceof URI) { 563 URI testURI = (URI) obj; 564 if (((scheme == null && testURI.scheme == null) 565 || (scheme != null && testURI.scheme != null && scheme.equals(testURI.scheme))) 566 && ((authority == null && testURI.authority == null) 567 || (authority != null && testURI.authority != null && authority.equals(testURI.authority))) 568 && ((path == null && testURI.path == null) 569 || (path != null && testURI.path != null && path.equals(testURI.path))) 570 && ((query == null && testURI.query == null) 571 || (query != null && testURI.query != null && query.equals(testURI.query))) 572 && ((fragment == null && testURI.fragment == null) 573 || (fragment != null && testURI.fragment != null && fragment.equals(testURI.fragment)))) { 574 return true; 575 } 576 } 577 return false; 578 } 579 580 585 public int hashCode() { 586 return (scheme == null ? 0 : scheme.hashCode()) 587 ^ (authority == null ? 0 : authority.hashCode()) 588 ^ (path == null ? 0 : path.hashCode()) 589 ^ (query == null ? 0 : query.hashCode()) 590 ^ (fragment == null ? 0 : fragment.hashCode()); 591 } 592 593 598 public String toString() { 599 StringBuffer uriSpecString = new StringBuffer (); 600 if (scheme != null) { 601 uriSpecString.append(scheme); 602 uriSpecString.append(':'); 603 } 604 if (authority != null) { 605 uriSpecString.append("//"); 606 escapePart(authority, uriSpecString); 607 } 608 escapePart(path, uriSpecString); 609 if (query != null) { 610 uriSpecString.append('?'); 611 escapePart(query, uriSpecString); 612 } 613 if (fragment != null) { 614 uriSpecString.append('#'); 615 escapePart(fragment, uriSpecString); 616 } 617 return uriSpecString.toString(); 618 } 619 620 625 public int getLength() { 626 int len = 0; 627 if (scheme != null) { 628 len += scheme.length()+1; 629 } 630 if (authority != null) { 631 len += authority.length()+2; 632 } 633 len += path.length(); 634 if (query != null) { 635 len += query.length()+1; 636 } 637 if (fragment != null) { 638 len += fragment.length()+1; 639 } 640 return len; 641 } 642 643 648 public boolean isHierarchical() { 649 return (scheme == null || path.charAt(0) == '/'); 650 } 651 652 657 public boolean isRelative() { 658 return (scheme == null); 659 } 660 661 666 private static boolean isDigit(char p_char) { 667 return p_char >= '0' && p_char <= '9'; 668 } 669 670 676 private static boolean isHex(char p_char) { 677 return (isDigit(p_char) || (p_char >= 'a' && p_char <= 'f') || (p_char >= 'A' && p_char <= 'F')); 678 } 679 680 685 private static boolean isAlpha(char p_char) { 686 return ((p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z')); 687 } 688 689 694 private static boolean isAlphanum(char p_char) { 695 return (isAlpha(p_char) || isDigit(p_char)); 696 } 697 698 704 private static boolean isReservedCharacter(char p_char) { 705 return RESERVED_CHARACTERS.indexOf(p_char) != -1; 706 } 707 708 713 private static boolean isUnreservedCharacter(char p_char) { 714 return (isAlphanum(p_char) || MARK_CHARACTERS.indexOf(p_char) != -1); 715 } 716 717 } 718 | Popular Tags |