001: /*
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: * --------------------------------------------------------------------------
021: * $Id: JmsServiceImpl.java 9829 2006-11-10 09:55:29Z danesa $
022: * --------------------------------------------------------------------------
023: */
024:
025: package org.objectweb.jonas.jms;
026:
027: import java.util.Enumeration;
028: import java.util.HashSet;
029: import java.util.Set;
030: import java.util.StringTokenizer;
031: import java.util.Vector;
032:
033: import javax.jms.Queue;
034: import javax.jms.Topic;
035: import javax.naming.Context;
036: import javax.naming.NamingException;
037:
038: import org.objectweb.jonas.common.Log;
039: import org.objectweb.jonas.jmx.JmxService;
040: import org.objectweb.jonas.jmx.JonasObjectName;
041: import org.objectweb.jonas.jtm.TransactionService;
042: import org.objectweb.jonas.management.ReconfiguredProp;
043: import org.objectweb.jonas.service.AbsServiceImpl;
044: import org.objectweb.jonas.service.ServiceException;
045: import org.objectweb.jonas.service.ServiceManager;
046: import org.objectweb.jonas_jms.JmsJmxManagement;
047: import org.objectweb.jonas_jms.JmsManagerImpl;
048: import org.objectweb.jonas_jms.api.JmsManager;
049: import org.objectweb.util.monolog.api.BasicLevel;
050: import org.objectweb.util.monolog.api.Logger;
051:
052: /**
053: * JMS Service implementation.
054: * @author Philippe Coq
055: * Contributor(s):
056: * Adriana Danes: highlight configuration properties
057: * 03.05.27 - Add support for monitoring of JMS destinations
058: */
059:
060: public class JmsServiceImpl extends AbsServiceImpl implements
061: JmsService, JmsServiceImplMBean {
062:
063: // loggers
064: static private Logger serverlog = null;
065: static private Logger loaderlog = null;
066:
067: // Service name as used to label configuration properties
068: public static final String SERVICE_NAME = "jms";
069:
070: // Configuration information used when starting the JMS service
071: String momProviderClassName;
072: Vector queueNames = new Vector();
073: Vector topicNames = new Vector();
074: private boolean momLocal;
075: String url;
076: String jmsClass;
077: TransactionService transactionService = null;
078:
079: // JMS manager
080: JmsManager jonasjms = null;
081: JmsJmxManagement jmsjmx = null;
082:
083: // JMS service configuration properties
084: public static final String COLLOCATED = "jonas.service.jms.collocated";
085: public static final String MOM = "jonas.service.jms.mom";
086: public static final String TOPICS = "jonas.service.jms.topics";
087: public static final String QUEUES = "jonas.service.jms.queues";
088: public static final String DESTINATIONS = "jonas.service.jms.dest";
089: public static final String URL = "jonas.service.jms.url";
090: public static final String CLASS = "jonas.service.jms.class";
091:
092: // Value used as sequence number by reconfiguration notifications
093: long sequenceNumber = 0;
094:
095: // -------------------------------------------------------------------
096: // Service Implementation
097: // -------------------------------------------------------------------
098:
099: /**
100: * Init the Service.
101: * Configuration information is passed thru a Context object.
102: */
103: public void doInit(Context ctx) throws ServiceException {
104:
105: // get loggers
106: serverlog = Log.getLogger(Log.JONAS_SERVER_PREFIX);
107: loaderlog = Log.getLogger(Log.JONAS_LOADER_PREFIX);
108: super .initLogger(Log.getLogger(Log.JONAS_MANAGEMENT_PREFIX));
109:
110: // Read the configuration information
111: try {
112: momProviderClassName = (String) ctx.lookup(MOM);
113: } catch (NamingException e) {
114: serverlog.log(BasicLevel.ERROR,
115: "JMS Service Cannot read configuration " + e);
116: throw new ServiceException(
117: "JMS Service Cannot read configuration ", e);
118: }
119:
120: String ql = null;
121: try {
122: ql = (String) ctx.lookup(QUEUES);
123: } catch (NamingException e) {
124: // No queue predefined
125: }
126: if (ql != null) {
127: StringTokenizer st = new StringTokenizer(ql, ",");
128: while (st.hasMoreTokens()) {
129: queueNames.add(st.nextToken().trim());
130: }
131: }
132:
133: String tl = null;
134: try {
135: tl = (String) ctx.lookup(TOPICS);
136: } catch (NamingException e) {
137: // No topic predefined
138: }
139: if (tl != null) {
140: StringTokenizer st = new StringTokenizer(tl, ",");
141: while (st.hasMoreTokens()) {
142: topicNames.add(st.nextToken().trim());
143: }
144: }
145:
146: String local = "true";
147: try {
148: local = (String) ctx.lookup(COLLOCATED);
149: } catch (NamingException e) {
150: // default value is collocated
151: }
152: momLocal = local.equalsIgnoreCase("true");
153:
154: url = "";
155: try {
156: url = (String) ctx.lookup(URL);
157: } catch (NamingException e) {
158: // default value is null string
159: }
160:
161: // Get the transaction service
162: try {
163: transactionService = (TransactionService) ServiceManager
164: .getInstance().getTransactionService();
165: } catch (Exception e) {
166: serverlog.log(BasicLevel.ERROR,
167: "Error when starting the JMS service " + e);
168: throw new ServiceException(
169: "Error when starting the JMS service ", e);
170: }
171:
172: if (serverlog.isLoggable(BasicLevel.DEBUG)) {
173: serverlog.log(BasicLevel.DEBUG, "JMS service initialized");
174: }
175: }
176:
177: /**
178: * Start the Service
179: * Initialization of the service is already done.
180: * For administrating objects we use the class specified in the jms.provider property
181: * by default we use the Joram implementation
182: */
183: public void doStart() throws ServiceException {
184:
185: if (momLocal) {
186: if (serverlog.isLoggable(BasicLevel.DEBUG)) {
187: serverlog.log(BasicLevel.DEBUG,
188: "Starting JMS Service with collocated MOM");
189: }
190: } else {
191: if (serverlog.isLoggable(BasicLevel.DEBUG)) {
192: serverlog.log(BasicLevel.DEBUG,
193: "Starting JMS Service with MOM at url " + url);
194: }
195: }
196:
197: jonasjms = JmsManagerImpl.getJmsManager();
198: jmsjmx = JmsManagerImpl.getJmsJmxManagement();
199:
200: Class c = null;
201: if (loaderlog.isLoggable(BasicLevel.DEBUG)) {
202: loaderlog.log(BasicLevel.DEBUG,
203: "JmsServiceImpl classloader="
204: + getClass().getClassLoader());
205: }
206: try {
207: ClassLoader loader = JmsManagerImpl.class.getClassLoader();
208: if (loader == null) {
209: loader = Thread.currentThread().getContextClassLoader();
210: }
211: c = loader.loadClass(momProviderClassName);
212: if (loaderlog.isLoggable(BasicLevel.DEBUG)) {
213: loaderlog.log(BasicLevel.DEBUG, momProviderClassName
214: + " classloader=" + loader);
215: }
216: } catch (Exception e) {
217: serverlog.log(BasicLevel.ERROR,
218: "JMS Service Cannot load admin class " + e);
219: throw new ServiceException(
220: "JMS Service Cannot load admin class", e);
221: }
222:
223: // initialization of the JmsManager with implementation class for Administration
224: try {
225: jonasjms.init(c, momLocal, url, transactionService
226: .getTransactionManager());
227: } catch (Exception e) {
228: serverlog.log(BasicLevel.ERROR,
229: "JMS Service Cannot init the JMS manager " + e);
230: throw new ServiceException(
231: "JMS Service Cannot init the JMS manager", e);
232: }
233:
234: // Create Topics and Queues
235: try {
236: // Create administered objects for Queues
237: for (int i = 0; i < queueNames.size(); i++) {
238: Queue q = jonasjms.createQueue((String) queueNames
239: .elementAt(i));
240: }
241:
242: // Create administered objects for Topics
243: for (int i = 0; i < topicNames.size(); i++) {
244: Topic t = jonasjms.createTopic((String) topicNames
245: .elementAt(i));
246: }
247: } catch (Exception ex) {
248: serverlog.log(BasicLevel.ERROR,
249: "JMS Service Cannot create administered object : "
250: + ex.toString());
251: try {
252: jonasjms.stop();
253: jonasjms = null;
254: } catch (Exception e) {
255: }
256: throw new ServiceException(
257: "JMS Service Cannot create administered object", ex);
258: }
259:
260: try {
261: // Register JmsService MBean : JmxJmsService
262: ((JmxService) ServiceManager.getInstance().getJmxService())
263: .getJmxServer().registerMBean(this ,
264: JonasObjectName.jmsService());
265: } catch (ServiceException se) {
266: // Jmx Service not available, do nothing
267: } catch (Exception e) {
268: serverlog.log(BasicLevel.ERROR,
269: "JmsService: Cannot start the JMS service:\n" + e);
270: throw new ServiceException(
271: "JmsService: Cannot start the JMS service", e);
272: }
273:
274: }
275:
276: /**
277: * Stop the JMS Service
278: */
279: public void doStop() throws ServiceException {
280:
281: try {
282: jonasjms.stop();
283: } catch (Exception e) {
284: serverlog.log(BasicLevel.ERROR,
285: "JMS Service Cannot stop the JMS manager " + e);
286: throw new ServiceException(
287: "JMS Service Cannot stop the JMS manager", e);
288: }
289: // unregister MBean
290: try {
291: // unregister jms Service MBean
292: ((JmxService) ServiceManager.getInstance().getJmxService())
293: .getJmxServer().unregisterMBean(
294: JonasObjectName.jmsService());
295: } catch (ServiceException se) {
296: // Jmx Service not available, do nothing
297: } catch (Exception e) {
298: serverlog.log(BasicLevel.ERROR,
299: "Cannot stop the JMS service:\n" + e);
300: throw new ServiceException("Cannot stop the JMS service", e);
301: }
302: serverlog.log(BasicLevel.DEBUG, "JMS Service stopped");
303: }
304:
305: // -------------------------------------------------------------------
306: // JMS Service Implementation
307: // -------------------------------------------------------------------
308:
309: public JmsManager getJmsManager() {
310: return jonasjms;
311: }
312:
313: /**
314: * MBean method
315: * @return the current number of Jms Connection Factory
316: */
317: public Integer getCurrentNumberOfJmsConnectionFactory() {
318: return new Integer(jmsjmx
319: .getCurrentNumberOfJmsConnectionFactory());
320: }
321:
322: /**
323: * MBean method
324: * @return the current number of Topic Jms Connection Factory
325: */
326: public Integer getCurrentNumberOfJmsTopicConnectionFactory() {
327: return new Integer(jmsjmx
328: .getCurrentNumberOfJmsTopicConnectionFactory());
329:
330: }
331:
332: /**
333: * MBean method
334: * @return the current number of Queue Jms Connection Factory
335: */
336: public Integer getCurrentNumberOfJmsQueueConnectionFactory() {
337: return new Integer(jmsjmx
338: .getCurrentNumberOfJmsQueueConnectionFactory());
339: }
340:
341: /**
342: * MBean method
343: * @return the current number of Topic Jms Destination
344: */
345: public Integer getCurrentNumberOfJmsTopicDestination() {
346: return new Integer(jmsjmx
347: .getCurrentNumberOfJmsTopicDestination());
348: }
349:
350: /**
351: * MBean method
352: * @return the current number of Queue Jms Destination
353: */
354: public Integer getCurrentNumberOfJmsQueueDestination() {
355: return new Integer(jmsjmx
356: .getCurrentNumberOfJmsQueueDestination());
357: }
358:
359: /**
360: * MBean method
361: * Create a new Jms queue destination
362: * @param String jndi Name
363: * not yet implement with a remote host
364: */
365: public void createJmsQueueDestination(String jndiName) {
366: try {
367: jonasjms.createQueue(jndiName);
368:
369: // Send to the listner MBean a notification containing the new value of this property and
370: // the indication that the new value has to be added to a list of values
371: ReconfiguredProp p = new ReconfiguredProp(QUEUES, jndiName,
372: false);
373: p.setAdd(true);
374: sendReconfigNotification(++sequenceNumber, SERVICE_NAME, p);
375: } catch (Exception e) {
376: serverlog.log(BasicLevel.ERROR,
377: "JmsService: Exception when create destination "
378: + jndiName + ": " + e);
379: }
380: }
381:
382: /**
383: * MBean method
384: * Create a new Jms topic destination
385: * @param String jndi Name
386: * not yet implement with a remote host
387: */
388: public void createJmsTopicDestination(String jndiName) {
389: try {
390: jonasjms.createTopic(jndiName);
391:
392: // Send to the listner MBean a notification containing the new value of this property and
393: // the indication that the new value has to be added to a list of values
394: ReconfiguredProp p = new ReconfiguredProp(TOPICS, jndiName,
395: false);
396: p.setAdd(true);
397: sendReconfigNotification(++sequenceNumber, SERVICE_NAME, p);
398: } catch (Exception e) {
399: serverlog.log(BasicLevel.ERROR,
400: "JmsService: Exception when create destination "
401: + jndiName + ": " + e);
402: }
403: }
404:
405: /**
406: * MBean method
407: * Remove a Jms destination
408: * @param String jndi name
409: */
410: public void removeJmsTopicDestination(String jndiName) {
411: try {
412: jmsjmx.removeJmsDestination(jndiName);
413:
414: // Send to the listner MBean a notification containing the new value of this property and
415: // the indication that the new value has to be removed from a list of values
416: ReconfiguredProp p = new ReconfiguredProp(TOPICS, jndiName,
417: false);
418: p.setAdd(false);
419: sendReconfigNotification(++sequenceNumber, SERVICE_NAME, p);
420: } catch (Exception e) {
421: // remove problem
422: serverlog
423: .log(BasicLevel.ERROR,
424: "JmsService: Exception when remove destination"
425: + e);
426: }
427: }
428:
429: /**
430: * MBean method
431: * Remove a Jms destination
432: * @param String jndi name
433: */
434: public void removeJmsQueueDestination(String jndiName) {
435: try {
436: jmsjmx.removeJmsDestination(jndiName);
437:
438: // Send to the listner MBean a notification containing the new value of this property and
439: // the indication that the new value has to be removed from a list of values
440: ReconfiguredProp p = new ReconfiguredProp(QUEUES, jndiName,
441: false);
442: p.setAdd(false);
443: sendReconfigNotification(++sequenceNumber, SERVICE_NAME, p);
444: } catch (Exception e) {
445: // remove problem
446: serverlog
447: .log(BasicLevel.ERROR,
448: "JmsService: Exception when remove destination"
449: + e);
450: }
451: }
452:
453: /**
454: * Remove a Jms destination
455: * @param String jndi name
456: */
457: public void removeJmsDestination(String jndiName) {
458: try {
459: String destType = jmsjmx.removeJmsDestination(jndiName);
460:
461: // Send to the listner MBean a notification containing the new value of this property and
462: // the indication that the new value has to be removed from a list of values
463: ReconfiguredProp p = null;
464: if (destType.equals("queue")) {
465: p = new ReconfiguredProp(QUEUES, jndiName, false);
466: } else if (destType.equals("topic")) {
467: p = new ReconfiguredProp(TOPICS, jndiName, false);
468: } else {
469: return;
470: }
471: p.setAdd(false);
472: sendReconfigNotification(++sequenceNumber, SERVICE_NAME, p);
473: } catch (Exception e) {
474: // remove problem
475: serverlog
476: .log(BasicLevel.ERROR,
477: "JmsService: Exception when remove destination"
478: + e);
479: }
480: }
481:
482: /**
483: * MBean method
484: * return Set of Queue Destinations Names
485: */
486: public Set getAllJmsQueueDestinationNames() {
487: HashSet result = new HashSet();
488: for (Enumeration enu = jonasjms.getQueuesNames(); enu
489: .hasMoreElements();) {
490: result.add(enu.nextElement());
491: }
492: return result;
493: }
494:
495: /**
496: * MBean method
497: * return Set of Topic Destination Names
498: */
499: public Set getAllJmsTopicDestinationNames() {
500: HashSet result = new HashSet();
501: for (Enumeration enu = jonasjms.getTopicsNames(); enu
502: .hasMoreElements();) {
503: result.add(enu.nextElement());
504: }
505: return result;
506: }
507:
508: /**
509: * MBean method
510: * return Set of Connection Factory Names
511: */
512: public Set getAllJmsConnectionFactoryNames() {
513: HashSet result = new HashSet();
514: return result;
515: }
516:
517: /**
518: * MBean method
519: * return Set of Queue Connection Factory Names
520: */
521: public Set getAllJmsQueueConnectionFactoryNames() {
522: HashSet result = new HashSet();
523: return result;
524: }
525:
526: /**
527: * MBean method
528: * return Set of Topic Connection Factory Names
529: */
530: public Set getAllJmsTopicConnectionFactoryNames() {
531: HashSet result = new HashSet();
532: return result;
533: }
534:
535: /**
536: * MBean method
537: * @return String name of default Queue Connection factory
538: */
539: public String getDefaultQueueConnectionFactoryName() {
540: return jmsjmx.getDefaultQueueConnectionFactoryName();
541: }
542:
543: /**
544: * MBean method
545: * @return String name of default Topic Connection factory
546: */
547: public String getDefaultTopicConnectionFactoryName() {
548: return jmsjmx.getDefaultTopicConnectionFactoryName();
549: }
550:
551: /**
552: * @return String name of default Connection factory
553: */
554: public String getDefaultConnectionFactoryName() {
555: return jmsjmx.getDefaultConnectionFactoryName();
556: }
557:
558: /**
559: * MBean method:
560: * save updated configuration
561: */
562: public void saveConfig() {
563: sendSaveNotification(++sequenceNumber, SERVICE_NAME);
564: }
565:
566: // Monitoring methods
567:
568: /**
569: * Get the messaging mode a connection factory belongs to
570: * @param jndiName connection factory name
571: * @return messaging mode
572: */
573: public String getConnectionFactoryMode(String jndiName) {
574: serverlog.log(BasicLevel.DEBUG, "");
575: String m = null;
576: try {
577: m = jmsjmx.getConnectionFactoryMode(jndiName);
578: } catch (IllegalStateException se) {
579: // nothing to do
580: } catch (Exception e) {
581: serverlog.log(BasicLevel.ERROR,
582: "Exception when calling monitoring operation " + e);
583: }
584: return m;
585: }
586:
587: /**
588: * Get number of pending messages on a queue
589: * @param jndiName queue name
590: * @return number of pending messages
591: */
592: public Integer getPendingMessages(String jndiName) {
593: serverlog.log(BasicLevel.DEBUG, "");
594: Integer nb = null;
595: int n;
596: try {
597: n = jmsjmx.getPendingMessages(jndiName);
598: nb = new Integer(n);
599: } catch (IllegalStateException se) {
600: // nothing to do
601: } catch (Exception e) {
602: serverlog.log(BasicLevel.ERROR,
603: "Exception when calling monitoring operation " + e);
604: }
605: return nb;
606: }
607:
608: /**
609: * Get number of pending requests on a queue
610: * @param jndiName queue name
611: * @return number of pending requests. If nb null, could not get this information.
612: */
613: public Integer getPendingRequests(String jndiName) {
614: if (serverlog.isLoggable(BasicLevel.DEBUG)) {
615: serverlog.log(BasicLevel.DEBUG, "");
616: }
617: Integer nb = null;
618: int n;
619: try {
620: n = jmsjmx.getPendingRequests(jndiName);
621: nb = new Integer(n);
622: } catch (IllegalStateException se) {
623: // nothing to do
624: } catch (Exception e) {
625: serverlog.log(BasicLevel.ERROR,
626: "Exception when calling monitoring operation " + e);
627: }
628: return nb;
629: }
630:
631: /**
632: * Get number of subscriptions on a topic
633: * @param jndiName topic name
634: * @return number of subscriptions
635: */
636: public Integer getSubscriptions(String jndiName) {
637: if (serverlog.isLoggable(BasicLevel.DEBUG)) {
638: serverlog.log(BasicLevel.DEBUG, "");
639: }
640: Integer nb = null;
641: int n;
642: try {
643: n = jmsjmx.getSubscriptions(jndiName);
644: nb = new Integer(n);
645: } catch (IllegalStateException se) {
646: // nothing to do
647: } catch (Exception e) {
648: serverlog.log(BasicLevel.ERROR,
649: "Exception when calling monitoring operation " + e);
650: }
651: return nb;
652: }
653:
654: /**
655: * @return the MOM's URL if distant or "" if collocated
656: */
657: public String getUrl() {
658: return url;
659: }
660:
661: public String getMom() {
662: return momProviderClassName;
663: }
664:
665: public Boolean isMomLocal() {
666: return new Boolean(momLocal);
667: }
668:
669: }
|