jdk/src/jdk.snmp/share/classes/sun/management/snmp/jvminstr/JvmMemGCTableMetaImpl.java
changeset 25859 3317bb8137f4
parent 14342 8435a30053c1
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2003, 2012, 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 package sun.management.snmp.jvminstr;
       
    26 
       
    27 
       
    28 // java imports
       
    29 //
       
    30 import java.io.Serializable;
       
    31 import java.util.List;
       
    32 import java.util.Map;
       
    33 import java.util.TreeMap;
       
    34 
       
    35 // jmx imports
       
    36 //
       
    37 import com.sun.jmx.snmp.SnmpOid;
       
    38 import com.sun.jmx.snmp.SnmpStatusException;
       
    39 
       
    40 // jdmk imports
       
    41 //
       
    42 import com.sun.jmx.snmp.agent.SnmpMib;
       
    43 import com.sun.jmx.snmp.agent.SnmpStandardObjectServer;
       
    44 
       
    45 import java.lang.management.MemoryManagerMXBean;
       
    46 import java.lang.management.GarbageCollectorMXBean;
       
    47 import java.lang.management.ManagementFactory;
       
    48 
       
    49 import sun.management.snmp.jvmmib.JvmMemGCTableMeta;
       
    50 import sun.management.snmp.util.SnmpCachedData;
       
    51 import sun.management.snmp.util.SnmpTableCache;
       
    52 import sun.management.snmp.util.SnmpTableHandler;
       
    53 import sun.management.snmp.util.MibLogger;
       
    54 import sun.management.snmp.util.JvmContextFactory;
       
    55 
       
    56 /**
       
    57  * The class is used for implementing the "JvmMemGCTable" table.
       
    58  */
       
    59 public class JvmMemGCTableMetaImpl extends  JvmMemGCTableMeta {
       
    60 
       
    61     static final long serialVersionUID = 8250461197108867607L;
       
    62 
       
    63     /**
       
    64      * This class acts as a filter over the SnmpTableHandler
       
    65      * used for the JvmMemoryManagerTable. It filters out
       
    66      * (skip) all MemoryManagerMXBean that are not instances of
       
    67      * GarbageCollectorMXBean so that only Garbage Collectors are
       
    68      * seen. This is a better solution than relying on
       
    69      * ManagementFactory.getGarbageCollectorMXBeans() because it makes it
       
    70      * possible to guarantee the consistency betwen the MemoryManager table
       
    71      * and the GCTable since both will be sharing the same cache.
       
    72      **/
       
    73     protected static class GCTableFilter {
       
    74 
       
    75         /**
       
    76          * Returns the index that immediately follows the given
       
    77          * <var>index</var>. The returned index is strictly greater
       
    78          * than the given <var>index</var>, and is contained in the table.
       
    79          * <br>If the given <var>index</var> is null, returns the first
       
    80          * index in the table.
       
    81          * <br>If there are no index after the given <var>index</var>,
       
    82          * returns null.
       
    83          * This method is an optimization for the case where the
       
    84          * SnmpTableHandler is in fact an instance of SnmpCachedData.
       
    85          **/
       
    86         public SnmpOid getNext(SnmpCachedData datas, SnmpOid index) {
       
    87 
       
    88             final boolean dbg = log.isDebugOn();
       
    89 
       
    90             // We're going to loop until we find an instance of
       
    91             // GarbageCollectorMXBean. First we attempt to find
       
    92             // the next element whose OID follows the given index.
       
    93             // If `index' is null, the insertion point is -1
       
    94             // (the next is 0 = -insertion - 1)
       
    95             //
       
    96             final int insertion = (index==null)?-1:datas.find(index);
       
    97             if (dbg) log.debug("GCTableFilter","oid="+index+
       
    98                                " at insertion="+insertion);
       
    99 
       
   100             int next;
       
   101             if (insertion > -1) next = insertion+1;
       
   102             else next = -insertion -1;
       
   103 
       
   104             // Now `next' points to the element that imediately
       
   105             // follows the given `index'. We're going to loop
       
   106             // through the table, starting at `next' (included),
       
   107             // and return the first element which is an instance
       
   108             // of GarbageCollectorMXBean.
       
   109             //
       
   110             for (;next<datas.indexes.length;next++) {
       
   111                 if (dbg) log.debug("GCTableFilter","next="+next);
       
   112                 final Object value = datas.datas[next];
       
   113                 if (dbg) log.debug("GCTableFilter","value["+next+"]=" +
       
   114                       ((MemoryManagerMXBean)value).getName());
       
   115                 if (value instanceof GarbageCollectorMXBean) {
       
   116                     // That's the next: return it.
       
   117                     if (dbg) log.debug("GCTableFilter",
       
   118                           ((MemoryManagerMXBean)value).getName() +
       
   119                           " is a  GarbageCollectorMXBean.");
       
   120                     return datas.indexes[next];
       
   121                 }
       
   122                 if (dbg) log.debug("GCTableFilter",
       
   123                       ((MemoryManagerMXBean)value).getName() +
       
   124                       " is not a  GarbageCollectorMXBean: " +
       
   125                       value.getClass().getName());
       
   126                 // skip to next index...
       
   127             }
       
   128             return null;
       
   129         }
       
   130 
       
   131         /**
       
   132          * Returns the index that immediately follows the given
       
   133          * <var>index</var>. The returned index is strictly greater
       
   134          * than the given <var>index</var>, and is contained in the table.
       
   135          * <br>If the given <var>index</var> is null, returns the first
       
   136          * index in the table.
       
   137          * <br>If there are no index after the given <var>index</var>,
       
   138          * returns null.
       
   139          **/
       
   140         public SnmpOid getNext(SnmpTableHandler handler, SnmpOid index) {
       
   141 
       
   142             // try to call the optimized method
       
   143             if (handler instanceof SnmpCachedData)
       
   144                 return getNext((SnmpCachedData)handler, index);
       
   145 
       
   146             // too bad - revert to non-optimized generic algorithm
       
   147             SnmpOid next = index;
       
   148             do {
       
   149                 next = handler.getNext(next);
       
   150                 final Object value = handler.getData(next);
       
   151                 if (value instanceof GarbageCollectorMXBean)
       
   152                     // That's the next! return it
       
   153                     return next;
       
   154                 // skip to next index...
       
   155             } while (next != null);
       
   156             return null;
       
   157         }
       
   158 
       
   159         /**
       
   160          * Returns the data associated with the given index.
       
   161          * If the given index is not found, null is returned.
       
   162          * Note that returning null does not necessarily means that
       
   163          * the index was not found.
       
   164          **/
       
   165         public Object  getData(SnmpTableHandler handler, SnmpOid index) {
       
   166             final Object value = handler.getData(index);
       
   167             if (value instanceof GarbageCollectorMXBean) return value;
       
   168             // Behaves as if there was nothing at this index...
       
   169             //
       
   170             return null;
       
   171         }
       
   172 
       
   173         /**
       
   174          * Returns true if the given <var>index</var> is present.
       
   175          **/
       
   176         public boolean contains(SnmpTableHandler handler, SnmpOid index) {
       
   177             if (handler.getData(index) instanceof GarbageCollectorMXBean)
       
   178                 return true;
       
   179             // Behaves as if there was nothing at this index...
       
   180             //
       
   181             return false;
       
   182         }
       
   183     }
       
   184 
       
   185 
       
   186     private transient JvmMemManagerTableMetaImpl managers = null;
       
   187     private static GCTableFilter filter = new GCTableFilter();
       
   188 
       
   189 
       
   190     /**
       
   191      * Constructor for the table. Initialize metadata for "JvmMemGCTableMeta".
       
   192      */
       
   193     public JvmMemGCTableMetaImpl(SnmpMib myMib,
       
   194                                  SnmpStandardObjectServer objserv) {
       
   195         super(myMib,objserv);
       
   196     }
       
   197 
       
   198     // Returns a pointer to the JvmMemManager meta node - we're going
       
   199     // to reuse its SnmpTableHandler by filtering out all that is
       
   200     // not a GarbageCollectorMXBean.
       
   201     private final JvmMemManagerTableMetaImpl getManagers(SnmpMib mib) {
       
   202         if (managers == null) {
       
   203             managers = (JvmMemManagerTableMetaImpl)
       
   204                 mib.getRegisteredTableMeta("JvmMemManagerTable");
       
   205         }
       
   206         return managers;
       
   207     }
       
   208 
       
   209     /**
       
   210      * Returns the JvmMemManagerTable SnmpTableHandler
       
   211      **/
       
   212     protected SnmpTableHandler getHandler(Object userData) {
       
   213         JvmMemManagerTableMetaImpl managerTable= getManagers(theMib);
       
   214         return managerTable.getHandler(userData);
       
   215     }
       
   216 
       
   217     // See com.sun.jmx.snmp.agent.SnmpMibTable
       
   218     protected SnmpOid getNextOid(Object userData)
       
   219         throws SnmpStatusException {
       
   220         // null means get the first OID.
       
   221         return getNextOid(null,userData);
       
   222     }
       
   223 
       
   224     // See com.sun.jmx.snmp.agent.SnmpMibTable
       
   225     protected SnmpOid getNextOid(SnmpOid oid, Object userData)
       
   226         throws SnmpStatusException {
       
   227         final boolean dbg = log.isDebugOn();
       
   228         try {
       
   229             if (dbg) log.debug("getNextOid", "previous=" + oid);
       
   230 
       
   231             // Get the data handler.
       
   232             //
       
   233             SnmpTableHandler handler = getHandler(userData);
       
   234             if (handler == null) {
       
   235                 // This should never happen.
       
   236                 // If we get here it's a bug.
       
   237                 //
       
   238                 if (dbg) log.debug("getNextOid", "handler is null!");
       
   239                 throw new
       
   240                     SnmpStatusException(SnmpStatusException.noSuchInstance);
       
   241             }
       
   242 
       
   243 
       
   244             // Get the next oid, using the GC filter.
       
   245             //
       
   246             final SnmpOid next = filter.getNext(handler,oid);
       
   247             if (dbg) log.debug("getNextOid", "next=" + next);
       
   248 
       
   249             // if next is null: we reached the end of the table.
       
   250             //
       
   251             if (next == null)
       
   252                 throw new
       
   253                     SnmpStatusException(SnmpStatusException.noSuchInstance);
       
   254 
       
   255             return next;
       
   256         } catch (RuntimeException x) {
       
   257             // debug. This should never happen.
       
   258             //
       
   259             if (dbg) log.debug("getNextOid",x);
       
   260             throw x;
       
   261         }
       
   262     }
       
   263 
       
   264 
       
   265     // See com.sun.jmx.snmp.agent.SnmpMibTable
       
   266     protected boolean contains(SnmpOid oid, Object userData) {
       
   267         // Get the handler.
       
   268         //
       
   269         SnmpTableHandler handler = getHandler(userData);
       
   270 
       
   271         // handler should never be null.
       
   272         //
       
   273         if (handler == null)
       
   274             return false;
       
   275         return filter.contains(handler,oid);
       
   276     }
       
   277 
       
   278     // See com.sun.jmx.snmp.agent.SnmpMibTable
       
   279     public Object getEntry(SnmpOid oid)
       
   280         throws SnmpStatusException {
       
   281 
       
   282         if (oid == null)
       
   283             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
       
   284 
       
   285         // Get the request contextual cache (userData).
       
   286         //
       
   287         final Map<Object, Object> m = JvmContextFactory.getUserData();
       
   288 
       
   289         // First look in the request contextual cache: maybe we've already
       
   290         // created this entry...
       
   291         //
       
   292 
       
   293         // We know in the case of this table that the index is an integer,
       
   294         // it is thus the first OID arc of the index OID.
       
   295         //
       
   296         final long   index    = oid.getOidArc(0);
       
   297 
       
   298         // We're going to use this name to store/retrieve the entry in
       
   299         // the request contextual cache.
       
   300         //
       
   301         // Revisit: Probably better programming to put all these strings
       
   302         //          in some interface.
       
   303         //
       
   304         final String entryTag = ((m==null)?null:("JvmMemGCTable.entry." +
       
   305                                                  index));
       
   306 
       
   307         // If the entry is in the cache, simply return it.
       
   308         //
       
   309         if (m != null) {
       
   310             final Object entry = m.get(entryTag);
       
   311             if (entry != null) return entry;
       
   312         }
       
   313 
       
   314         // Entry was not in request cache. Make a new one.
       
   315         //
       
   316         // Get the data hanler.
       
   317         //
       
   318         SnmpTableHandler handler = getHandler(m);
       
   319 
       
   320         // handler should never be null.
       
   321         //
       
   322         if (handler == null)
       
   323             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
       
   324 
       
   325         // Use the filter to retrieve only GarabageCollectorMBean data.
       
   326         //
       
   327         final Object data = filter.getData(handler,oid);
       
   328 
       
   329         // data may be null if the OID we were given is not valid.
       
   330         // (e.g. it identifies a MemoryManager which is not a
       
   331         // GarbageCollector)
       
   332         //
       
   333         if (data == null)
       
   334             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
       
   335 
       
   336         // Make a new entryy (transient object that will be kept only
       
   337         // for the duration of the request.
       
   338         //
       
   339         final Object entry =
       
   340             new JvmMemGCEntryImpl((GarbageCollectorMXBean)data,(int)index);
       
   341 
       
   342         // Put the entry in the request cache in case we need it later
       
   343         // in the processing of the request. Note that we could have
       
   344         // optimized this by making JvmMemGCEntryImpl extend
       
   345         // JvmMemManagerEntryImpl, and then make sure that
       
   346         // JvmMemManagerTableMetaImpl creates an instance of JvmMemGCEntryImpl
       
   347         // instead of JvmMemManagerEntryImpl when the associated data is
       
   348         // an instance of GarbageCollectorMXBean. This would have made it
       
   349         // possible to share the transient entry object.
       
   350         // As it is, we may have two transient objects that points to
       
   351         // the same underlying MemoryManagerMXBean (which is definitely
       
   352         // not a problem - but is only a small dysatisfaction)
       
   353         //
       
   354         if (m != null && entry != null) {
       
   355             m.put(entryTag,entry);
       
   356         }
       
   357 
       
   358         return entry;
       
   359     }
       
   360 
       
   361     static final MibLogger log = new MibLogger(JvmMemGCTableMetaImpl.class);
       
   362 }