1 /* 2 * Copyright (c) 2004, 2008, 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.perfdata.monitor.protocol.local; 27 28 import java.util.*; 29 import java.lang.reflect.*; 30 import java.io.*; 31 32 import sun.jvmstat.monitor.*; 33 import sun.jvmstat.monitor.event.*; 34 import sun.jvmstat.perfdata.monitor.*; 35 36 /** 37 * Concrete implementation of the AbstractMonitoredVm class for the 38 * <em>local:</em> protocol for the HotSpot PerfData monitoring implementation. 39 * <p> 40 * This class provides the ability to attach to the instrumentation buffer 41 * of a live target Java Virtual Machine through a HotSpot specific attach 42 * mechanism. 43 * 44 * @author Brian Doherty 45 * @since 1.5 46 */ 47 public class LocalMonitoredVm extends AbstractMonitoredVm { 48 49 /** 50 * List of registered listeners. 51 */ 52 private ArrayList<VmListener> listeners; 53 54 /** 55 * Task performing listener notification. 56 */ 57 private NotifierTask task; 58 59 /** 60 * Create a LocalMonitoredVm instance. 61 * 62 * @param vmid the vm identifier specifying the target JVM 63 * @param interval the sampling interval 64 */ 65 public LocalMonitoredVm(VmIdentifier vmid, int interval) 66 throws MonitorException { 67 super(vmid, interval); 68 this.pdb = new PerfDataBuffer(vmid); 69 listeners = new ArrayList<VmListener>(); 70 } 71 72 /** 73 * {@inheritDoc}. 74 */ 75 public void detach() { 76 if (interval > 0) { 77 /* 78 * if the notifier task is running, stop it, otherwise it can 79 * access non-existent memory once we've detached from the 80 * underlying buffer. 81 */ 82 if (task != null) { 83 task.cancel(); 84 task = null; 85 } 86 } 87 super.detach(); 88 } 89 90 /** 91 * {@inheritDoc}. 92 */ 93 public void addVmListener(VmListener l) { 94 synchronized(listeners) { 95 listeners.add(l); 96 if (task == null) { 97 task = new NotifierTask(); 98 LocalEventTimer timer = LocalEventTimer.getInstance(); 99 timer.schedule(task, interval, interval); 100 } 101 } 102 } 103 104 /** 105 * {@inheritDoc}. 106 */ 107 public void removeVmListener(VmListener l) { 108 synchronized(listeners) { 109 listeners.remove(l); 110 if (listeners.isEmpty() && task != null) { 111 task.cancel(); 112 task = null; 113 } 114 } 115 } 116 117 /** 118 * {@inheritDoc}. 119 */ 120 public void setInterval(int newInterval) { 121 synchronized(listeners) { 122 if (newInterval == interval) { 123 return; 124 } 125 126 int oldInterval = interval; 127 super.setInterval(newInterval); 128 129 if (task != null) { 130 task.cancel(); 131 NotifierTask oldTask = task; 132 task = new NotifierTask(); 133 LocalEventTimer timer = LocalEventTimer.getInstance(); 134 CountedTimerTaskUtils.reschedule(timer, oldTask, task, 135 oldInterval, newInterval); 136 } 137 } 138 } 139 140 /** 141 * Fire MonitoredVmStructureChanged events. 142 * 143 * @param inserted List of Monitor objects inserted. 144 * @param removed List of Monitor objects removed. 145 */ 146 void fireMonitorStatusChangedEvents(List inserted, List removed) { 147 MonitorStatusChangeEvent ev = null; 148 ArrayList registered = null; 149 150 synchronized (listeners) { 151 registered = (ArrayList)listeners.clone(); 152 } 153 154 for (Iterator i = registered.iterator(); i.hasNext(); /* empty */) { 155 VmListener l = (VmListener)i.next(); 156 // lazily create the event object; 157 if (ev == null) { 158 ev = new MonitorStatusChangeEvent(this, inserted, removed); 159 } 160 l.monitorStatusChanged(ev); 161 } 162 } 163 164 /** 165 * Fire MonitoredUpdated events. 166 */ 167 void fireMonitorsUpdatedEvents() { 168 VmEvent ev = null; 169 ArrayList<VmListener> registered = null; 170 171 synchronized (listeners) { 172 registered = cast(listeners.clone()); 173 } 174 175 for (VmListener l : registered) { 176 // lazily create the event object; 177 if (ev == null) { 178 ev = new VmEvent(this); 179 } 180 l.monitorsUpdated(ev); 181 } 182 } 183 184 /** 185 * Class to notify listeners of Monitor related events for 186 * the target JVM. 187 */ 188 private class NotifierTask extends CountedTimerTask { 189 public void run() { 190 super.run(); 191 try { 192 MonitorStatus status = getMonitorStatus(); 193 List inserted = status.getInserted(); 194 List removed = status.getRemoved(); 195 196 if (!inserted.isEmpty() || !removed.isEmpty()) { 197 fireMonitorStatusChangedEvents(inserted, removed); 198 } 199 fireMonitorsUpdatedEvents(); 200 } catch (MonitorException e) { 201 // XXX: use logging api 202 System.err.println("Exception updating monitors for " 203 + getVmIdentifier()); 204 e.printStackTrace(); 205 } 206 } 207 } 208 // Suppress unchecked cast warning msg. 209 @SuppressWarnings("unchecked") 210 static <T> T cast(Object x) { 211 return (T) x; 212 } 213 }