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 // jmx imports
  28 //
  29 import javax.management.MBeanServer;
  30 import com.sun.jmx.snmp.SnmpStatusException;
  31 import com.sun.jmx.snmp.SnmpDefinitions;
  32 
  33 // jdmk imports
  34 //
  35 import com.sun.jmx.snmp.agent.SnmpMib;
  36 
  37 import java.util.Map;
  38 import java.lang.management.ManagementFactory;
  39 import java.lang.management.MemoryUsage;
  40 import java.lang.management.MemoryType;
  41 import java.lang.management.MemoryMXBean;
  42 import javax.management.openmbean.CompositeData;
  43 
  44 import sun.management.snmp.jvmmib.JvmMemoryMBean;
  45 import sun.management.snmp.jvmmib.EnumJvmMemoryGCCall;
  46 import sun.management.snmp.jvmmib.EnumJvmMemoryGCVerboseLevel;
  47 import sun.management.snmp.util.MibLogger;
  48 import sun.management.snmp.util.JvmContextFactory;
  49 
  50 /**
  51  * The class is used for implementing the "JvmMemory" group.
  52  */
  53 public class JvmMemoryImpl implements JvmMemoryMBean {
  54 
  55     /**
  56      * Variable for storing the value of "JvmMemoryGCCall".
  57      *
  58      * "This object makes it possible to remotelly trigger the
  59      * Garbage Collector in the JVM.
  60      *
  61      * This object's syntax is an enumeration which defines:
  62      *
  63      * * Two state values, that can be returned from a GET request:
  64      *
  65      * unsupported(1): means that remote invocation of gc() is not
  66      * supported by the SNMP agent.
  67      * supported(2)  : means that remote invocation of gc() is supported
  68      * by the SNMP agent.
  69      *
  70      * * One action value, that can be provided in a SET request to
  71      * trigger the garbage collector:
  72      *
  73      * start(3)      : means that a manager wishes to trigger
  74      * garbage collection.
  75      *
  76      * * Two result value, that will be returned as a result of a
  77      * SET request when remote invocation of gc is supported
  78      * by the SNMP agent:
  79      *
  80      * started(4)       : means that garbage collection was
  81      * successfully triggered. It does not mean
  82      * however that the action was successfullly
  83      * completed: gc might still be running when
  84      * this value is returned.
  85      * failed(5)     : means that garbage collection couldn't be
  86      * triggered.
  87      *
  88      * * If remote invocation is not supported by the SNMP agent, then
  89      * unsupported(1) will always be returned as a result of either
  90      * a GET request, or a SET request with start(3) as input value.
  91      *
  92      * * If a SET request with anything but start(3) is received, then
  93      * the agent will return a wrongValue error.
  94      *
  95      * See java.management.MemoryMXBean.gc()
  96      * "
  97      *
  98      */
  99     final static EnumJvmMemoryGCCall JvmMemoryGCCallSupported
 100         = new EnumJvmMemoryGCCall("supported");
 101     final static EnumJvmMemoryGCCall JvmMemoryGCCallStart
 102         = new EnumJvmMemoryGCCall("start");
 103     final static EnumJvmMemoryGCCall JvmMemoryGCCallFailed
 104         = new EnumJvmMemoryGCCall("failed");
 105     final static EnumJvmMemoryGCCall JvmMemoryGCCallStarted
 106         = new EnumJvmMemoryGCCall("started");
 107 
 108     /**
 109      * Variable for storing the value of "JvmMemoryGCVerboseLevel".
 110      *
 111      * "State of the -verbose:gc state.
 112      *
 113      * verbose: if the -verbose:gc flag is on,
 114      * silent:  otherwise.
 115      *
 116      * See java.management.MemoryMXBean.isVerbose(),
 117      * java.management.MemoryMXBean.setVerbose()
 118      * "
 119      *
 120      */
 121     final static EnumJvmMemoryGCVerboseLevel JvmMemoryGCVerboseLevelVerbose =
 122         new EnumJvmMemoryGCVerboseLevel("verbose");
 123     final static EnumJvmMemoryGCVerboseLevel JvmMemoryGCVerboseLevelSilent =
 124         new EnumJvmMemoryGCVerboseLevel("silent");
 125 
 126     /**
 127      * Constructor for the "JvmMemory" group.
 128      * If the group contains a table, the entries created through an
 129      * SNMP SET will not be registered in Java DMK.
 130      */
 131     public JvmMemoryImpl(SnmpMib myMib) {
 132     }
 133 
 134 
 135     /**
 136      * Constructor for the "JvmMemory" group.
 137      * If the group contains a table, the entries created through an
 138      * SNMP SET will be AUTOMATICALLY REGISTERED in Java DMK.
 139      */
 140     public JvmMemoryImpl(SnmpMib myMib, MBeanServer server) {
 141         // no entry will be registered since the table is virtual.
 142     }
 143 
 144     final static String heapMemoryTag = "jvmMemory.getHeapMemoryUsage";
 145     final static String nonHeapMemoryTag = "jvmMemory.getNonHeapMemoryUsage";
 146 
 147     private MemoryUsage getMemoryUsage(MemoryType type) {
 148         if (type == MemoryType.HEAP) {
 149             return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
 150         } else {
 151             return ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
 152         }
 153     }
 154 
 155     MemoryUsage getNonHeapMemoryUsage() {
 156         try {
 157             final Map<Object, Object> m = JvmContextFactory.getUserData();
 158 
 159             if (m != null) {
 160                 final MemoryUsage cached = (MemoryUsage)
 161                     m.get(nonHeapMemoryTag);
 162                 if (cached != null) {
 163                     log.debug("getNonHeapMemoryUsage",
 164                           "jvmMemory.getNonHeapMemoryUsage found in cache.");
 165                     return cached;
 166                 }
 167 
 168                 final MemoryUsage u = getMemoryUsage(MemoryType.NON_HEAP);
 169 
 170                 //  getNonHeapMemoryUsage() never returns null.
 171                 //
 172                 // if (u == null) u=MemoryUsage.INVALID;
 173 
 174                 m.put(nonHeapMemoryTag,u);
 175                 return u;
 176             }
 177             // Should never come here.
 178             // Log error!
 179             log.trace("getNonHeapMemoryUsage",
 180                       "ERROR: should never come here!");
 181             return getMemoryUsage(MemoryType.NON_HEAP);
 182         } catch (RuntimeException x) {
 183             log.trace("getNonHeapMemoryUsage",
 184                   "Failed to get NonHeapMemoryUsage: " + x);
 185             log.debug("getNonHeapMemoryUsage",x);
 186             throw x;
 187         }
 188 
 189     }
 190 
 191     MemoryUsage getHeapMemoryUsage() {
 192         try {
 193             final Map<Object, Object> m = JvmContextFactory.getUserData();
 194 
 195             if (m != null) {
 196                 final MemoryUsage cached = (MemoryUsage)m.get(heapMemoryTag);
 197                 if (cached != null) {
 198                     log.debug("getHeapMemoryUsage",
 199                           "jvmMemory.getHeapMemoryUsage found in cache.");
 200                     return cached;
 201                 }
 202 
 203                 final MemoryUsage u = getMemoryUsage(MemoryType.HEAP);
 204 
 205                 // getHeapMemoryUsage() never returns null.
 206                 //
 207                 // if (u == null) u=MemoryUsage.INVALID;
 208 
 209                 m.put(heapMemoryTag,u);
 210                 return u;
 211             }
 212 
 213             // Should never come here.
 214             // Log error!
 215             log.trace("getHeapMemoryUsage", "ERROR: should never come here!");
 216             return getMemoryUsage(MemoryType.HEAP);
 217         } catch (RuntimeException x) {
 218             log.trace("getHeapMemoryUsage",
 219                   "Failed to get HeapMemoryUsage: " + x);
 220             log.debug("getHeapMemoryUsage",x);
 221             throw x;
 222         }
 223     }
 224 
 225     static final Long Long0 = 0L;
 226 
 227     /**
 228      * Getter for the "JvmMemoryNonHeapMaxSize" variable.
 229      */
 230     public Long getJvmMemoryNonHeapMaxSize()
 231         throws SnmpStatusException {
 232         final long val = getNonHeapMemoryUsage().getMax();
 233         if (val > -1) return  val;
 234         else return Long0;
 235     }
 236 
 237     /**
 238      * Getter for the "JvmMemoryNonHeapCommitted" variable.
 239      */
 240     public Long getJvmMemoryNonHeapCommitted() throws SnmpStatusException {
 241         final long val = getNonHeapMemoryUsage().getCommitted();
 242         if (val > -1) return val;
 243         else return Long0;
 244     }
 245 
 246     /**
 247      * Getter for the "JvmMemoryNonHeapUsed" variable.
 248      */
 249     public Long getJvmMemoryNonHeapUsed() throws SnmpStatusException {
 250         final long val = getNonHeapMemoryUsage().getUsed();
 251         if (val > -1) return val;
 252         else return Long0;
 253     }
 254 
 255     /**
 256      * Getter for the "JvmMemoryNonHeapInitSize" variable.
 257      */
 258     public Long getJvmMemoryNonHeapInitSize() throws SnmpStatusException {
 259         final long val = getNonHeapMemoryUsage().getInit();
 260         if (val > -1) return val;
 261         else return Long0;
 262     }
 263 
 264     /**
 265      * Getter for the "JvmMemoryHeapMaxSize" variable.
 266      */
 267     public Long getJvmMemoryHeapMaxSize() throws SnmpStatusException {
 268         final long val = getHeapMemoryUsage().getMax();
 269         if (val > -1) return val;
 270         else return Long0;
 271     }
 272 
 273     /**
 274      * Getter for the "JvmMemoryGCCall" variable.
 275      */
 276     public EnumJvmMemoryGCCall getJvmMemoryGCCall()
 277         throws SnmpStatusException {
 278         final Map<Object,Object> m = JvmContextFactory.getUserData();
 279 
 280         if (m != null) {
 281             final EnumJvmMemoryGCCall cached
 282                 = (EnumJvmMemoryGCCall) m.get("jvmMemory.getJvmMemoryGCCall");
 283             if (cached != null) return cached;
 284         }
 285         return JvmMemoryGCCallSupported;
 286     }
 287 
 288     /**
 289      * Setter for the "JvmMemoryGCCall" variable.
 290      */
 291     public void setJvmMemoryGCCall(EnumJvmMemoryGCCall x)
 292         throws SnmpStatusException {
 293         if (x.intValue() == JvmMemoryGCCallStart.intValue()) {
 294             final Map<Object, Object> m = JvmContextFactory.getUserData();
 295 
 296             try {
 297                 ManagementFactory.getMemoryMXBean().gc();
 298                 if (m != null) m.put("jvmMemory.getJvmMemoryGCCall",
 299                                      JvmMemoryGCCallStarted);
 300             } catch (Exception ex) {
 301                 if (m != null) m.put("jvmMemory.getJvmMemoryGCCall",
 302                                      JvmMemoryGCCallFailed);
 303             }
 304             return;
 305         }
 306         throw new SnmpStatusException(SnmpDefinitions.snmpRspWrongValue);
 307     }
 308 
 309     /**
 310      * Checker for the "JvmMemoryGCCall" variable.
 311      */
 312     public void checkJvmMemoryGCCall(EnumJvmMemoryGCCall x)
 313         throws SnmpStatusException {
 314         if (x.intValue() != JvmMemoryGCCallStart.intValue())
 315         throw new SnmpStatusException(SnmpDefinitions.snmpRspWrongValue);
 316     }
 317 
 318     /**
 319      * Getter for the "JvmMemoryHeapCommitted" variable.
 320      */
 321     public Long getJvmMemoryHeapCommitted() throws SnmpStatusException {
 322         final long val = getHeapMemoryUsage().getCommitted();
 323         if (val > -1) return val;
 324         else return Long0;
 325     }
 326 
 327     /**
 328      * Getter for the "JvmMemoryGCVerboseLevel" variable.
 329      */
 330     public EnumJvmMemoryGCVerboseLevel getJvmMemoryGCVerboseLevel()
 331         throws SnmpStatusException {
 332         if (ManagementFactory.getMemoryMXBean().isVerbose())
 333             return JvmMemoryGCVerboseLevelVerbose;
 334         else
 335             return JvmMemoryGCVerboseLevelSilent;
 336     }
 337 
 338     /**
 339      * Setter for the "JvmMemoryGCVerboseLevel" variable.
 340      */
 341     public void setJvmMemoryGCVerboseLevel(EnumJvmMemoryGCVerboseLevel x)
 342         throws SnmpStatusException {
 343         if (JvmMemoryGCVerboseLevelVerbose.intValue() == x.intValue())
 344             ManagementFactory.getMemoryMXBean().setVerbose(true);
 345         else
 346             ManagementFactory.getMemoryMXBean().setVerbose(false);
 347     }
 348 
 349     /**
 350      * Checker for the "JvmMemoryGCVerboseLevel" variable.
 351      */
 352     public void checkJvmMemoryGCVerboseLevel(EnumJvmMemoryGCVerboseLevel x)
 353         throws SnmpStatusException {
 354         // Nothing to check...
 355     }
 356 
 357     /**
 358      * Getter for the "JvmMemoryHeapUsed" variable.
 359      */
 360     public Long getJvmMemoryHeapUsed() throws SnmpStatusException {
 361         final long val = getHeapMemoryUsage().getUsed();
 362         if (val > -1) return val;
 363         else return Long0;
 364     }
 365 
 366     /**
 367      * Getter for the "JvmMemoryHeapInitSize" variable.
 368      */
 369     public Long getJvmMemoryHeapInitSize() throws SnmpStatusException {
 370         final long val = getHeapMemoryUsage().getInit();
 371         if (val > -1) return val;
 372         else return Long0;
 373     }
 374 
 375     /**
 376      * Getter for the "JvmMemoryPendingFinalCount" variable.
 377      */
 378     public Long getJvmMemoryPendingFinalCount()
 379         throws SnmpStatusException {
 380         final long val = ManagementFactory.getMemoryMXBean().
 381             getObjectPendingFinalizationCount();
 382 
 383         if (val > -1) return val;
 384 
 385         // Should never happen... but stay safe all the same.
 386         //
 387         else return 0L;
 388     }
 389 
 390     static final MibLogger log = new MibLogger(JvmMemoryImpl.class);
 391 }