Skip to content

Commit 439391a

Browse files
author
Dariusz Suchojad
committed
SESPRINGPYTHONPY-132: Added ref docs.
git-svn-id: https://src.springframework.org/svn/se-springpython-py/sandbox/dsuch/jira/SESPRINGPYTHONPY-132@737 ce8fead1-4192-4296-8608-a705134b927f
1 parent 80340b8 commit 439391a

File tree

1 file changed

+269
-11
lines changed
  • springpython/docs/reference/src

1 file changed

+269
-11
lines changed

springpython/docs/reference/src/jms.xml

Lines changed: 269 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,39 @@
4545
<para>
4646
JMS messaging with Spring Python revolves around the idea of using
4747
a connection factory for obtaining a connection to a JMS provider and
48-
<classname>springpython.jms.core.JmsTemplate</classname> as a means for
48+
<classname>
49+
<link linkend="jms-jms-template">springpython.jms.core.JmsTemplate</link>
50+
</classname> as a means for
4951
sending and receiving messages. A JmsTemplate instance is tied
5052
to a connection factory however a single connection factory may be safely
5153
reused across multiple JmsTemplates.
5254
</para>
55+
<para>
56+
In addition to that,
57+
<classname>
58+
<link linkend="jms-simple-message-listener-container">springpython.jms.listener.SimpleMessageListenerContainer</link>
59+
</classname>
60+
allows for a purely configuration-driven way to set up background JMS
61+
listeners to receive messages from JMS providers.
62+
</para>
5363
</section>
5464

5565
<section id="jms-dependencies">
5666
<title>Dependencies</title>
5767
<para>
5868
Support for JMS messaging with WebSphere MQ is built on top of
59-
the CPython-only <ulink url="http://pymqi.sf.net">PyMQI</ulink> library which provides
69+
the CPython-only <ulink url="https://launchpad.net/pymqi">PyMQI</ulink> library which provides
6070
Python applications an access to WebSphere MQ queue managers. You need to separately install
6171
PyMQI in order to use <classname>springpython.jms.factory.WebSphereMQConnectionFactory</classname>.
6272
PyMQI, in turn, needs a <emphasis>WebSphere MQ client</emphasis>, a runtime library
6373
which may be freely downloaded from IBM's site.
6474
</para>
75+
<para>
76+
<classname>SimpleMessageListenerContainer</classname>, a Spring Python component which
77+
helps with running background JMS listeners, requires the installation
78+
of <ulink url="http://code.google.com/p/circuits/">Circuits 1.2+</ulink>
79+
and <ulink url="http://pypi.python.org/pypi/threadpool">threadpool 1.2.7 or newer.</ulink>
80+
</para>
6581
</section>
6682

6783
<section id="jms-quick-start">
@@ -112,7 +128,7 @@ objects:
112128
queue_manager: QM.1
113129
channel: SVRCONN.1
114130
host: 192.168.1.121
115-
listener_port: 1434
131+
listener_port: "1434"
116132
117133
- object: MyTemplate
118134
class: springpython.jms.core.JmsTemplate
@@ -197,7 +213,7 @@ objects:
197213
queue_manager: QM.1
198214
channel: SVRCONN.1
199215
host: 192.168.1.121
200-
listener_port: 1434
216+
listener_port: "1434"
201217
202218
- object: MyTemplate
203219
class: springpython.jms.core.JmsTemplate
@@ -230,6 +246,54 @@ jms_template.receive(queue1)
230246
# care of shutting down the factory. No need for manually destroying it.
231247
]]></programlisting>
232248

