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<String, Monitor> 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<>(); 83 this.aliasMap = new HashMap<>(); 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 @SuppressWarnings("deprecation") 162 private void buildAliasMap() { 163 assert Thread.holdsLock(this); 164 165 URL aliasURL = null; 166 String filename = System.getProperty("sun.jvmstat.perfdata.aliasmap"); 167 168 if (filename != null) { 169 File f = new File(filename); 170 try { 171 aliasURL = f.toURL(); 172 173 } catch (MalformedURLException e) { 174 throw new IllegalArgumentException(e); 175 } 176 } else { 177 aliasURL = getClass().getResource( 178 "/sun/jvmstat/perfdata/resources/aliasmap"); 179 } 180 181 assert aliasURL != null; 182 183 AliasFileParser aliasParser = new AliasFileParser(aliasURL); 184 185 try { 186 aliasParser.parse(aliasMap); 187 188 } catch (IOException e) { 189 System.err.println("Error processing " + filename + ": " 190 + e.getMessage()); 191 } catch (SyntaxException e) { 192 System.err.println("Syntax error parsing " + filename + ": " 193 + e.getMessage()); 194 } 195 } 196 197 /** 198 * Find the Monitor object for the named counter by using one of its 199 * aliases. 200 */ 201 protected Monitor findByAlias(String name) { 202 assert Thread.holdsLock(this); 203 204 Monitor m = aliasCache.get(name); 205 if (m == null) { 206 ArrayList<String> al = aliasMap.get(name); 207 if (al != null) { 208 for (Iterator<String> i = al.iterator(); i.hasNext() && m == null; ) { 209 String alias = i.next(); 210 m = monitors.get(alias); 211 } 212 } 213 } 214 return m; 215 } 216 217 218 /** 219 * Find a named Instrumentation object. 220 * 221 * This method will look for the named instrumentation object in the 222 * instrumentation exported by this Java Virtual Machine. If an 223 * instrumentation object with the given name exists, a Monitor interface 224 * to that object will be return. Otherwise, the method returns 225 * <tt>null</tt>. The method will map requests for instrumention objects 226 * using old names to their current names, if applicable. 227 * 228 * 229 * 230 * @param name the name of the Instrumentation object to find. 231 * @return Monitor - the {@link Monitor} object that can be used to 232 * monitor the named instrumentation object, or 233 * <tt>null</tt> if the named object doesn't exist. 234 * @throws MonitorException Thrown if an error occurs while communicating 235 * with the target Java Virtual Machine. 236 */ 237 public Monitor findByName(String name) throws MonitorException { 238 Monitor m = null; 239 240 synchronized (this) { 241 if (monitors.isEmpty()) { 242 buildMonitorMap(monitors); 243 buildAliasMap(); 244 } 245 246 // look for the requested monitor 247 m = monitors.get(name); 248 if (m == null) { 249 // not found - load any new monitors, and try again. 250 getNewMonitors(monitors); 251 m = monitors.get(name); 252 } 253 if (m == null) { 254 // still not found, look for aliases 255 m = findByAlias(name); 256 } 257 } 258 return m; 259 } 260 261 /** 262 * Find all Instrumentation objects with names matching the given pattern. 263 * 264 * This method returns a {@link List} of Monitor objects such that 265 * the name of each object matches the given pattern. 266 * 267 * @param patternString a string containing a pattern as described in 268 * {@link java.util.regex.Pattern}. 269 * @return List<Monitor> - a List of {@link Monitor} objects that can be used to 270 * monitor the instrumentation objects whose names match 271 * the given pattern. If no instrumentation objects have` 272 * names matching the given pattern, then an empty List 273 * is returned. 274 * @throws MonitorException Thrown if an error occurs while communicating 275 * with the target Java Virtual Machine. 276 * @see java.util.regex.Pattern 277 */ 278 public List<Monitor> findByPattern(String patternString) 279 throws MonitorException, PatternSyntaxException { 280 281 synchronized(this) { 282 if (monitors.isEmpty()) { 283 buildMonitorMap(monitors); 284 } else { 285 getNewMonitors(monitors); 286 } 287 } 288 289 Pattern pattern = Pattern.compile(patternString); 290 Matcher matcher = pattern.matcher(""); 291 List<Monitor> matches = new ArrayList<>(); 292 293 Set<Map.Entry<String,Monitor>> monitorSet = monitors.entrySet(); 294 295 for (Iterator<Map.Entry<String, Monitor>> i = monitorSet.iterator(); i.hasNext(); /* empty */) { 296 Map.Entry<String, Monitor> me = i.next(); 297 String name = me.getKey(); 298 Monitor m = me.getValue(); 299 300 // apply pattern to monitor item name 301 matcher.reset(name); 302 303 // if the pattern matches, then add monitor to list 304 if (matcher.lookingAt()) { 305 matches.add(me.getValue()); 306 } 307 } 308 return matches; 309 } 310 311 /** 312 * Get a list of the inserted and removed monitors since last called. 313 * 314 * @return MonitorStatus - the status of available Monitors for the 315 * target Java Virtual Machine. 316 * @throws MonitorException Thrown if communications errors occur 317 * while communicating with the target. 318 */ 319 public MonitorStatus getMonitorStatus() throws MonitorException { 320 synchronized(this) { 321 if (monitors.isEmpty()) { 322 buildMonitorMap(monitors); 323 } 324 return getMonitorStatus(monitors); 325 } 326 } 327 328 // PerfDataBuffer implementation specific classes 329 330 /** 331 * get the list of inserted and removed monitors since last called. 332 * 333 * @param m the map of Monitors. 334 * @throws MonitorException Thrown if communications errors occur 335 * while communicating with the target. 336 */ 337 protected abstract MonitorStatus getMonitorStatus(Map<String, Monitor> m) 338 throws MonitorException; 339 340 /** 341 * build the map of Monitor objects. 342 * 343 * @param m the map of Monitors. 344 * @throws MonitorException Thrown if communications errors occur 345 * while communicating with the target. 346 */ 347 protected abstract void buildMonitorMap(Map<String, Monitor> m) throws MonitorException; 348 349 /** 350 * get the new Monitor objects from the Map of Monitor objects. 351 * 352 * @param m the map of Monitors. 353 * @throws MonitorException Thrown if communications errors occur 354 * while communicating with the target. 355 */ 356 protected abstract void getNewMonitors(Map<String, Monitor> m) throws MonitorException; 357 }