1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20
21 package org.apache.james.postage.jmx;
22
23 import org.apache.james.postage.execution.Sampler;
24 import org.apache.james.postage.result.PostageRunnerResult;
25 import org.apache.james.postage.result.JVMResourcesRecord;
26 import org.apache.james.postage.SamplingException;
27
28 import javax.management.remote.JMXConnector;
29 import javax.management.remote.JMXServiceURL;
30 import javax.management.remote.JMXConnectorFactory;
31 import javax.management.openmbean.CompositeDataSupport;
32 import javax.management.AttributeList;
33 import javax.management.MBeanServerConnection;
34 import javax.management.ObjectName;
35 import javax.management.Attribute;
36 import java.io.IOException;
37 import java.util.Iterator;
38
39 /***
40 * the peek into the James JVM is done using the build-in management (JMX) of J2SE 5 (and probably later)
41 * you must start James under a J2SE 5 compatible JVM and
42 * add some system properties to the phoenix.[sh|bat] file (all on one line):<br/>
43 * <br/>
44 * <code>
45 * JVM_OPTS="-Djava.ext.dirs=$JVM_EXT_DIRS
46 * -Dcom.sun.management.jmxremote
47 * -Dcom.sun.management.jmxremote.ssl=false
48 * -Dcom.sun.management.jmxremote.authenticate=false
49 * -Dcom.sun.management.jmxremote.port=10201 "
50 * </code>
51 * <br/>
52 * this class does not even compile on Java versions before JSE 5.<br/>
53 */
54 public class JVMResourceSamplerWorker implements Sampler {
55
56 private String m_host;
57 private int m_port;
58 private PostageRunnerResult m_results;
59
60 private MBeanServerConnection m_mBeanServerConnection;
61
62 public JVMResourceSamplerWorker(String host, int port, PostageRunnerResult results) {
63 m_host = host;
64 m_port = port;
65 m_results = results;
66 }
67
68 public void connectRemoteJamesJMXServer() throws SamplingException {
69 String serviceURL = "service:jmx:rmi:///jndi/rmi://" + m_host + ":" + m_port + "/jmxrmi";
70 try {
71 JMXServiceURL jmxServiceURL = new JMXServiceURL(serviceURL);
72 JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
73 m_mBeanServerConnection = jmxConnector.getMBeanServerConnection();
74 } catch (IOException e) {
75 throw new SamplingException("could not connect to " + serviceURL, e);
76 }
77 }
78
79 private void takeMemorySample(JVMResourcesRecord jvmResourcesRecord) throws SamplingException {
80 CompositeDataSupport data = null;
81 data = getRemoteAttributeValue("java.lang:type=Memory", "HeapMemoryUsage");
82 jvmResourcesRecord.setMemoryCommitted(((Long)data.get("committed")).longValue());
83 jvmResourcesRecord.setMemoryInit(((Long)data.get("init")).longValue());
84 jvmResourcesRecord.setMemoryMax(((Long)data.get("max")).longValue());
85 jvmResourcesRecord.setMemoryUsed(((Long)data.get("used")).longValue());
86 }
87
88 private void takeThreadingSample(JVMResourcesRecord jvmResourcesRecord) throws SamplingException {
89 CompositeDataSupport data = null;
90 AttributeList attributes = getRemoteThreadingAttributeValues();
91 jvmResourcesRecord.setThreadCountCurrent(((Integer)getAttributeValue(attributes, "ThreadCount")).longValue());
92 jvmResourcesRecord.setThreadCountPeak(((Integer)getAttributeValue(attributes, "PeakThreadCount")).longValue());
93 jvmResourcesRecord.setThreadCountTotalStarted(((Long)getAttributeValue(attributes, "TotalStartedThreadCount")).longValue());
94 }
95
96 private CompositeDataSupport getRemoteAttributeValue(String jmxObjectName, String attributeName) throws SamplingException {
97 CompositeDataSupport data;
98 try {
99 ObjectName name = new ObjectName(jmxObjectName);
100 data = (CompositeDataSupport)m_mBeanServerConnection.getAttribute(name, attributeName);
101 } catch (IOException e) {
102 throw new SamplingException("lost connection to JMX server", e);
103 } catch (Exception e) {
104 throw new SamplingException("failed to take memory sample", e);
105 }
106 return data;
107 }
108
109 private AttributeList getRemoteThreadingAttributeValues() throws SamplingException {
110 try {
111 ObjectName name = new ObjectName("java.lang:type=Threading");
112 String[] attributeNames = new String[] {"PeakThreadCount", "ThreadCount", "TotalStartedThreadCount"};
113 AttributeList attributes = m_mBeanServerConnection.getAttributes(name, attributeNames);
114 return attributes;
115 } catch (IOException e) {
116 throw new SamplingException("lost connection to JMX server", e);
117 } catch (Exception e) {
118 throw new SamplingException("failed to take memory sample", e);
119 }
120 }
121
122 private Object getAttributeValue(AttributeList attributeList, String key) {
123 for (Iterator iterator = attributeList.iterator(); iterator.hasNext();) {
124 Attribute attribute = (Attribute)iterator.next();
125 if (attribute.getName().equals(key)) return attribute.getValue();
126 }
127 return null;
128 }
129
130 public void doSample() throws SamplingException {
131 JVMResourcesRecord jvmResourcesRecord = new JVMResourcesRecord();
132 takeMemorySample(jvmResourcesRecord);
133 takeThreadingSample(jvmResourcesRecord);
134 m_results.addJVMResult(jvmResourcesRecord);
135 }
136 }