blob: 5d285607f82179252d4e4b0e95e0e21a2ed970c1 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.jvmstat.monitor;
27
28import java.util.*;
29import java.net.*;
30import java.lang.reflect.*;
31
32import sun.jvmstat.monitor.event.HostListener;
33
34/**
35 * An abstraction for a host that contains instrumented Java Virtual
36 * Machines. The class provides abstract factory methods for creating
37 * concrete instances of this class and factory methods for creating
38 * {@link MonitoredVm} instances. Concrete implementations of this class
39 * provide methods for managing the communications protocols and provide
40 * for event notification.
41 *
42 * @author Brian Doherty
43 * @since 1.5
44 *
45 * @see HostIdentifier
46 * @see VmIdentifier
47 * @see MonitoredVm
48 * @see HostListener
49 */
50public abstract class MonitoredHost {
51 private static Map<HostIdentifier, MonitoredHost> monitoredHosts =
52 new HashMap<HostIdentifier, MonitoredHost>();
53
54 /*
55 * The monitoring implementation override mechanism. The value of
56 * this property is used as the class name for the concrete MonitoredHost
57 * subclass that implements the monitoring APIs. Setting this property
58 * will cause the remaining override mechanisms to be ignored. When
59 * this mechanism is used, the HostIdentifier scheme name, which
60 * indicates the communications protocol, is not used to locate a
61 * the protocol specific package. However, the HostIdentifier is
62 * still passed to the corresponding single arg constructor.
63 * This property is not expected to be set in normal circumstances.
64 */
65 private static final String IMPL_OVERRIDE_PROP_NAME =
66 "sun.jvmstat.monitor.MonitoredHost";
67
68 /*
69 * The monitoring package name override mechanism. The value
70 * the this property is used as base package name for the
71 * monitoring implementation package. This property is not
72 * expected to be set under normal circumstances.
73 */
74 private static final String IMPL_PKG_PROP_NAME =
75 "sun.jvmstat.monitor.package";
76 private static final String IMPL_PACKAGE =
77 System.getProperty(IMPL_PKG_PROP_NAME, "sun.jvmstat.perfdata");
78
79 /*
80 * The default optimized local protocol override mechanism. The value
81 * of this property is used to construct the default package name
82 * for the default optimized local protocol as follows:
83 * <IMPL_PACKAGE>.monitor.<LOCAL_PROTOCOL>
84 * This property is not expected to be set under normal circumstances.
85 */
86 private static final String LOCAL_PROTOCOL_PROP_NAME =
87 "sun.jvmstat.monitor.local";
88 private static final String LOCAL_PROTOCOL =
89 System.getProperty(LOCAL_PROTOCOL_PROP_NAME, "local");
90
91 /*
92 * The default remote protocol override mechanism. The value of
93 * this property is used to construct the default package name
94 * for the default remote protocol protocol as follows:
95 * <IMPL_PACKAGE>.monitor.protocol.<REMOTE_PROTOCOL>
96 * This property is not expected to be set under normal circumstances.
97 */
98 private static final String REMOTE_PROTOCOL_PROP_NAME =
99 "sun.jvmstat.monitor.remote";
100 private static final String REMOTE_PROTOCOL =
101 System.getProperty(REMOTE_PROTOCOL_PROP_NAME, "rmi");
102
103 /*
104 * The default class name of the MonitoredHost implementation subclass.
105 * There is no override mechanism for this variable, other than the
106 * IMPL_OVERRIDE_PROP_NAME override, which is larger in scope. A concrete
107 * instance of this class is expected to be found in:
108 * <IMPL_PACKAGE>.monitor.protocol.<protocol>.<MONITORED_HOST_CLASS>
109 */
110 private static final String MONITORED_HOST_CLASS = "MonitoredHostProvider";
111
112 /**
113 * The HostIdentifier for this MonitoredHost instance.
114 */
115 protected HostIdentifier hostId;
116
117 /**
118 * The polling interval, in milliseconds, for this MonitoredHost instance.
119 */
120 protected int interval;
121
122 /**
123 * The last Exception encountered while polling this MonitoredHost.
124 */
125 protected Exception lastException;
126
127 /**
128 * Factory method to construct MonitoredHost instances to manage
129 * connections to the host indicated by <tt>hostIdString</tt>
130 *
131 * @param hostIdString a String representation of a {@link HostIdentifier}
132 * @return MonitoredHost - the MonitoredHost instance for communicating
133 * with the indicated host using the protocol
134 * specified in hostIdString.
135 * @throws MonitorException Thrown if monitoring errors occur.
136 * @throws URISyntaxException Thrown when the hostIdString is poorly
137 * formed. This exception may get encapsulated
138 * into MonitorException in a future revision.
139 */
140 public static MonitoredHost getMonitoredHost(String hostIdString)
141 throws MonitorException, URISyntaxException {
142 HostIdentifier hostId = new HostIdentifier(hostIdString);
143 return getMonitoredHost(hostId);
144 }
145
146 /**
147 * Factory method to construct a MonitoredHost instance to manage the
148 * connection to the Java Virtual Machine indicated by <tt>vmid</tt>.
149 *
150 * This method provide a convenient short cut for attaching to a specific
151 * instrumented Java Virtual Machine. The information in the VmIdentifier
152 * is used to construct a corresponding HostIdentifier, which in turn is
153 * used to create the MonitoredHost instance.
154 *
155 * @param vmid The identifier for the target Java Virtual Machine.
156 * @return MonitoredHost - The MonitoredHost object needed to attach to
157 * the target Java Virtual Machine.
158 *
159 * @throws MonitorException Thrown if monitoring errors occur.
160 */
161 public static MonitoredHost getMonitoredHost(VmIdentifier vmid)
162 throws MonitorException {
163 // use the VmIdentifier to construct the corresponding HostIdentifier
164 HostIdentifier hostId = new HostIdentifier(vmid);
165 return getMonitoredHost(hostId);
166 }
167
168 /**
169 * Factory method to construct a MonitoredHost instance to manage the
170 * connection to the host indicated by <tt>hostId</tt>.
171 *
172 * @param hostId the identifier for the target host.
173 * @return MonitoredHost - The MonitoredHost object needed to attach to
174 * the target host.
175 *
176 * @throws MonitorException Thrown if monitoring errors occur.
177 */
178 public static MonitoredHost getMonitoredHost(HostIdentifier hostId)
179 throws MonitorException {
180 /*
181 * determine the class name to load. If the system property is set,
182 * use the indicated class. otherwise, use the default class.
183 */
184 String classname = System.getProperty(IMPL_OVERRIDE_PROP_NAME);
185 MonitoredHost mh = null;
186
187 synchronized(monitoredHosts) {
188 mh = monitoredHosts.get(hostId);
189 if (mh != null) {
190 if (mh.isErrored()) {
191 monitoredHosts.remove(hostId);
192 } else {
193 return mh;
194 }
195 }
196 }
197
198 hostId = resolveHostId(hostId);
199
200 if (classname == null) {
201 // construct the class name
202 classname = IMPL_PACKAGE + ".monitor.protocol."
203 + hostId.getScheme() + "." + MONITORED_HOST_CLASS;
204 }
205
206 try {
207 // run the constructor taking a single String parameter.
208 Class<?> c = Class.forName(classname);
209
210 Constructor cons = c.getConstructor(
211 new Class[] { hostId.getClass() }
212 );
213
214 mh = (MonitoredHost)cons.newInstance(new Object[] { hostId } );
215
216 synchronized(monitoredHosts) {
217 monitoredHosts.put(mh.hostId, mh);
218 }
219 return mh;
220 } catch (ClassNotFoundException e) {
221 // from Class.forName();
222 throw new IllegalArgumentException("Could not find " + classname
223 + ": " + e.getMessage(), e);
224 } catch (NoSuchMethodException e) {
225 // from Class.getConstructor();
226 throw new IllegalArgumentException(
227 "Expected constructor missing in " + classname + ": "
228 + e.getMessage(), e);
229 } catch (IllegalAccessException e) {
230 // from Constructor.newInstance()
231 throw new IllegalArgumentException(
232 "Unexpected constructor access in " + classname + ": "
233 + e.getMessage(), e);
234 } catch (InstantiationException e) {
235 throw new IllegalArgumentException(classname + "is abstract: "
236 + e.getMessage(), e);
237 } catch (InvocationTargetException e) {
238 Throwable cause = e.getCause();
239 if (cause instanceof MonitorException) {
240 throw (MonitorException)cause;
241 }
242 throw new RuntimeException("Unexpected exception", e);
243 }
244 }
245
246 /**
247 * Method to resolve unspecified components of the given HostIdentifier
248 * by constructing a new HostIdentifier that replaces the unspecified
249 * components with the default values.
250 *
251 * @param hostId the unresolved HostIdentifier.
252 * @return HostIdentifier - a resolved HostIdentifier.
253 *
254 * @throws MonitorException Thrown if monitoring errors occur.
255 */
256 protected static HostIdentifier resolveHostId(HostIdentifier hostId)
257 throws MonitorException {
258 String hostname = hostId.getHost();
259 String scheme = hostId.getScheme();
260 StringBuffer sb = new StringBuffer();
261
262 assert hostname != null;
263
264 if (scheme == null) {
265 if (hostname.compareTo("localhost") == 0) {
266 scheme = LOCAL_PROTOCOL;
267 } else {
268 scheme = REMOTE_PROTOCOL;
269 }
270 }
271
272 sb.append(scheme).append(":").append(hostId.getSchemeSpecificPart());
273
274 String frag = hostId.getFragment();
275 if (frag != null) {
276 sb.append("#").append(frag);
277 }
278
279 try {
280 return new HostIdentifier(sb.toString());
281 } catch (URISyntaxException e) {
282 // programming error - HostIdentifier was valid.
283 assert false;
284 throw new IllegalArgumentException("Malformed URI created: "
285 + sb.toString());
286 }
287 }
288
289 /**
290 * Return the resolved HostIdentifier for this MonitoredHost.
291 *
292 * @return HostIdentifier - the resolved HostIdentifier.
293 */
294 public HostIdentifier getHostIdentifier() {
295 return hostId;
296 }
297
298 /* ---- Methods to support polled MonitoredHost Implementations ----- */
299
300 /**
301 * Set the polling interval for this MonitoredHost.
302 *
303 * @param interval the polling interval, in milliseconds
304 */
305 public void setInterval(int interval) {
306 this.interval = interval;
307 }
308
309 /**
310 * Get the polling interval.
311 *
312 * @return int - the polling interval in milliseconds for this MonitoredHost
313 */
314 public int getInterval() {
315 return interval;
316 }
317
318 /**
319 * Set the last exception encountered while polling this MonitoredHost.
320 *
321 * @param lastException the last exception encountered;
322 */
323 public void setLastException(Exception lastException) {
324 this.lastException = lastException;
325 }
326
327 /**
328 * Get the last exception encountered while polling this MonitoredHost.
329 *
330 * @return Exception - the last exception occurred while polling this
331 * MonitoredHost, or <tt>null</tt> if no exception
332 * has occurred or the exception has been cleared,
333 */
334 public Exception getLastException() {
335 return lastException;
336 }
337
338 /**
339 * Clear the last exception.
340 */
341 public void clearLastException() {
342 lastException = null;
343 }
344
345 /**
346 * Test if this MonitoredHost is in the errored state. If this method
347 * returns true, then the Exception returned by getLastException()
348 * indicates the Exception that caused the error condition.
349 *
350 * @return boolean - true if the MonitoredHost instance has experienced
351 * an error, or false if it hasn't or if any past
352 * error has been cleared.
353 */
354 public boolean isErrored() {
355 return lastException != null;
356 }
357
358 /**
359 * Get the MonitoredVm for the given Java Virtual Machine. The default
360 * sampling interval is used for the MonitoredVm instance.
361 *
362 * @param id the VmIdentifier specifying the target Java Virtual Machine.
363 * @return MonitoredVm - the MonitoredVm instance for the target Java
364 * Virtual Machine.
365 * @throws MonitorException Thrown if monitoring errors occur.
366 */
367 public abstract MonitoredVm getMonitoredVm(VmIdentifier id)
368 throws MonitorException;
369
370 /**
371 * Get the MonitoredVm for the given Java Virtual Machine. The sampling
372 * interval is set to the given interval.
373 *
374 * @param id the VmIdentifier specifying the target Java Virtual Machine.
375 * @param interval the sampling interval for the target Java Virtual Machine.
376 * @return MonitoredVm - the MonitoredVm instance for the target Java
377 * Virtual Machine.
378 * @throws MonitorException Thrown if monitoring errors occur.
379 */
380 public abstract MonitoredVm getMonitoredVm(VmIdentifier id, int interval)
381 throws MonitorException;
382
383 /**
384 * Detach from the indicated MonitoredVm.
385 *
386 * @param vm the monitored Java Virtual Machine.
387 * @throws MonitorException Thrown if monitoring errors occur.
388 */
389 public abstract void detach(MonitoredVm vm) throws MonitorException;
390
391 /**
392 * Add a HostListener. The given listener is added to the list
393 * of HostListener objects to be notified of MonitoredHost related events.
394 *
395 * @param listener the HostListener to add.
396 * @throws MonitorException Thrown if monitoring errors occur.
397 */
398 public abstract void addHostListener(HostListener listener)
399 throws MonitorException;
400
401 /**
402 * Remove a HostListener. The given listener is removed from the list
403 * of HostListener objects to be notified of MonitoredHost related events.
404 *
405 * @param listener the HostListener to add.
406 * @throws MonitorException Thrown if monitoring errors occur.
407 */
408 public abstract void removeHostListener(HostListener listener)
409 throws MonitorException;
410
411 /**
412 * Return the current set of active Java Virtual Machines for this
413 * MonitoredHost. The returned Set contains {@link Integer} instances
414 * holding the local virtual machine identifier, or <em>lvmid</em>
415 * for each instrumented Java Virtual Machine currently available.
416 *
417 * @return Set - the current set of active Java Virtual Machines associated
418 * with this MonitoredHost, or the empty set of none.
419 * @throws MonitorException Thrown if monitoring errors occur.
420 */
421 public abstract Set<Integer> activeVms() throws MonitorException;
422}