001: /*
002: * Copyright 2003-2006 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: package sun.management.snmp.jvminstr;
026:
027: // java imports
028: //
029: import com.sun.jmx.mbeanserver.Util;
030: import java.io.Serializable;
031: import java.util.List;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.HashMap;
035: import java.util.TreeMap;
036: import java.util.Collections;
037:
038: // jmx imports
039: //
040: import javax.management.MBeanServer;
041: import javax.management.ObjectName;
042: import com.sun.jmx.snmp.SnmpOid;
043: import com.sun.jmx.snmp.SnmpStatusException;
044:
045: // jdmk imports
046: //
047: import com.sun.jmx.snmp.agent.SnmpMib;
048: import com.sun.jmx.snmp.agent.SnmpStandardObjectServer;
049: import com.sun.jmx.snmp.agent.SnmpMibTable;
050:
051: import java.lang.management.MemoryManagerMXBean;
052: import java.lang.management.MemoryPoolMXBean;
053:
054: import sun.management.snmp.jvmmib.JvmMemMgrPoolRelTableMeta;
055: import sun.management.snmp.util.SnmpTableCache;
056: import sun.management.snmp.util.SnmpCachedData;
057: import sun.management.snmp.util.SnmpTableHandler;
058: import sun.management.snmp.util.MibLogger;
059: import sun.management.snmp.util.JvmContextFactory;
060:
061: /**
062: * The class is used for implementing the "JvmMemMgrPoolRelTable" group.
063: */
064: public class JvmMemMgrPoolRelTableMetaImpl extends
065: JvmMemMgrPoolRelTableMeta implements Serializable {
066:
067: /**
068: * A concrete implementation of {@link SnmpTableCache}, for the
069: * jvmMemMgrPoolRelTable.
070: **/
071: private static class JvmMemMgrPoolRelTableCache extends
072: SnmpTableCache {
073:
074: final private JvmMemMgrPoolRelTableMetaImpl meta;
075:
076: /**
077: * Create a weak cache for the jvmMemMgrPoolRelTable.
078: * @param validity validity of the cached data, in ms.
079: **/
080: JvmMemMgrPoolRelTableCache(JvmMemMgrPoolRelTableMetaImpl meta,
081: long validity) {
082: this .validity = validity;
083: this .meta = meta;
084: }
085:
086: /**
087: * Call <code>getTableDatas(JvmContextFactory.getUserData())</code>.
088: **/
089: public SnmpTableHandler getTableHandler() {
090: final Map userData = JvmContextFactory.getUserData();
091: return getTableDatas(userData);
092: }
093:
094: /**
095: * Builds a map pool-name => pool-index from the SnmpTableHandler
096: * of the JvmMemPoolTable.
097: **/
098: private static Map<String, SnmpOid> buildPoolIndexMap(
099: SnmpTableHandler handler) {
100: // optimization...
101: if (handler instanceof SnmpCachedData)
102: return buildPoolIndexMap((SnmpCachedData) handler);
103:
104: // not optimizable... too bad.
105: final Map<String, SnmpOid> m = new HashMap<String, SnmpOid>();
106: SnmpOid index = null;
107: while ((index = handler.getNext(index)) != null) {
108: final MemoryPoolMXBean mpm = (MemoryPoolMXBean) handler
109: .getData(index);
110: if (mpm == null)
111: continue;
112: final String name = mpm.getName();
113: if (name == null)
114: continue;
115: m.put(name, index);
116: }
117: return m;
118: }
119:
120: /**
121: * Builds a map pool-name => pool-index from the SnmpTableHandler
122: * of the JvmMemPoolTable.
123: * Optimized algorithm.
124: **/
125: private static Map<String, SnmpOid> buildPoolIndexMap(
126: SnmpCachedData cached) {
127: if (cached == null)
128: return Collections.emptyMap();
129: final SnmpOid[] indexes = cached.indexes;
130: final Object[] datas = cached.datas;
131: final int len = indexes.length;
132: final Map<String, SnmpOid> m = new HashMap<String, SnmpOid>(
133: len);
134: for (int i = 0; i < len; i++) {
135: final SnmpOid index = indexes[i];
136: if (index == null)
137: continue;
138: final MemoryPoolMXBean mpm = (MemoryPoolMXBean) datas[i];
139: if (mpm == null)
140: continue;
141: final String name = mpm.getName();
142: if (name == null)
143: continue;
144: m.put(name, index);
145: }
146: return m;
147: }
148:
149: /**
150: * Return a table handler that holds the jvmMemManagerTable table data.
151: * This method return the cached table data if it is still
152: * valid, recompute it and cache the new value if it's not.
153: * If it needs to recompute the cached data, it first
154: * try to obtain the list of memory managers from the request
155: * contextual cache, and if it is not found, it calls
156: * <code>ManagementFactory.getMemoryMBean().getMemoryManagers()</code>
157: * and caches the value.
158: * This ensures that
159: * <code>ManagementFactory.getMemoryMBean().getMemoryManagers()</code>
160: * is not called more than once per request, thus ensuring a
161: * consistent view of the table.
162: **/
163: protected SnmpCachedData updateCachedDatas(Object userData) {
164: // Get the MemoryManager table
165: final SnmpTableHandler mmHandler = meta
166: .getManagerHandler(userData);
167:
168: // Get the MemoryPool table
169: final SnmpTableHandler mpHandler = meta
170: .getPoolHandler(userData);
171:
172: // Time stamp for the cache
173: final long time = System.currentTimeMillis();
174:
175: // Build a Map poolname -> index
176: final Map poolIndexMap = buildPoolIndexMap(mpHandler);
177:
178: // For each memory manager, get the list of memory pools
179: // For each memory pool, find its index in the memory pool table
180: // Create a row in the relation table.
181: final TreeMap<SnmpOid, Object> table = new TreeMap<SnmpOid, Object>(
182: SnmpCachedData.oidComparator);
183: updateTreeMap(table, userData, mmHandler, mpHandler,
184: poolIndexMap);
185:
186: return new SnmpCachedData(time, table);
187: }
188:
189: /**
190: * Get the list of memory pool associated with the
191: * given MemoryManagerMXBean.
192: **/
193: protected String[] getMemoryPools(Object userData,
194: MemoryManagerMXBean mmm, long mmarc) {
195: final String listTag = "JvmMemManager." + mmarc
196: + ".getMemoryPools";
197:
198: String[] result = null;
199: if (userData instanceof Map) {
200: result = (String[]) ((Map) userData).get(listTag);
201: if (result != null)
202: return result;
203: }
204:
205: if (mmm != null) {
206: result = mmm.getMemoryPoolNames();
207: }
208: if ((result != null) && (userData instanceof Map)) {
209: Map<Object, Object> map = Util.cast(userData);
210: map.put(listTag, result);
211: }
212:
213: return result;
214: }
215:
216: protected void updateTreeMap(TreeMap<SnmpOid, Object> table,
217: Object userData, MemoryManagerMXBean mmm,
218: SnmpOid mmIndex, Map poolIndexMap) {
219:
220: // The MemoryManager index is an int, so it's the first
221: // and only subidentifier.
222: final long mmarc;
223: try {
224: mmarc = mmIndex.getOidArc(0);
225: } catch (SnmpStatusException x) {
226: log.debug("updateTreeMap",
227: "Bad MemoryManager OID index: " + mmIndex);
228: log.debug("updateTreeMap", x);
229: return;
230: }
231:
232: // Cache this in userData + get it from cache?
233: final String[] mpList = getMemoryPools(userData, mmm, mmarc);
234: if (mpList == null || mpList.length < 1)
235: return;
236:
237: final String mmmName = mmm.getName();
238: for (int i = 0; i < mpList.length; i++) {
239: final String mpmName = mpList[i];
240: if (mpmName == null)
241: continue;
242: final SnmpOid mpIndex = (SnmpOid) poolIndexMap
243: .get(mpmName);
244: if (mpIndex == null)
245: continue;
246:
247: // The MemoryPool index is an int, so it's the first
248: // and only subidentifier.
249: final long mparc;
250: try {
251: mparc = mpIndex.getOidArc(0);
252: } catch (SnmpStatusException x) {
253: log.debug("updateTreeMap",
254: "Bad MemoryPool OID index: " + mpIndex);
255: log.debug("updateTreeMap", x);
256: continue;
257: }
258: // The MemoryMgrPoolRel table indexed is composed
259: // of the MemoryManager index, to which the MemoryPool
260: // index is appended.
261: final long[] arcs = { mmarc, mparc };
262:
263: final SnmpOid index = new SnmpOid(arcs);
264:
265: table.put(index, new JvmMemMgrPoolRelEntryImpl(mmmName,
266: mpmName, (int) mmarc, (int) mparc));
267: }
268: }
269:
270: protected void updateTreeMap(TreeMap<SnmpOid, Object> table,
271: Object userData, SnmpTableHandler mmHandler,
272: SnmpTableHandler mpHandler, Map poolIndexMap) {
273: if (mmHandler instanceof SnmpCachedData) {
274: updateTreeMap(table, userData,
275: (SnmpCachedData) mmHandler, mpHandler,
276: poolIndexMap);
277: return;
278: }
279:
280: SnmpOid mmIndex = null;
281: while ((mmIndex = mmHandler.getNext(mmIndex)) != null) {
282: final MemoryManagerMXBean mmm = (MemoryManagerMXBean) mmHandler
283: .getData(mmIndex);
284: if (mmm == null)
285: continue;
286: updateTreeMap(table, userData, mmm, mmIndex,
287: poolIndexMap);
288: }
289: }
290:
291: protected void updateTreeMap(TreeMap<SnmpOid, Object> table,
292: Object userData, SnmpCachedData mmHandler,
293: SnmpTableHandler mpHandler, Map poolIndexMap) {
294:
295: final SnmpOid[] indexes = mmHandler.indexes;
296: final Object[] datas = mmHandler.datas;
297: final int size = indexes.length;
298: for (int i = size - 1; i > -1; i--) {
299: final MemoryManagerMXBean mmm = (MemoryManagerMXBean) datas[i];
300: if (mmm == null)
301: continue;
302: updateTreeMap(table, userData, mmm, indexes[i],
303: poolIndexMap);
304: }
305: }
306: }
307:
308: // The weak cache for this table.
309: protected SnmpTableCache cache;
310:
311: private transient JvmMemManagerTableMetaImpl managers = null;
312: private transient JvmMemPoolTableMetaImpl pools = null;
313:
314: /**
315: * Constructor for the table. Initialize metadata for
316: * "JvmMemMgrPoolRelTableMeta".
317: * The reference on the MBean server is updated so the entries
318: * created through an SNMP SET will be AUTOMATICALLY REGISTERED
319: * in Java DMK.
320: */
321: public JvmMemMgrPoolRelTableMetaImpl(SnmpMib myMib,
322: SnmpStandardObjectServer objserv) {
323: super (myMib, objserv);
324: this .cache = new JvmMemMgrPoolRelTableCache(this ,
325: ((JVM_MANAGEMENT_MIB_IMPL) myMib).validity());
326: }
327:
328: // Returns a pointer to the JvmMemManager meta node - we're going
329: // to reuse its SnmpTableHandler in order to implement the
330: // relation table.
331: private final JvmMemManagerTableMetaImpl getManagers(SnmpMib mib) {
332: if (managers == null) {
333: managers = (JvmMemManagerTableMetaImpl) mib
334: .getRegisteredTableMeta("JvmMemManagerTable");
335: }
336: return managers;
337: }
338:
339: // Returns a pointer to the JvmMemPool meta node - we're going
340: // to reuse its SnmpTableHandler in order to implement the
341: // relation table.
342: private final JvmMemPoolTableMetaImpl getPools(SnmpMib mib) {
343: if (pools == null) {
344: pools = (JvmMemPoolTableMetaImpl) mib
345: .getRegisteredTableMeta("JvmMemPoolTable");
346: }
347: return pools;
348: }
349:
350: /**
351: * Returns the JvmMemManagerTable SnmpTableHandler
352: **/
353: protected SnmpTableHandler getManagerHandler(Object userData) {
354: final JvmMemManagerTableMetaImpl managerTable = getManagers(theMib);
355: return managerTable.getHandler(userData);
356: }
357:
358: /**
359: * Returns the JvmMemPoolTable SnmpTableHandler
360: **/
361: protected SnmpTableHandler getPoolHandler(Object userData) {
362: final JvmMemPoolTableMetaImpl poolTable = getPools(theMib);
363: return poolTable.getHandler(userData);
364: }
365:
366: // See com.sun.jmx.snmp.agent.SnmpMibTable
367: protected SnmpOid getNextOid(Object userData)
368: throws SnmpStatusException {
369: // null means get the first OID.
370: return getNextOid(null, userData);
371: }
372:
373: // See com.sun.jmx.snmp.agent.SnmpMibTable
374: protected SnmpOid getNextOid(SnmpOid oid, Object userData)
375: throws SnmpStatusException {
376: final boolean dbg = log.isDebugOn();
377: if (dbg)
378: log.debug("getNextOid", "previous=" + oid);
379:
380: // Get the data handler.
381: //
382: SnmpTableHandler handler = getHandler(userData);
383: if (handler == null) {
384: // This should never happen.
385: // If we get here it's a bug.
386: //
387: if (dbg)
388: log.debug("getNextOid", "handler is null!");
389: throw new SnmpStatusException(
390: SnmpStatusException.noSuchInstance);
391: }
392:
393: // Get the next oid
394: //
395: final SnmpOid next = handler.getNext(oid);
396: if (dbg)
397: log.debug("getNextOid", "next=" + next);
398:
399: // if next is null: we reached the end of the table.
400: //
401: if (next == null)
402: throw new SnmpStatusException(
403: SnmpStatusException.noSuchInstance);
404:
405: return next;
406: }
407:
408: // See com.sun.jmx.snmp.agent.SnmpMibTable
409: protected boolean contains(SnmpOid oid, Object userData) {
410:
411: // Get the handler.
412: //
413: SnmpTableHandler handler = getHandler(userData);
414:
415: // handler should never be null.
416: //
417: if (handler == null)
418: return false;
419:
420: return handler.contains(oid);
421: }
422:
423: // See com.sun.jmx.snmp.agent.SnmpMibTable
424: public Object getEntry(SnmpOid oid) throws SnmpStatusException {
425:
426: if (oid == null || oid.getLength() < 2)
427: throw new SnmpStatusException(
428: SnmpStatusException.noSuchInstance);
429:
430: // Get the request contextual cache (userData).
431: //
432: final Map<Object, Object> m = JvmContextFactory.getUserData();
433:
434: // We know in the case of this table that the index is composed
435: // of two integers,
436: // o The MemoryManager is the first OID arc of the index OID.
437: // o The MemoryPool is the second OID arc of the index OID.
438: //
439: final long mgrIndex = oid.getOidArc(0);
440: final long poolIndex = oid.getOidArc(1);
441:
442: // We're going to use this name to store/retrieve the entry in
443: // the request contextual cache.
444: //
445: // Revisit: Probably better programming to put all these strings
446: // in some interface.
447: //
448: final String entryTag = ((m == null) ? null
449: : ("JvmMemMgrPoolRelTable.entry." + mgrIndex + "." + poolIndex));
450:
451: // If the entry is in the cache, simply return it.
452: //
453: if (m != null) {
454: final Object entry = m.get(entryTag);
455: if (entry != null)
456: return entry;
457: }
458:
459: // The entry was not in the cache, make a new one.
460: //
461: // Get the data hanler.
462: //
463: SnmpTableHandler handler = getHandler(m);
464:
465: // handler should never be null.
466: //
467: if (handler == null)
468: throw new SnmpStatusException(
469: SnmpStatusException.noSuchInstance);
470:
471: // Get the data associated with our entry.
472: //
473: final Object data = handler.getData(oid);
474:
475: // data may be null if the OID we were given is not valid.
476: //
477: if (!(data instanceof JvmMemMgrPoolRelEntryImpl))
478: throw new SnmpStatusException(
479: SnmpStatusException.noSuchInstance);
480:
481: // make the new entry (transient object that will be kept only
482: // for the duration of the request.
483: //
484: final Object entry = (JvmMemMgrPoolRelEntryImpl) data;
485: // XXXXX Revisit
486: // new JvmMemMgrPoolRelEntryImpl((MemoryManagerMXBean)data,
487: // (int)mgrIndex,(int)poolIndex);
488:
489: // Put the entry in the cache in case we need it later while processing
490: // the request.
491: //
492: if (m != null && entry != null) {
493: m.put(entryTag, entry);
494: }
495:
496: return entry;
497: }
498:
499: /**
500: * Get the SnmpTableHandler that holds the jvmMemManagerTable data.
501: * First look it up in the request contextual cache, and if it is
502: * not found, obtain it from the weak cache.
503: * <br>The request contextual cache will be released at the end of the
504: * current requests, and is used only to process this request.
505: * <br>The weak cache is shared by all requests, and is only
506: * recomputed when it is found to be obsolete.
507: * <br>Note that the data put in the request contextual cache is
508: * never considered to be obsolete, in order to preserve data
509: * coherency.
510: **/
511: protected SnmpTableHandler getHandler(Object userData) {
512: final Map<Object, Object> m;
513: if (userData instanceof Map)
514: m = Util.cast(userData);
515: else
516: m = null;
517:
518: // Look in the contextual cache.
519: if (m != null) {
520: final SnmpTableHandler handler = (SnmpTableHandler) m
521: .get("JvmMemMgrPoolRelTable.handler");
522: if (handler != null)
523: return handler;
524: }
525:
526: // No handler in contextual cache, make a new one.
527: final SnmpTableHandler handler = cache.getTableHandler();
528:
529: if (m != null && handler != null)
530: m.put("JvmMemMgrPoolRelTable.handler", handler);
531:
532: return handler;
533: }
534:
535: static final MibLogger log = new MibLogger(
536: JvmMemMgrPoolRelTableMetaImpl.class);
537: }
|