finish nms quickstart docs

add minimal wcf quickstart docs
This commit is contained in:
markpollack
2008-08-14 08:09:02 +00:00
parent 3f5d910936
commit 2e9f948ffd
11 changed files with 299 additions and 69 deletions

View File

@@ -9,19 +9,22 @@
messaging to implement a system for purchasing a stock. To purchase a
stock, a client application will send a stock request message containing
the information about the stock, i.e. ticker symbol, quantity, etc. The
client request message will be recieved by the server where it will
perform business processing on the requst, for example to determine if the
user has sufficient credit to purchase the stock or if the user is even
allowed to make the purchase due to existing account restrictions. Usually
the server application will persist state about the request and forward it
on to an execute venue where the actual execution of the stock request is
peformed. In addition, market data for the stock will be sent from the
server process to the client. The high level messaging flow is shown
below.</para>
client request message will be received by the server where it will
perform business processing on the request, for example to determine if
the user has sufficient credit to purchase the stock or if the user is
even allowed to make the purchase due to existing account restrictions.
These are typically external processes as well. Usually the server
application will persist state about the request and forward it on to an
execute venue where the actual execution of the stock request is
performed. In addition, market data for the stock will be sent from the
server process to the client. The high level exchange of information is
shown below.</para>
<para></para>
<para></para>
<mediaobject>
<imageobject>
<imagedata fileref="images/nms-quickstart.jpg" scale="75" />
</imageobject>
</mediaobject>
</section>
<section>
@@ -42,9 +45,14 @@
one based on messaging or another middleware technology. The messaging
flow showing the queues and topics used is shown below.</para>
<para> </para>
<mediaobject>
<imageobject>
<imagedata fileref="images/nms-quickstart-msg-destinations.jpg"
role="" scale="75" />
</imageobject>
</mediaobject>
<para></para>
<para>Queues are shown in red and topics in green.</para>
</section>
<section>
@@ -52,7 +60,7 @@
<para>Gateways represent the service operation to send a message. The
client will send a stock request to the server based on the contract
defined by the <classname>IStockService</classname> interface . </para>
defined by the <classname>IStockService</classname> interface .</para>
<programlisting> public interface IStockService
{
@@ -61,7 +69,7 @@
<para>The server will send market data to the clients based on the
contract defined by the <classname>IMarketDataService</classname>
interface. </para>
interface.</para>
<programlisting> public interface IMarketDataService
{
@@ -78,7 +86,7 @@
created. Implementations that use messaging to communicate will be based
on the Spring's <classname>NmsGateway</classname> class and will be
discussed later. stub or mock implementations can be used for testing
purposes. </para>
purposes.</para>
</section>
<section>
@@ -113,7 +121,7 @@
</programlisting>
<para>Running xsd.exe on this schema will result in a class that contains
properties for each of the element names. A parital code listing of the
properties for each of the element names. A partial code listing of the
TradeRequest class is shown below</para>
<programlisting>// This code was generated by a tool.
@@ -148,7 +156,7 @@
<para>When sending a response back to the client the type
<classname>TradeResponse</classname> will be used. The schema for the
<classname>TradeResponse</classname> is shown below </para>
<classname>TradeResponse</classname> is shown below</para>
<programlisting>&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://www.springframework.net/nms/common/2008-08-05"&gt;
@@ -202,10 +210,10 @@
</section>
<section>
<title>Mesage Handlers</title>
<title>Message Handlers</title>
<para>When the <classname>TradeRequest</classname> message is received by
the server, it wll be handled by the class
the server, it will be handled by the class
<classname>Spring.NmsQuickStart.Server.Handlers.StockAppHandler
</classname>shown below</para>
@@ -236,6 +244,186 @@
}
}</programlisting>
<para>The stub implementations of the services, located in the namespace
<literal>Spring.NmsQuickStart.Server.Services.Stubs</literal>, will result
in always sending back a error-free trade response message. A realistic
implementation would likely have the execution venue and trading service
be remote services and the trading service could be implemented as a local
transactional service layer that uses spring's declarative transaction
management features.</para>
<para>The client will receive a TradeResponse message as well as a
Hashtable of data representing the market data. The message handle for the
client is the class Spring.NmsQuickStart.Client.Handlers.StockAppHandler
and is shown below.</para>
<programlisting> public class StockAppHandler
{
// definition of stockController omitted for brevity.
public void Handle(Hashtable data)
{
// forward to controller to update view
stockController.UpdateMarketData(data);
}
public void Handle(TradeResponse tradeResponse)
{
// forward to controller to update view
stockController.UpdateTrade(tradeResponse);
}
}</programlisting>
<para>What is important to note about these handlers is that they contain
no messaging API artifacts. As such you can write unit and integration
tests against these classes independent of the middleware. The missing
link between the messaging world and the objects processed by the message
handlers are message converters. Spring's messaging helper classes, i.e.
SimpleMessageListenerContainer and NmsTemplate use message converters to
pass data to the handlers and to send data via messaging for gateway
implementations</para>
</section>
<section>
<title>Message Converters</title>
<para>The implementation of IMessageConverter used is
<classname>Spring.NmsQuickStart.Common.Converters.XmlMessageConverter</classname>.
This converter adds the ability to marshal and unmarshal objects to and
from XML strings. It also uses Spring's
<classname>SimpleMessageConverter</classname> to convert Hashtables,
strings, and byte arrays. In order to pass information about the
serialized type, type information is put in the message properties. The
type information can be either the class name or an integer value
identifying the type. In systems where the client and server are deployed
together and are tightly coupled, sharing the class name is a convenient
shortcut. The alternative is to register a type for a given integer value.
The XML configuration used to configure these objects is shown
below</para>
<programlisting> &lt;object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common"&gt;
&lt;property name="TypeMapper" ref="TypeMapper"/&gt;
&lt;/object&gt;
&lt;object name="TypeMapper" type="Spring.NmsQuickStart.Common.Converters.TypeMapper, Spring.NmsQuickStart.Common"&gt;
&lt;!-- use simple configuation style --&gt;
&lt;property name="DefaultNamespace" value="Spring.NmsQuickStart.Common.Data"/&gt;
&lt;property name="DefaultAssemblyName" value="Spring.NmsQuickStart.Common"/&gt;
&lt;/object&gt;</programlisting>
<para>This configuration is common between the server and the
client.</para>
</section>
<section>
<title>Messaging Infrastructure</title>
<para>The implementations of the gateway interfaces inherit from Spring's
helper class <classname>NmsGatewaySupport</classname> in order to get easy
access to a NmsTemplate for sending. The implementation of the
IStockService interface is shown below</para>
<programlisting> public class NmsStockServiceGateway : NmsGatewaySupport, IStockService
{
private IDestination defaultReplyToQueue;
public IDestination DefaultReplyToQueue
{
set { defaultReplyToQueue = value; }
}
public void Send(TradeRequest tradeRequest)
{ // post process message
NmsTemplate.ConvertAndSendWithDelegate(tradeRequest, delegate(IMessage message)
{
message.NMSReplyTo = defaultReplyToQueue;
message.NMSCorrelationID = new Guid().ToString();
return message;
});
}
}</programlisting>
<para>The use of an anonymous delegate allows makes it very easy to apply
any post processing logic to the converted message. </para>
<para>The object definition for the
<classname>NmsStockServiceGateway</classname> is shown below along with
its dependent object definitions of NmsTemplate and the
ConnectionFactory.</para>
<para><programlisting> &lt;object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client"&gt;
&lt;property name="NmsTemplate" ref="<emphasis role="bold">NmsTemplate</emphasis>"/&gt;
&lt;property name="DefaultReplyToQueue"&gt;
&lt;object type="Apache.NMS.ActiveMQ.Commands.ActiveMQQueue, Apache.NMS.ActiveMQ"&gt;
&lt;constructor-arg value="APP.STOCK.JOE"/&gt;
&lt;/object&gt;
&lt;/property&gt;
&lt;/object&gt;
&lt;object name="<emphasis role="bold">NmsTemplate</emphasis>" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms"&gt;
&lt;property name="ConnectionFactory" ref="<emphasis role="bold">ConnectionFactory</emphasis>"/&gt;
&lt;property name="DefaultDestinationName" value="APP.STOCK.REQUEST"/&gt;
&lt;property name="MessageConverter" ref="XmlMessageConverter"/&gt;
&lt;/object&gt;
&lt;object id="<emphasis role="bold">ConnectionFactory</emphasis>" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ"&gt;
&lt;constructor-arg index="0" value="tcp://localhost:61616"/&gt;
&lt;/object&gt;</programlisting>In this example the 'raw'
<classname>Apache.NMS.ActiveMQ.ConnectionFactory </classname>connection
factory was used. It would be more efficient resource wise to use Spring's
<classname>CachingConnectionFactory</classname> wrapper class so that
connections will not be open and closed for each message send as well as
allowing for the caching of other intermediate NMS API objects such as
sessions and message producers.</para>
<para>A similar configuration is used on the server to configure the class
<classname>Spring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway
</classname>that implements the <classname>IMarketDataService</classname>
interface. </para>
<para>Since the client is also a consumer of messages, on the topic
APP.STOCK.MARKETDATA and the queue APP.STOCK.JOE (for Trader Joe!), two
message listener containers are defined as shown below. </para>
<programlisting> &lt;nms:listener-container connection-factory="ConnectionFactory"&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.JOE" /&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.MARKETDATA" pubsub-domain="true"/&gt;
&lt;/nms:listener-container&gt;</programlisting>
<para>Refer to the <link linkend="messaging">messages reference
docs</link> for all the available attributes to configure the container
and also the section on <link
linkend="xsd-config-body-schemas-nms">registering the NMS schema</link>
with Spring..</para>
<para>On the server we define a message listener container for the queue
APP.STOCK.REQUEST but set the concurrency property to 10 so that 10
threads will be consuming messages from the queue.</para>
<programlisting> &lt;nms:listener-container connection-factory="ConnectionFactory" concurrency="<emphasis
role="bold">10</emphasis>"&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.REQUEST" /&gt;
&lt;/nms:listener-container&gt;</programlisting>
</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
hardcoded 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" />
</imageobject>
</mediaobject>
<para></para>
</section>
</chapter>