blob: 65b7b1b8852f2beed5dd540ddb7595e5c9a360dd [file] [log] [blame]
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.management.snmp.jvminstr;
// java imports
//
import java.util.Hashtable;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.lang.ref.WeakReference;
// jmx imports
//
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.InstanceAlreadyExistsException;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
import javax.management.Notification;
import javax.management.ListenerNotFoundException;
import javax.management.openmbean.CompositeData;
// jdmk imports
//
import com.sun.jmx.snmp.agent.SnmpMib;
import com.sun.jmx.snmp.daemon.SnmpAdaptorServer;
import com.sun.jmx.snmp.SnmpPeer;
import com.sun.jmx.snmp.SnmpParameters;
import com.sun.jmx.snmp.SnmpOidTable;
import com.sun.jmx.snmp.SnmpOid;
import com.sun.jmx.snmp.SnmpVarBindList;
import com.sun.jmx.snmp.SnmpVarBind;
import com.sun.jmx.snmp.SnmpCounter;
import com.sun.jmx.snmp.SnmpCounter64;
import com.sun.jmx.snmp.SnmpString;
import com.sun.jmx.snmp.SnmpInt;
import com.sun.jmx.snmp.Enumerated;
import com.sun.jmx.snmp.agent.SnmpMibTable;
import sun.management.snmp.jvmmib.JVM_MANAGEMENT_MIBOidTable;
import sun.management.snmp.jvmmib.JVM_MANAGEMENT_MIB;
import sun.management.snmp.jvmmib.JvmMemoryMeta;
import sun.management.snmp.jvmmib.JvmThreadingMeta;
import sun.management.snmp.jvmmib.JvmRuntimeMeta;
import sun.management.snmp.jvmmib.JvmClassLoadingMeta;
import sun.management.snmp.jvmmib.JvmCompilationMeta;
import sun.management.snmp.util.MibLogger;
import sun.management.snmp.util.SnmpCachedData;
import sun.management.snmp.util.SnmpTableHandler;
//java management imports
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryType;
public class JVM_MANAGEMENT_MIB_IMPL extends JVM_MANAGEMENT_MIB {
private static final long serialVersionUID = -8104825586888859831L;
private static final MibLogger log =
new MibLogger(JVM_MANAGEMENT_MIB_IMPL.class);
private static WeakReference<SnmpOidTable> tableRef;
public static SnmpOidTable getOidTable() {
SnmpOidTable table = null;
if(tableRef == null) {
table = new JVM_MANAGEMENT_MIBOidTable();
tableRef = new WeakReference<SnmpOidTable>(table);
return table;
}
table = tableRef.get();
if(table == null) {
table = new JVM_MANAGEMENT_MIBOidTable();
tableRef = new WeakReference<SnmpOidTable>(table);
}
return table;
}
/**
* Handler waiting for memory <CODE>Notification</CODE>.
* Translate each JMX notification in SNMP trap.
*/
private class NotificationHandler implements NotificationListener {
public void handleNotification(Notification notification,
Object handback) {
log.debug("handleNotification", "Received notification [ " +
notification.getType() + "]");
String type = notification.getType();
if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) ||
type.equals(MemoryNotificationInfo.
MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) {
MemoryNotificationInfo minfo = MemoryNotificationInfo.
from((CompositeData) notification.getUserData());
SnmpCounter64 count = new SnmpCounter64(minfo.getCount());
SnmpCounter64 used =
new SnmpCounter64(minfo.getUsage().getUsed());
SnmpString poolName = new SnmpString(minfo.getPoolName());
SnmpOid entryIndex =
getJvmMemPoolEntryIndex(minfo.getPoolName());
if (entryIndex == null) {
log.error("handleNotification",
"Error: Can't find entry index for Memory Pool: "
+ minfo.getPoolName() +": " +
"No trap emitted for " + type);
return;
}
SnmpOid trap = null;
final SnmpOidTable mibTable = getOidTable();
try {
SnmpOid usedOid = null;
SnmpOid countOid = null;
if (type.equals(MemoryNotificationInfo.
MEMORY_THRESHOLD_EXCEEDED)) {
trap = new SnmpOid(mibTable.
resolveVarName("jvmLowMemoryPoolUsageNotif").getOid());
usedOid =
new SnmpOid(mibTable.
resolveVarName("jvmMemPoolUsed").getOid() +
"." + entryIndex);
countOid =
new SnmpOid(mibTable.
resolveVarName("jvmMemPoolThreshdCount").getOid()
+ "." + entryIndex);
} else if (type.equals(MemoryNotificationInfo.
MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) {
trap = new SnmpOid(mibTable.
resolveVarName("jvmLowMemoryPoolCollectNotif").
getOid());
usedOid =
new SnmpOid(mibTable.
resolveVarName("jvmMemPoolCollectUsed").getOid() +
"." + entryIndex);
countOid =
new SnmpOid(mibTable.
resolveVarName("jvmMemPoolCollectThreshdCount").
getOid() +
"." + entryIndex);
}
//Datas
SnmpVarBindList list = new SnmpVarBindList();
SnmpOid poolNameOid =
new SnmpOid(mibTable.
resolveVarName("jvmMemPoolName").getOid() +
"." + entryIndex);
SnmpVarBind varCount = new SnmpVarBind(countOid, count);
SnmpVarBind varUsed = new SnmpVarBind(usedOid, used);
SnmpVarBind varPoolName = new SnmpVarBind(poolNameOid,
poolName);
list.add(varPoolName);
list.add(varCount);
list.add(varUsed);
sendTrap(trap, list);
}catch(Exception e) {
log.error("handleNotification",
"Exception occured : " + e);
}
}
}
}
/**
* List of notification targets.
*/
private ArrayList<NotificationTarget> notificationTargets =
new ArrayList<NotificationTarget>();
private final NotificationEmitter emitter;
private final NotificationHandler handler;
/**
* Instantiate a JVM MIB intrusmentation.
* A <CODE>NotificationListener</CODE> is added to the <CODE>MemoryMXBean</CODE>
* <CODE>NotificationEmitter</CODE>
*/
public JVM_MANAGEMENT_MIB_IMPL() {
handler = new NotificationHandler();
emitter = (NotificationEmitter) ManagementFactory.getMemoryMXBean();
emitter.addNotificationListener(handler, null, null);
}
private synchronized void sendTrap(SnmpOid trap, SnmpVarBindList list) {
final Iterator iterator = notificationTargets.iterator();
final SnmpAdaptorServer adaptor =
(SnmpAdaptorServer) getSnmpAdaptor();
if (adaptor == null) {
log.error("sendTrap", "Cannot send trap: adaptor is null.");
return;
}
if (!adaptor.isActive()) {
log.config("sendTrap", "Adaptor is not active: trap not sent.");
return;
}
while(iterator.hasNext()) {
NotificationTarget target = null;
try {
target = (NotificationTarget) iterator.next();
SnmpPeer peer =
new SnmpPeer(target.getAddress(), target.getPort());
SnmpParameters p = new SnmpParameters();
p.setRdCommunity(target.getCommunity());
peer.setParams(p);
log.debug("handleNotification", "Sending trap to " +
target.getAddress() + ":" + target.getPort());
adaptor.snmpV2Trap(peer, trap, list, null);
}catch(Exception e) {
log.error("sendTrap",
"Exception occured while sending trap to [" +
target + "]. Exception : " + e);
log.debug("sendTrap",e);
}
}
}
/**
* Add a notification target.
* @param target The target to add
* @throws IllegalArgumentException If target parameter is null.
*/
public synchronized void addTarget(NotificationTarget target)
throws IllegalArgumentException {
if(target == null)
throw new IllegalArgumentException("Target is null");
notificationTargets.add(target);
}
/**
* Remove notification listener.
*/
public void terminate() {
try {
emitter.removeNotificationListener(handler);
}catch(ListenerNotFoundException e) {
log.error("terminate", "Listener Not found : " + e);
}
}
/**
* Add notification targets.
* @param targets A list of
* <CODE>sun.management.snmp.jvminstr.NotificationTarget</CODE>
* @throws IllegalArgumentException If targets parameter is null.
*/
public synchronized void addTargets(List<NotificationTarget> targets)
throws IllegalArgumentException {
if(targets == null)
throw new IllegalArgumentException("Target list is null");
notificationTargets.addAll(targets);
}
/**
* Factory method for "JvmMemory" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmMemory")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmMemory" group (JvmMemory)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmMemoryMBean"
* interface.
**/
protected Object createJvmMemoryMBean(String groupName,
String groupOid, ObjectName groupObjname,
MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmMemoryMBean"
// interface.
//
if (server != null)
return new JvmMemoryImpl(this,server);
else
return new JvmMemoryImpl(this);
}
/**
* Factory method for "JvmMemory" group metadata class.
*
* You can redefine this method if you need to replace the default
* generated metadata class with your own customized class.
*
* @param groupName Name of the group ("JvmMemory")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the metadata class generated for the
* "JvmMemory" group (JvmMemoryMeta)
*
**/
protected JvmMemoryMeta createJvmMemoryMetaNode(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
return new JvmMemoryMetaImpl(this, objectserver);
}
/**
* Factory method for "JvmThreading" group metadata class.
*
* You can redefine this method if you need to replace the default
* generated metadata class with your own customized class.
*
* @param groupName Name of the group ("JvmThreading")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the metadata class generated for the
* "JvmThreading" group (JvmThreadingMeta)
*
**/
protected JvmThreadingMeta createJvmThreadingMetaNode(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
return new JvmThreadingMetaImpl(this, objectserver);
}
/**
* Factory method for "JvmThreading" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmThreading")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmThreading" group (JvmThreading)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmThreadingMBean"
* interface.
**/
protected Object createJvmThreadingMBean(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmThreadingMBean"
// interface.
//
if (server != null)
return new JvmThreadingImpl(this,server);
else
return new JvmThreadingImpl(this);
}
/**
* Factory method for "JvmRuntime" group metadata class.
*
* You can redefine this method if you need to replace the default
* generated metadata class with your own customized class.
*
* @param groupName Name of the group ("JvmRuntime")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the metadata class generated for the
* "JvmRuntime" group (JvmRuntimeMeta)
*
**/
protected JvmRuntimeMeta createJvmRuntimeMetaNode(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
return new JvmRuntimeMetaImpl(this, objectserver);
}
/**
* Factory method for "JvmRuntime" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmRuntime")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmRuntime" group (JvmRuntime)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmRuntimeMBean"
* interface.
**/
protected Object createJvmRuntimeMBean(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmRuntimeMBean"
// interface.
//
if (server != null)
return new JvmRuntimeImpl(this,server);
else
return new JvmRuntimeImpl(this);
}
/**
* Factory method for "JvmCompilation" group metadata class.
*
* You can redefine this method if you need to replace the default
* generated metadata class with your own customized class.
*
* @param groupName Name of the group ("JvmCompilation")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the metadata class generated for the
* "JvmCompilation" group (JvmCompilationMeta)
*
**/
protected JvmCompilationMeta
createJvmCompilationMetaNode(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
// If there is no compilation system, the jvmCompilation will not
// be instantiated.
//
if (ManagementFactory.getCompilationMXBean() == null) return null;
return super.createJvmCompilationMetaNode(groupName,groupOid,
groupObjname,server);
}
/**
* Factory method for "JvmCompilation" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmCompilation")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmCompilation" group (JvmCompilation)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmCompilationMBean"
* interface.
**/
protected Object createJvmCompilationMBean(String groupName,
String groupOid, ObjectName groupObjname, MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmCompilationMBean"
// interface.
//
if (server != null)
return new JvmCompilationImpl(this,server);
else
return new JvmCompilationImpl(this);
}
/**
* Factory method for "JvmOS" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmOS")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmOS" group (JvmOS)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmOSMBean"
* interface.
**/
protected Object createJvmOSMBean(String groupName,
String groupOid, ObjectName groupObjname, MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmOSMBean"
// interface.
//
if (server != null)
return new JvmOSImpl(this,server);
else
return new JvmOSImpl(this);
}
/**
* Factory method for "JvmClassLoading" group MBean.
*
* You can redefine this method if you need to replace the default
* generated MBean class with your own customized class.
*
* @param groupName Name of the group ("JvmClassLoading")
* @param groupOid OID of this group
* @param groupObjname ObjectName for this group (may be null)
* @param server MBeanServer for this group (may be null)
*
* @return An instance of the MBean class generated for the
* "JvmClassLoading" group (JvmClassLoading)
*
* Note that when using standard metadata,
* the returned object must implement the "JvmClassLoadingMBean"
* interface.
**/
protected Object createJvmClassLoadingMBean(String groupName,
String groupOid,
ObjectName groupObjname,
MBeanServer server) {
// Note that when using standard metadata,
// the returned object must implement the "JvmClassLoadingMBean"
// interface.
//
if (server != null)
return new JvmClassLoadingImpl(this,server);
else
return new JvmClassLoadingImpl(this);
}
static String validDisplayStringTC(String str) {
if(str == null) return "";
if(str.length() > DISPLAY_STRING_MAX_LENGTH) {
return str.substring(0, DISPLAY_STRING_MAX_LENGTH);
}
else
return str;
}
static String validJavaObjectNameTC(String str) {
if(str == null) return "";
if(str.length() > JAVA_OBJECT_NAME_MAX_LENGTH) {
return str.substring(0, JAVA_OBJECT_NAME_MAX_LENGTH);
}
else
return str;
}
static String validPathElementTC(String str) {
if(str == null) return "";
if(str.length() > PATH_ELEMENT_MAX_LENGTH) {
return str.substring(0, PATH_ELEMENT_MAX_LENGTH);
}
else
return str;
}
static String validArgValueTC(String str) {
if(str == null) return "";
if(str.length() > ARG_VALUE_MAX_LENGTH) {
return str.substring(0, ARG_VALUE_MAX_LENGTH);
}
else
return str;
}
/**
* WARNING: This should probably be moved to JvmMemPoolTableMetaImpl
**/
private SnmpTableHandler getJvmMemPoolTableHandler(Object userData) {
final SnmpMibTable meta =
getRegisteredTableMeta("JvmMemPoolTable");
if (! (meta instanceof JvmMemPoolTableMetaImpl)) {
final String err = ((meta==null)?"No metadata for JvmMemPoolTable":
"Bad metadata class for JvmMemPoolTable: " +
meta.getClass().getName());
log.error("getJvmMemPoolTableHandler", err);
return null;
}
final JvmMemPoolTableMetaImpl memPoolTable =
(JvmMemPoolTableMetaImpl) meta;
return memPoolTable.getHandler(userData);
}
/**
* WARNING: This should probably be moved to JvmMemPoolTableMetaImpl
**/
private int findInCache(SnmpTableHandler handler,
String poolName) {
if (!(handler instanceof SnmpCachedData)) {
if (handler != null) {
final String err = "Bad class for JvmMemPoolTable datas: " +
handler.getClass().getName();
log.error("getJvmMemPoolEntry", err);
}
return -1;
}
final SnmpCachedData data = (SnmpCachedData)handler;
final int len = data.datas.length;
for (int i=0; i < data.datas.length ; i++) {
final MemoryPoolMXBean pool = (MemoryPoolMXBean) data.datas[i];
if (poolName.equals(pool.getName())) return i;
}
return -1;
}
/**
* WARNING: This should probably be moved to JvmMemPoolTableMetaImpl
**/
private SnmpOid getJvmMemPoolEntryIndex(SnmpTableHandler handler,
String poolName) {
final int index = findInCache(handler,poolName);
if (index < 0) return null;
return ((SnmpCachedData)handler).indexes[index];
}
private SnmpOid getJvmMemPoolEntryIndex(String poolName) {
return getJvmMemPoolEntryIndex(getJvmMemPoolTableHandler(null),
poolName);
}
// cache validity
//
// Should we define a property for this? Should we have different
// cache validity periods depending on which table we cache?
//
public long validity() {
return DEFAULT_CACHE_VALIDITY_PERIOD;
}
// Defined in RFC 2579
private final static int DISPLAY_STRING_MAX_LENGTH=255;
private final static int JAVA_OBJECT_NAME_MAX_LENGTH=1023;
private final static int PATH_ELEMENT_MAX_LENGTH=1023;
private final static int ARG_VALUE_MAX_LENGTH=1023;
private final static int DEFAULT_CACHE_VALIDITY_PERIOD=1000;
}