249+
<para>
250+
Here's a sample YAML context utilizing the SimpleMessageListenerContainer
251+
component and an accompanying Python code using it. As you can see,
252+
a mere fact of providing the configuration allows for receiving
253+
the messages.
254+
</para>
255+
<programlisting><![CDATA[
256+
objects:
257+
- object: connection_factory
258+
class: springpython.jms.factory.WebSphereMQConnectionFactory
259+
properties:
260+
queue_manager: QM.1
261+
channel: SVRCONN.1
262+
host: 192.168.1.121
263+
listener_port: "1434"
264+
265+
- object: message_handler
266+
class: app.MyMessageHandler
267+
268+
- object: listener_container
269+
class: springpython.jms.listener.SimpleMessageListenerContainer
270+
properties:
271+
factory: {ref: connection_factory}
272+
handler: {ref: message_handler}
273+
destination: TEST.1
274+
]]></programlisting>
275+
276+
<programlisting><![CDATA[
277+
278+
# app.py
279+
280+
from springpython.config import YamlConfig
281+
from springpython.context import ApplicationContext
282+
283+
class MyMessageHandler(object):
284+
def handle(self, message):
285+
print "Got message!", message
286+
287+
if __name__ == "__main__":
288+
289+
# Obtaining a context will automatically start the SimpleMessageListenerContainer and its listeners in background.
290+
container = ApplicationContext(YamlConfig("./context.yml"))
291+
292+
while True:
293+
# Here goes the application's logic. Any JMS messages, as configured
294+
# in ./context.yml, will be passed in to a singleton MyMessageHandler instance.
295+
pass
296+
]]></programlisting>
233297
</section>
234298
</section>
235299

@@ -444,7 +508,7 @@ objects:
444508
queue_manager: QM.1
445509
channel: SVRCONN.1
446510
host: 192.168.1.121
447-
listener_port: 1434
511+
listener_port: "1434"
448512
]]></programlisting>
449513

450514
<para>
@@ -483,7 +547,8 @@ objects:
483547
<title>springpython.jms.core.JmsTemplate</title>
484548

485549
<para>
486-
JmsTemplate is the class to use for sending and receiving JMS messages.
550+
JmsTemplate is the class to use for sending JMS messages; along
551+
with SimpleMessageListenerContainer it may also be used in order to receive them.
487552
A template must be associated with a connection factory and once
488553
configured, may be used for communicating in both directions. It's
489554
up to you to decide whether in your circumstances it makes sense
@@ -533,7 +598,7 @@ objects:
533598
queue_manager: QM.1
534599
channel: SVRCONN.1
535600
host: 192.168.1.121
536-
listener_port: 1434
601+
listener_port: "1434"
537602
538603
- object: jms_template
539604
class: springpython.jms.core.JmsTemplate
@@ -876,6 +941,12 @@ print jms_template.receive(queue2, 2000)
876941
# We're not using an IoC so we need to shut down the connection factory ourselves.
877942
factory.destroy()
878943
]]></programlisting>
944+
945+
<para>
946+
Note that <link linkend="jms-simple-message-listener-container">SimpleMessageListenerContainer</link>
947+
provides a complementary way for receiving the messages, particularly
948+
well suited for long-running processes, such as servers.
949+
</para>
879950

880951
</section>
881952

@@ -1090,6 +1161,170 @@ factory.destroy()
10901161
</section>
10911162
</section>
10921163

