jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/PerfDataBufferImpl.java
changeset 43592 14c12a5689d3
parent 43591 62824732af55
parent 43562 0cdf61c416d4
child 43593 06bce0388880
equal deleted inserted replaced
43591:62824732af55 43592:14c12a5689d3
     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      * {@code null}. 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      *                   {@code null} 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 }