001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.monitor;
023:
024: import java.util.ArrayList;
025: import java.util.Arrays;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Set;
029: import java.util.TreeSet;
030:
031: import javax.naming.Context;
032: import javax.naming.InitialContext;
033: import javax.naming.NamingException;
034: import javax.naming.Reference;
035: import javax.naming.StringRefAddr;
036:
037: import org.jboss.util.naming.NonSerializableFactory;
038: import org.jboss.system.ServiceMBeanSupport;
039:
040: /**
041: * MBean implementation for providing Locking Stats for EntityBeans
042: *
043: * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
044: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
045: * @version $Revision: 57209 $
046: */
047: public class EntityLockMonitor extends ServiceMBeanSupport implements
048: EntityLockMonitorMBean {
049: // Constants ----------------------------------------------------
050:
051: public static final String JNDI_NAME = "EntityLockMonitor";
052:
053: // Protected -----------------------------------------------------
054:
055: protected HashMap monitorMap = new HashMap();
056: protected long contenders = 0;
057: protected long maxContenders = 0;
058: protected ArrayList times = new ArrayList();
059: protected long contentions = 0;
060: protected long totalTime = 0;
061: protected long sumContenders = 0;
062:
063: // Constructors -------------------------------------------------
064:
065: public EntityLockMonitor() {
066: // empty
067: }
068:
069: // ServiceMBeanSupport overrides ---------------------------------
070:
071: protected void startService() throws Exception {
072: bind();
073:
074: log.info("EntityLockMonitor started");
075: }
076:
077: protected void stopService() {
078: try {
079: unbind();
080: } catch (Exception ignored) {
081: }
082:
083: log.info("EntityLockMonitor stopped");
084: }
085:
086: // Attributes ----------------------------------------------------
087:
088: /**
089: * @jmx.managed-attribute
090: */
091: public synchronized long getAverageContenders() {
092: if (contentions == 0) {
093: return 0;
094: } else {
095: return sumContenders / contentions;
096: }
097: }
098:
099: /**
100: * @jmx.managed-attribute
101: */
102: public synchronized long getMaxContenders() {
103: return maxContenders;
104: }
105:
106: /**
107: * @jmx.managed-attribute
108: */
109: public synchronized long getMedianWaitTime() {
110: if (times.size() < 1) {
111: return 0;
112: }
113:
114: Long[] alltimes = (Long[]) times
115: .toArray(new Long[times.size()]);
116: long[] thetimes = new long[alltimes.length];
117: for (int i = 0; i < thetimes.length; i++) {
118: thetimes[i] = alltimes[i].longValue();
119: }
120: Arrays.sort(thetimes);
121: return thetimes[thetimes.length / 2];
122: }
123:
124: /**
125: * @jmx.managed-attribute
126: */
127: public synchronized long getTotalContentions() {
128: return contentions;
129: }
130:
131: // Operations ----------------------------------------------------
132:
133: /**
134: * @jmx.managed-operation
135: */
136: public Set listMonitoredBeans() {
137: synchronized (monitorMap) {
138: return new TreeSet(monitorMap.keySet());
139: }
140: }
141:
142: /**
143: * @jmx.managed-operation
144: *
145: * @return the LockMonitor that corresponds to the jndiName or null
146: */
147: public LockMonitor getLockMonitor(String jndiName) {
148: synchronized (monitorMap) {
149: return (LockMonitor) monitorMap.get(jndiName);
150: }
151: }
152:
153: /**
154: * @jmx.managed-operation
155: */
156: public String printLockMonitor() {
157: StringBuffer rtn = new StringBuffer();
158: rtn.append("<table width=\"1\" border=\"1\">");
159: rtn
160: .append("<tr><td><b>EJB JNDI-NAME</b></td><td><b>Total Lock Time</b></td><td><b>Num Contentions</b></td><td><b>Time Outs</b></td><td><b>Max Contenders</b></td></tr>");
161: synchronized (monitorMap) {
162: Iterator it = monitorMap.keySet().iterator();
163: while (it.hasNext()) {
164: rtn.append("<tr>");
165: String jndiName = (String) it.next();
166: rtn.append("<td>");
167: rtn.append(jndiName);
168: rtn.append("</td>");
169: LockMonitor lm = (LockMonitor) monitorMap.get(jndiName);
170: rtn.append("<td>");
171: rtn.append(("" + lm.getTotalTime()));
172: rtn.append("</td><td>");
173: rtn.append(("" + lm.getNumContentions()));
174: rtn.append("</td><td>");
175: rtn.append(("" + lm.getTimeouts()));
176: rtn.append("</td><td>");
177: rtn.append(("" + lm.getMaxContenders()));
178: rtn.append("</td></tr>");
179: }
180: }
181: rtn.append("</table>");
182: return rtn.toString();
183: }
184:
185: /**
186: * @jmx.managed-operation
187: */
188: public synchronized void clearMonitor() {
189: contenders = 0;
190: maxContenders = 0;
191: times.clear();
192: contentions = 0;
193: totalTime = 0;
194: sumContenders = 0;
195:
196: synchronized (monitorMap) {
197: Iterator it = monitorMap.keySet().iterator();
198: while (it.hasNext()) {
199: String jndiName = (String) it.next();
200: LockMonitor lm = (LockMonitor) monitorMap.get(jndiName);
201: lm.reset();
202: }
203: }
204: }
205:
206: // Public -------------------------------------------------------
207:
208: public synchronized void incrementContenders() {
209: ++contenders;
210: ++contentions;
211: sumContenders += contenders;
212:
213: if (contenders > maxContenders) {
214: maxContenders = contenders;
215: }
216: }
217:
218: public synchronized void decrementContenders(long time) {
219: times.add(new Long(time));
220: --contenders;
221: }
222:
223: public LockMonitor getEntityLockMonitor(String jndiName) {
224: LockMonitor lm = null;
225:
226: synchronized (monitorMap) {
227: lm = (LockMonitor) monitorMap.get(jndiName);
228: if (lm == null) {
229: lm = new LockMonitor(this );
230: monitorMap.put(jndiName, lm);
231: }
232: }
233: return lm;
234: }
235:
236: // Private -------------------------------------------------------
237:
238: private void bind() throws NamingException {
239: Context ctx = new InitialContext();
240:
241: // Ah ! We aren't serializable, so we use a helper class
242: NonSerializableFactory.bind(JNDI_NAME, this );
243:
244: // The helper class NonSerializableFactory uses address type nns, we go on to
245: // use the helper class to bind ourselves in JNDI
246: StringRefAddr addr = new StringRefAddr("nns", JNDI_NAME);
247: Reference ref = new Reference(
248: EntityLockMonitor.class.getName(), addr,
249: NonSerializableFactory.class.getName(), null);
250: ctx.bind(JNDI_NAME, ref);
251: }
252:
253: private void unbind() throws NamingException {
254: new InitialContext().unbind(JNDI_NAME);
255: NonSerializableFactory.unbind(JNDI_NAME);
256: }
257:
258: }
|