Thursday, 4 September 2008

Displaying OC4J JVM MBean Statistics from a JMX Client

The JVM Mbean within an OC4J 10.1.3.x container has some useful statistic which are displayed in ASC MBean browser. Here is some code which shows how to obtain those from a JMX client.

So the MBean we want to access is as follows:

oc4j:j2eeType=JVM,name=single,J2EEServer=standalone

And the statistics we want to display which ASC shows for us are as follows:

  • FreeHeapSize
  • ActiveThreads
  • HeapSize
So here is the code we will use from a JMX Client. The method which obtains the statistics we need is called "showStats(ObjectName)"


package oracle.support.oc4j.standalone;

import java.text.DateFormat;

import java.util.Date;
import java.util.logging.Logger;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.j2ee.statistics.JVMStats;
import javax.management.j2ee.statistics.Statistic;
import javax.management.j2ee.statistics.BoundedRangeStatistic;

public class JVMMonitor implements Runnable
{
private final Logger logger = Logger.getLogger(this.getClass().getName());
private static final DateFormat DATEFORMAT = DateFormat.getInstance();
private OC4JConnection con = null;
private MBeanServerConnection mbs = null;
private String targetMBean = "oc4j:j2eeType=JVM,name=single,J2EEServer=standalone";
private ObjectName mbean = null;

public JVMMonitor() throws Exception
{
// retrieve an OC4JConnection object this is a singleton class
con = OC4JConnection.getInstance();
mbs = con.getConnection();
mbean = new ObjectName(targetMBean);
System.out.println("** JVM Details **");
System.out.printf("Opmn Managed: %s\n",
mbs.getAttribute(mbean, "opmnEnabled"));
System.out.printf("Java Version: %s\n",
mbs.getAttribute(mbean, "javaVersion"));
System.out.printf("Java Vendor: %s\n",
mbs.getAttribute(mbean, "javaVendor"));
System.out.printf("Host Node: %s\n",
mbs.getAttribute(mbean, "node"));
System.out.printf("RMI Port: %s\n",
mbs.getAttribute(mbean, "rmiPort"));
System.out.printf("RMIS Port: %s\n",
mbs.getAttribute(mbean, "rmisPort"));
System.out.printf("RMI IP: %s\n",
mbs.getAttribute(mbean, "rmiServerAddress"));

}

public void run ()
{

System.out.println("\n");
try
{
System.out.printf("--> Current JVM Details [%s]\n\n",
DATEFORMAT.format(new Date()));


showStats(mbean);
System.out.printf("\n<-- End...\n");
}
catch (Exception e)
{
System.out.println("Error in run()");
e.printStackTrace();
}
finally
{
//con.close();
}
}

private void showStats(ObjectName cp) throws Exception
{

JVMStats stats =
(JVMStats) mbs.getAttribute(cp, "stats");

Object mem = null;
mem = mbs.getAttribute(cp, "totalMemory");
Long memLong = null;
memLong = (Long) mem;

System.out.printf("Total Memory: %s\n", memLong.intValue()/1024/1024 + "M");

mem = mbs.getAttribute(cp, "freeMemory");
memLong = (Long) mem;
System.out.printf("Free Memory: %s\n",
memLong.intValue()/1024/1024 + "M");

System.out.printf("HeapSize: %s\n",
stats.getHeapSize().getCurrent()/1024 + "M");
System.out.printf("HighWaterMark: %s\n",
stats.getHeapSize().getHighWaterMark()/1024 + "M");
System.out.printf("LowWaterMark: %s\n",
stats.getHeapSize().getLowWaterMark()/1024 + "M");

Statistic[] allStats = stats.getStatistics();

for (Statistic s: allStats)
{
if (!s.getName().equalsIgnoreCase("UpTime"))
{
System.out.println("\n--");
System.out.printf("JVM Statistic [%s]\n", s.getName());
System.out.printf("Description : %s\n", s.getDescription());
System.out.printf("Unit : %s\n", s.getUnit());
System.out.printf("Last Sample Time : %s\n", new Date(s.getLastSampleTime()));

BoundedRangeStatistic brs = (BoundedRangeStatistic) s;

if (s.getUnit().equals("THREADS"))
{
System.out.printf("High WaterMark : %s\n", brs.getHighWaterMark());
System.out.printf("Low WaterMark : %s\n", brs.getLowWaterMark());
System.out.printf("Current : %s\n", brs.getCurrent());
}
else
{
System.out.printf("High WaterMark : %s\n", brs.getHighWaterMark()/1024 + "M");
System.out.printf("Low WaterMark : %s\n", brs.getLowWaterMark()/1024 + "M");
System.out.printf("Current : %s\n", brs.getCurrent()/1024 + "M");
}

}
}


}

}



So the output would then be as follows:

** JVM Details **
Opmn Managed: true
Java Version: 1.5.0_06
Java Vendor: Sun Microsystems Inc.
Host Node: beast.au.oracle.com
RMI Port: 12406
RMIS Port: 12706
RMI IP: 10.187.80.70

JVMMonitor
Period to report results in seconds is : 5

** Started [4/09/08 11:29] with 5(sec) interval between reports **


--> Current JVM Details [4/09/08 11:29]

Total Memory: 515M
Free Memory: 453M
HeapSize: 515M
HighWaterMark: 550M
LowWaterMark: 504M

--
JVM Statistic [FreeHeapSize]
Description : The amount of free heap memory
Unit : KILO BYTES
Last Sample Time : Thu Sep 04 11:06:44 EST 2008
High WaterMark : 515M
Low WaterMark : 433M
Current : 453M

