All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nyla.solutions.global.patterns.jmx.JMX Maven / Gradle / Ivy

package nyla.solutions.global.patterns.jmx;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.ThreadMXBean;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.management.AttributeChangeNotification;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import nyla.solutions.global.patterns.Disposable;


/**
 * Wrapper class that interfaces with JMX
 * 
 *  Sample URL 
 *  "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi";
 *  String urlText = "service:jmx:rmi:///jndi/rmi://host:port/jmxrmi";
 *  
 *  
 *    This object is based JMX object in the NYLA Java framework
 *    
 *    @link https://github.com/ggreen/nyla/blob/master/dev/Solutions.Global/src/main/java/nyla/solutions/global/patterns/jmx/JMX.java
 *    
 * @author Gregory Green
 *
 */
public class JMX implements AutoCloseable, Disposable
{
   /**
    * MemoryMX_NAME = "java.lang:type=Memory"
    */
   private static final String MemoryMX_NAME = "java.lang:type=Memory";
   
   /**
    * ThreadMX_NAME = "java.lang:type=Threading"
    */
   private static final String ThreadMX_NAME = "java.lang:type=Threading";
   
   /**
	 *
	 * @return RuntimeMXBean.getSystemProperties
	 */
	public String getSystemProperty(String key)
	throws MalformedObjectNameException, InstanceNotFoundException
	{
		TabularData td =getAttribute(new ObjectName("java.lang:type=Runtime"), "SystemProperties");
		
		String [] keyArray = {key};
		
		 CompositeData cd = td.get(keyArray);
		 
		 return toText(cd);
		 
	}// --------------------------------------------------------
	public String toText(CompositeData cd)
	{ 
		if(cd == null)
			return null;
		
		 Object property = cd.get("value");
		 
		 return String.valueOf(property);
	}// --------------------------------------------------------
   /**
    * >p>Invokes an operation on an MBean.

* @param objectName * @param operationName * @param params * @param signature * @return */ public Object invoke(ObjectName objectName,String operationName,Object[] params, String[] signature) { return invoke(null, objectName, operationName,params, signature); }// -------------------------------------------------------- /** * >p>Invokes an operation on an MBean.

* @param objectName * @param operationName * @param params * @param signature * @return */ public Object invoke(Class interfaceClass, ObjectName objectName,String operationName,Object[] params, String[] signature) { try { if(interfaceClass != null) javax.management.JMX.newMBeanProxy(connection, objectName, interfaceClass); return this.connection.invoke(objectName, operationName, params, signature); } catch(Exception e) { throw new RuntimeException("Unable to invoke objectName:"+objectName+ " operationName:"+operationName,e); } }// -------------------------------------------------------- @SuppressWarnings("unchecked") public T newBean(Class interfaceClass, ObjectName objectName) { if(interfaceClass == null) return null; return (T)javax.management.JMX.newMBeanProxy(connection, objectName, interfaceClass); }// -------------------------------------------------------- /** * * @param objectName * @param attributes * @return the attributes for the given object name */ @SuppressWarnings("unchecked") public T getAttribute(ObjectName objectName, String attribute) throws InstanceNotFoundException { try { return (T)this.connection.getAttribute(objectName, attribute); } catch(InstanceNotFoundException e) { throw e; } catch(Exception e) { throw new RuntimeException("Unable to get attributes objectName:"+objectName+ " attribute:"+attribute,e); } }// -------------------------------------------------------- /** * Connect to a remote JMX server * @param connectionURL (example: service:jmx:rmi:///jndi/rmi://host:9999/jmxrmi) * @param userName the user name * @param password the user's password */ private JMX(String host,int port, String userName, char[] password) { this.host = host; this.port = port; String connectionURL = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host,port); if (connectionURL == null || connectionURL.length() == 0) throw new IllegalArgumentException("connectionURL"); try { JMXServiceURL url = new JMXServiceURL(connectionURL); Map map = null; //Populate credentials if(userName != null && userName.length() > 0) { map = new HashMap(); if(password == null || password.length == 0) throw new SecurityException("password required"); String[] credentials = new String[]{ userName, new String(password) }; map.put(JMXConnector.CREDENTIALS, credentials); } jmxc = JMXConnectorFactory.connect(url, map); connection = jmxc.getMBeanServerConnection(); } catch (SecurityException e) { if(userName == null || userName.length() ==0 || password == null || password.length ==0) { throw new JMXSecurityException("Security exception: Add "+JmxSecurity.JMX_PROPERTY_FILE_NM+" to classpath the provide valid"+ " values for properties \""+JmxSecurity.JMX_USERNAME_PROP+"\" and \""+JmxSecurity.JMX_PASSWORD_PROP+"\""); } throw new JMXSecurityException("Cannot authenticate username:"+userName+" to connectionURL="+connectionURL+" error:"+e.getMessage(), e); } catch (Exception e) { throw new JMXConnectionException("Cannot connect to URL="+connectionURL+" ERROR:"+e.getMessage()); } }// ---------------------------------------------- public static List getLocalRuntimeArguments() { return ManagementFactory.getRuntimeMXBean().getInputArguments(); }// ----------------------------------------------- /** * * @param host the JMX host * @param port the jmx port * @return */ public static JMX connect(String host, int port) { return connect(host,port,JmxSecurity.getJmxUserName(),JmxSecurity.getJmxPassword()); }// -------------------------------------------------------- public static JMX connect(String host, int port, String user, char[] password) { return new JMX(host,port,user,password); }// -------------------------------------------------------- /** * @return domains from connection * @throws IOException * @see javax.management.MBeanServerConnection#getDomains() */ public String[] getDomains() throws IOException { return connection.getDomains(); }// ---------------------------------------------- public Set queryMBeans(ObjectName objectName,QueryExp queryExp) throws IOException { return this.jmxc.getMBeanServerConnection().queryMBeans(objectName, queryExp); }// -------------------------------------------------------- /** * * @param args (URL) (user) (password) * @throws Exception */ public static void main(String[] args) throws Exception { String host = null; int port; String userName = null; char[] password = null; if(args.length < 2) { System.out.println("Usage java "+JMX.class.getCanonicalName()+" host port (userName password)?"); System.exit(-1); } host = args[0]; port = Integer.parseInt(args[1]); if(args.length > 2) { if(args.length < 4) { System.out.println("Usage java "+JMX.class.getCanonicalName()+" host port userName password"); System.exit(-1); } userName = args[2]; password = args[3].toCharArray(); } JMX jmx = JMX.connect(host,port, userName, password); // Get domains from MBeanServer // System.out.println("\nDomains:"); String[] domains = jmx.getDomains(); Arrays.sort(domains); for (int i = 0; i < domains.length; i++) { System.out.println("\tDomain = " + domains[i]); } //waitForEnterPressed(); // Get MBeanServer's default domain // System.out.println("\nMBeanServer default domain = " + jmx.getDefaultDomain()); // Get MBean count // System.out.println("\nMBean count = " + jmx.getMBeanCount()); // Query MBean names // System.out.println("\nQuery MBeanServer MBeans:"); Set names =jmx.searchObjectNames(null); ObjectName objectName = null; for (Iterator itera = names.iterator();itera.hasNext();) { objectName = itera.next(); System.out.println("getCanonicalName="+objectName.getCanonicalName()); } System.out.println("=========Memory Usage========="); MemoryMXBean memory = jmx.getMemory(); System.out.println("memory.getObjectPendingFinalizationCount="+memory.getObjectPendingFinalizationCount()); MemoryUsage memoryUsage = memory.getHeapMemoryUsage(); System.out.println("memory.getCommitted="+memoryUsage.getCommitted()); System.out.println("memory.getUsed="+memoryUsage.getUsed()); System.out.println("=========Thread Usage========="); ThreadMXBean thread = jmx.getThread(); System.out.println("thread.getPeakThreadCount="+thread.getPeakThreadCount()); System.out.println("thread.getDaemonThreadCount="+thread.getDaemonThreadCount()); System.out.println("thread.getThreadCount="+thread.getThreadCount()); System.out.println("thread.getTotalStartedThreadCount="+thread.getTotalStartedThreadCount()); jmx.registerMemoryNotifications(new ClientListener(), null); System.out.println("Enter key to exit"); System.in.read(); }// ---------------------------------------------- public static class ClientListener implements NotificationListener { public void handleNotification(Notification notification, Object handback) { System.out.println("\nReceived notification:"); System.out.println("\tClassName: " + notification.getClass().getName()); System.out.println("\tSource: " + notification.getSource()); System.out.println("\tType: " + notification.getType()); System.out.println("\tMessage: " + notification.getMessage()); if (notification instanceof AttributeChangeNotification) { AttributeChangeNotification acn = (AttributeChangeNotification) notification; System.out.println("\tAttributeName: " + acn.getAttributeName()); System.out.println("\tAttributeType: " + acn.getAttributeType()); System.out.println("\tNewValue: " + acn.getNewValue()); System.out.println("\tOldValue: " + acn.getOldValue()); } } } /** * @return * @throws IOException * @see javax.management.MBeanServerConnection#getDefaultDomain() */ public String getDefaultDomain() throws IOException { return connection.getDefaultDomain(); } /** * @return * @throws IOException * @see javax.management.MBeanServerConnection#getMBeanCount() */ public Integer getMBeanCount() throws IOException { return connection.getMBeanCount(); } /** * @param objectName ex: GemFire:*,name=* * @param queryExp * @return * @throws IOException * @see javax.management.MBeanServerConnection#queryNames(javax.management.ObjectName, javax.management.QueryExp) */ public Set searchObjectNames(String objectNamePattern) { return searchObjectNames(objectNamePattern,null); }// -------------------------------------------------------- /** * * Example Query * * QueryExp query = Query.and(Query.eq(Query.attr("Enabled"), Query.value(true)), Query.eq(Query.attr("Owner"), Query.value("Duke"))); * * @param objectNamePattern the object names to look for * @param queryExp the query express * @return */ public Set searchObjectNames(String objectNamePattern, QueryExp queryExp) { try { ObjectName objectName = null; if(objectNamePattern != null) objectName = new ObjectName(objectNamePattern); return connection.queryNames(objectName, queryExp); } catch (MalformedObjectNameException e) { throw new RuntimeException("Invalid objectNamePattern"+objectNamePattern,e); } catch (IOException e) { throw new RuntimeException("Unable to query names with objectNamePattern:"+objectNamePattern,e); } }// -------------------------------------------------------- /** * * @return MemoryMXBean referred by java.lang:type=Memory */ public MemoryMXBean getMemory() { try { return (MemoryMXBean)ManagementFactory.newPlatformMXBeanProxy(connection, MemoryMX_NAME, MemoryMXBean.class); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } }// ---------------------------------------------- /** * * @return MBean with TheadMX_NAME = "java.lang:type=Threading" */ public ThreadMXBean getThread() { try { return (ThreadMXBean)ManagementFactory.newPlatformMXBeanProxy(connection, ThreadMX_NAME, ThreadMXBean.class); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } }// ---------------------------------------------- /** * Implements the disposable interface to close the JMX connection */ public void dispose() { if(!disposed) { try { jmxc.close(); } catch(Exception e) {} } disposed = true; }// ---------------------------------------------- /** * Print warning is JMC connection were not closed */ // protected void finalize() throws Throwable // { // super.finalize(); // // //if(this.connection != null || this.jmxc != null) // // System.err.println(this+" MEMORY LEAK, JMX connection has not been closed!"); // }// ---------------------------------------------- /** * * Adds a listener to a registered MBean. Notifications emitted by the MBean will be forwarded to the listener. * @param name - The name of the MBean on which the listener should be added. * @param listener - The listener object which will handle the notifications emitted by the registered MBean. * @param filter - The filter object. If filter is null, no filtering will be performed before handling notifications. * @param handback - The context to be sent to the listener when a notification is emitted. * @throws InstanceNotFoundException * @throws IOException */ public void addNotificationListener(ObjectName objectName, NotificationListener notificationListener, NotificationFilter notificationFilter, Object handback) throws InstanceNotFoundException, IOException { connection.addNotificationListener(objectName, notificationListener, notificationFilter, handback); }// ---------------------------------------------- /** * Allows a listener to be registered within the MemoryMXBean as a notification listener * usage threshold exceeded notification - for notifying that the memory usage of a memory pool is increased * and has reached or exceeded its usage threshold value. * * collection usage threshold exceeded notification - for notifying that the memory usage * of a memory pool is greater than or equal to its collection usage threshold * after the Java virtual machine has expended effort in recycling unused objects in that memory pool. * * The notification emitted is a Notification instance whose user data is set to a CompositeData that * represents a MemoryNotificationInfo object containing information about the memory pool when the * notification was constructed. The CompositeData contains the attributes as described in MemoryNotificationInfo. * * @param notificationListener listener to be alerted * @param handback object to be passed back to notification listener when notification occurs */ public void registerMemoryNotifications(NotificationListener notificationListener, Object handback) { NotificationEmitter emitter = (NotificationEmitter) this.getMemory(); emitter.addNotificationListener(notificationListener, null, handback); }// ---------------------------------------------- /** * @return the host */ public String getHost() { return host; } /** * @return the port */ public int getPort() { return port; }// -------------------------------------------------------- @Override public void close() { this.dispose(); } private final JMXConnector jmxc; private boolean disposed = false; private final MBeanServerConnection connection; private final String host; private final int port; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy