View Full Version : DMLC - will it be a registered MBean
barathwajram
May 18th, 2007, 11:04 AM
Hi
I have some DefaultMessageListenerContainer in my application.
I am figuring out a way to start and stop these beans either using a custom client or through the mbean console of WAS. Does spring register this DMLC as a MBean in the server or not. How will i be able to start and stop this object at runtime.
Any ideas are appreciated.
Thanks
Barath
Cyrille Le Clerc
May 20th, 2007, 01:06 PM
Hello Barrath,
DefaultMessageListenerContainer can not benefit of automatic jmx-exposition as it is not annoted and it does implement an MBean interface (DefaultMessageListenerContainerMBean or DynamicMBean).
A way to expose DefaultMessageListenerContainer via JMX is to subclass it and implement one of the Spring auto jmx-exposition mechanisms (annotation or interface).
Here is a solution using annotations. It basically overrides the getter, setters and operations to expose with the appropriate annotation (@ManagedAttribute and @ManagedOperation).
Implementation notes:
When the getter/setter/operation to expose is final, it has been renamed with the 'Container' prefix.
JMX descriptions are based on the Javadoc
This class implements SelfNaming interface to compose the ObjectName with @ManagedResource.objectName value and the bean name.
/**
* <p>
* Spring JMX-ification of <code>DefaultMessageListenerContainer</code> via subclassing.
* </p>
* <p>
* Methods are just overridden if they are not <code>final</code>. Otherwise, the name is prefixed by
* <code>container</code>. JMX descriptions are inspired of the javadoc of the attributes and methods;
* </p>
* <p>
* Implement {@link SelfNaming} to append the bean name to the object name
* </p>
*
* @author <a href="mailto:cyrille.leclerc@pobox.com">Cyrille Le Clerc</a>
*/
@ManagedResource(objectName = "application:type=SpringJmsMessageListener")
public class JmxAnnotedDefaultMessageListenerContainer extends DefaultMessageListenerContainer implements SelfNaming {
@ManagedAttribute(description = "Level of caching that this listener container is allowed to apply "
+ "(CACHE_NONE = 0, CACHE_CONNECTION = 1, CACHE_SESSION = 2, CACHE_CONSUMER = 3)")
@Override
public int getCacheLevel() {
return super.getCacheLevel();
}
@ManagedAttribute(description = "JMS client ID for the shared Connection created and used "
+ "by this container, if any")
@Override
public String getClientId() {
return super.getClientId();
}
/**
* Override {@link DefaultMessageListenerContainer#getActiveConsumerC ount()} with another name because it is
* <code>final</code>.
*
* @see #getActiveConsumerCount()
*/
@ManagedAttribute(description = "Return the number of currently active consumers. "
+ "This number will always be inbetween 'concurrentConsumers and "
+ "'maxConcurrentConsumers', but might be lower than 'scheduledConsumerCount' "
+ "(in case of some consumers being scheduled but not executed at the moment)")
public int getContainerActiveConsumerCount() {
return super.getActiveConsumerCount();
}
/**
* Override {@link DefaultMessageListenerContainer#getConcurrentConsu mers()} with another name because it is
* <code>final</code>.
*
* @see #getConcurrentConsumers()
*/
@ManagedAttribute(description = "Return the 'concurrentConsumer' setting. "
+ "This returns the currently configured 'concurrentConsumers' value; "
+ " the number of currently scheduled/active consumers might differ.")
public int getContainerConcurrentConsumers() {
return super.getConcurrentConsumers();
}
/**
* Combine names from {link {@link #getDestination()} and {@link #getDestinationName()}.
*
* @throws JMSException
*
* @see #getDestination()
* @see #getDestinationName()
*/
@ManagedAttribute(description = "Name of the destination to receive messages from")
public String getContainerDestinationName() throws JMSException {
String destinationName = null;
if (super.getDestinationName() != null) {
destinationName = super.getDestinationName();
}
if (super.getDestination() != null) {
Destination destination = super.getDestination();
if (destination instanceof Queue) {
Queue queue = (Queue) destination;
destinationName = "Queue: " + queue.getQueueName();
} else if (destination instanceof Topic) {
Topic topic = (Topic) destination;
destinationName = "Topic: " + topic.getTopicName();
} else {
// should not occur
}
}
return destinationName;
}
/**
* Override {@link DefaultMessageListenerContainer#getMaxConcurrentCo nsumers()} with another name because it is
* <code>final</code>.
*
* @see #getMaxConcurrentConsumers()
*/
@ManagedAttribute(description = "Return the 'maxConcurrentConsumer' setting. "
+ "This returns the currently configured 'maxConcurrentConsumers' value; "
+ "the number of currently scheduled/active consumers might differ.")
public int getContainerMaxConcurrentConsumers() {
return super.getMaxConcurrentConsumers();
}
/**
* Override {@link DefaultMessageListenerContainer#getScheduledConsum erCount()} with another name because it is
* <code>final</code>.
*
* @see #getScheduledConsumerCount()
*/
@ManagedAttribute(description = "Return the number of currently scheduled consumers. "
+ "This number will always be inbetween 'concurrentConsumers' and "
+ "'maxConcurrentConsumers', but might be higher than 'activeConsumerCount' "
+ "(in case of some consumers being scheduled but not executed at the moment).")
public int getContainerScheduledConsumerCount() {
return super.getScheduledConsumerCount();
}
@ManagedAttribute(description = "name of a durable subscription to create, if any.")
@Override
public String getDurableSubscriptionName() {
return super.getDurableSubscriptionName();
}
@ManagedAttribute(description = "Limit for idle executions of a receive task")
@Override
public int getIdleTaskExecutionLimit() {
return super.getIdleTaskExecutionLimit();
}
@ManagedAttribute(description = "Maximum number of messages to process in one task")
@Override
public int getMaxMessagesPerTask() {
return super.getMaxMessagesPerTask();
}
@ManagedAttribute(description = "JMS message selector expression (or null if none)")
@Override
public String getMessageSelector() {
return super.getMessageSelector();
}
/**
* Compose <code>objectName</code> with <code>@ManagedResource#objectName</code> annotation and the bean name obtained via <code>BeanNameAware</code>
* contract.
*
* @see org.springframework.jmx.export.naming.SelfNaming#g etObjectName()
* @see ManagedResource#objectName()
* @see BeanNameAware
*/
public ObjectName getObjectName() throws MalformedObjectNameException {
ManagedResource managedResource = JmxAnnotedDefaultMessageListenerContainer.class
.getAnnotation(ManagedResource.class);
String objectNameAsString = managedResource.objectName() + ",beanName=" + getBeanName();
return ObjectName.getInstance(objectNameAsString);
}
@ManagedAttribute(description = "Acknowledgement mode for JMS sessions "
+ "(SESSION_TRANSACTED = 0, AUTO_ACKNOWLEDGE = 1, CLIENT_ACKNOWLEDGE = 2, DUPS_OK_ACKNOWLEDGE = 3")
@Override
public int getSessionAcknowledgeMode() {
return super.getSessionAcknowledgeMode();
}
/**
* Can NOT override {@link AbstractJmsListeningContainer#isActive()} because this method is final. We use another
* name to jmx-annotate this attribute
*/
@ManagedAttribute(description = "Return whether this container is currently active, "
+ "that is, whether it has been set up but not shut down yet.")
public boolean isContainerActive() {
return super.isActive();
}
/**
* Override {@link AbstractJmsListeningContainer#isRunning()} with another name because this method is
* <code>final</code>.
*
* @see #isRunning()
*/
@ManagedAttribute(description = "Return whether this container is currently running, "
+ "that is, whether it has been set up but not shut down yet.")
public boolean isContainerRunning() {
return super.isRunning();
}
@ManagedOperation(description = "Start this container")
@Override
public void start() throws JmsException {
super.start();
}
@ManagedOperation(description = "Stop this container")
@Override
public void stop() throws JmsException {
super.stop();
}
}
I also attached a test case to display the exposed attributes.
Hope this helps,
Cyrille
Arjen Poutsma
May 21st, 2007, 04:49 AM
Alternatively, expose the container by using a InterfaceBasedMBeanInfoAssembler rather than a MetadataMBeanInfoAssembler, and expose it by means of the Lifecycle interface, which constains start(), stop(), and isRunning().
barathwajram
May 23rd, 2007, 10:57 AM
Thanks. That was helpfull.
Barath
Cyrille Le Clerc
Nov 22nd, 2010, 07:11 PM
Hello,
For the update, we have packaged a detailed and documented version of a JMX enabled version of the DefaultMessageListener at ManagedSpringJmsDefaultMessageListenerContainer (http://code.google.com/p/xebia-france/wiki/ManagedSpringJmsDefaultMessageListenerContainer) (1).
We also developed JMX enabled JMS ConnectionFactory, Spring JMS CachingConnectionFactory and many other JMX enabled components : Commons DBCP DataSource, util concurrent ThreadPoolExecutor / ExecutorService, etc
All these components have Spring XML namespace configuration.
All the details are here : XebiaManagementExtras (http://code.google.com/p/xebia-france/wiki/XebiaManagementExtras) (2).
Hope this helps,
Cyrille
(1) http://code.google.com/p/xebia-france/wiki/ManagedSpringJmsDefaultMessageListenerContainer
(2) http://code.google.com/p/xebia-france/wiki/XebiaManagementExtras
Powered by vBulletin® Version 4.2.1 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.