--
JVM Statistic [ActiveThreads]
Description : The number of active thread(s)
Unit : THREADS
Last Sample Time : Thu Sep 04 11:06:44 EST 2008
High WaterMark : 64
Low WaterMark : 4
Current : 64

--
JVM Statistic [HeapSize]
Description : The size of the JVM's heap
Unit : KILO BYTES
Last Sample Time : Thu Sep 04 11:06:44 EST 2008
High WaterMark : 550M
Low WaterMark : 504M
Current : 515M

<-- End...

Few people asked for this class itself.

OC4JConnection.java


  
package oracle.support.oc4j.standalone;

import java.io.FileInputStream;

import java.util.Hashtable;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import oracle.oc4j.admin.jmx.remote.api.JMXConnectorConstant;

public class OC4JConnection
{
private static Properties myProperties = new Properties();
private JMXConnector jmxCon = null;
private static OC4JConnection instance = null;
private final Logger logger = Logger.getLogger(this.getClass().getName());
private String username = null;
private String password = null;
private String url = null;

private OC4JConnection
(Properties inProps) throws Exception
{

try
{
processProps(inProps);

logger.log
(Level.INFO, "Username = " + username);
logger.log
(Level.INFO, "Service URL = " + url);

// Define the connection target
JMXServiceURL serviceUrl = new JMXServiceURL(url);

Hashtable env = new Hashtable();

env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
"oracle.oc4j.admin.jmx.remote");

Hashtable credentials = new Hashtable();

credentials.put
(JMXConnectorConstant.CREDENTIALS_LOGIN_KEY, username);
credentials.put(JMXConnectorConstant.CREDENTIALS_PASSWORD_KEY,
password);

env.put(JMXConnector.CREDENTIALS, credentials);

jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);
// Connect to the target OC4J instance defined in the JMXServiceURL
jmxCon.connect();
logger.log
(Level.INFO, "Connected to OC4J");
}
catch (Exception e)
{
logger.log
(Level.SEVERE,
"** [OC4JConnection()] : Unable to obtain Stand Alone Connection",
e);
e.printStackTrace();
}
}

public static OC4JConnection getInstance() throws Exception
{
if(instance == null)
{
myProperties.load(new FileInputStream("build.properties"));
instance = new OC4JConnection(myProperties);
}

return instance;
}

private void processProps(Properties inProps)
{
username = inProps.getProperty("username");
password = inProps.getProperty("password");
url = inProps.getProperty("serviceurl");

}

public MBeanServerConnection getConnection ()
{
MBeanServerConnection mbs = null;

if (jmxCon != null)
{
try
{
mbs = jmxCon.getMBeanServerConnection();
}
catch (Throwable t)
{
logger.log
(Level.SEVERE,
"**[getConnection] : Unable to retrieve MBeanServerConnection");
}
}

return mbs;
}

/**
* Determine if the client is currently connected
* @return true if connected
*/
public boolean isConnected ()
{
boolean ret = false;
if (jmxCon == null)
{
return false;
}
else
{
try
{
jmxCon.getConnectionId();
return true;
}
catch (Throwable t)
{
//
}
}

return ret;
}

/**
* Close the JMXConnector.
*/
public void close ()
{
if (jmxCon != null)
{
try
{
jmxCon.close();
jmxCon = null;
logger.log
(Level.INFO, "Closed Connection to OC4J");
}
catch (Throwable t)
{
}
}
}
}

7 comments:

lowsignal said...

Where does the OC4JConnection class come from?

Pas Apicella said...

That's a separate class which actually is used to connect to the OC4J Container itself using JMX.

Once connected the method getConnection() will return the actual MBeanServer Connection.

TommyBoy said...

Glad I found this post. I'm testing nearly identical code against version 10.1.3.3.0, but run into a casting exception. Everything is good except trying to get data from the stats attribute. I pull the JVMStats from the MBean OK. I get Statistics[], as you do with stats.getStatistics(). As I loop thru Statistics[], I get an exception when casting a Statistic to a BoundedRangeStatistic. How did you get away with that?
Running this:
BoundedRangeStatistic brs ;
stats =
(JVMStats) _mbs.getAttribute(objName, "stats") ;

Statistic[] allStats = stats.getStatistics() ;

for(Statistic s: allStats) {

brs = (BoundedRangeStatistic) s;
and so on.....

When it hits the brs=... I get:
java.lang.ClassCastException: oracle.oc4j.admin.management.shared.statistic.CountStatisticImpl

Thanks for your attention.

Pas Apicella said...

It's been a while since I created these MBean client utilities but as a guess here is where I think the problem is. The run time error is PERHAPS due to the fact your using a different client version versus the server version so in short you want to do this:

OAS 10.1.3.4 - Jdeveloper 10.1.3.4 (client)
OAS 10.1.3.5 - Jdeveloper 10.1.3.5 (client)
.....

Note: The client doesn't need to be jdev BUT it's vital that you use an OAS client side distribution which matches the OAS server version. Another way is to use the JAR files from the server on your client and most of all use the exact same JDK version used on the client to that of the server.

That should work I believe. Here is the OAS client side distribution you can download in case your not using that, be sure to get the version which matches your server.

http://buttso.blogspot.com/2006/05/oc4j-adminclient-distribution.html

Anonymous said...

Glad to find this post.
Cheers here from Melbourne

Learning Websphere said...

Could you please provide me the OC4JConnection class.

Pas Apicella said...

I added the class to the main entry above.