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 com.sun.jmx.mbeanserver.Util;
  31 import java.io.Serializable;
  32 import java.util.List;
  33 import java.util.Map;
  34 import java.util.TreeMap;
  35 
  36 // jmx imports
  37 //
  38 import com.sun.jmx.snmp.SnmpOid;
  39 import com.sun.jmx.snmp.SnmpStatusException;
  40 
  41 // jdmk imports
  42 //
  43 import com.sun.jmx.snmp.agent.SnmpMib;
  44 import com.sun.jmx.snmp.agent.SnmpStandardObjectServer;
  45 
  46 import java.lang.management.MemoryManagerMXBean;
  47 import java.lang.management.ManagementFactory;
  48 
  49 import sun.management.snmp.jvmmib.JvmMemManagerTableMeta;
  50 import sun.management.snmp.util.SnmpTableCache;
  51 import sun.management.snmp.util.SnmpNamedListTableCache;
  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 "JvmMemManagerTable" table.
  58  *
  59  * This custom implementation show how to implement an SNMP table
  60  * over a weak cache, recomputing the cahed data when needed.
  61  */
  62 public class JvmMemManagerTableMetaImpl extends JvmMemManagerTableMeta {
  63 
  64     static final long serialVersionUID = 36176771566817592L;
  65 
  66     /**
  67      * A concrete implementation of {@link SnmpNamedListTableCache}, for the
  68      * jvmMemManagerTable.
  69      **/
  70     private static class JvmMemManagerTableCache
  71         extends SnmpNamedListTableCache {
  72 
  73         static final long serialVersionUID = 6564294074653009240L;
  74 
  75         /**
  76          * Create a weak cache for the jvmMemManagerTable.
  77          * @param validity validity of the cached data, in ms.
  78          **/
  79         JvmMemManagerTableCache(long validity) {
  80             this.validity = validity;
  81         }
  82 
  83         /**
  84          * Use the MemoryManagerMXBean name as key.
  85          * @param context A {@link TreeMap} as allocated by the parent
  86          *        {@link SnmpNamedListTableCache} class.
  87          * @param rawDatas List of {@link MemoryManagerMXBean}, as
  88          *        returned by
  89          * <code>ManagementFactory.getMemoryMBean().getMemoryManagers()</code>
  90          * @param rank The <var>rank</var> of <var>item</var> in the list.
  91          * @param item The <var>rank</var><super>th</super>
  92          *        <code>MemoryManagerMXBean</code> in the list.
  93          * @return  <code>((MemoryManagerMXBean)item).getName()</code>
  94          **/
  95         protected String getKey(Object context, List<?> rawDatas,
  96                                 int rank, Object item) {
  97             if (item == null) return null;
  98             final String name = ((MemoryManagerMXBean)item).getName();
  99             log.debug("getKey", "key=" + name);
 100             return name;
 101         }
 102 
 103         /**
 104          * Call <code>getTableHandler(JvmContextFactory.getUserData())</code>.
 105          **/
 106         public SnmpTableHandler getTableHandler() {
 107             final Map<Object, Object> userData = JvmContextFactory.getUserData();
 108             return getTableDatas(userData);
 109         }
 110 
 111         /**
 112          * Return the key used to cache the raw data of this table.
 113          **/
 114         protected String getRawDatasKey() {
 115             return "JvmMemManagerTable.getMemoryManagers";
 116         }
 117 
 118         /**
 119          * Call ManagementFactory.getMemoryManagerMXBeans() to
 120          * load the raw data of this table.
 121          **/
 122         protected List<MemoryManagerMXBean> loadRawDatas(Map<Object, Object> userData) {
 123             return ManagementFactory.getMemoryManagerMXBeans();
 124         }
 125 
 126     }
 127 
 128     // The weak cache for this table.
 129     protected SnmpTableCache cache;
 130 
 131     /**
 132      * Constructor for the table. Initialize metadata for
 133      * "JvmMemManagerTableMeta".
 134      * The reference on the MBean server is updated so the entries
 135      * created through an SNMP SET will be AUTOMATICALLY REGISTERED
 136      * in Java DMK.
 137      */
 138     public JvmMemManagerTableMetaImpl(SnmpMib myMib,
 139                                       SnmpStandardObjectServer objserv) {
 140         super(myMib,objserv);
 141         this.cache = new
 142             JvmMemManagerTableCache(((JVM_MANAGEMENT_MIB_IMPL)myMib).
 143                                     validity());
 144     }
 145 
 146     // See com.sun.jmx.snmp.agent.SnmpMibTable
 147     protected SnmpOid getNextOid(Object userData)
 148         throws SnmpStatusException {
 149         // null means get the first OID.
 150         return getNextOid(null,userData);
 151     }
 152 
 153     // See com.sun.jmx.snmp.agent.SnmpMibTable
 154     protected SnmpOid getNextOid(SnmpOid oid, Object userData)
 155         throws SnmpStatusException {
 156         final boolean dbg = log.isDebugOn();
 157         if (dbg) log.debug("getNextOid", "previous=" + oid);
 158 
 159 
 160         // Get the data handler.
 161         //
 162         SnmpTableHandler handler = getHandler(userData);
 163         if (handler == null) {
 164             // This should never happen.
 165             // If we get here it's a bug.
 166             //
 167             if (dbg) log.debug("getNextOid", "handler is null!");
 168             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
 169         }
 170 
 171         // Get the next oid
 172         //
 173         final SnmpOid next = handler.getNext(oid);
 174         if (dbg) log.debug("getNextOid", "next=" + next);
 175 
 176         // if next is null: we reached the end of the table.
 177         //
 178         if (next == null)
 179             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
 180 
 181         return next;
 182     }
 183 
 184 
 185     // See com.sun.jmx.snmp.agent.SnmpMibTable
 186     protected boolean contains(SnmpOid oid, Object userData) {
 187 
 188         // Get the handler.
 189         //
 190         SnmpTableHandler handler = getHandler(userData);
 191 
 192         // handler should never be null.
 193         //
 194         if (handler == null)
 195             return false;
 196 
 197         return handler.contains(oid);
 198     }
 199 
 200     // See com.sun.jmx.snmp.agent.SnmpMibTable
 201     public Object getEntry(SnmpOid oid)
 202         throws SnmpStatusException {
 203 
 204         if (oid == null)
 205             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
 206 
 207         // Get the request contextual cache (userData).
 208         //
 209         final Map<Object, Object> m = JvmContextFactory.getUserData();
 210 
 211         // We know in the case of this table that the index is an integer,
 212         // it is thus the first OID arc of the index OID.
 213         //
 214         final long   index    = oid.getOidArc(0);
 215 
 216         // We're going to use this name to store/retrieve the entry in
 217         // the request contextual cache.
 218         //
 219         // Revisit: Probably better programming to put all these strings
 220         //          in some interface.
 221         //
 222         final String entryTag = ((m==null)?null:("JvmMemManagerTable.entry." +
 223                                                  index));
 224 
 225         // If the entry is in the cache, simply return it.
 226         //
 227         if (m != null) {
 228             final Object entry = m.get(entryTag);
 229             if (entry != null) return entry;
 230         }
 231 
 232         // The entry was not in the cache, make a new one.
 233         //
 234         // Get the data hanler.
 235         //
 236         SnmpTableHandler handler = getHandler(m);
 237 
 238         // handler should never be null.
 239         //
 240         if (handler == null)
 241             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
 242 
 243         // Get the data associated with our entry.
 244         //
 245         final Object data = handler.getData(oid);
 246 
 247         // data may be null if the OID we were given is not valid.
 248         //
 249         if (data == null)
 250             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
 251 
 252         // make the new entry (transient object that will be kept only
 253         // for the duration of the request.
 254         //
 255         final Object entry =
 256             new JvmMemManagerEntryImpl((MemoryManagerMXBean)data,(int)index);
 257 
 258         // Put the entry in the cache in case we need it later while processing
 259         // the request.
 260         //
 261         if (m != null && entry != null) {
 262             m.put(entryTag,entry);
 263         }
 264 
 265         return entry;
 266     }
 267 
 268     /**
 269      * Get the SnmpTableHandler that holds the jvmMemManagerTable data.
 270      * First look it up in the request contextual cache, and if it is
 271      * not found, obtain it from the weak cache.
 272      * <br>The request contextual cache will be released at the end of the
 273      * current requests, and is used only to process this request.
 274      * <br>The weak cache is shared by all requests, and is only
 275      * recomputed when it is found to be obsolete.
 276      * <br>Note that the data put in the request contextual cache is
 277      *     never considered to be obsolete, in order to preserve data
 278      *     coherency.
 279      **/
 280     protected SnmpTableHandler getHandler(Object userData) {
 281         final Map<Object, Object> m;
 282         if (userData instanceof Map) m=Util.cast(userData);
 283         else m=null;
 284 
 285         // Look in the contextual cache.
 286         if (m != null) {
 287             final SnmpTableHandler handler =
 288                 (SnmpTableHandler)m.get("JvmMemManagerTable.handler");
 289             if (handler != null) return handler;
 290         }
 291 
 292         // No handler in contextual cache, make a new one.
 293         final SnmpTableHandler handler = cache.getTableHandler();
 294 
 295         if (m != null && handler != null )
 296             m.put("JvmMemManagerTable.handler",handler);
 297 
 298         return handler;
 299     }
 300 
 301     static final MibLogger log =
 302         new MibLogger(JvmMemManagerTableMetaImpl.class);
 303 }