001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.stats;
006:
007: import org.apache.commons.collections.set.ListOrderedSet;
008:
009: import com.tc.logging.TCLogger;
010: import com.tc.logging.TCLogging;
011: import com.tc.management.beans.L2MBeanNames;
012: import com.tc.net.protocol.tcm.MessageChannel;
013: import com.tc.object.ObjectID;
014: import com.tc.object.net.ChannelStats;
015: import com.tc.object.net.DSOChannelManagerEventListener;
016: import com.tc.object.net.DSOChannelManagerMBean;
017: import com.tc.objectserver.api.GCStats;
018: import com.tc.objectserver.api.NoSuchObjectException;
019: import com.tc.objectserver.api.ObjectInstanceMonitorMBean;
020: import com.tc.objectserver.api.ObjectManagerEventListener;
021: import com.tc.objectserver.api.ObjectManagerMBean;
022: import com.tc.objectserver.core.impl.ServerManagementContext;
023: import com.tc.objectserver.lockmanager.api.DeadlockChain;
024: import com.tc.objectserver.lockmanager.api.LockMBean;
025: import com.tc.objectserver.lockmanager.api.LockManagerMBean;
026: import com.tc.objectserver.mgmt.ManagedObjectFacade;
027: import com.tc.objectserver.tx.ServerTransactionManagerEventListener;
028: import com.tc.objectserver.tx.ServerTransactionManagerMBean;
029: import com.tc.stats.statistics.CountStatistic;
030: import com.tc.stats.statistics.DoubleStatistic;
031: import com.tc.stats.statistics.Statistic;
032:
033: import java.util.ArrayList;
034: import java.util.Iterator;
035: import java.util.Map;
036: import java.util.Set;
037:
038: import javax.management.MBeanServer;
039: import javax.management.MalformedObjectNameException;
040: import javax.management.NotCompliantMBeanException;
041: import javax.management.ObjectName;
042:
043: /**
044: * This is the top-level MBean for the DSO subsystem, off which to hang JSR-77 Stats and Config MBeans.
045: *
046: * @see DSOMBean
047: * @see DSOStatsImpl
048: */
049: public class DSO extends AbstractNotifyingMBean implements DSOMBean {
050:
051: private final static TCLogger logger = TCLogging
052: .getLogger(DSO.class);
053: private final static String DSO_OBJECT_NAME_PREFIX = L2MBeanNames.DSO
054: .getCanonicalName()
055: + ",";
056:
057: private final DSOStatsImpl dsoStats;
058: private final ObjectManagerMBean objMgr;
059: private final MBeanServer mbeanServer;
060: private final ArrayList rootObjectNames = new ArrayList();
061: private final Set clientObjectNames = new ListOrderedSet();
062: private final DSOChannelManagerMBean channelMgr;
063: private final ServerTransactionManagerMBean txnMgr;
064: private final LockManagerMBean lockMgr;
065: private final ChannelStats channelStats;
066: private final ObjectInstanceMonitorMBean instanceMonitor;
067:
068: public DSO(final ServerManagementContext context,
069: final MBeanServer mbeanServer)
070: throws NotCompliantMBeanException {
071: super (DSOMBean.class);
072: try {
073: // TraceImplementation.init(TraceTags.LEVEL_TRACE);
074: } catch (Exception e) {/**/
075: }
076: this .mbeanServer = mbeanServer;
077: this .dsoStats = new DSOStatsImpl(context);
078: this .lockMgr = context.getLockManager();
079: this .objMgr = context.getObjectManager();
080: this .channelMgr = context.getChannelManager();
081: this .txnMgr = context.getTransactionManager();
082: this .channelStats = context.getChannelStats();
083: this .instanceMonitor = context.getInstanceMonitor();
084:
085: // add various listeners (do this before the setupXXX() methods below so we don't ever miss anything)
086: txnMgr.addRootListener(new TransactionManagerListener());
087: objMgr.addListener(new ObjectManagerListener());
088: channelMgr.addEventListener(new ChannelManagerListener());
089:
090: setupRoots();
091: setupClients();
092: }
093:
094: public void reset() {
095: // TODO: implement this?
096: }
097:
098: public DSOStats getStats() {
099: return dsoStats;
100: }
101:
102: public CountStatistic getObjectFlushRate() {
103: return getStats().getObjectFlushRate();
104: }
105:
106: public DoubleStatistic getCacheHitRatio() {
107: return getStats().getCacheHitRatio();
108: }
109:
110: public CountStatistic getCacheMissRate() {
111: return getStats().getCacheMissRate();
112: }
113:
114: public CountStatistic getTransactionRate() {
115: return getStats().getTransactionRate();
116: }
117:
118: public CountStatistic getObjectFaultRate() {
119: return getStats().getObjectFaultRate();
120: }
121:
122: public Statistic[] getStatistics(String[] names) {
123: return getStats().getStatistics(names);
124: }
125:
126: public GCStats[] getGarbageCollectorStats() {
127: return getStats().getGarbageCollectorStats();
128: }
129:
130: public ObjectName[] getRoots() {
131: synchronized (rootObjectNames) {
132: return (ObjectName[]) rootObjectNames
133: .toArray(new ObjectName[rootObjectNames.size()]);
134: }
135: }
136:
137: public LockMBean[] getLocks() {
138: return this .lockMgr.getAllLocks();
139: }
140:
141: public ObjectName[] getClients() {
142: synchronized (clientObjectNames) {
143: return (ObjectName[]) clientObjectNames
144: .toArray(new ObjectName[clientObjectNames.size()]);
145: }
146: }
147:
148: public DeadlockChain[] scanForDeadLocks() {
149: return this .lockMgr.scanForDeadlocks();
150: }
151:
152: public DSOClassInfo[] getClassInfo() {
153: Map counts = instanceMonitor.getInstanceCounts();
154: DSOClassInfo[] rv = new DSOClassInfo[counts.size()];
155:
156: int i = 0;
157: for (Iterator iter = counts.keySet().iterator(); iter.hasNext();) {
158: String type = (String) iter.next();
159: int count = ((Integer) counts.get(type)).intValue();
160: rv[i++] = new DSOClassInfo(type, count);
161: }
162:
163: return rv;
164: }
165:
166: public ManagedObjectFacade lookupFacade(ObjectID objectID, int limit)
167: throws NoSuchObjectException {
168: return this .objMgr.lookupFacade(objectID, limit);
169: }
170:
171: private void setupRoots() {
172: for (Iterator iter = objMgr.getRootNames(); iter.hasNext();) {
173: String name = (String) iter.next();
174: final ObjectID rootID;
175: try {
176: rootID = objMgr.lookupRootID(name);
177: } catch (Exception e) {
178: e.printStackTrace();
179: continue;
180: }
181:
182: addRootMBean(name, rootID);
183: }
184: }
185:
186: private void setupClients() {
187: MessageChannel[] channels = channelMgr.getActiveChannels();
188: for (int i = 0; i < channels.length; i++) {
189: addClientMBean(channels[i]);
190: }
191: }
192:
193: private ObjectName makeClientObjectName(MessageChannel channel) {
194: try {
195: return new ObjectName(DSO_OBJECT_NAME_PREFIX + "channelID="
196: + channel.getChannelID().toLong());
197: } catch (MalformedObjectNameException e) {
198: // this shouldn't happen
199: throw new RuntimeException(e);
200: }
201: }
202:
203: private ObjectName makeRootObjectName(String name, ObjectID id) {
204: try {
205: return new ObjectName(DSO_OBJECT_NAME_PREFIX + "rootID="
206: + id.toLong());
207: } catch (MalformedObjectNameException e) {
208: // this shouldn't happen
209: throw new RuntimeException(e);
210: }
211: }
212:
213: private void addRootMBean(String name, ObjectID rootID) {
214: // XXX: There should be a cleaner way to do this ignore
215: if (name.startsWith("@")) {
216: // ignore iternal roots
217: return;
218: }
219:
220: synchronized (rootObjectNames) {
221: ObjectName rootName = makeRootObjectName(name, rootID);
222: if (mbeanServer.isRegistered(rootName)) {
223: // this can happen since the initial root setup races with the object manager "root created" event
224: logger.debug("Root MBean already registered for name "
225: + rootName);
226: return;
227: }
228:
229: DSORoot dsoRoot = new DSORoot(rootID, objMgr, name);
230: try {
231: mbeanServer.registerMBean(dsoRoot, rootName);
232: rootObjectNames.add(rootName);
233: sendNotification(ROOT_ADDED, rootName);
234: } catch (Exception e) {
235: logger.error(e);
236: }
237: }
238: }
239:
240: private void removeClientMBean(MessageChannel channel) {
241: ObjectName clientName = makeClientObjectName(channel);
242:
243: synchronized (clientObjectNames) {
244: try {
245: if (mbeanServer.isRegistered(clientName)) {
246: sendNotification(CLIENT_DETACHED, clientName);
247: mbeanServer.unregisterMBean(clientName);
248: }
249: } catch (Exception e) {
250: logger.error(e);
251: } finally {
252: clientObjectNames.remove(clientName);
253: }
254: }
255: }
256:
257: private void addClientMBean(final MessageChannel channel) {
258: synchronized (clientObjectNames) {
259: ObjectName clientName = makeClientObjectName(channel);
260: if (mbeanServer.isRegistered(clientName)) {
261: logger
262: .debug("channel MBean already registered for name "
263: + clientName);
264: return;
265: }
266:
267: try {
268: final DSOClient client = new DSOClient(channel,
269: channelStats);
270: mbeanServer.registerMBean(client, clientName);
271: clientObjectNames.add(clientName);
272: sendNotification(CLIENT_ATTACHED, clientName);
273: } catch (Exception e) {
274: logger.error("Unable to register DSO client MBean", e);
275: }
276: }
277: }
278:
279: private class TransactionManagerListener implements
280: ServerTransactionManagerEventListener {
281:
282: public void rootCreated(String name, ObjectID rootID) {
283: addRootMBean(name, rootID);
284: }
285:
286: }
287:
288: private class ObjectManagerListener implements
289: ObjectManagerEventListener {
290: public void garbageCollectionComplete(GCStats stats, Set deleted) {
291: sendNotification(GC_COMPLETED, stats);
292: }
293:
294: }
295:
296: private class ChannelManagerListener implements
297: DSOChannelManagerEventListener {
298:
299: public void channelCreated(MessageChannel channel) {
300: addClientMBean(channel);
301: }
302:
303: public void channelRemoved(MessageChannel channel) {
304: removeClientMBean(channel);
305: }
306:
307: }
308:
309: }
|