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 }