1 /* 2 * Copyright (c) 2004, 2014, 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; 27 28 import sun.jvmstat.monitor.*; 29 import java.util.*; 30 import java.nio.*; 31 import java.io.*; 32 import java.net.*; 33 import java.util.regex.*; 34 35 /** 36 * The base classes for the concrete implementations of the HotSpot 37 * PerfData instrumentation buffer. 38 * 39 * @author Brian Doherty 40 * @since 1.5 41 * @see AbstractPerfDataBuffer 42 */ 43 public abstract class PerfDataBufferImpl { 44 45 /** 46 * The buffer containing the instrumentation data. 47 */ 48 protected ByteBuffer buffer; 49 50 /** 51 * A Map of monitor objects found in the instrumentation buffer. 52 */ 53 protected Map<String, Monitor> monitors; 54 55 /** 56 * The Local Java Virtual Machine Identifier for this buffer. 57 */ 58 protected int lvmid; 59 60 /** 61 * A Map of monitor object names to aliases as read in from the alias map 62 * file. 63 */ 64 protected Map<String, ArrayList<String>> aliasMap; 65 66 /** 67 * A cache of resolved monitor aliases. 68 */ 69 protected Map aliasCache; 70 71 72 /** 73 * Constructor. 74 * 75 * @param buffer the ByteBuffer containing the instrumentation data. 76 * @param lvmid the Local Java Virtual Machine Identifier for this 77 * instrumentation buffer. 78 */ 79 protected PerfDataBufferImpl(ByteBuffer buffer, int lvmid) { 80 this.buffer = buffer; 81 this.lvmid = lvmid; 82 this.monitors = new TreeMap<String, Monitor>(); 83 this.aliasMap = new HashMap<String, ArrayList<String>>(); 84 this.aliasCache = new HashMap(); 85 } 86 87 /** 88 * Get the Local Java Virtual Machine Identifier, or <em>lvmid</em> 89 * for the target JVM associated with this instrumentation buffer. 90 * 91 * @return int - the lvmid 92 */ 93 public int getLocalVmId() { 94 return lvmid; 95 } 96 97 /** 98 * Get a copy of the raw instrumentation data. 99 * This method is used to get a copy of the current bytes in the 100 * instrumentation buffer. It is generally used for transporting 101 * those bytes over the network. 102 * 103 * @return byte[] - a copy of the bytes in the instrumentation buffer. 104 */ 105 public byte[] getBytes() { 106 ByteBuffer bb = null; 107 synchronized (this) { 108 /* 109 * this operation is potentially time consuming, and the result 110 * is unused when the getBytes() interface is used. However, the 111 * call is necessary in order to synchronize this monitoring 112 * client with the target jvm, which assures that the receiver 113 * of the byte[] gets an image that is initialized to a usable 114 * state. Otherwise, they might only get a snapshot of an 115 * empty instrumentation buffer immediately after it was created. 116 */ 117 try { 118 if (monitors.isEmpty()) { 119 buildMonitorMap(monitors); 120 } 121 } catch (MonitorException e) { 122 /* 123 * just ignore this here and let the receiver of the 124 * byte[] detect and handle the problem. 125 */ 126 } 127 bb = buffer.duplicate(); 128 } 129 bb.rewind(); 130 byte[] bytes = new byte[bb.limit()]; 131 bb.get(bytes); 132 return bytes; 133 } 134 135 /** 136 * Get the capacity of the instrumentation buffer. 137 * 138 * @return int - the capacity, or size, of the instrumentation buffer. 139 */ 140 public int getCapacity() { 141 return buffer.capacity(); 142 } 143 144 /** 145 * Get the ByteBuffer containing the instrumentation data. 146 * 147 * @return ByteBuffer - a ByteBuffer object that refers to the 148 * instrumentation data. 149 */ 150 ByteBuffer getByteBuffer() { 151 // receiver is responsible for assuring that the buffer's state 152 // is that of an initialized target. 153 return buffer; 154 } 155 156 /** 157 * Build the alias mapping. Uses the default alias map file unless 158 * the sun.jvmstat.perfdata.aliasmap file indicates some other 159 * file as the source. 160 */ 161 private void buildAliasMap() { 162 assert Thread.holdsLock(this); 163 164 URL aliasURL = null; 165 String filename = System.getProperty("sun.jvmstat.perfdata.aliasmap"); 166 167 if (filename != null) { 168 File f = new File(filename); 169 try { 170 aliasURL = f.toURL(); 171 172 } catch (MalformedURLException e) { 173 throw new IllegalArgumentException(e); 174 } 175 } else { 176 aliasURL = getClass().getResource( 177 "/sun/jvmstat/perfdata/resources/aliasmap"); 178 } 179 180 assert aliasURL != null; 181 182 AliasFileParser aliasParser = new AliasFileParser(aliasURL); 183 184 try { 185 aliasParser.parse(aliasMap); 186 187 } catch (IOException e) { 188 System.err.println("Error processing " + filename + ": " 189 + e.getMessage()); 190 } catch (SyntaxException e) { 191 System.err.println("Syntax error parsing " + filename + ": " 192 + e.getMessage()); 193 } 194 } 195 196 /** 197 * Find the Monitor object for the named counter by using one of its 198 * aliases. 199 */ 200 protected Monitor findByAlias(String name) { 201 assert Thread.holdsLock(this); 202 203 Monitor m = (Monitor)aliasCache.get(name); 204 if (m == null) { 205 ArrayList al = aliasMap.get(name); 206 if (al != null) { 207 for (Iterator i = al.iterator(); i.hasNext() && m == null; ) { 208 String alias = (String)i.next(); 209 m = monitors.get(alias); 210 } 211 } 212 } 213 return m; 214 } 215 216 217 /** 218 * Find a named Instrumentation object. 219 * 220 * This method will look for the named instrumentation object in the 221 * instrumentation exported by this Java Virtual Machine. If an 222 * instrumentation object with the given name exists, a Monitor interface 223 * to that object will be return. Otherwise, the method returns 224 * <tt>null</tt>. The method will map requests for instrumention objects 225 * using old names to their current names, if applicable. 226 * 227 * 228 * 229 * @param name the name of the Instrumentation object to find. 230 * @return Monitor - the {@link Monitor} object that can be used to 231 * monitor the the named instrumentation object, or 232 * <tt>null</tt> if the named object doesn't exist. 233 * @throws MonitorException Thrown if an error occurs while communicating 234 * with the target Java Virtual Machine. 235 */ 236 public Monitor findByName(String name) throws MonitorException { 237 Monitor m = null; 238 239 synchronized (this) { 240 if (monitors.isEmpty()) { 241 buildMonitorMap(monitors); 242 buildAliasMap(); 243 } 244 245 // look for the requested monitor 246 m = monitors.get(name); 247 if (m == null) { 248 // not found - load any new monitors, and try again. 249 getNewMonitors(monitors); 250 m = monitors.get(name); 251 } 252 if (m == null) { 253 // still not found, look for aliases 254 m = findByAlias(name); 255 } 256 } 257 return m; 258 } 259 260 /** 261 * Find all Instrumentation objects with names matching the given pattern. 262 * 263 * This method returns a {@link List} of Monitor objects such that 264 * the name of each object matches the given pattern. 265 * 266 * @param patternString a string containing a pattern as described in 267 * {@link java.util.regex.Pattern}. 268 * @return List<Monitor> - a List of {@link Monitor} objects that can be used to 269 * monitor the instrumentation objects whose names match 270 * the given pattern. If no instrumentation objects have` 271 * names matching the given pattern, then an empty List 272 * is returned. 273 * @throws MonitorException Thrown if an error occurs while communicating 274 * with the target Java Virtual Machine. 275 * @see java.util.regex.Pattern 276 */ 277 public List<Monitor> findByPattern(String patternString) 278 throws MonitorException, PatternSyntaxException { 279 280 synchronized(this) { 281 if (monitors.isEmpty()) { 282 buildMonitorMap(monitors); 283 } else { 284 getNewMonitors(monitors); 285 } 286 } 287 288 Pattern pattern = Pattern.compile(patternString); 289 Matcher matcher = pattern.matcher(""); 290 List<Monitor> matches = new ArrayList<Monitor>(); 291 292 Set monitorSet = monitors.entrySet(); 293 294 for (Iterator i = monitorSet.iterator(); i.hasNext(); /* empty */) { 295 Map.Entry me = (Map.Entry)i.next(); 296 String name = (String)me.getKey(); 297 Monitor m = (Monitor)me.getValue(); 298 299 // apply pattern to monitor item name 300 matcher.reset(name); 301 302 // if the pattern matches, then add monitor to list 303 if (matcher.lookingAt()) { 304 matches.add((Monitor)me.getValue()); 305 } 306 } 307 return matches; 308 } 309 310 /** 311 * Get a list of the inserted and removed monitors since last called. 312 * 313 * @return MonitorStatus - the status of available Monitors for the 314 * target Java Virtual Machine. 315 * @throws MonitorException Thrown if communications errors occur 316 * while communicating with the target. 317 */ 318 public MonitorStatus getMonitorStatus() throws MonitorException { 319 synchronized(this) { 320 if (monitors.isEmpty()) { 321 buildMonitorMap(monitors); 322 } 323 return getMonitorStatus(monitors); 324 } 325 } 326 327 // PerfDataBuffer implementation specific classes 328 329 /** 330 * get the list of inserted and removed monitors since last called. 331 * 332 * @param m the map of Monitors. 333 * @throws MonitorException Thrown if communications errors occur 334 * while communicating with the target. 335 */ 336 protected abstract MonitorStatus getMonitorStatus(Map<String, Monitor> m) 337 throws MonitorException; 338 339 /** 340 * build the map of Monitor objects. 341 * 342 * @param m the map of Monitors. 343 * @throws MonitorException Thrown if communications errors occur 344 * while communicating with the target. 345 */ 346 protected abstract void buildMonitorMap(Map<String, Monitor> m) throws MonitorException; 347 348 /** 349 * get the new Monitor objects from the Map of Monitor objects. 350 * 351 * @param m the map of Monitors. 352 * @throws MonitorException Thrown if communications errors occur 353 * while communicating with the target. 354 */ 355 protected abstract void getNewMonitors(Map<String, Monitor> m) throws MonitorException; 356 }