This note demonstrates how to create and deploy an MDP, and how to control it, using both Spring’s inbuilt component management mechanisms, and JMX.
We have a number of JMS listeners in our application. Having ported our hardware to a grid of virtual machines, we want the feature to switch-on and switch-off the listeners on the VMs, and re-allocate the listeners to VMs across the grid on-demand, to make best use of the resources.
This note just deals briefly with configuring the MDP, and switching it on and off.
- What is an MDP?
- MDP stands for Message Driven Pojo.
In the EJB world we have MDBs (Message Driven Beans). These are standard JEE components which are configured on a server and which act as a Message Listener.
Spring provides MDPs as an answer to MDBs.
Some helpful links are:
http://java.sun.com/j2se/1.5.0/docs/guide/jmx/overview/JMXoverviewTOC.html
Extract from the Spring Config XML file spring_context_jms.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<!-- Destination configuration -->
<
bean
id
=
"sample_queue"
class
=
"org.apache.activemq.command.ActiveMQQueue"
autowire
=
"constructor"
>
<
constructor-arg
>
<
value
>SAMPLE.QUEUE</
value
>
</
constructor-arg
>
</
bean
>
<!-- Message Listener Container configuration -->
<
bean
id
=
"sample_jmsContainer"
class
=
"org.springframework.jms.listener.DefaultMessageListenerContainer102"
>
<
property
name
=
"connectionFactory"
ref
=
"activeMqQueueConnectionFactory"
/>
<
property
name
=
"destination"
ref
=
" sample_queue"
/>
<
property
name
=
"messageListener"
ref
=
"sample_messageListener"
/>
</
bean
>
<!-- Message Driven POJO (MDP) configuration -->
<
bean
id
=
"sample_messageListener"
class
=
"jmsexample.ExampleListener"
>
<
property
name
=
"listener"
ref
=
"sample_jmsContainer"
/>
</
bean
>
|
The sample class we create (sample_messageListener of class “jmsexample.ExampleListener”) must extend javax.jms.MessageListener and implement the “onMessage” method.
As seen from the Spring configuration above, we have provided this as a ref to the “messageListener” property in the “DefaultMessageListenerContainer102” class.
Also as seen above, we have provided a ref to “sample_jmsContainer” in the bean “sample_messageListener”. (This is so that we are able to expose it using JMX – as discussed further on).
The MDPs are deployed in a Web application as JMSWebApplication.war.
Follows is an extract from the web.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<
display-name
>JMSWebApplication</
display-name
>
<
welcome-file-list
>
<
welcome-file
>index.jsp</
welcome-file
>
<
welcome-file
>default.html</
welcome-file
>
</
welcome-file-list
>
<
context-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:spring_context.xml</
param-value
>
</
context-param
>
<
listener
>
<
description
>Context Loader Listener</
description
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>
|
Follows is a relevant extract from the client jsp:
01
02
03
04
05
06
07
08
09
10
11
12
|
<%
@page
import
=
"org.springframework.beans.factory.BeanFactory,org.springframework.context.ApplicationContext,org.springframework.context.support.ClassPathXmlApplicationContext,org.springframework.jms.listener.DefaultMessageListenerContainer102,org.springframework.web.context.WebApplicationContext,org.springframework.web.context.support.WebApplicationContextUtils"
%>
ServletContext context = application
.getContext(
"/JMSWebApplication"
);
WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(context);
DefaultMessageListenerContainer102 listener = (DefaultMessageListenerContainer102) wac
.getBean(
"sample_jmsContainer"
);
listener.stop();
//listener.start();
|
This involves configuring Spring JMX.
Since this is deployed in Tomcat, we will enable JMX in Tomcat and connect to it using jconsole to control this component.
1
2
3
4
5
6
7
8
9
|
<
bean
id
=
"exporter"
class
=
"org.springframework.jmx.export.MBeanExporter"
>
<
property
name
=
"beans"
>
<
map
>
<
entry
key
=
"bean:name=sample_listener_jmx"
value-ref
=
" sample_messageListener"
/>
</
map
>
</
property
>
</
bean
>
|
Provide these (self-explanatory) arguments to the JVM while starting up Tomcat
1
2
3
|
-Dcom.sun.management.jmxremote.port=10088 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
|
(Note the “startListener” and “stopListener” methods, and use of the “DefaultMessageListenerContainer102” class.)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package
jmsexample;
< imports come here ... >
public
class
ExampleListener
implements
MessageListener {
private
DefaultMessageListenerContainer102 listener;
< other variables here ... >
public
void
onMessage(Message message) {
< Business Logic here ... >
}
@ManagedAttribute
(description =
"Starts the Listener"
, currencyTimeLimit =
15
)
public
void
startListener() {
System.out.println(
"Starting listener"
);
getListener().start();
System.out.println(
"listener started "
+ getListener().isRunning());
}
@ManagedAttribute
(description =
"Stops the Listener"
, currencyTimeLimit =
15
)
public
void
stopListener() {
System.out.println(
"Stopping listener"
);
getListener().stop();
System.out.println(
"listener stopped "
+ getListener().isRunning());
}
public
DefaultMessageListenerContainer102 getListener() {
return
listener;
}
public
void
setListener(DefaultMessageListenerContainer102 listener) {
this
.listener = listener;
}
< other methods here ...>
}
|
(Note the “startListener” and “stopListener” methods exposed)
The remote connection string here, for example, is service:jmx:rmi:///jndi/rmi://localhost:10088/jmxrmi
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
String address =
"service:jmx:rmi:///jndi/rmi://localhost:10088/jmxrmi"
;
JMXServiceURL serviceURL =
new
JMXServiceURL(address);
Map<String, Object> environment =
null
;
JMXConnector connector = JMXConnectorFactory.connect(serviceURL,
environment);
MBeanServerConnection mBeanConnection = connector
.getMBeanServerConnection();
ObjectName exampleServiceName = ObjectName
.getInstance(
"bean:name=sample_listener_jmx"
);
mBeanConnection.invoke(exampleServiceName,
"startListener"
,
null
,
null
);
//mBeanConnection.invoke(exampleServiceName, "stopListener", null, null);
|