1164+
<section id="jms-simple-message-listener-container">
1165+
<title>springpython.jms.listener.SimpleMessageListenerContainer and background JMS listeners</title>
1166+
1167+
<para>
1168+
SimpleMessageListenerContainer is a configuration-driven component
1169+
which is used to receive messages from JMS destinations. Once configured,
1170+
the container starts as many background listeners as requested and
1171+
each listener gets assigned a pool of threads to handle the incoming
1172+
requests. The number of listeners started and threads in a pool is
1173+
fixed upon the configuration is read and the container is started,
1174+
they cannot be dynamically altered in runtime.
1175+
</para>
1176+
<para>
1177+
The advantage of using SimpleMessageListenerContainer comes from
1178+
the fact that all you need to do in order to receive the messages
1179+
is to create your own handler class and to configure the container,
1180+
no JMS coding is required so you're focusing on creating the business
1181+
logic, not on the JMS boilerplate.
1182+
</para>
1183+
1184+
<para>
1185+
<table id="jms-simple-message-listener-container-properties">
1186+
1187+
<title><classname>SimpleMessageListenerContainer</classname> properties</title>
1188+
1189+
<tgroup cols="2">
1190+
<tbody>
1191+
<row>
1192+
<entry>factory</entry>
1193+
<entry>A reference to a JMS connection factory;
1194+
defaults to None and must be set manually.
1195+
</entry>
1196+
</row>
1197+
<row>
1198+
<entry>destination</entry>
1199+
<entry>Name of a JMS destination to read the messages
1200+
off. Defaults to None and must be set manually.
1201+
</entry>
1202+
</row>
1203+
<row>
1204+
<entry>handler</entry>
1205+
<entry>A reference to an object which will be receiving
1206+
messages read from the JMS destination. A handler must
1207+
implement <emphasis>handle(self, message)</emphasis>
1208+
method, of which the <emphasis>message</emphasis> argument
1209+
is a <link linkend="jms-text-message">TextMessage</link>
1210+
instance. There is a convenience class,
1211+
<classname>springpython.jms.listener.MessageHandler</classname>,
1212+
which exposes such a method. The exact number of handlers
1213+
available for message processing is controlled via
1214+
the <emphasis>handlers_per_listener</emphasis>
1215+
property. The <emphasis>handler</emphasis> parameter
1216+
defaults to None and must be set manually.
1217+
</entry>
1218+
</row>
1219+
<row>
1220+
<entry>concurrent_listeners</entry>
1221+
<entry>Sets a number of background processes that
1222+
connect to a JMS provider and read messages off
1223+
the destination. Default value is 1.
1224+
</entry>
1225+
</row>
1226+
<row>
1227+
<entry>handlers_per_listener</entry>
1228+
<entry>Each concurrent listener is assigned a thread pool
1229+
of a fixed size, given by the <emphasis>handlers_per_listener</emphasis>
1230+
parameter. Upon receiving a message, it will be dispatched
1231+
to a thread which will in turn invoke the message
1232+
handler's <emphasis>handle</emphasis> method.
1233+
The pool's size defaults to 2.
1234+
</entry>
1235+
</row>
1236+
<row>
1237+
<entry>wait_interval</entry>
1238+
<entry>A value in milliseconds expressing how often
1239+
each of the listeners will check for the arrival
1240+
of a new message. Defaults to 1000 (1 second).
1241+
</entry>
1242+
</row>
1243+
</tbody>
1244+
</tgroup>
1245+
</table>
1246+
</para>
1247+
1248+
<para>
1249+
Here's an example showing SimpleMessageListenerContainer in action
1250+
together with YamlConfig's abstract objects definitions.
1251+
customer_queue, credit_account_queue and deposit_account_queue
1252+
subclass the listener_container object which holds the information
1253+
common to all definitions of JMS destinations. 4 listeners will
1254+
be assigned to each of the JMS destination, every listener will be
1255+
assigned a pool of 5 threads for handling the messages read;
1256+
a wait interval of 700 milliseconds has been set.
1257+
1258+
<programlisting><![CDATA[
1259+
objects:
1260+
- object: connection_factory
1261+
class: springpython.jms.factory.WebSphereMQConnectionFactory
1262+
properties:
1263+
queue_manager: QM.1
1264+
channel: SVRCONN.1
1265+
host: 192.168.1.121
1266+
listener_port: "1434"
1267+
1268+
- object: message_handler
1269+
class: app.MyMessageHandler
1270+
1271+
- object: listener_container
1272+
abstract: True
1273+
class: springpython.jms.listener.SimpleMessageListenerContainer
1274+
concurrent_listeners: "4"
1275+
handlers_per_listener: "5"
1276+
wait_interval: "700"
1277+
properties:
1278+
factory: {ref: connection_factory}
1279+
handler: {ref: message_handler}
1280+
1281+
- object: customer_queue
1282+
parent: listener_container
1283+
properties:
1284+
destination: CUST.QUEUE.1
1285+
1286+
- object: credit_account_queue
1287+
parent: listener_container
1288+
properties:
1289+
destination: CREDACCT.QUEUE.1
1290+
1291+
- object: deposit_account_queue
1292+
parent: listener_container
1293+
properties:
1294+
destination: DEPACCT.QUEUE.1
1295+
]]></programlisting>
1296+
1297+
Here's a Python code using the above IoC configuration. Note that the fact
1298+
of reading a configuration alone suffices for JMS listeners to be started and
1299+
run in the background of the main application.
1300+
1301+
<programlisting><![CDATA[
1302+
# app.py
1303+
1304+
from springpython.config import YamlConfig
1305+
from springpython.context import ApplicationContext
1306+
1307+
class MyMessageHandler(object):
1308+
def handle(self, message):
1309+
print "Got message!", message
1310+
1311+
if __name__ == "__main__":
1312+
1313+
# Obtaining a context will automatically start the SimpleMessageListenerContainer
1314+
# and its listeners in background.
1315+
container = ApplicationContext(YamlConfig("./context.yml"))
1316+
1317+
while True:
1318+
# Here goes the main application's logic, which does nothing in this case.
1319+
# However, the listeners have been already started and incoming messages
1320+
# will be passed in to MyMessageHandler instance (as configured in YamlConfig).
1321+
pass
1322+
]]></programlisting>
1323+
1324+
</para>
1325+
1326+
</section>
1327+
10931328
<section id="jms-text-message">
10941329
<title>springpython.jms.core.TextMessage</title>
10951330

