/* * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.jvmstat.monitor; import java.util.*; import java.net.*; import java.lang.reflect.*; import sun.jvmstat.monitor.event.HostListener; /** * An abstraction for a host that contains instrumented Java Virtual * Machines. The class provides abstract factory methods for creating * concrete instances of this class and factory methods for creating * {@link MonitoredVm} instances. Concrete implementations of this class * provide methods for managing the communications protocols and provide * for event notification. * * @author Brian Doherty * @since 1.5 * * @see HostIdentifier * @see VmIdentifier * @see MonitoredVm * @see HostListener */ public abstract class MonitoredHost { private static Map<HostIdentifier, MonitoredHost> monitoredHosts = new HashMap<HostIdentifier, MonitoredHost>(); /* * The monitoring implementation override mechanism. The value of * this property is used as the class name for the concrete MonitoredHost * subclass that implements the monitoring APIs. Setting this property * will cause the remaining override mechanisms to be ignored. When * this mechanism is used, the HostIdentifier scheme name, which * indicates the communications protocol, is not used to locate a * the protocol specific package. However, the HostIdentifier is * still passed to the corresponding single arg constructor. * This property is not expected to be set in normal circumstances. */ private static final String IMPL_OVERRIDE_PROP_NAME = "sun.jvmstat.monitor.MonitoredHost"; /* * The monitoring package name override mechanism. The value * the this property is used as base package name for the * monitoring implementation package. This property is not * expected to be set under normal circumstances. */ private static final String IMPL_PKG_PROP_NAME = "sun.jvmstat.monitor.package"; private static final String IMPL_PACKAGE = System.getProperty(IMPL_PKG_PROP_NAME, "sun.jvmstat.perfdata"); /* * The default optimized local protocol override mechanism. The value * of this property is used to construct the default package name * for the default optimized local protocol as follows: * <IMPL_PACKAGE>.monitor.<LOCAL_PROTOCOL> * This property is not expected to be set under normal circumstances. */ private static final String LOCAL_PROTOCOL_PROP_NAME = "sun.jvmstat.monitor.local"; private static final String LOCAL_PROTOCOL = System.getProperty(LOCAL_PROTOCOL_PROP_NAME, "local"); /* * The default remote protocol override mechanism. The value of * this property is used to construct the default package name * for the default remote protocol protocol as follows: * <IMPL_PACKAGE>.monitor.protocol.<REMOTE_PROTOCOL> * This property is not expected to be set under normal circumstances. */ private static final String REMOTE_PROTOCOL_PROP_NAME = "sun.jvmstat.monitor.remote"; private static final String REMOTE_PROTOCOL = System.getProperty(REMOTE_PROTOCOL_PROP_NAME, "rmi"); /* * The default class name of the MonitoredHost implementation subclass. * There is no override mechanism for this variable, other than the * IMPL_OVERRIDE_PROP_NAME override, which is larger in scope. A concrete * instance of this class is expected to be found in: * <IMPL_PACKAGE>.monitor.protocol.<protocol>.<MONITORED_HOST_CLASS> */ private static final String MONITORED_HOST_CLASS = "MonitoredHostProvider"; /** * The HostIdentifier for this MonitoredHost instance. */ protected HostIdentifier hostId; /** * The polling interval, in milliseconds, for this MonitoredHost instance. */ protected int interval; /** * The last Exception encountered while polling this MonitoredHost. */ protected Exception lastException; /** * Factory method to construct MonitoredHost instances to manage * connections to the host indicated by <tt>hostIdString</tt> * * @param hostIdString a String representation of a {@link HostIdentifier} * @return MonitoredHost - the MonitoredHost instance for communicating * with the indicated host using the protocol * specified in hostIdString. * @throws MonitorException Thrown if monitoring errors occur. * @throws URISyntaxException Thrown when the hostIdString is poorly * formed. This exception may get encapsulated * into MonitorException in a future revision. */ public static MonitoredHost getMonitoredHost(String hostIdString) throws MonitorException, URISyntaxException { HostIdentifier hostId = new HostIdentifier(hostIdString); return getMonitoredHost(hostId); } /** * Factory method to construct a MonitoredHost instance to manage the * connection to the Java Virtual Machine indicated by <tt>vmid</tt>. * * This method provide a convenient short cut for attaching to a specific * instrumented Java Virtual Machine. The information in the VmIdentifier * is used to construct a corresponding HostIdentifier, which in turn is * used to create the MonitoredHost instance. * * @param vmid The identifier for the target Java Virtual Machine. * @return MonitoredHost - The MonitoredHost object needed to attach to * the target Java Virtual Machine. * * @throws MonitorException Thrown if monitoring errors occur. */ public static MonitoredHost getMonitoredHost(VmIdentifier vmid) throws MonitorException { // use the VmIdentifier to construct the corresponding HostIdentifier HostIdentifier hostId = new HostIdentifier(vmid); return getMonitoredHost(hostId); } /** * Factory method to construct a MonitoredHost instance to manage the * connection to the host indicated by <tt>hostId</tt>. * * @param hostId the identifier for the target host. * @return MonitoredHost - The MonitoredHost object needed to attach to * the target host. * * @throws MonitorException Thrown if monitoring errors occur. */ public static MonitoredHost getMonitoredHost(HostIdentifier hostId) throws MonitorException { /* * determine the class name to load. If the system property is set, * use the indicated class. otherwise, use the default class. */ String classname = System.getProperty(IMPL_OVERRIDE_PROP_NAME); MonitoredHost mh = null; synchronized(monitoredHosts) { mh = monitoredHosts.get(hostId); if (mh != null) { if (mh.isErrored()) { monitoredHosts.remove(hostId); } else { return mh; } } } hostId = resolveHostId(hostId); if (classname == null) { // construct the class name classname = IMPL_PACKAGE + ".monitor.protocol." + hostId.getScheme() + "." + MONITORED_HOST_CLASS; } try { // run the constructor taking a single String parameter. Class<?> c = Class.forName(classname); Constructor cons = c.getConstructor( new Class[] { hostId.getClass() } ); mh = (MonitoredHost)cons.newInstance(new Object[] { hostId } ); synchronized(monitoredHosts) { monitoredHosts.put(mh.hostId, mh); } return mh; } catch (ClassNotFoundException e) { // from Class.forName(); throw new IllegalArgumentException("Could not find " + classname + ": " + e.getMessage(), e); } catch (NoSuchMethodException e) { // from Class.getConstructor(); throw new IllegalArgumentException( "Expected constructor missing in " + classname + ": " + e.getMessage(), e); } catch (IllegalAccessException e) { // from Constructor.newInstance() throw new IllegalArgumentException( "Unexpected constructor access in " + classname + ": " + e.getMessage(), e); } catch (InstantiationException e) { throw new IllegalArgumentException(classname + "is abstract: " + e.getMessage(), e); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof MonitorException) { throw (MonitorException)cause; } throw new RuntimeException("Unexpected exception", e); } } /** * Method to resolve unspecified components of the given HostIdentifier * by constructing a new HostIdentifier that replaces the unspecified * components with the default values. * * @param hostId the unresolved HostIdentifier. * @return HostIdentifier - a resolved HostIdentifier. * * @throws MonitorException Thrown if monitoring errors occur. */ protected static HostIdentifier resolveHostId(HostIdentifier hostId) throws MonitorException { String hostname = hostId.getHost(); String scheme = hostId.getScheme(); StringBuffer sb = new StringBuffer(); assert hostname != null; if (scheme == null) { if (hostname.compareTo("localhost") == 0) { scheme = LOCAL_PROTOCOL; } else { scheme = REMOTE_PROTOCOL; } } sb.append(scheme).append(":").append(hostId.getSchemeSpecificPart()); String frag = hostId.getFragment(); if (frag != null) { sb.append("#").append(frag); } try { return new HostIdentifier(sb.toString()); } catch (URISyntaxException e) { // programming error - HostIdentifier was valid. assert false; throw new IllegalArgumentException("Malformed URI created: " + sb.toString()); } } /** * Return the resolved HostIdentifier for this MonitoredHost. * * @return HostIdentifier - the resolved HostIdentifier. */ public HostIdentifier getHostIdentifier() { return hostId; } /* ---- Methods to support polled MonitoredHost Implementations ----- */ /** * Set the polling interval for this MonitoredHost. * * @param interval the polling interval, in milliseconds */ public void setInterval(int interval) { this.interval = interval; } /** * Get the polling interval. * * @return int - the polling interval in milliseconds for this MonitoredHost */ public int getInterval() { return interval; } /** * Set the last exception encountered while polling this MonitoredHost. * * @param lastException the last exception encountered; */ public void setLastException(Exception lastException) { this.lastException = lastException; } /** * Get the last exception encountered while polling this MonitoredHost. * * @return Exception - the last exception occurred while polling this * MonitoredHost, or <tt>null</tt> if no exception * has occurred or the exception has been cleared, */ public Exception getLastException() { return lastException; } /** * Clear the last exception. */ public void clearLastException() { lastException = null; } /** * Test if this MonitoredHost is in the errored state. If this method * returns true, then the Exception returned by getLastException() * indicates the Exception that caused the error condition. * * @return boolean - true if the MonitoredHost instance has experienced * an error, or false if it hasn't or if any past * error has been cleared. */ public boolean isErrored() { return lastException != null; } /** * Get the MonitoredVm for the given Java Virtual Machine. The default * sampling interval is used for the MonitoredVm instance. * * @param id the VmIdentifier specifying the target Java Virtual Machine. * @return MonitoredVm - the MonitoredVm instance for the target Java * Virtual Machine. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract MonitoredVm getMonitoredVm(VmIdentifier id) throws MonitorException; /** * Get the MonitoredVm for the given Java Virtual Machine. The sampling * interval is set to the given interval. * * @param id the VmIdentifier specifying the target Java Virtual Machine. * @param interval the sampling interval for the target Java Virtual Machine. * @return MonitoredVm - the MonitoredVm instance for the target Java * Virtual Machine. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract MonitoredVm getMonitoredVm(VmIdentifier id, int interval) throws MonitorException; /** * Detach from the indicated MonitoredVm. * * @param vm the monitored Java Virtual Machine. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract void detach(MonitoredVm vm) throws MonitorException; /** * Add a HostListener. The given listener is added to the list * of HostListener objects to be notified of MonitoredHost related events. * * @param listener the HostListener to add. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract void addHostListener(HostListener listener) throws MonitorException; /** * Remove a HostListener. The given listener is removed from the list * of HostListener objects to be notified of MonitoredHost related events. * * @param listener the HostListener to add. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract void removeHostListener(HostListener listener) throws MonitorException; /** * Return the current set of active Java Virtual Machines for this * MonitoredHost. The returned Set contains {@link Integer} instances * holding the local virtual machine identifier, or <em>lvmid</em> * for each instrumented Java Virtual Machine currently available. * * @return Set - the current set of active Java Virtual Machines associated * with this MonitoredHost, or the empty set of none. * @throws MonitorException Thrown if monitoring errors occur. */ public abstract Set<Integer> activeVms() throws MonitorException; }