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 {@code List<Monitor>} - a List of {@link Monitor} 270 * objects that can be used to 271 * monitor the instrumentation objects whose names match 272 * the given pattern. If no instrumentation objects have` 273 * names matching the given pattern, then an empty List 274 * is returned. 275 * @throws MonitorException Thrown if an error occurs while communicating 276 * with the target Java Virtual Machine. 277 * @see java.util.regex.Pattern 278 */ 279 public List<Monitor> findByPattern(String patternString) 280 throws MonitorException, PatternSyntaxException { 281 282 synchronized(this) { 283 if (monitors.isEmpty()) { 284 buildMonitorMap(monitors); 285 } else { 286 getNewMonitors(monitors); 287 } 288 } 289 290 Pattern pattern = Pattern.compile(patternString); 291 Matcher matcher = pattern.matcher(""); 292 List<Monitor> matches = new ArrayList<>(); 293 294 Set<Map.Entry<String,Monitor>> monitorSet = monitors.entrySet(); 295 296 for (Iterator<Map.Entry<String, Monitor>> i = monitorSet.iterator(); i.hasNext(); /* empty */) { 297 Map.Entry<String, Monitor> me = i.next(); 298 String name = me.getKey(); 299 Monitor m = me.getValue(); 300 301 // apply pattern to monitor item name 302 matcher.reset(name); 303 304 // if the pattern matches, then add monitor to list 305 if (matcher.lookingAt()) { 306 matches.add(me.getValue()); 307 } 308 } 309 return matches; 310 } 311 312 /** 313 * Get a list of the inserted and removed monitors since last called. 314 * 315 * @return MonitorStatus - the status of available Monitors for the 316 * target Java Virtual Machine. 317 * @throws MonitorException Thrown if communications errors occur 318 * while communicating with the target. 319 */ 320 public MonitorStatus getMonitorStatus() throws MonitorException { 321 synchronized(this) { 322 if (monitors.isEmpty()) { 323 buildMonitorMap(monitors); 324 } 325 return getMonitorStatus(monitors); 326 } 327 } 328 329 // PerfDataBuffer implementation specific classes 330 331 /** 332 * get the list of inserted and removed monitors since last called. 333 * 334 * @param m the map of Monitors. 335 * @throws MonitorException Thrown if communications errors occur 336 * while communicating with the target. 337 */ 338 protected abstract MonitorStatus getMonitorStatus(Map<String, Monitor> m) 339 throws MonitorException; 340 341 /** 342 * build the map of Monitor objects. 343 * 344 * @param m the map of Monitors. 345 * @throws MonitorException Thrown if communications errors occur 346 * while communicating with the target. 347 */ 348 protected abstract void buildMonitorMap(Map<String, Monitor> m) throws MonitorException; 349 350 /** 351 * get the new Monitor objects from the Map of Monitor objects. 352 * 353 * @param m the map of Monitors. 354 * @throws MonitorException Thrown if communications errors occur 355 * while communicating with the target. 356 */ 357 protected abstract void getNewMonitors(Map<String, Monitor> m) throws MonitorException; 358 }