@@ -1530,10 +1765,15 @@ Hello!
15301765
</para>
15311766

15321767
<para>
1533-
The only JMS logger currently employed by Spring Python is
1534-
<classname>springpython.jms.factory.WebSphereMQConnectionFactory</classname>
1535-
and here's how it can be configured to work at the
1536-
<classname>INFO</classname> level:
1768+
JMS loggers currently employed by Spring Python are
1769+
<classname>springpython.jms.factory.WebSphereMQConnectionFactory</classname>,
1770+
<classname>springpython.jms.listener.SimpleMessageListenerContainer</classname> and
1771+
<classname>springpython.jms.listener.WebSphereMQListener(<emphasis>LISTENER_INSTANCE_ID</emphasis>)</classname>.
1772+
</para>
1773+
1774+
<para>
1775+
Here's how the WebSphere MQ connection factory's logger can be
1776+
configured to work at the <classname>INFO</classname> level:
15371777
</para>
15381778

15391779
<programlisting><![CDATA[
@@ -1578,6 +1818,24 @@ jms_logger.setLevel(level=TRACE1)
15781818
jms_logger.addHandler(handler)
15791819
]]></programlisting>
15801820

1821+
<para>
1822+
<classname>springpython.jms.listener.SimpleMessageListenerContainer</classname>
1823+
is the logger used by the JMS listener container itself.
1824+
</para>
1825+
1826+
<para>
1827+
Each WebSphere MQ listener is assigned a
1828+
<classname>springpython.jms.listener.WebSphereMQListener(<emphasis>LISTENER_INSTANCE_ID</emphasis>)</classname>
1829+
logger, where <emphasis>LISTENER_INSTANCE_ID</emphasis> is an identifier
1830+
uniquely associated with a listener to form a full name of a logger,
1831+
such as
1832+
<classname>springpython.jms.listener.WebSphereMQListener(0xc7f5e0)</classname>.
1833+
To be precise, its value is obtained by invoking hex(id(self)) on the listener's
1834+
instance. Note that the value is not guaranteed to be globally unique,
1835+
it's just an identifier of the Python object so its value may be
1836+
very well reused across application's restarts.
1837+
</para>
1838+
15811839
<para>
15821840
How much information is being logged depends on the logging level, the
15831841
average message size, the messages'

0 commit comments

Comments
 (0)