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 26package sun.jvmstat.monitor; 27 28import java.net.URISyntaxException; 29import java.util.HashMap; 30import java.util.Map; 31import java.util.ServiceLoader; 32import java.util.Set; 33 34import sun.jvmstat.monitor.event.HostListener; 35 36/** 37 * An abstraction for a host that contains instrumented Java Virtual 38 * Machines. The class provides abstract factory methods for creating 39 * concrete instances of this class and factory methods for creating 40 * {@link MonitoredVm} instances. Concrete implementations of this class 41 * provide methods for managing the communications protocols and provide 42 * for event notification. 43 * 44 * @author Brian Doherty 45 * @since 1.5 46 * 47 * @see HostIdentifier 48 * @see VmIdentifier 49 * @see MonitoredVm 50 * @see HostListener 51 */ 52public abstract class MonitoredHost { 53 private static Map<HostIdentifier, MonitoredHost> monitoredHosts = 54 new HashMap<HostIdentifier, MonitoredHost>(); 55 56 /* 57 * The default optimized local protocol override mechanism. The value 58 * of this property is used to construct the default package name 59 * for the default optimized local protocol as follows: 60 * <IMPL_PACKAGE>.monitor.<LOCAL_PROTOCOL> 61 * This property is not expected to be set under normal circumstances. 62 */ 63 private static final String LOCAL_PROTOCOL_PROP_NAME = 64 "sun.jvmstat.monitor.local"; 65 private static final String LOCAL_PROTOCOL = 66 System.getProperty(LOCAL_PROTOCOL_PROP_NAME, "local"); 67 68 /* 69 * The default remote protocol override mechanism. The value of 70 * this property is used to construct the default package name 71 * for the default remote protocol protocol as follows: 72 * <IMPL_PACKAGE>.monitor.protocol.<REMOTE_PROTOCOL> 73 * This property is not expected to be set under normal circumstances. 74 */ 75 private static final String REMOTE_PROTOCOL_PROP_NAME = 76 "sun.jvmstat.monitor.remote"; 77 private static final String REMOTE_PROTOCOL = 78 System.getProperty(REMOTE_PROTOCOL_PROP_NAME, "rmi"); 79 80 /** 81 * The HostIdentifier for this MonitoredHost instance. 82 */ 83 protected HostIdentifier hostId; 84 85 /** 86 * The polling interval, in milliseconds, for this MonitoredHost instance. 87 */ 88 protected int interval; 89 90 /** 91 * The last Exception encountered while polling this MonitoredHost. 92 */ 93 protected Exception lastException; 94 95 /** 96 * Factory method to construct MonitoredHost instances to manage 97 * connections to the host indicated by {@code hostIdString} 98 * 99 * @param hostIdString a String representation of a {@link HostIdentifier} 100 * @return MonitoredHost - the MonitoredHost instance for communicating 101 * with the indicated host using the protocol 102 * specified in hostIdString. 103 * @throws MonitorException Thrown if monitoring errors occur. 104 * @throws URISyntaxException Thrown when the hostIdString is poorly 105 * formed. This exception may get encapsulated 106 * into MonitorException in a future revision. 107 */ 108 public static MonitoredHost getMonitoredHost(String hostIdString) 109 throws MonitorException, URISyntaxException { 110 HostIdentifier hostId = new HostIdentifier(hostIdString); 111 return getMonitoredHost(hostId); 112 } 113 114 /** 115 * Factory method to construct a MonitoredHost instance to manage the 116 * connection to the Java Virtual Machine indicated by {@code vmid}. 117 * 118 * This method provide a convenient short cut for attaching to a specific 119 * instrumented Java Virtual Machine. The information in the VmIdentifier 120 * is used to construct a corresponding HostIdentifier, which in turn is 121 * used to create the MonitoredHost instance. 122 * 123 * @param vmid The identifier for the target Java Virtual Machine. 124 * @return MonitoredHost - The MonitoredHost object needed to attach to 125 * the target Java Virtual Machine. 126 * 127 * @throws MonitorException Thrown if monitoring errors occur. 128 */ 129 public static MonitoredHost getMonitoredHost(VmIdentifier vmid) 130 throws MonitorException { 131 // use the VmIdentifier to construct the corresponding HostIdentifier 132 HostIdentifier hostId = new HostIdentifier(vmid); 133 return getMonitoredHost(hostId); 134 } 135 136 137 /* 138 * Load the MonitoredHostServices 139 */ 140 private static ServiceLoader<MonitoredHostService> monitoredHostServiceLoader = 141 ServiceLoader.load(MonitoredHostService.class, MonitoredHostService.class.getClassLoader()); 142 143 /** 144 * Factory method to construct a MonitoredHost instance to manage the 145 * connection to the host indicated by {@code hostId}. 146 * 147 * @param hostId the identifier for the target host. 148 * @return MonitoredHost - The MonitoredHost object needed to attach to 149 * the target host. 150 * 151 * @throws MonitorException Thrown if monitoring errors occur. 152 */ 153 public static MonitoredHost getMonitoredHost(HostIdentifier hostId) 154 throws MonitorException { 155 MonitoredHost mh = null; 156 157 synchronized(monitoredHosts) { 158 mh = monitoredHosts.get(hostId); 159 if (mh != null) { 160 if (mh.isErrored()) { 161 monitoredHosts.remove(hostId); 162 } else { 163 return mh; 164 } 165 } 166 } 167 168 hostId = resolveHostId(hostId); 169 170 for (MonitoredHostService mhs : monitoredHostServiceLoader) { 171 if (mhs.getScheme().equals(hostId.getScheme())) { 172 mh = mhs.getMonitoredHost(hostId); 173 } 174 } 175 176 if (mh == null) { 177 throw new IllegalArgumentException("Could not find MonitoredHost for scheme: " + hostId.getScheme()); 178 } 179 180 synchronized(monitoredHosts) { 181 monitoredHosts.put(mh.hostId, mh); 182 } 183 184 return mh; 185 } 186 187 /** 188 * Method to resolve unspecified components of the given HostIdentifier 189 * by constructing a new HostIdentifier that replaces the unspecified 190 * components with the default values. 191 * 192 * @param hostId the unresolved HostIdentifier. 193 * @return HostIdentifier - a resolved HostIdentifier. 194 * 195 * @throws MonitorException Thrown if monitoring errors occur. 196 */ 197 protected static HostIdentifier resolveHostId(HostIdentifier hostId) 198 throws MonitorException { 199 String hostname = hostId.getHost(); 200 String scheme = hostId.getScheme(); 201 StringBuilder sb = new StringBuilder(); 202 203 assert hostname != null; 204 205 if (scheme == null) { 206 if (hostname.compareTo("localhost") == 0) { 207 scheme = LOCAL_PROTOCOL; 208 } else { 209 scheme = REMOTE_PROTOCOL; 210 } 211 } 212 213 sb.append(scheme).append(":").append(hostId.getSchemeSpecificPart()); 214 215 String frag = hostId.getFragment(); 216 if (frag != null) { 217 sb.append("#").append(frag); 218 } 219 220 try { 221 return new HostIdentifier(sb.toString()); 222 } catch (URISyntaxException e) { 223 // programming error - HostIdentifier was valid. 224 assert false; 225 throw new IllegalArgumentException("Malformed URI created: " 226 + sb.toString()); 227 } 228 } 229 230 /** 231 * Return the resolved HostIdentifier for this MonitoredHost. 232 * 233 * @return HostIdentifier - the resolved HostIdentifier. 234 */ 235 public HostIdentifier getHostIdentifier() { 236 return hostId; 237 } 238 239 /* ---- Methods to support polled MonitoredHost Implementations ----- */ 240 241 /** 242 * Set the polling interval for this MonitoredHost. 243 * 244 * @param interval the polling interval, in milliseconds 245 */ 246 public void setInterval(int interval) { 247 this.interval = interval; 248 } 249 250 /** 251 * Get the polling interval. 252 * 253 * @return int - the polling interval in milliseconds for this MonitoredHost 254 */ 255 public int getInterval() { 256 return interval; 257 } 258 259 /** 260 * Set the last exception encountered while polling this MonitoredHost. 261 * 262 * @param lastException the last exception encountered; 263 */ 264 public void setLastException(Exception lastException) { 265 this.lastException = lastException; 266 } 267 268 /** 269 * Get the last exception encountered while polling this MonitoredHost. 270 * 271 * @return Exception - the last exception occurred while polling this 272 * MonitoredHost, or {@code null} if no exception 273 * has occurred or the exception has been cleared, 274 */ 275 public Exception getLastException() { 276 return lastException; 277 } 278 279 /** 280 * Clear the last exception. 281 */ 282 public void clearLastException() { 283 lastException = null; 284 } 285 286 /** 287 * Test if this MonitoredHost is in the errored state. If this method 288 * returns true, then the Exception returned by getLastException() 289 * indicates the Exception that caused the error condition. 290 * 291 * @return boolean - true if the MonitoredHost instance has experienced 292 * an error, or false if it hasn't or if any past 293 * error has been cleared. 294 */ 295 public boolean isErrored() { 296 return lastException != null; 297 } 298 299 /** 300 * Get the MonitoredVm for the given Java Virtual Machine. The default 301 * sampling interval is used for the MonitoredVm instance. 302 * 303 * @param id the VmIdentifier specifying the target Java Virtual Machine. 304 * @return MonitoredVm - the MonitoredVm instance for the target Java 305 * Virtual Machine. 306 * @throws MonitorException Thrown if monitoring errors occur. 307 */ 308 public abstract MonitoredVm getMonitoredVm(VmIdentifier id) 309 throws MonitorException; 310 311 /** 312 * Get the MonitoredVm for the given Java Virtual Machine. The sampling 313 * interval is set to the given interval. 314 * 315 * @param id the VmIdentifier specifying the target Java Virtual Machine. 316 * @param interval the sampling interval for the target Java Virtual Machine. 317 * @return MonitoredVm - the MonitoredVm instance for the target Java 318 * Virtual Machine. 319 * @throws MonitorException Thrown if monitoring errors occur. 320 */ 321 public abstract MonitoredVm getMonitoredVm(VmIdentifier id, int interval) 322 throws MonitorException; 323 324 /** 325 * Detach from the indicated MonitoredVm. 326 * 327 * @param vm the monitored Java Virtual Machine. 328 * @throws MonitorException Thrown if monitoring errors occur. 329 */ 330 public abstract void detach(MonitoredVm vm) throws MonitorException; 331 332 /** 333 * Add a HostListener. The given listener is added to the list 334 * of HostListener objects to be notified of MonitoredHost related events. 335 * 336 * @param listener the HostListener to add. 337 * @throws MonitorException Thrown if monitoring errors occur. 338 */ 339 public abstract void addHostListener(HostListener listener) 340 throws MonitorException; 341 342 /** 343 * Remove a HostListener. The given listener is removed from the list 344 * of HostListener objects to be notified of MonitoredHost related events. 345 * 346 * @param listener the HostListener to add. 347 * @throws MonitorException Thrown if monitoring errors occur. 348 */ 349 public abstract void removeHostListener(HostListener listener) 350 throws MonitorException; 351 352 /** 353 * Return the current set of active Java Virtual Machines for this 354 * MonitoredHost. The returned Set contains {@link Integer} instances 355 * holding the local virtual machine identifier, or <em>lvmid</em> 356 * for each instrumented Java Virtual Machine currently available. 357 * 358 * @return Set - the current set of active Java Virtual Machines associated 359 * with this MonitoredHost, or the empty set of none. 360 * @throws MonitorException Thrown if monitoring errors occur. 361 */ 362 public abstract Set<Integer> activeVms() throws MonitorException; 363} 364