001: /*
002: * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.jvmstat.perfdata.monitor;
027:
028: import sun.jvmstat.monitor.*;
029: import java.util.*;
030: import java.nio.*;
031: import java.io.*;
032: import java.net.*;
033: import java.util.regex.*;
034:
035: /**
036: * The base classes for the concrete implementations of the HotSpot
037: * PerfData instrumentation buffer.
038: *
039: * @author Brian Doherty
040: * @version 1.11, 05/09/07
041: * @since 1.5
042: * @see AbstractPerfDataBuffer
043: */
044: public abstract class PerfDataBufferImpl {
045:
046: /**
047: * The buffer containing the instrumentation data.
048: */
049: protected ByteBuffer buffer;
050:
051: /**
052: * A Map of monitor objects found in the instrumentation buffer.
053: */
054: protected Map<String, Monitor> monitors;
055:
056: /**
057: * The Local Java Virtual Machine Identifier for this buffer.
058: */
059: protected int lvmid;
060:
061: /**
062: * A Map of monitor object names to aliases as read in from the alias map
063: * file.
064: */
065: protected Map<String, ArrayList<String>> aliasMap;
066:
067: /**
068: * A cache of resolved monitor aliases.
069: */
070: protected Map aliasCache;
071:
072: /**
073: * Constructor.
074: *
075: * @param buffer the ByteBuffer containing the instrumentation data.
076: * @param lvmid the Local Java Virtual Machine Identifier for this
077: * instrumentation buffer.
078: */
079: protected PerfDataBufferImpl(ByteBuffer buffer, int lvmid) {
080: this .buffer = buffer;
081: this .lvmid = lvmid;
082: this .monitors = new TreeMap<String, Monitor>();
083: this .aliasMap = new HashMap<String, ArrayList<String>>();
084: this .aliasCache = new HashMap();
085: }
086:
087: /**
088: * Get the Local Java Virtual Machine Identifier, or <em>lvmid</em>
089: * for the target JVM associated with this instrumentation buffer.
090: *
091: * @return int - the lvmid
092: */
093: public int getLocalVmId() {
094: return lvmid;
095: }
096:
097: /**
098: * Get a copy of the raw instrumentation data.
099: * 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 reciever 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
166: .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 = (Monitor) aliasCache.get(name);
205: if (m == null) {
206: ArrayList al = aliasMap.get(name);
207: if (al != null) {
208: for (Iterator i = al.iterator(); i.hasNext()
209: && m == null;) {
210: String alias = (String) i.next();
211: m = (Monitor) monitors.get(alias);
212: }
213: }
214: }
215: return m;
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 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<Monitor>();
292:
293: Set monitorSet = monitors.entrySet();
294:
295: for (Iterator i = monitorSet.iterator(); i.hasNext(); /* empty */) {
296: Map.Entry me = (Map.Entry) i.next();
297: String name = (String) me.getKey();
298: Monitor m = (Monitor) 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((Monitor) 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(
338: Map<String, Monitor> m) 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)
348: 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)
358: throws MonitorException;
359: }
|