1 7 8 9 package javax.management.remote; 10 11 import java.io.IOException ; 12 import java.io.Serializable ; 13 import java.net.InetAddress ; 14 import java.net.MalformedURLException ; 15 import java.net.UnknownHostException ; 16 import java.util.BitSet ; 17 import java.util.StringTokenizer ; 18 19 import com.sun.jmx.remote.util.ClassLogger; 20 import com.sun.jmx.remote.util.EnvHelp; 21 22 101 public class JMXServiceURL implements Serializable { 102 103 private static final long serialVersionUID = 8173364409860779292L; 104 105 121 public JMXServiceURL(String serviceURL) throws MalformedURLException { 122 final int serviceURLLength = serviceURL.length(); 123 124 126 for (int i = 0; i < serviceURLLength; i++) { 127 char c = serviceURL.charAt(i); 128 if (c < 32 || c >= 127) { 129 throw new MalformedURLException ("Service URL contains " + 130 "non-ASCII character 0x" + 131 Integer.toHexString(c)); 132 } 133 } 134 135 final String requiredPrefix = "service:jmx:"; 137 final int requiredPrefixLength = requiredPrefix.length(); 138 if (!serviceURL.regionMatches(true, 0, requiredPrefix, 141 0, requiredPrefixLength)) { 143 throw new MalformedURLException ("Service URL must start with " + 144 requiredPrefix); 145 } 146 147 int[] ptr = new int[1]; 148 149 final int protoStart = requiredPrefixLength; 151 final int protoEnd = indexOf(serviceURL, ':', protoStart); 152 this.protocol = 153 serviceURL.substring(protoStart, protoEnd).toLowerCase(); 154 155 if (!serviceURL.regionMatches(protoEnd, "://", 0, 3)) { 156 throw new MalformedURLException ("Missing \"://\" after " + 157 "protocol name"); 158 } 159 160 final int hostStart = protoEnd + 3; 162 final int hostEnd; 163 if (hostStart < serviceURLLength 164 && serviceURL.charAt(hostStart) == '[') { 165 hostEnd = serviceURL.indexOf(']', hostStart) + 1; 166 if (hostEnd == 0) 167 throw new MalformedURLException ("Bad host name: [ without ]"); 168 this.host = serviceURL.substring(hostStart + 1, hostEnd - 1); 169 if (!isNumericIPv6Address(this.host)) { 170 throw new MalformedURLException ("Address inside [...] must " + 171 "be numeric IPv6 address"); 172 } 173 } else { 174 hostEnd = 175 indexOfFirstNotInSet(serviceURL, hostNameBitSet, hostStart); 176 this.host = serviceURL.substring(hostStart, hostEnd); 177 } 178 179 final int portEnd; 181 if (hostEnd < serviceURLLength && serviceURL.charAt(hostEnd) == ':') { 182 if (this.host.length() == 0) { 183 throw new MalformedURLException ("Cannot give port number " + 184 "without host name"); 185 } 186 final int portStart = hostEnd + 1; 187 portEnd = 188 indexOfFirstNotInSet(serviceURL, numericBitSet, portStart); 189 final String portString = serviceURL.substring(portStart, portEnd); 190 try { 191 this.port = Integer.parseInt(portString); 192 } catch (NumberFormatException e) { 193 throw new MalformedURLException ("Bad port number: \"" + 194 portString + "\": " + e); 195 } 196 } else { 197 portEnd = hostEnd; 198 this.port = 0; 199 } 200 201 final int urlPathStart = portEnd; 203 if (urlPathStart < serviceURLLength) 204 this.urlPath = serviceURL.substring(urlPathStart); 205 else 206 this.urlPath = ""; 207 208 validate(); 209 } 210 211 233 public JMXServiceURL(String protocol, String host, int port) 234 throws MalformedURLException { 235 this(protocol, host, port, null); 236 } 237 238 260 public JMXServiceURL(String protocol, String host, int port, 261 String urlPath) 262 throws MalformedURLException { 263 if (protocol == null) 264 protocol = "jmxmp"; 265 266 if (host == null) { 267 InetAddress local; 268 try { 269 local = InetAddress.getLocalHost(); 270 } catch (UnknownHostException e) { 271 throw new MalformedURLException ("Local host name unknown: " + 272 e); 273 } 274 275 host = local.getHostName(); 276 277 284 try { 285 validateHost(host); 286 } catch (MalformedURLException e) { 287 if (logger.fineOn()) { 288 logger.fine("JMXServiceURL", 289 "Replacing illegal local host name " + 290 host + " with numeric IP address " + 291 "(see RFC 1034)", e); 292 } 293 host = local.getHostAddress(); 294 296 } 297 } 298 299 if (host.startsWith("[")) { 300 if (!host.endsWith("]")) { 301 throw new MalformedURLException ("Host starts with [ but " + 302 "does not end with ]"); 303 } 304 host = host.substring(1, host.length() - 1); 305 if (!isNumericIPv6Address(host)) { 306 throw new MalformedURLException ("Address inside [...] must " + 307 "be numeric IPv6 address"); 308 } 309 if (host.startsWith("[")) 310 throw new MalformedURLException ("More than one [[...]]"); 311 } 312 313 this.protocol = protocol.toLowerCase(); 314 this.host = host; 315 this.port = port; 316 317 if (urlPath == null) 318 urlPath = ""; 319 this.urlPath = urlPath; 320 321 validate(); 322 } 323 324 private void validate() throws MalformedURLException { 325 326 328 final int protoEnd = indexOfFirstNotInSet(protocol, protocolBitSet, 0); 329 if (protoEnd == 0 || protoEnd < protocol.length() 330 || !alphaBitSet.get(protocol.charAt(0))) { 331 throw new MalformedURLException ("Missing or invalid protocol " + 332 "name: \"" + protocol + "\""); 333 } 334 335 337 validateHost(); 338 339 341 if (port < 0) 342 throw new MalformedURLException ("Bad port: " + port); 343 344 346 if (urlPath.length() > 0) { 347 if (!urlPath.startsWith("/") && !urlPath.startsWith(";")) 348 throw new MalformedURLException ("Bad URL path: " + urlPath); 349 } 350 } 351 352 private void validateHost() throws MalformedURLException { 353 if (host.length() == 0) { 354 if (port != 0) { 355 throw new MalformedURLException ("Cannot give port number " + 356 "without host name"); 357 } 358 return; 359 } 360 361 validateHost(host); 362 } 363 364 private static void validateHost(String h) 365 throws MalformedURLException { 366 367 if (isNumericIPv6Address(h)) { 368 374 try { 375 InetAddress.getByName(h); 376 } catch (Exception e) { 377 381 MalformedURLException bad = 382 new MalformedURLException ("Bad IPv6 address: " + h); 383 EnvHelp.initCause(bad, e); 384 throw bad; 385 } 386 } else { 387 407 final int hostLen = h.length(); 408 char lastc = '.'; 409 boolean sawDot = false; 410 char componentStart = 0; 411 412 loop: 413 for (int i = 0; i < hostLen; i++) { 414 char c = h.charAt(i); 415 boolean isAlphaNumeric = alphaNumericBitSet.get(c); 416 if (lastc == '.') 417 componentStart = c; 418 if (isAlphaNumeric) 419 lastc = 'a'; 420 else if (c == '-') { 421 if (lastc == '.') 422 break; lastc = '-'; 424 } else if (c == '.') { 425 sawDot = true; 426 if (lastc != 'a') 427 break; lastc = '.'; 429 } else { 430 lastc = '.'; break; 432 } 433 } 434 435 try { 436 if (lastc != 'a') 437 throw randomException; 438 if (sawDot && !alphaBitSet.get(componentStart)) { 439 446 StringTokenizer tok = new StringTokenizer (h, ".", true); 447 for (int i = 0; i < 4; i++) { 448 String ns = tok.nextToken(); 449 int n = Integer.parseInt(ns); 450 if (n < 0 || n > 255) 451 throw randomException; 452 if (i < 3 && !tok.nextToken().equals(".")) 453 throw randomException; 454 } 455 if (tok.hasMoreTokens()) 456 throw randomException; 457 } 458 } catch (Exception e) { 459 throw new MalformedURLException ("Bad host: \"" + h + "\""); 460 } 461 } 462 } 463 464 private static final Exception randomException = new Exception (); 465 466 467 472 public String getProtocol() { 473 return protocol; 474 } 475 476 492 public String getHost() { 493 return host; 494 } 495 496 502 public int getPort() { 503 return port; 504 } 505 506 514 public String getURLPath() { 515 return urlPath; 516 } 517 518 535 public String toString() { 536 538 if (toString != null) 539 return toString; 540 StringBuffer buf = new StringBuffer ("service:jmx:"); 541 buf.append(getProtocol()).append("://"); 542 final String getHost = getHost(); 543 if (isNumericIPv6Address(getHost)) 544 buf.append('[').append(getHost).append(']'); 545 else 546 buf.append(getHost); 547 final int getPort = getPort(); 548 if (getPort != 0) 549 buf.append(':').append(getPort); 550 buf.append(getURLPath()); 551 toString = buf.toString(); 552 return toString; 553 } 554 555 569 public boolean equals(Object obj) { 570 if (!(obj instanceof JMXServiceURL )) 571 return false; 572 JMXServiceURL u = (JMXServiceURL ) obj; 573 return 574 (u.getProtocol().equalsIgnoreCase(getProtocol()) && 575 u.getHost().equalsIgnoreCase(getHost()) && 576 u.getPort() == getPort() && 577 u.getURLPath().equals(getURLPath())); 578 } 579 580 public int hashCode() { 581 return toString().hashCode(); 582 } 583 584 587 private static boolean isNumericIPv6Address(String s) { 588 return (s.indexOf(':') >= 0); 590 } 591 592 private static int indexOf(String s, char c, int fromIndex) { 594 int index = s.indexOf(c, fromIndex); 595 if (index < 0) 596 return s.length(); 597 else 598 return index; 599 } 600 601 private static int indexOfFirstNotInSet(String s, BitSet set, 602 int fromIndex) { 603 final int slen = s.length(); 604 int i = fromIndex; 605 while (true) { 606 if (i >= slen) 607 break; 608 char c = s.charAt(i); 609 if (c >= 128) 610 break; if (!set.get(c)) 612 break; 613 i++; 614 } 615 return i; 616 } 617 618 private final static BitSet alphaBitSet = new BitSet (128); 619 private final static BitSet numericBitSet = new BitSet (128); 620 private final static BitSet alphaNumericBitSet = new BitSet (128); 621 private final static BitSet protocolBitSet = new BitSet (128); 622 private final static BitSet hostNameBitSet = new BitSet (128); 623 static { 624 627 628 for (char c = '0'; c <= '9'; c++) 629 numericBitSet.set(c); 630 631 for (char c = 'A'; c <= 'Z'; c++) 632 alphaBitSet.set(c); 633 for (char c = 'a'; c <= 'z'; c++) 634 alphaBitSet.set(c); 635 636 alphaNumericBitSet.or(alphaBitSet); 637 alphaNumericBitSet.or(numericBitSet); 638 639 protocolBitSet.or(alphaNumericBitSet); 640 protocolBitSet.set('+'); 641 protocolBitSet.set('-'); 642 643 hostNameBitSet.or(alphaNumericBitSet); 644 hostNameBitSet.set('-'); 645 hostNameBitSet.set('.'); 646 } 647 648 private static void addCharsToBitSet(BitSet set, String chars) { 649 for (int i = 0; i < chars.length(); i++) 650 set.set(chars.charAt(i)); 651 } 652 653 656 private final String protocol; 657 658 661 private final String host; 662 663 666 private final int port; 667 668 671 private final String urlPath; 672 673 676 private transient String toString; 677 678 private static final ClassLogger logger = 679 new ClassLogger("javax.management.remote.misc", "JMXServiceURL"); 680 } 681 | Popular Tags |