1 /* 2 * Copyright (c) 2004, 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 26 package sun.jvmstat.monitor; 27 28 import java.net.*; 29 30 /** 31 * An abstraction that identifies a target Java Virtual Machine. 32 * The VmIdentifier, or vmid, provides a convenient string representation 33 * of the information needed to locate and communicate with a target 34 * Java Virtual Machine. The string, based on a {@link URI}, may specify 35 * the communications protocol, host name, local vm identifier, and protocol 36 * specific information for a target Java Virtual Machine. The format for 37 * a VmIdentifier string is: 38 * <pre> 39 * [<I>protocol</I>:][<I>//</I>]<I><B>lvmid</B></I>[<I>@hostname</I>][<I>:port</I>][<I>/servername</I>] 40 * </pre> 41 * The only required component of this string is the Local Virtual Machine 42 * Identifier, or {@code lvmid}, which uniquely identifies the target 43 * Java Virtual Machine on a host. The optional components of the VmIdentifier 44 * include: 45 * <ul> 46 * <li>{@code protocol} - The communications protocol. A VmIdentifier 47 * omitting the protocol must be resolved against a HostIdentifier 48 * using {@link HostIdentifier#resolve}. 49 * </li> 50 * <li>{@code hostname} - A hostname or IP address indicating the target 51 * host. A VmIdentifier omitting the protocol must be resolved 52 * against a HostIdentifier using {@link HostIdentifier#resolve}. 53 * </li> 54 * <li>{@code port} - The port for the communications protocol. 55 * Treatment of the {@code port} parameter is implementation 56 * (protocol) specific. A VmIdentifier omitting the protocol should 57 * be resolved against a HostIdentifier using 58 * {@link HostIdentifier#resolve}. 59 * </li> 60 * <li>{@code servername} - The treatment of the Path, Query, and 61 * Fragment components of the VmIdentifier are implementation 62 * (protocol) dependent. A VmIdentifier omitting the protocol should 63 * be resolved against a HostIdentifier using 64 * {@link HostIdentifier#resolve}. 65 * </li> 66 * </ul> 67 * <p> 68 * All VmIdentifier instances are constructed as absolute, hierarchical URIs. 69 * The constructors will accept relative (and even some malformed, 70 * though convenient) URI strings. Such strings are transformed into 71 * legitimate, absolute URI strings. 72 * <p> 73 * With the exception of <em>file:</em> based VmIdentifier strings, all 74 * VmIdentifier strings must include a {@code lvmid}. Attempting to construct 75 * a non-file based VmIdentifier that doesn't include a {@code lvmid} 76 * component will result in a {@code MonitorException}. 77 * <p> 78 * Here are some examples of VmIdentifier strings. 79 * <ul> 80 * <li>Relative URIs 81 * <ul> 82 * <li><em>1234</em> - Specifies the Java Virtual Machine 83 * identified by lvmid <em>1234</em> on an unnamed host. 84 * This string is transformed into the absolute form 85 * <em>//1234</em>, which must be resolved against a 86 * HostIdentifier. 87 * </li> 88 * <li><em>1234@hostname</em> - Specifies the Java Virtual 89 * Machine identified by lvmid <em>1234</em> on host 90 * <em>hostname</em> with an unnamed protocol. 91 * This string is transformed into the absolute form 92 * <em>//1234@hostname</em>, which must be resolved against 93 * a HostIdentifier. 94 * </li> 95 * <li><em>1234@hostname:2099</em> - Specifies the Java Virtual 96 * Machine identified by lvmid <em>1234</em> on host 97 * <em>hostname</em> with an unnamed protocol, but with 98 * port <em>2099</em>. This string is transformed into 99 * the absolute form <em>//1234@hostname:2099</em>, which 100 * must be resolved against a HostIdentifier. 101 * </li> 102 * </ul> 103 * </li> 104 * <li>Absolute URIs 105 * <ul> 106 * <li><em>rmi://1234@hostname:2099/remoteobjectname</em> - 107 * Specifies the Java Virtual Machine identified by lvmid 108 * <em>1234</em> on host <em>hostname</em> accessed 109 * using the <em>rmi:</em> protocol through the rmi remote 110 * object named <em>remoteobjectname</em> as registered with 111 * the <em>rmiserver</em> on port <em>2099</em> on host 112 * <em>hostname</em>. 113 * </li> 114 * <li><em>file:/path/file</em> - Identifies a Java Virtual Machine 115 * through accessing a special file based protocol to use as 116 * the communications mechanism. 117 * </li> 118 * </ul> 119 * </li> 120 * </ul> 121 * 122 * @see URI 123 * @see HostIdentifier 124 * @author Brian Doherty 125 * @since 1.5 126 */ 127 public class VmIdentifier { 128 private URI uri; 129 130 /** 131 * creates a canonical representation of the uriString. This method 132 * performs certain translations depending on the type of URI generated 133 * by the string. 134 */ 135 private URI canonicalize(String uriString) throws URISyntaxException { 136 if (uriString == null) { 137 uriString = "local://0@localhost"; 138 return new URI(uriString); 139 } 140 141 URI u = new URI(uriString); 142 143 if (u.isAbsolute()) { 144 if (u.isOpaque()) { 145 /* 146 * rmi:1234@hostname/path#fragment converted to 147 * rmi://1234@hostname/path#fragment 148 */ 149 u = new URI(u.getScheme(), "//" + u.getSchemeSpecificPart(), 150 u.getFragment()); 151 } 152 } else { 153 /* 154 * make the uri absolute, if possible. A relative URI doesn't 155 * specify the scheme part, so it's safe to prepend a "//" and 156 * try again. 157 */ 158 if (!uriString.startsWith("//")) { 159 if (u.getFragment() == null) { 160 u = new URI("//" + u.getSchemeSpecificPart()); 161 } else { 162 u = new URI("//" + u.getSchemeSpecificPart() + "#" 163 + u.getFragment()); 164 } 165 } 166 } 167 return u; 168 } 169 170 /** 171 * check that the VmIdentifier includes a unique numerical identifier 172 * for the target JVM. 173 */ 174 private void validate() throws URISyntaxException { 175 // file:// uri, which is a special case where the lvmid is not required. 176 String s = getScheme(); 177 if ((s != null) && (s.compareTo("file") == 0)) { 178 return; 179 } 180 if (getLocalVmId() == -1) { 181 throw new URISyntaxException(uri.toString(), "Local vmid required"); 182 } 183 } 184 185 /** 186 * Create a VmIdentifier instance from a string value. 187 * 188 * @param uriString a string representing a target Java Virtual Machine. 189 * The syntax of the string must conforms to the rules 190 * specified in the class documentation. 191 * @throws URISyntaxException Thrown when the uriString or its canonical 192 * form is poorly formed. 193 */ 194 public VmIdentifier(String uriString) throws URISyntaxException { 195 URI u; 196 try { 197 u = canonicalize(uriString); 198 } catch (URISyntaxException e) { 199 /* 200 * a vmid of the form 1234@hostname:1098 causes an exception, 201 * so try again with a leading "//" 202 */ 203 if (uriString.startsWith("//")) { 204 throw e; 205 } 206 u = canonicalize("//"+uriString); 207 } 208 209 uri = u; 210 211 // verify that we have a valid lvmid 212 validate(); 213 } 214 215 /** 216 * Create a VmIdentifier instance from a URI object. 217 * 218 * @param uri a well formed, absolute URI indicating the 219 * target Java Virtual Machine. 220 * @throws URISyntaxException Thrown if the URI is missing some 221 * required component. 222 */ 223 public VmIdentifier(URI uri) throws URISyntaxException { 224 this.uri = uri; 225 validate(); 226 } 227 228 /** 229 * Return the corresponding HostIdentifier for this VmIdentifier. 230 * <p> 231 * This method constructs a HostIdentifier object from the VmIdentifier. 232 * If the VmIdentifier is not specific about the protocol or other 233 * components of the URI, then the resulting HostIdentifier will 234 * be constructed based on this missing information. Typically, the 235 * missing components will have result in the HostIdentifier assigning 236 * assumed defaults that allow the VmIdentifier to be resolved according 237 * to those defaults. 238 * <p> 239 * For example, a VmIdentifier that specifies only a {@code lvmid} 240 * will result in a HostIdentifier for <em>localhost</em> utilizing 241 * the default local protocol, <em>local:</em>. A VmIdentifier that 242 * specifies both a {@code vmid} and a {@code hostname} will result 243 * in a HostIdentifier for the specified host with the default remote 244 * protocol, <em>rmi:</em>, using the protocol defaults for the 245 * {@code port} and {@code servername} components. 246 * 247 * @return HostIdentifier - the host identifier for the host containing 248 * the Java Virtual Machine represented by this 249 * VmIdentifier. 250 * @throws URISyntaxException Thrown if a bad host URI is constructed. 251 * This exception may get encapsulated into 252 * a MonitorException in a future version. 253 */ 254 public HostIdentifier getHostIdentifier() throws URISyntaxException { 255 StringBuilder sb = new StringBuilder(); 256 if (getScheme() != null) { 257 sb.append(getScheme()).append(":"); 258 } 259 sb.append("//").append(getHost()); 260 if (getPort() != -1) { 261 sb.append(":").append(getPort()); 262 } 263 if (getPath() != null) { 264 sb.append(getPath()); 265 } 266 return new HostIdentifier(sb.toString()); 267 } 268 269 /** 270 * Return the Scheme, or protocol, portion of this VmIdentifier. 271 * 272 * @return String - the scheme for this VmIdentifier. 273 * @see URI#getScheme() 274 */ 275 public String getScheme() { 276 return uri.getScheme(); 277 } 278 279 /** 280 * Return the Scheme Specific Part of this VmIdentifier. 281 * 282 * @return String - the Scheme Specific Part for this VmIdentifier. 283 * @see URI#getSchemeSpecificPart() 284 */ 285 public String getSchemeSpecificPart() { 286 return uri.getSchemeSpecificPart(); 287 } 288 289 /** 290 * Return the UserInfo part of this VmIdentifier. 291 * 292 * @return String - the UserInfo part for this VmIdentifier. 293 * @see URI#getUserInfo() 294 */ 295 public String getUserInfo() { 296 return uri.getUserInfo(); 297 } 298 299 /** 300 * Return the Host part of this VmIdentifier. 301 * 302 * @return String - the Host part for this VmIdentifier. 303 * @see URI#getHost() 304 */ 305 public String getHost() { 306 return uri.getHost(); 307 } 308 309 /** 310 * Return the Port part of this VmIdentifier. 311 * 312 * @return int - the Port part for this VmIdentifier. 313 * @see URI#getPort() 314 */ 315 public int getPort() { 316 return uri.getPort(); 317 } 318 319 /** 320 * Return the Authority part of this VmIdentifier. 321 * 322 * @return String - the Authority part for this VmIdentifier. 323 * @see URI#getAuthority() 324 */ 325 public String getAuthority() { 326 return uri.getAuthority(); 327 } 328 329 /** 330 * Return the Path part of this VmIdentifier. 331 * 332 * @return String - the Path part for this VmIdentifier. 333 * @see URI#getPath() 334 */ 335 public String getPath() { 336 return uri.getPath(); 337 } 338 339 /** 340 * Return the Query part of this VmIdentifier. 341 * 342 * @return String - the Query part for this VmIdentifier. 343 * @see URI#getQuery() 344 */ 345 public String getQuery() { 346 return uri.getQuery(); 347 } 348 349 /** 350 * Return the Fragment part of this VmIdentifier. 351 * 352 * @return String - the Fragment part for this VmIdentifier. 353 * @see URI#getFragment() 354 */ 355 public String getFragment() { 356 return uri.getFragment(); 357 } 358 359 /** 360 * Return the Local Virtual Machine Identifier for this VmIdentifier. 361 * The Local Virtual Machine Identifier is also known as the 362 * <em>lvmid</em>. 363 * 364 * @return int - the lvmid for this VmIdentifier. 365 */ 366 public int getLocalVmId() { 367 int result = -1; 368 try { 369 if (uri.getUserInfo() == null) { 370 result = Integer.parseInt(uri.getAuthority()); 371 } else { 372 result = Integer.parseInt(uri.getUserInfo()); 373 } 374 } catch (NumberFormatException e) { } 375 return result; 376 } 377 378 /** 379 * Return the mode indicated in this VmIdentifier. 380 * 381 * @return String - the mode string. If no mode is specified, then "r" 382 * is returned. otherwise, the specified mode is returned. 383 */ 384 public String getMode() { 385 String query = getQuery(); 386 if (query != null) { 387 String[] queryArgs = query.split("\\+"); 388 for (int i = 0; i < queryArgs.length; i++) { 389 if (queryArgs[i].startsWith("mode=")) { 390 int index = queryArgs[i].indexOf('='); 391 return queryArgs[i].substring(index+1); 392 } 393 } 394 } 395 return "r"; 396 } 397 398 /** 399 * Return the URI associated with the VmIdentifier. 400 * 401 * @return URI - the URI. 402 * @see URI 403 */ 404 public URI getURI() { 405 return uri; 406 } 407 408 /** 409 * Return the hash code for this VmIdentifier. The hash code is 410 * identical to the hash code for the contained URI. 411 * 412 * @return int - the hashcode. 413 * @see URI#hashCode() 414 */ 415 public int hashCode() { 416 return uri.hashCode(); 417 } 418 419 /** 420 * Test for quality with other objects. 421 * 422 * @param object the object to be test for equality. 423 * @return boolean - returns true if the given object is of type 424 * VmIdentifier and its URI field is equal to 425 * this object's URI field. Otherwise, return false. 426 * 427 * @see URI#equals(Object) 428 */ 429 public boolean equals(Object object) { 430 if (object == this) { 431 return true; 432 } 433 if (!(object instanceof VmIdentifier)) { 434 return false; 435 } 436 return uri.equals(((VmIdentifier)object).uri); 437 } 438 439 /** 440 * Convert to a string representation. Conversion is identical to 441 * calling getURI().toString(). This may change in a future release. 442 * 443 * @return String - a String representation of the VmIdentifier. 444 * 445 * @see URI#toString() 446 */ 447 public String toString() { 448 return uri.toString(); 449 } 450 }