276 lines
13 KiB
XML
276 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
/*
|
|
* Copyright 2002-2010 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
-->
|
|
<chapter version="5" xml:id="msmq-quickstart"
|
|
xmlns="http://docbook.org/ns/docbook"
|
|
xmlns:ns6="http://www.w3.org/1999/xlink"
|
|
xmlns:ns5="http://www.w3.org/1999/xhtml"
|
|
xmlns:ns4="http://www.w3.org/2000/svg"
|
|
xmlns:ns3="http://www.w3.org/1998/Math/MathML"
|
|
xmlns:ns="http://docbook.org/ns/docbook">
|
|
<title>MSMQ QuickStart</title>
|
|
|
|
<section>
|
|
<title>Introduction</title>
|
|
|
|
<para>The MSMQ quick start application demonstrates how to use
|
|
asynchronous messaging to implement a system for purchasing a stock. Is
|
|
follows the same basic approach as in the <link
|
|
linkend="nms-quickstart">NMS QuickStart</link> but is adapted as need for
|
|
use with MSMQ. Please read the introduction in that chapter to get an
|
|
overview of the system.</para>
|
|
|
|
<para>When there is direct overlap in functionality between the MSMQ and
|
|
NMS quickstart a reference to the appropriate section in the NMS
|
|
QuickStart documentation is given.</para>
|
|
|
|
<note>
|
|
<para>To follow this MSMQ QuickStart load the solution file found in the
|
|
directory
|
|
<literal><spring-install-dir>\examples\Spring\Spring.MsmqQuickStart</literal></para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Message Destinations</title>
|
|
|
|
<para>To communicate between th client and server a pair of queues will be
|
|
used. Messages sent from the client to the server will use the
|
|
transactional queue named <literal>.\Private$\request.txqueue</literal>.
|
|
Messages sent from the server to the client will use the transactional
|
|
queue <literal>.\Private$\response.joe.txqueue</literal>. The queue for
|
|
messages that cannot be processed, so called 'poison messages' will be
|
|
sent to the queue <literal>.\Private$\dead.txqueue</literal>. You can
|
|
create these queues using the computer management administration console.
|
|
Private queues are used to simplify the application setup
|
|
requirements.</para>
|
|
|
|
<note>
|
|
<para>You must create the queues mentioned previously using standard
|
|
Windows Computer Management console to manage MSMQ. This <link
|
|
ns6:href="http://www.worldofasp.net/tut/MSMQ/Basic_Introduction_about_MSMQ_in_NET_Framework_98.aspx">article</link>
|
|
covers the basics of creating the queus in the management console.
|
|
</para>
|
|
</note>
|
|
|
|
<para>Since MSMQ does not natively support the publish-subscribe messaging
|
|
style as in other messaging systems, Apache MQ, IBM Websphere MQ, TIBCO
|
|
EMS, the market data information is sent on the same queue as the
|
|
responses from the server to the client for trade requests..</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Gateways</title>
|
|
|
|
<para>The gateway interfaces are the same as those described in the NMS
|
|
QuickStart <link linkend="nms-gateways">here</link>.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Message Data</title>
|
|
|
|
<para>TradeRequest and TradeResponse messages are defined using XML Schema
|
|
and classes are generated from that schema. This is the same approach as
|
|
described in more details in the NMS QuickStart <link
|
|
linkend="nms-messagedata">here</link>.</para>
|
|
|
|
<para>An important difference in the types of message data formats
|
|
supported 'out-of-the-box' with Apache, IBM, TIBCO as compared to
|
|
Microsoft MSMQ is the latter support sending a hashtable data structure.
|
|
As a result, the hashtable that was used to send market data information
|
|
from the server to the client was changed to be of type System.String in
|
|
the MSMQ example.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Message Handlers</title>
|
|
|
|
<para>The message handlers are the same as used in the NMS QuickStart
|
|
<link linkend="nms-handlers">here</link>, aside from the change of the
|
|
hashtable data structure to a string. This is an important benefit of
|
|
enforcing a separation between the messaging specific classes and the
|
|
business processing layer.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>MessageConverters</title>
|
|
|
|
<para>The message converter used is
|
|
Spring.Messaging.Support.Converters.XmlMessageConverter. It is configured
|
|
by specifying the data types that will be send and received. Here is a
|
|
configuration example for types generated from the XML Schema and a plain
|
|
string.</para>
|
|
|
|
<programlisting language="myxml"><object id="xmlMessageConverter" type="Spring.Messaging.Support.Converters.XmlMessageConverter, Spring.Messaging">
|
|
<property name="TargetTypes">
|
|
<list>
|
|
<value>Spring.MsmqQuickStart.Common.Data.TradeRequest, Spring.MsmqQuickStart.Common</value>
|
|
<value>Spring.MsmqQuickStart.Common.Data.TradeResponse, Spring.MsmqQuickStart.Common</value>
|
|
<value>System.String, mscorlib</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Messaging Infrastructure</title>
|
|
|
|
<para>The implementations of the gateway interfaces inherit from Spring's
|
|
helper class <literal>MessageQueueGatewaySupport</literal> in order to get
|
|
easy access to a <literal>MessageQueueTemplate</literal> for sending. The
|
|
implementation of the <literal>IStockService</literal> interface is shown
|
|
below</para>
|
|
|
|
<programlisting language="csharp">public class <classname>MsmqStockServiceGateway</classname> : <classname>MessageQueueGatewaySupport</classname>, <classname>IStockService</classname>
|
|
{
|
|
private <classname>Random</classname> random = new <classname>Random</classname>();
|
|
|
|
private string defaultResponseQueueObjectName;
|
|
|
|
public string DefaultResponseQueueObjectName
|
|
{
|
|
set { defaultResponseQueueObjectName = value; }
|
|
}
|
|
|
|
public void Send(<classname>TradeRequest</classname> tradeRequest)
|
|
{
|
|
<classname>MessageQueueTemplate</classname>.ConvertAndSend(tradeRequest, delegate(<classname>Message</classname> message)
|
|
{
|
|
message.ResponseQueue = GetResponseQueue();
|
|
message.AppSpecific = random.Next();
|
|
return message;
|
|
});
|
|
}
|
|
|
|
private <classname>MessageQueue</classname> GetResponseQueue()
|
|
{
|
|
return <classname>MessageQueueFactory</classname>.CreateMessageQueue(defaultResponseQueueObjectName);
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The <literal>Send</literal> method is using MessageQueueTemplate's
|
|
<literal>ConvertAndSend(object obj, MessagePostProcessorDelegate
|
|
messagePostProcessorDelegate)</literal> method. The anonymous delegate
|
|
allows you to modify the message properties, such as ResponseQueue and
|
|
AppSpecific after the message has been converted from an object but before
|
|
it has been sent. The use of an anonymous delegate allows makes it very
|
|
easy to apply any post processing logic to the converted message.</para>
|
|
|
|
<para>The configuration for <literal>MsmqStockServiceGateway</literal> and
|
|
all its dependencies is shown below, highlighting important dependency
|
|
links.</para>
|
|
|
|
<programlisting language="myxml"><object name="stockServiceGateway" type="Spring.MsmqQuickStart.Client.Gateways.MsmqStockServiceGateway, Spring.MsmqQuickStart.Client">
|
|
<property name="MessageQueueTemplate" ref="<emphasis role="bold">messageQueueTemplate</emphasis>"/>
|
|
<property name="DefaultResponseQueueObjectName" value="responseTxQueue"/>
|
|
</object>
|
|
|
|
<object id="<emphasis role="bold">messageQueueTemplate</emphasis>" type="Spring.Messaging.Core.MessageQueueTemplate, Spring.Messaging">
|
|
<property name="DefaultMessageQueueObjectName" value="requestTxQueue"/>
|
|
<property name="MessageConverterObjectName" value="<emphasis role="bold">xmlMessageConverter</emphasis>"/>
|
|
</object>
|
|
|
|
<object id="<emphasis role="bold">xmlMessageConverter</emphasis>" type="Spring.Messaging.Support.Converters.XmlMessageConverter, Spring.Messaging">
|
|
<property name="TargetTypes">
|
|
<list>
|
|
<value>Spring.MsmqQuickStart.Common.Data.TradeRequest, Spring.MsmqQuickStart.Common</value>
|
|
<value>Spring.MsmqQuickStart.Common.Data.TradeResponse, Spring.MsmqQuickStart.Common</value>
|
|
<value>System.String, mscorlib</value>
|
|
</list>
|
|
</property>
|
|
</object>
|
|
|
|
<object id="requestTxQueue" type="Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging">
|
|
<property name="Path" value=".\Private$\request.txqueue"/>
|
|
<property name="MessageReadPropertyFilterSetAll" value="true"/>
|
|
</object>
|
|
|
|
<object id="responseTxQueue" type="Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging">
|
|
<property name="Path" value=".\Private$\response.joe.txqueue"/>
|
|
<property name="MessageReadPropertyFilterSetAll" value="true"/>
|
|
</object></programlisting>
|
|
|
|
<para>Since the client also needs to listen to incoming messages on the
|
|
responseTxQueue, a
|
|
<literal>TransactionalMessageListenerContainer</literal> is configured.
|
|
The configuration for the message listener container and all its
|
|
dependencies is shown below, highlighting important dependency
|
|
links.</para>
|
|
|
|
<programlisting language="myxml"><!-- MSMQ Transaction Manager -->
|
|
<object id="messageQueueTransactionManager" type="Spring.Messaging.Core.MessageQueueTransactionManager, Spring.Messaging"/>
|
|
|
|
<!-- Message Listener Container that uses MSMQ transactional for receives -->
|
|
<object id="transactionalMessageListenerContainer" type="Spring.Messaging.Listener.TransactionalMessageListenerContainer, Spring.Messaging">
|
|
<property name="MessageQueueObjectName" value="responseTxQueue"/>
|
|
<property name="PlatformTransactionManager" ref="messageQueueTransactionManager"/>
|
|
<property name="MessageListener" ref="<emphasis role="bold">messageListenerAdapter</emphasis>"/>
|
|
<property name="MessageTransactionExceptionHandler" ref="<emphasis
|
|
role="bold">sendToQueueExceptionHandler</emphasis>"/>
|
|
|
|
</object>
|
|
|
|
<!-- Delegate to plain CLR object for message handling -->
|
|
<object id="<emphasis role="bold">messageListenerAdapter</emphasis>" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging">
|
|
<property name="HandlerObject" ref="stockAppHandler"/>
|
|
<property name="DefaultHandlerMethod" value="Handle"/>
|
|
<property name="MessageConverterObjectName" value="xmlMessageConverter"/>
|
|
</object>
|
|
|
|
<object id="<emphasis role="bold">sendToQueueExceptionHandler</emphasis>" type="Spring.Messaging.Listener.SendToQueueExceptionHandler, Spring.Messaging">
|
|
<property name="MessageQueueObjectName" value="<emphasis role="bold">deadTxQueue</emphasis>"/>
|
|
</object>
|
|
|
|
<object id="<emphasis role="bold">deadTxQueue</emphasis>" type="Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging">
|
|
<property name="Path" value=".\Private$\dead.queue"/>
|
|
<property name="MessageReadPropertyFilterSetAll" value="true"/>
|
|
</object></programlisting>
|
|
|
|
<para>A similar configuration is used on the server to configure the class
|
|
<literal>Spring.MsmqQuickStart.Server.Gateways.MarketDataServiceGateway
|
|
</literal>that implements the <literal>IMarketDataService</literal>
|
|
interface and a <literal>TransactionalMessageListenerContainer</literal>
|
|
to process messages on the requestTxQueue. You can increase the number of
|
|
processing thread in the
|
|
<literal>TransactionalMessageListenerContainer</literal> by setting the
|
|
property <literal>MaxConcurrentListeners</literal>, the default value is
|
|
1.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Running the application</title>
|
|
|
|
<para>To run both the client and server make sure that you select
|
|
'Multiple Startup Projects' within VS.NET. The GUI has a button to make a
|
|
hard coded trade request and show confirmation in a text box. A text area
|
|
is used to display the market data. There is a 'Get Portfolio' button that
|
|
is not implemented at the moment. A picture of the GUI after it has been
|
|
running for a while and trade has been sent and responded to is shown
|
|
below.</para>
|
|
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata fileref="images/nms-quickstart-gui.png"></imagedata>
|
|
</imageobject>
|
|
</mediaobject>
|
|
|
|
<para></para>
|
|
</section>
|
|
</chapter>
|