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.mq.server.jmx;
023:
024: import java.util.StringTokenizer;
025:
026: import javax.naming.InitialContext;
027: import javax.naming.NamingException;
028:
029: import javax.management.MBeanRegistration;
030: import javax.management.MBeanServer;
031: import javax.management.ObjectName;
032: import javax.management.MalformedObjectNameException;
033: import javax.management.InvalidAttributeValueException;
034: import javax.management.InstanceNotFoundException;
035: import javax.management.MBeanException;
036: import javax.management.ReflectionException;
037:
038: import org.jboss.logging.Logger;
039: import org.jboss.system.ServiceMBeanSupport;
040: import org.jboss.util.naming.Util;
041:
042: import org.jboss.mq.MessageStatistics;
043: import org.jboss.mq.SpyDestination;
044: import org.jboss.mq.server.BasicQueueParameters;
045: import org.jboss.mq.server.JMSDestinationManager;
046: import org.jboss.mq.server.MessageCounter;
047: import org.jboss.mq.server.Receivers;
048: import org.w3c.dom.Element;
049:
050: /**
051: * Super class for destination managers.
052: *
053: * @author <a href="pra@tim.se">Peter Antman</a>
054: * @version $Revision: 60195 $
055: */
056: abstract public class DestinationMBeanSupport extends
057: ServiceMBeanSupport implements DestinationMBean,
058: MBeanRegistration {
059: protected SpyDestination spyDest;
060: protected String destinationName;
061: protected String jndiName;
062: protected boolean jndiBound;
063: protected ObjectName jbossMQService;
064: //String securityConf;
065: protected Element securityConf;
066: /** The basic parameters */
067: protected BasicQueueParameters parameters = new BasicQueueParameters();
068: /** Destination JNDI name */
069: ObjectName expiryDestination;
070:
071: /**
072: * A optional security manager. Must be set to use security conf.
073: */
074: protected ObjectName securityManager;
075:
076: /**
077: * Get the value of JBossMQService.
078: *
079: * @return value of JBossMQService.
080: */
081: public ObjectName getDestinationManager() {
082: return jbossMQService;
083: }
084:
085: /**
086: * Set the value of JBossMQService.
087: *
088: * @param v Value to assign to JBossMQService.
089: */
090: public void setDestinationManager(ObjectName jbossMQService) {
091: this .jbossMQService = jbossMQService;
092: }
093:
094: protected SpyDestination getSpyDest() {
095: return spyDest;
096: }
097:
098: public void setSecurityConf(org.w3c.dom.Element securityConf)
099: throws Exception {
100: log.debug("Setting securityConf: " + securityConf);
101: this .securityConf = securityConf;
102: }
103:
104: protected Element getSecurityConf() {
105: return securityConf;
106: }
107:
108: public void setSecurityManager(ObjectName securityManager) {
109: this .securityManager = securityManager;
110: }
111:
112: protected ObjectName getSecurityManager() {
113: return securityManager;
114: }
115:
116: public void createService() throws Exception {
117: // Copy default values from the server when null or zero
118: if (parameters.receiversImpl == null)
119: parameters.receiversImpl = (Class) server.getAttribute(
120: jbossMQService, "ReceiversImpl");
121: if (parameters.recoveryRetries == 0)
122: parameters.recoveryRetries = ((Integer) server
123: .getAttribute(jbossMQService, "RecoveryRetries"))
124: .intValue();
125: }
126:
127: public void startService() throws Exception {
128:
129: setupSecurityManager();
130: setupExpiryDestination();
131:
132: }
133:
134: protected void setupSecurityManager()
135: throws InstanceNotFoundException, MBeanException,
136: ReflectionException {
137: if (securityManager != null) {
138: // Set securityConf at manager
139: getServer().invoke(
140: securityManager,
141: "addDestination",
142: new Object[] { spyDest.getName(), securityConf },
143: new String[] { "java.lang.String",
144: "org.w3c.dom.Element" });
145: }
146: }
147:
148: protected void setupExpiryDestination() throws Exception {
149: if (expiryDestination != null) {
150: String jndi = (String) getServer().getAttribute(
151: expiryDestination, "JNDIName");
152: InitialContext ctx = new InitialContext();
153: try {
154: parameters.expiryDestination = (SpyDestination) ctx
155: .lookup(jndi);
156: } finally {
157: ctx.close();
158: }
159: }
160: }
161:
162: public void stopService() throws Exception {
163: // unbind from JNDI
164: if (jndiBound) {
165: InitialContext ctx = getInitialContext();
166: try {
167: log.info("Unbinding JNDI name: " + jndiName);
168: Util.unbind(ctx, jndiName);
169: } finally {
170: ctx.close();
171: }
172: jndiName = null;
173: jndiBound = false;
174: }
175:
176: JMSDestinationManager jmsServer = (JMSDestinationManager) server
177: .getAttribute(jbossMQService, "Interceptor");
178: if (jmsServer != null)
179: jmsServer.closeDestination(spyDest);
180:
181: // TODO: need to remove from JMSServer
182: teardownSecurityManager();
183: }
184:
185: protected void teardownSecurityManager()
186: throws InstanceNotFoundException, MBeanException,
187: ReflectionException {
188: if (securityManager != null) {
189: // Set securityConf at manager
190: getServer().invoke(securityManager, "removeDestination",
191: new Object[] { spyDest.getName() },
192: new String[] { "java.lang.String" });
193: }
194: }
195:
196: protected ObjectName getObjectName(MBeanServer server,
197: ObjectName name) throws MalformedObjectNameException {
198: destinationName = name.getKeyProperty("name");
199: if (destinationName == null || destinationName.length() == 0) {
200: throw new MalformedObjectNameException(
201: "Property 'name' not provided");
202: }
203:
204: // re-setup the logger with a more descriptive name
205: log = Logger.getLogger(getClass().getName() + "."
206: + destinationName);
207:
208: return name;
209: }
210:
211: /**
212: * Sets the JNDI name for this topic
213: *
214: * @param name Name to bind this topic to in the JNDI tree
215: */
216: public synchronized void setJNDIName(String name) throws Exception {
217: if (spyDest == null) { // nothing to bind yet, startService will recall us
218: jndiName = name;
219: return;
220: }
221:
222: if (name == null) {
223: throw new InvalidAttributeValueException(
224: "Destination JNDI names can not be null");
225: }
226:
227: InitialContext ic = getInitialContext();
228: try {
229: if (jndiName != null && jndiBound) {
230: Util.unbind(ic, jndiName); //Remove old jndi name
231: jndiName = null;
232: jndiBound = false;
233: }
234:
235: Util.rebind(ic, name, spyDest);
236: jndiName = name;
237: jndiBound = true;
238: } finally {
239: ic.close();
240: }
241:
242: log.info("Bound to JNDI name: " + jndiName);
243: }
244:
245: protected InitialContext getInitialContext() throws NamingException {
246: InitialContext ic = new InitialContext();
247: return ic;
248: }
249:
250: /**
251: * Gets the JNDI name use by this topic
252: *
253: * @return The JNDI name currently in use
254: */
255: public String getJNDIName() {
256: return jndiName;
257: }
258:
259: /**
260: * Get destination message counter array
261: *
262: * @return MessageCounter[]
263: */
264: abstract public MessageCounter[] getMessageCounter();
265:
266: /**
267: * Get destination stats array
268: *
269: * @return MessageStatistics[]
270: * @throws Exception for any error
271: */
272: abstract public MessageStatistics[] getMessageStatistics()
273: throws Exception;
274:
275: /**
276: * List destination message counter as HTML table
277: *
278: * @return String
279: */
280: public String listMessageCounter() {
281: MessageCounter[] counter = getMessageCounter();
282: if (counter == null)
283: return null;
284:
285: String ret = "<table width=\"100%\" border=\"1\" cellpadding=\"1\" cellspacing=\"1\">"
286: + "<tr>"
287: + "<th>Type</th>"
288: + "<th>Name</th>"
289: + "<th>Subscription</th>"
290: + "<th>Durable</th>"
291: + "<th>Count</th>"
292: + "<th>CountDelta</th>"
293: + "<th>Depth</th>"
294: + "<th>DepthDelta</th>"
295: + "<th>Last Add</th>" + "</tr>";
296:
297: for (int i = 0; i < counter.length; i++) {
298: String data = counter[i].getCounterAsString();
299: StringTokenizer token = new StringTokenizer(data, ",");
300: String value;
301:
302: ret += "<tr bgcolor=\"#"
303: + ((i % 2) == 0 ? "FFFFFF" : "F0F0F0") + "\">";
304:
305: ret += "<td>" + token.nextToken() + "</td>"; // type
306: ret += "<td>" + token.nextToken() + "</td>"; // name
307: ret += "<td>" + token.nextToken() + "</td>"; // subscription
308: ret += "<td>" + token.nextToken() + "</td>"; // durable
309:
310: ret += "<td>" + token.nextToken() + "</td>"; // count
311:
312: value = token.nextToken(); // countDelta
313:
314: if (value.equalsIgnoreCase("0"))
315: value = "-";
316:
317: ret += "<td>" + value + "</td>";
318:
319: ret += "<td>" + token.nextToken() + "</td>"; // depth
320:
321: value = token.nextToken(); // depthDelta
322:
323: if (value.equalsIgnoreCase("0"))
324: value = "-";
325:
326: ret += "<td>" + value + "</td>";
327:
328: ret += "<td>" + token.nextToken() + "</td>"; // date last add
329:
330: ret += "</tr>";
331: }
332:
333: ret += "</table>";
334:
335: return ret;
336: }
337:
338: /**
339: * Reset destination message counter
340: */
341: public void resetMessageCounter() {
342: MessageCounter[] counter = getMessageCounter();
343: if (counter == null)
344: return;
345:
346: for (int i = 0; i < counter.length; i++) {
347: counter[i].resetCounter();
348: }
349: }
350:
351: /**
352: * List destination message counter history as HTML table
353: *
354: * @return String
355: */
356: public String listMessageCounterHistory() {
357: MessageCounter[] counter = getMessageCounter();
358: if (counter == null)
359: return null;
360:
361: String ret = "";
362:
363: for (int i = 0; i < counter.length; i++) {
364: // destination name
365: ret += (counter[i].getDestinationTopic() ? "Topic '"
366: : "Queue '");
367: ret += counter[i].getDestinationName() + "'";
368:
369: if (counter[i].getDestinationSubscription() != null)
370: ret += "Subscription '"
371: + counter[i].getDestinationSubscription() + "'";
372:
373: // table header
374: ret += "<table width=\"100%\" border=\"1\" cellpadding=\"1\" cellspacing=\"1\">"
375: + "<tr>" + "<th>Date</th>";
376:
377: for (int j = 0; j < 24; j++)
378: ret += "<th width=\"4%\">" + j + "</th>";
379:
380: ret += "<th>Total</th></tr>";
381:
382: // get history data as CSV string
383: StringTokenizer tokens = new StringTokenizer(counter[i]
384: .getHistoryAsString(), ",\n");
385:
386: // get history day count
387: int days = Integer.parseInt(tokens.nextToken());
388:
389: for (int j = 0; j < days; j++) {
390: // next day counter row
391: ret += "<tr bgcolor=\"#"
392: + ((j % 2) == 0 ? "FFFFFF" : "F0F0F0") + "\">";
393:
394: // date
395: ret += "<td>" + tokens.nextToken() + "</td>";
396:
397: // 24 hour counters
398: int total = 0;
399:
400: for (int k = 0; k < 24; k++) {
401: int value = Integer.parseInt(tokens.nextToken()
402: .trim());
403:
404: if (value == -1) {
405: ret += "<td></td>";
406: } else {
407: ret += "<td>" + value + "</td>";
408:
409: total += value;
410: }
411: }
412:
413: ret += "<td>" + total + "</td></tr>";
414: }
415:
416: ret += "</table><br><br>";
417: }
418:
419: return ret;
420: }
421:
422: /**
423: * Reset destination message counter history
424: */
425: public void resetMessageCounterHistory() {
426: MessageCounter[] counter = getMessageCounter();
427: if (counter == null)
428: return;
429:
430: for (int i = 0; i < counter.length; i++) {
431: counter[i].resetHistory();
432: }
433: }
434:
435: /**
436: * Sets the destination message counter history day limit
437: * <0: unlimited, =0: disabled, > 0 maximum day count
438: *
439: * @param days maximum day count
440: */
441: public void setMessageCounterHistoryDayLimit(int days) {
442: if (days < -1)
443: days = -1;
444:
445: parameters.messageCounterHistoryDayLimit = days;
446: if (getState() != STARTED)
447: return;
448:
449: MessageCounter[] counter = getMessageCounter();
450: for (int i = 0; i < counter.length; ++i)
451: counter[i].setHistoryLimit(days);
452: }
453:
454: /**
455: * Gets the destination message counter history day limit
456: * @return Maximum day count
457: */
458: public int getMessageCounterHistoryDayLimit() {
459: return parameters.messageCounterHistoryDayLimit;
460: }
461:
462: public int getMaxDepth() {
463: return parameters.maxDepth;
464: }
465:
466: public void setMaxDepth(int depth) {
467: parameters.maxDepth = depth;
468: }
469:
470: public boolean getInMemory() {
471: return parameters.inMemory;
472: }
473:
474: public void setInMemory(boolean mode) {
475: parameters.inMemory = mode;
476: }
477:
478: /**
479: * Returns the message redelivery limit; the number of redelivery attempts
480: * before a message is moved to the DLQ.
481: */
482: public int getRedeliveryLimit() {
483: return parameters.redeliveryLimit;
484: }
485:
486: /**
487: * Sets the redelivery limit.
488: */
489: public void setRedeliveryLimit(int limit) {
490: if (limit < 0)
491: throw new IllegalArgumentException(
492: "Negative redelivery limit: " + limit);
493:
494: parameters.redeliveryLimit = limit;
495: }
496:
497: /**
498: * Returns the message redelivery delay, the delay in milliseconds before a
499: * rolled back or recovered message is redelivered
500: */
501: public long getRedeliveryDelay() {
502: return parameters.redeliveryDelay;
503: }
504:
505: /**
506: * Sets the Message redelivery delay in milliseconds.
507: */
508: public void setRedeliveryDelay(long rDelay) {
509: if (rDelay < 0)
510: throw new IllegalArgumentException(
511: "Negative redelivery delay: " + rDelay);
512:
513: parameters.redeliveryDelay = rDelay;
514: }
515:
516: public Class getReceiversImpl() {
517: return parameters.receiversImpl;
518: }
519:
520: public void setReceiversImpl(Class clazz) {
521: if (clazz != null
522: && Receivers.class.isAssignableFrom(clazz) == false)
523: throw new IllegalArgumentException("Class "
524: + clazz.getName()
525: + " is not a Receivers implementation");
526: parameters.receiversImpl = clazz;
527: }
528:
529: public int getRecoveryRetries() {
530: return parameters.recoveryRetries;
531: }
532:
533: public void setRecoveryRetries(int retries) {
534: parameters.recoveryRetries = retries;
535: }
536:
537: public ObjectName getExpiryDestination() {
538: return expiryDestination;
539: }
540:
541: public void setExpiryDestination(ObjectName expiryDestination) {
542: this.expiryDestination = expiryDestination;
543: }
544:
545: }
|