HOME  DEMO  |  BUY NOW
FixMQ FixMQ
The J2EE FIX Engine

    FixMQ  (c) 2004-2005 Octatec Ltd
   

Contents

Introduction

FixMQ is a FixEngine that delivers FIX messages to Applications as JMS messages and forwards JMS messages from applications to remote FixEngines. FixMQ handles all aspects of the Fix session level protocol - it takes incoming JMS MapMessages, adds headers, checksums, sequence numbers and converts it to a Fix message. It reads incoming Fix messages and converts them to JMS MapMessages and passes them to the Application. Resends and Heartbeats are handled transparently to the application.

FixMQ presents a JMS interface to the Application layer. This makes FixMQ an ideal choice for use in a J2EE Container, however,  just as JMS can be used in standalone java applications,  FixMQ and be used equally well in standalone/J2SE or J2EE applications.

Architecture

FixMQengine is a standalone java process. It accesses a JMS system and sends/receives messages from queues specified in properties files. A 3rd party JMS server is required.

FixMQengine can be started in Client or Server Mode. You may run as many instances of FixMQengine on as many different machines as you require. You can run multiple Server-Mode instances and multiple Client-Mode instances, but note: a FixMQengine instance must be either in Client-Mode or Server-Mode, not both. One FixMQengine instance can handle multiple Fix Sessions.

When in Client-Mode FixMQengine initiates logon requests to a remote FixEngine. When in Server-Mode FixMQengine accepts logon requets from any number of remote FixEngines.

FixMQengine used from a J2EE Application

fixMQengine used from a J2EE application

FixMQengine used from a standalone Application

FixMQengine used from a J2SE application

There is a light-weight API that makes accessing the JMS  FixMQengine easier. In fact, you don't need to use the API at all, you can access the JMS queues directly and build and send the JMS messages yourself, however, using the light-weight api makes this much easier.  The source code for the API is included with the distribution.

FixMQengine takes input FIX messages from a 3rd party and presents them to use applications as JMS messages. FixMQengine takes JMS messages from user applications and converts them to FIX messages and sends them to a 3rd party. FixMQengine handles all aspects of the FIX session level protocol, including heartbeats, sequence numbers, resends etc. FixMQengine requires the presence of a JMS server, something like JBOSS is ideal. (If you want a java-based FIX solution without the requirement for a JMS server, see Octatec's AFI/J system)

Installing, Configuring and Running

Installing

Just unzip the archive into a directory of your choosing. After 28 days, the system will  require the input of a licence-key in order to work. Use the setlic.sh (Unix/Linux) or setlic.cmd (Windows) to enter the license key, once you have purchased it here.

At the top level directory, you will find fixmq.jar, this is a convenience jar that allows your client applications to easily connect to FixMQengine using JMS. You don't actually need to use this jar to use fixMQengine, you could use JMS directly, but this jar makes certain aspects that could be error prone (such as deciding which queue to send and receive on) much easier to use. The source code for this jar is included in fixmq-src.jar. We strongly recommend you use this jar, and the samples and examples all use this jar. The jar  fixmq-src.jar also contains the source code for the samples included with the installation.

Also at the top level directory is the  fixmq-engine.jar. This is the actual FixMQengine.

The jar fixmq-test.jar is also in the top level directory, this contains the compiled class files for the samples included with the installation.

The sub directory run-samples contains scripts and configurations to run a sample client application and a sample server application.  The samples are covered in more detail in a separate section. The samples supplied work with either JBOSS or OpenJMS, we found that JBOSS performs much much better that OpenJMS when using FixMQengine

Configuring

Whether running in Client Mode or Server Mode the FixMQengine requires a properties file to be specified on the command line that defines the basic JMS properties and queue names. Configuring Server Mode is more complex than Client Mode as every FIX-engine that might try and connect to the Server must be defined in the Server-mode properties file.

In Client Mode there are at least 2 properties files used,  one to configure the Client FixEngine (mostly relating to queues), and then one to define each Client FixSession (mostly relating to Fix parameters),  to specify who you are going to connect to, thus there can be one or many FixSession properties files.  In Server Mode, there is only one properties file, Each Remote Fix System that is going to connect to us must be listed in the Server Fix Engine properties file

The following queues are required by FixMQengine...

At the heart of configuring FixMQengine is defining the queues, FixMQengine requires one 'admin' queue when running in Client mode and two 'admin' queues when running in server mode, plus an IN and OUT 'session' queue for each connected Fix Session.

admin.command.queue - this is primarily used to tell the FixMQengine in client mode to initiate a connection to a remote Fix Engine.
admin.reply.queue - this is only required in Server mode when it is used to receive incoming connection requests from remote Fix Engines.
session.inbound.queue - once a Fix session is established, messages coming in are received on this queue.
session.outbound.queue
- once a Fix session is established, messages are sent to the remote Fix Engine on this queue.

Client Mode Engine Properties File

This is an example properties file that defines a configuration that uses JBOSS as the JMS server. The properties file is passed to the FixMQengine on the command line.

mode=client

log.dir=C:\\Temp\\FixMQ-logs

log.append=true
log.level=debug
initial.context.factory=org.jnp.interfaces.NamingContextFactory
context.provider.url=jnp://localhost:1099
connection.factory=ConnectionFactory

queue.name.prefix=queue/
#an optional parameter to specify a prefix applied to all queue names

admin.command.queue=FixMQ_adminCmd_cli


tests.allowed=true

#provider.specific.jms.type
=????
#an optional parameter, only needed if the JMS provider required it

The mode property must be present and can be either client or server.

The log.dir property defines the directory were the log files will be written.

The log.append property allows the log-file to be overwritten or appended to, it can be true or false.

The log.level property sets the logging level, it can be debug, info, warn or error. The default value is debug.

The initial.context.factory property defines the initial context factory of the JMS implementation being used.

The context.provider.url property defines the JMS implementation's context provider url.

The connection.factory property defines the JMS implementation's connection factory class.

The queue.name.prefix property defines a prefix that is added to all queue names, it need not be specified if no prefix is needed, for JBOSS, specify queue/

The provider.specific.jms.type property can be used to define a JMS type that will be set in all outward messages if the JMS provider requires this.

The admin.command.queue property defines the name of the queue used to send admin messages from the application to FixMQengine. It can be any name you want. If  queue.name.prefix is  present,  the value of this property is prefixed to the queue name before it is used.

The tests.allowed property allows tests to be run, normally this should be false, but when the tests apps are being run, it should be true. It
allows fixMQengine to simulate certain behaviors on receipt of certain messages, such being killed by kill -9.

Client Session Properties File

This is an example properties file that defines a client session. The properties contained in the file are passed to the FixMQengine from the application during the process of opening a client session. The properties need not be contained in a file at all, they could be generated by the application at run-time, but it is easier if you specify the properties in a file. The session properties file is not specific to any particular JMS provider.

session.inbound.queue=fix_in_testsrvr
session.outbound.queue=fix_out_testsrvr

log.append=true
log.level=debug
target.fix.id=testsrvr
target.fix.subid=testsrvr_sub
local.fix.id=local
local.fix.subid=local_sub

validate.sub.ids=false

socket.host=localhost
socket.port=1090

fix.version=FIX.4.3
heart.beat.interval=15
request.resend.permission=true

forward.heartbeat=false
forward.rejection=false
honour.out.of.seq.resend=true
manual.session.switch=false

local.heart.beat.rate=0
local.heart.beat.timeout=0
#local heart beats are not the same as fix heartbeats, and should not normally be required

#
external.validator=<...optional validator class...>
#optional parameter to include custom validation of incoming fix messages

The session.inbound.queue property specifies the JMS queue that receives messages coming IN from the remote fix engine.

The session.outbound.queue property specifies the JMS queue where FixMQengine listens for messages to send to the remote fix engine.
You will have to define both of these queues in your JMS providers configuration. The distribution contains sample configurations for JBOSS and OpenJMS

The log.append property specifies whether the log files will be appended or overwritten each time FixMQengine is started; you will normally want to append them, except perhaps when testing. Regardless of this setting, a new log directory is started every day, unless 'longer-than-24-hour connectivity' is in operation (see manual.session.switch below)

The log.level property sets the logging level, it can be debug, info, warn or error. The default value is value that set in the engine properties file.

The target.fix.id property specifies the fix-id of the remote Fix engine, it will be supplied to you by the organization you are connecting to.

The target.fix.subid property specifies the fix-sub-id of the remote Fix engine, it will be supplied to you by the organization you are connecting to. You need not specify target.fix.subid if sub-ids are not to be used.

The local.fix.id property specifies the fix-id of the local Fix engine. You will need to ensure that the FixEngine you are connecting to is expecting you to send the id you specify here.

The local.fix.subid property specifies the fix-sub-id of the local Fix engine. You will need to ensure that the FixEngine you are connecting to is expecting you to send the sub-id you specify here. You need not specify local.fix.subid if sub-ids are not to be used.

The validate.sub.ids property will, if set to true, enable checking of sub-ids sent by the remote fix-engine during validation of incoming messages.

The socket.host property specifies the host-name of the remote Fix-Engine, it will be supplied to you by the organization you are connecting to.  You will need to ensure that fire-walls at both your side and the remote side will allow connections to be made.

The socket.port property specifies the port the remote Fix-Engine will be listening on, it will be supplied to you by the organization you are connecting to.

The fix.version property specifies the Fix version to be used, it must match the expectations of the remote Fix Engine.. Valid values are 4.0 .4.1 4.2 4.3 or 4.4

The heart.beat.interval property defines the FIX heart beat interval to use.

The request.resend.permission property, if set to true, forces FixMQengine to ask the client application for permission to re-send any business messages that the remote FixEngine has requested; in this situation use isResendPermissionRequest() to  query the incoming JMS message.

The forward.heartbeat property, if set to true, causes FixMQengine to send FIX heartbeats to the application, normally you should not need to set this true.

The forward.rejection property, if set to true, causes FixMQengine to send FIX session-level rejections to the application, normally you should not need to set this true, as business messages should have their own rejection-message which would always get forwarded to the application, this property specifically refers to session-level rejections.

The honour.out.of.seq.resend property, if set to true, allows FixMQengine to respond to resend-requests, even if the sequence number in the re-send request is incorrect. This helps to avoid possible deadlock situations.

The manual.session.switch property, if set to true, prevents FixMQengine from starting a new session each day. In this case, the current session runs until the application issues a FixSession.reset(). NB, a session is defined by continually increasing in and out sequence numbers, not by stopping/starting or logging-in logging-off. With normal, 'less-than-24-hour-connectivity', FixMQengine will close sometime before midnight, and restart sometime after midnight, and automatically start a new session (reset sequence numbers back to 0), with manual.session.switch set to true, FixMQengine will not automatically start a new session.

The local.heart.beat.rate and local.heart.beat.timeout parameters should not be confused with the FIX heartbeat (heart.beat.interval) above. These parameters define a heartbeat (in milliseconds) that can occur between the Application and the FixMQengine on a per-session basis. Normally, you will leave this parameter unset, or set to 0, in which case no Local heartbeat will occur.  When the FixMQengine terminates either by a Unix/Linux kill command (not kill -9) or by a windows Ctrl+C,  it will inform all applications via a 'CLOSED' message, and they will know that the session is closed. There are 2 situations where the applications won't get informed, (1) if the FixMQengine is killed with kill -9 or (2) if the JMS interface being used by FixMQengine shuts down the connections to the JMS server as part of the JVM shutdown procedure, and if that shutdown runs before FixMQengine can send its 'CLOSED' message. If either of these 2 cases are prevalent you can use local heartbeats to detect when the FixMQengine has closed. In one sense, it doesn't matter if the FixMQengine 'goes away', the application can happily pump out messages and be none the wiser; however, it seems convenient, if the application can have some notification that the FixMQengine is down, and it shouldn't expect its messages to be delivered anytime soon. The default settings for these parameters are 0 and 0. If you need to set these parameters, values of 15000 and 1000 are recommended.

The external.validator property can be used to define a validator that plugs into FixMQengine.

Server Mode Engine Properties File

This is an example properties file that defines a configuration that uses JBOSS as the JMS server. The properties file is passed to the FixMQengine on the command line.

When in Server Mode, FixMQengine listens for incoming login requests, and then starts a new session to service the new Fix Client. It notifies the application of the new session as it is created.

All expected Fix Clients must be defined in the Engine Properties file, there is no Session Properties file. This properties file allows 2 FIX clients to connect. The properties are, for the most part, the same as those available in the Client Engine and Session properties files.

mode=server

log.dir=C:\\Temp\\FixMQ-logs
log.append=true
log.level=debug
initial.context.factory=org.jnp.interfaces.NamingContextFactory
context.provider.url=jnp://localhost:1099
connection.factory=ConnectionFactory

queue.name.prefix=queue/

admin.command.queue=FixMQ_adminCmd_srv
admin.reply.queue=FixMQ_adminReply_srv

tests.allowed=false

socket.port=1090
# note - no hostname is defined as we listen
#
for incoming connections from any host

########################################################
## define our local fix-id

# if we need to present different fix-ids to different clients
# a new instance of fixMQengine will need to run, a fixMQengine
# in server mode can support many clients, but it always
# has the same local fix-id

local.fix.id=testsrvr
local.fix.subid=testsrvr_sub


########################################################
## allow a remote client with id 'cli1' to connect to us

cli1=enabled

# specify the queue names to be used for the 'cli1' client

send_queue.cli1=cli1_snd_q
receive_queue.cli1=cli1_rcv_q
cli1.log.append=true
cli1.
heart.beat.interval=10

########################################################
## allow a remote client with id 'cli2' to connect to us

cli2=enabled

# specify the queue names to be used for the 'cli2' client

send_queue.cli2=cli2_snd_q
receive_queue.cli2=cli2_rcv_q
cli2.log.append=
true
cli2.heart.beat.interval=10

The cli1=enabled property specifies that a logon with a particular local-id (cli1) is to be enabled. This property takes the general form of ???=enable, where ??? is the local-id found in the logon message, it can be any string that doesn't contain white-spaces. If the property is not present, or set to anything other than enabled, logon attempts with local-ids of ??? are rejected.

The send_queue.??? property defines the queue used for sending messages to the application, the ??? represents the local-id present in the incoming logon message.

The receive_queue.??? property defines the queue used for receiving messages from the application, the ??? represents the local-id present in the incoming logon message. You will need to define the queue-names specified by both send_queue.??? and receive_queue.??? in the configuration of the JMS server you are using.

???.log.level
???.validate.sub.ids
???.fix.version
???.heart.beat.interval
???.request.resend.permission

???.forward.heartbeat
???.forward.rejection
???.honour.out.of.seq.resend
???.manual.session.switch
???.local.heart.beat.rate
???.local.heart.beat.timeout
???.external.validator
The individual clients that can connect have the same properties available as those in the Client Session properties file above, with the addition of the incoming local-id in front of the property name as in ???.heart.beat.interval, e.g. cli1.heart.beat.interval

Property Default Values

The following default values are used for absent properties

validate.sub.ids=false
fix.version=4.3
heart.beat.interval=15
request.resend.permission=false

forward.heartbeat=false
forward.rejection=false
honour.out.of.seq.resend=true
manual.session.switch=false

Configuration Anomalies Required By Different JMS Products

These parameters are all set within the 'Engine' properties file, not the 'Fix Session' properties file

Defining Factories and Queues without using JNDI and the Initial Context.

You may find that your JMS provider does not support the creation of Factories or Queues through an InitialContext object. In order to create the objects, the following properties are supported. Notably Sonic MQ is like this, and using JNDI is not available 'out-of-the-box' for Websphere MQ.

You can do without the Initial Context Factory, and create the Connection Factory directly as follows...

initial.context.factory=#
This tells the system not to use an initial context.

connection.factory=@progress.message.jclient.QueueConnectionFactory
This tells the system to create a new connection factory object directly (the leaning @ in the value indicates this)

It may be that the connection factory you have create requires initialization (this is the case for Websphere MQ). In this situation, you can specify that one initialization method be called with at most 1 string parameter using the following properties..
factory.init.method=setQueueManager
factory.init.method.param.needed=true
factory.init.method.param.value=
In the above example, an empty string is passed as the parameter, if you want to pass a null , don't specify factory.init.method.param.value at all. If no parameter should be passed, set factory.init.method.param.needed=false.

When it comes to Queue Creation, the default behavior is to lookup the queue name using JNDI. However, if we don't have an initial context factory we can't do that. There are 2 alternative queue creation methods supported, one is to 'new' a Queue object, the other is to use the sessions createQueue() method.

queue.creator=@progress.message.jclient.Queue
This specifies the class to use when creating queues, a new object is create by reflection, passing in the queue name as the only parameter to the constructor.
Alternatively, if the JMS provide requires it, you can specify queue.creator=session which tells the system to use the session's createQueue() method to access the queues (Websphere MQ requires this). If you don't specify queue.creator or specify queue.creator=jndi, the system will use JNDI to lookup the queue name.

Specifying Messages Should Be 'Wrapped'

You may find that your JMS provider does not like names that don't conform to java variable name conventions being placed in a MapMessage, e.g. a name of "35" would cause an error, but "_35" would be OK. FixMQ uses numeric names extensively in the MapMessage, as this matches the name of the Fix Tag. If you  are in this situation, specify wrap.map.message=true, the system will then silently append a leading underscore (_) to all names in the MapMessage object, letting you use it as normal, but you must use the FixSession.createMapMessage() method to get a 'WrappedMapMessage', and then use FixSession.sendFixMsg() to send the 'WrappedMapMessage'. You should also use FixSession.getMapMessage() when receiving a message in onMessage() rather than just casting to a MapMessage, in this way, you get a 'WrappedMapMessage' that hides the leading underscore from you. Remember, this is only an issue if you set wrap.map.message=true. Notably, WebSphere MQ suffers from this problem, if you try to put a name like "35" into a WebSphere MQ MapMessage, you get
    Error creating client session: javax.jms.MessageFormatException:
    MQJMS1066: Inva
lid message element name: 35

Specifying a Separate Session to be used for Synchronous Operations.

You may find that your JMS provider requires a separate session to be used for receiving Synchronous and Asynchronous messages. Setting the following parameter causes the system to use separate sessions for permanent queues when receiving Synchronous and Asynchronous messages. Note the system will still use the same session when the queue is a temporary queue. (notably Sonic MQ requires this setting).

separate.sync.async.session=true

FIX Over SSL

The FixMQengine can be configured to create SSL Sockets using the following parameters. These should be set as appropriate in the Engine configuration (either client or serevr)

ssl.sockets=true

ssl.local.keystore=<keystore containing the local private key>
ssl.local.keystore.password=<keystore password>

ssl.remote.keystore=<keystore containing the remote public key>
ssl.remote.keystore.password=<keystore password>

Starting FixMQengine

To start FixMQengine, just issue the command...

java com.octatec.fixengine.FixQMengine  properties-file

You will need the com.octatec.fixengine and  com.octatec.fixmq classes on your classpath, as well as the classes that implement the JMS interface you are using. See the samples for the various jars needed if you are using JBOSS, OpenJMS, SonixMQ, WebsphereMQ, or FioranoMQ as the JMS provider. There is a set of Run_* scripts to run the client and server samples using one of these provides

Getting Started - Client Application

Creating a Client Application is simpler than creating a server application since a server listens for incoming logon requests and must then create a session to handle the logon, whereas a client application just initiates the logon. A client application can, of course initiate multiple client sessions. In the sample code provide, see the ClientTest class for a working example.

The first step is to to set up a client-mode properties file that configures the FixMQengine, and then set up a properties file that configures a specific session

Before running the client application, you need to start FixMQengine from the command line, passing it the FixMQengine client-mode properties file.

Then initialize a connection to the FixMQengine as follows.

import com.octatec.fixmq.*;

FixSession mFixSession = new FixSession();
mFixSession.init(<properties file used to start FixMQengine>);

Then open a Fix Session to a remote Fix Engine

     QueueReceiver mFixReceiver;
     ...
mFixReceiver  = mFixSession.openClientSession(<client session properties file>, null);   
MessageListener
listener = new MyFixMsgListener()
mFixReceiver.setMessageListener(listener);

You need to implement a standard JMS message listener; this will receive Fix Messages as well as FixMQengine 'admin' messages. A skeleton implementation is as follows. In the sample code supplied, see AbstractTest.onFixMessage() for an example handler.

    void onMessage(Message msg)
    {
       
MapMessage mapmsg = (MapMessage)msg;
        try {
           
           
mFixSession.logMsgEvent(); // make this call just to register a message
                                      // has arrived, this is important for detecting
                                      // 'session timeouts'                                    
           
            if( FixSession.isErrorReply(mapmsg))
            {
           
    ... error...
                // although this is an error, it doesn't indicate the end of the session
                // you will always get a CLOSED (see below)
            }
            else if( FixSession.isFixMsg(mapmsg))
            {
                ...process the fix message...
                // you will only get business messages here, things like
                // heartbeats, test-requests, resends etc are handled automatically
                // by the FixMQengine  

            }
            else if( FixSession.isResendPermissionRequest(mapmsg) )
            {
                // you can examine the message and decide if you
                // want to re-send it or not (true or false)
                // if 'false', the engine will send a GapFill instead
               
mFixSession.sendResendPermissionReply(mapmsg, true);
            }
            else if( fixSession.isClosedAdminMsg(mapmsg) )
            {
               
mFixReceiver.close();
               
mFixReceiver = null;
                // you may use this notification to trigger an attempt to
                // re-open the session, or just notify the application that
                // the connection is closed
            }
                       
           
mFixSession.commitFixMsgRead();
                // incoming messages are transactional, so must be committed
                // once you have fully processed it
           
        }
        catch( JMSException e)
        {
           ...an unexpected JMSException...
        }       
    }


Examining a Fix Message...

String msgType  = (String)mapmsg.get(FixTag.MsgType);
String tagValue = (String)mapmsg.get(FixTag.<tag-name>);

FixTags are defined in the FixTag class

Sending A Fix Message...

try {

    if(
mFixSession.fixSessionInactive() )
    {
       // first check that the FIX session is currently active
       // if not, you can report the problem and/or
try to
       // re-open the session

       return;

       //NB: its not a big problem if you send messages when the
FIX       
       //
session is 'inactive', messages will get stored in JMS for
       //future transmission, but its probably more convenient if you
       //know that the FIX session is no longer active
    }

    MapMessage fixMsg = mFixSessioncreateMapMessage();
        // we create a new message object each time we send
        // news, but we could re-use a pre-created message object

    mFixSession.initCmd(message);

           fixMsg.setString(FixTag.MsgType, <a message type>);

    fixMsg.setString(FixTag.<a tag name>, <tag value>);
    ...
    fixMsg.setString(FixTag.<a tag name>, <tag value>);

    mFixSession.sendFixMsg(fixMsg );

    mFixSession.commitFixMsgSend();
}
catch( Exception e)
{
    System.err.println("Error sending DiscardInSeqNos command: "+e);
    e.printStackTrace();
}
       

Getting Started - Server Application

A server application revolves around a FixServerSession  for which you must implement a MessageListener. The MessageListener receives messages when clients connect - you then use a simple API call to create a FixSession to communicate with the FIX client, you use the FixSession just the same in a Server Application as in a Client Application. In the sample code provide, see the ServerTest class for a working example.

The first step is to to set up a server-mode properties file that configures the FixMQengine.

Then create a FixServerSession and add a MessageListener

QueueReceiver mAdminReceiver;
...
FixServerSession fixServerSession = new FixServerSession();
fixServerSession.init(<engine properties file>);
mAdminReceiver = fixServerSession.start();
mAdminReceiver.setMessageListener(new MyServerMessageListener() );

A Skeleton implementation of  the AdminReceiver message listener is as follows, its main purpose is to create new FixSessions in response to a client connection. In the sample code provide, see the ServerTest.onServerMessage() for a working example.

void onMessage(Message msg)
{
    MapMessage mapmsg = (MapMessage) msg;

    // we are here because a remote FIX-client has logged
    // on OR there is an error in the fixMQengine
   
    try {
       
        if( FixServerSession.isErrorReply(mapmsg))
        {
            ...error message...
        }
        else if( mFixServerSession.isServerClosed(mapmsg))
        {
            mAdminReceiver.close();
            mAdminReceiver = null;
        }
        else if( FixServerSession.isClientConnection(mapmsg) )
        {
            // we have a client connection          
            FixSession fixSession = fixServerSession.accept(mapmsg);
                // accept the connection and get a FixSession object to handle the
                // session, fixSession is a variable that will be needed
                // extensively when processing/sending fix messages
               
            QueueReceiver rcv = fixSession.getReceiver();
            rcv.setMessageListener(new MyFixMsgListener());
                // see above for a skeleton implementation of
                // the fix-session MessageListener
        }
    }
    catch( Throwable e )
    {
        System.err.println("error reading Admin MapMessage: "+e);
        e.printStackTrace();
    }
}

Once a  fixSession has been 'accepted' by fixServerSession.accept(mapmsg)you can use the fixSession just as in a Client Application, you should add a listener that follows exactly the same pattern as the one in the Client example above.

Sample Applications

The samples are contained in the package com.octatec.fixmq.test, the source is available in the jar fixmq-src.jar, and the compiled classes are available in fixmq-test.jar.

The Client Sample is implemented in class ClientTest and the Server Sample is implemented in ServerTest. Both classes are derived from  AbstractTest which contains a MessageListener implementation and methods to process all the 'menu' commands.

Both the server and client application present a simple text-based menu from which you can issue commands, the menu is implemented in the Menu class.

The directory run-samples in the installation contains properties files and scripts to run the samples against either a JBOSS or OpenJMS server, together with sample configurations for JBOSS and OpenJMS. A separate section explains the queue configurations needed by the sample applications.

The Server Sample Application

The Server Application is required by the Client Application, so this is covered first.

To run the Server Application, first ensure JBOSS (or OpenJMS) is running with the sample queue configuration installed. Then cd to run-samples\server-app and start FixMQengine in server mode using RunServer_jboss.cmd. Then run the server application, RunServerApp_jboss.cmd

When Running the Server Application, it presents a menu and automatically listens for incoming fix connections. When an incoming connection is received, a message is displayed, and the menu-commands become available. In order to generate an incoming session, just run the Client Application and take the "o) open" option. The Serer Application supports multiple clients, the ? menu command lists all connected clients and the @ menu command allows you to switch a client session to the 'foreground' in the sense that subsequent menu commands are directed at the 'foreground' session. (The concept of a 'foreground' session is purely an artifact of the simple text menu application, and  is not present in FixMQengine or the application API).

server menu

Brief Structure of the server application

server test application classes

When the Server Application starts, it firstly creates and initializes a FixServerSession calling mFixServerSession.init(mEngineClientPropsFile), It gets a standard JMS Queue Receiver, QueueReceiver adminReceiver = mFixServerSession.start(),  and adds a message listener, adminReceiver.setMessageListener(new MessageListener() ).  Note: if you kill the FixMQengine, the test server application will try and re-initiate a connection to the engine whenever you issue a command, if the engine has been killed with a -9, the app will not notice the engine has gone away unless you issue the ?) list command which explicitly tests that the engine is present.

The purpose of the FixServerSession  message listener is to receive connection requests from client Fix engines. The onServerMessage(MapMessage mapmsg) method receives incoming JMS messages and uses FixServerSession.isClientConnection(mapmsg) to test if it is an incoming connection request, if it is, it creates a new FixSession using mFixSession = mFixServerSession.accept(mapmsg). It gets a normal JMS QueueReceiver for the FixSession using QueueReceiver rcv = mFixSession.getReceiver() and adds a listener using,  rcv.setMessageListener(listener).

The FixSession and its associated listener is how the application interacts with individual Fix Sessions.

Once you have started the Server Application,  you should then start the Client Application.

The Client Sample Application

Once the Server Application is running, start the Client Application. To do this, cd to run-samples\client-app and start FixMQengine in client mode using RunClient_jboss.cmd. Then run the client application, RunClientApp_jboss.cmd.

When the Client Application is running, take the o option, which will ask for a properties file, just hit return to use the default properties file that will initiate a connection to the already running Server Application .

client menu

Once you have made a connection, you can use either the Client or Server application menus to issue test commands.

Brief Structure of the client application

client test application classes

Creating a client Fix Session is much simpler than a server session. The sample client app uses QueueReceiver fixReceiver = mFixSession.openClientSession(mClientSessionPropsFile, null) to open a Fix Client session, if an error occurs creating the session, an exception will be thrown. Once openClientSession returns, the test application adds a MessageListener using  fixReceiver.setMessageListener(listener).

The FixMsgListener class is defined as a member of AbstractTest and is used to service both the Client Application and Server Application fix sessions.

The Test Menu Options

In the test applications, menu options 1-8 issue test commands that provokes 'failure behavior' in the FixMQengine so that its ability to recover from such failures can be tested. The FixMQengine will only process the failure tests if  the tests.allowed property is set to true, so there is no danger of ever accidentally running the tests in a production system.

In the scenarios below, the commands have ben issue from the Client Application and received in the Server, it would work the same if the command was issued in the Server application.

The first four menu commands test failures of messages being sent from the application to the remote Fix Engine

1) Exception Sending message
An exception is thrown in the FixMQengine, closing the session. The exception is thrown as if it occurred while writing the Fix Journal and before the message is sent to the remote side. When you open the session  again (using 'o'), the message will get redelivered to FixMQengine via JMS and will hence be sent to the remote side. The message is a NEWS message with the text "NEWS[exception sending]", so when that message arrives,
the test is a success.

2)kill -9 writing send jnl
This test simulates a kill -9 being received while the Fix Journal is being written. In this test, the journal entry is partial written, thus corrupting the journal. The fixMQengine will need to be re-started (because it was killed). Once re-started, and the session opened, the Fix Message will be received again via JMS in the FixMQengine, and it will be sent to the remote side. The message is a NEWS message with the text "NEWS[kill writing send jnl]", so when that message arrives, the test is a success.

3) kill -9 after commit
This test simulates a kill -9 being received after the JMS commit. After the client Engine is restarted and the session opened (using 'o') the remote side will request the missing message and you will see a NEWS message with text "NEWS[kill after commit] arrive".

4) exception from JMS commit
This test simulates an error from the JMS commit. An exception is thrown as if the JMS commit call failed. When you open the session  again (using 'o'), the message will get redelivered to FixMQengine via JMS and will hence be sent to the remote side. The message is a NEWS message with the text "NEWS[jms commit error]".

The second four menu commands test failures of messages arriving from the remote Fix Engine and being delivered to the application.

These tests send a non-standard Fix Message to the remote side that provokes certain failures, provided tests.allowed is true

5) exception before JMS send
A Fix message is received as normal by FixMQengine, and an exception is thrown before it is sent to the application (causing the session to close). Once the session is re-opened (using 'o'), you should see a message with  type=_X1 arrive.
 
6) exception before JMS commit
A Fix message is received as normal, and sent to the application, an exception is thrown before the message-send is committed. Once the session is re-opened (using 'o'), you should see a message with  type=_X2 arrive.

7) kill -9 after JMS commit 
A Fix message is received as normal, and sent to the application, and the message-send is committed. Then the system exits before the next expected sequence number is incremented. Restart the Server Engine and Application, then open the client session (using 'o'), you should see a message with  type=_X3 arrive in the other side.
 
8) kill -9 after seq-num incr
A message is received as normal, and sent to the application, and the message-send is committed. Then an exception is thrown after the next expected sequence number is incremented The server will receive a message with type=_X4 before it exits.

Application API

import com.octatec.fixmq.*; // implemented in fixmq.jar

Class FixSession

See the sample application and the getting started section above for examples of how to use this class.

public void init(String engineConfigProperties) throws FixMqException,JMSException
Initialize the FixSession from a properties file, the file should be the same one as is passed to the FixMQengine on the commands line. Note: this method does not start FixMQengine, you need to do that separately from the command line, then call this method to initialize your application's connection to FixMQengine.

public QueueReceiver openClientSession(String sessionPropsFile, Properties extraLoginTags)
throws FixMqException, NamingException, JMSException, IOException
public QueueReceiver openClientSession(Properties sessionProps, Properties extraLoginTags)
throws FixMqException, NamingException, JMSException, IOException

Open a new Client session based on a set of properties. Extra login tags can be supplied is required in the form of an additional set of properties

public MapMessage createMapMessage() throws JMSException

A convenience method to create a MapMessage object.

public void initFixMsg(MapMessage mmsg) throws JMSException
A convenience method to initialize a MapMessage ready for adding Fix Tags. Once you have initialized your map message, you can set tags in the form of name value pairs on the MapMessage, e.g.  message.setString(FixTag.MsgType, FixMsgType.News);  and message.setString(FixTag.Text, text); Fix Message Types are defined in FixMsgType and FixTags are defined in the FixTag class, but if you want to send non-standard tags, there is no problem with this, just set the Tag/Value on the message

public void sendFixMsg(MapMessage mmsg)throws JMSException

Send a fix message (note: after sending any Fix message, it must eventually be committed)

public void reset() throws JMSException
Send the 'reset' fix message

public void logout(String text) throws JMSException
Send the 'logout' fix message

public void commitFixMsgSend()throws JMSException
public void commitFixMsgRead()throws JMSException

After any Fix message has been sent, it must eventually be committed. The JMS session used to send Fix messages is transactional

public void close() throws JMSException
Close all local JMS resources associated with this FixSession. Note: this closes the fix session object, once closed, a FixSession object cannot be re-used. If you just want to close the fix session itself, use the logout() method.

public boolean fixSessionInactive()
You should call this method before sending a Fix Message or an Admin Command, if  FixMQengine is not running, or is the FIX session has been closed, it will return true. Although the connection between the client and FixMQengine is a loosely coupled JMS connection, in general, you don't want to be pumping out Fix Messages if the FixMQengine is down - the messages would get stored by the JMS server and eventually sent to the FixMQengine, but because there is often a 'timeliness' factor in the sending of Fix Messages, its better no know if the message is not going to be delivered because of an obvious problem.

public void logMsgEvent()
You should call this method from the onMessage handler, it helps in deciding if the FixMQengine is running.

public QueueReceiver acceptConnection(MapMessage clientConnectMsg) throws JMSException, NamingException
This method should be called from the onMessage handler of the FixServerSession objet to accept a new session.

public QueueReceiver getReceiver()
public QueueSender getAdminSender()
public QueueSession getAdminSession()
public QueueConnection getConnection()

Utility methods to get various JMS properties used to connect to the FixMQengine. Normally, you will not need to use these methods, but they are available if needed.

public String getName()
public String getLocalName()

Get the name(Fix TargetId) and LocalName(Fix LocalId) of this session.

public void initCmd(MapMessage mmsg) throws JMSException
Initialize a MapMessage ready for use to send an Admin message. Normally you will not need this method, it is used internally, but is public just in case you should need it.

public void sendAdminCmd(MapMessage mmsg)throws JMSException
Send a MapMessage containing a Admin command. Normally you will not need this method, it is used internally, but is public just in case you should need it.

public static boolean isResendPermissionRequest(MapMessage mmsg) throws JMSException
public static boolean isResendPermissionRequest(int itype) throws JMSException
Convenience methods to test the type of message received, These methods are testing for the Resend-Permission-Request sent by the FixMQengine. If the request.resend.permission property is true the FixMQEngine will seek permission from the application before re-sending any messages. You should use these methods from the onMessage handler to check for the resend request, and respond to it.

public void beginResendPermissionSession(Message requestMsg)
throws JMSException

public void sendResendPermissionReply(Message requestMsg, boolean ok)
throws JMSException

public void endResendPermissionSession() throws JMSException

Convenience methods to respond to the Resend-Permission-Protocol used by the FixMQengine. See the sample onMessage handler for an example of their use.

public static boolean isErrorReply(MapMessage mmsg) throws JMSException
public static boolean isErrorReply(int itype) throws JMSException
public static boolean isFixMsg(int itype) throws JMSException
public static boolean isFixMsg(MapMessage mmsg) throws JMSException
public static boolean isAdminMsg(MapMessage mmsg) throws JMSException
public boolean isClosedAdminMsg(MapMessage mmsg) throws JMSException

Utility methods for testing the type of message received in the onMessage handler. Of particular note is the  isClosedAdminMsg() method that will always eventually return true, after either a normal logout (initiated from either side) or a connection error.

public static String getErrorText(MapMessage mmsg) throws JMSException
This method can be used to extract the error text from an Error Reply.

Class FixServerSession

See the sample application and the getting started section above for examples of how to use this class.

public void init(String engineConfigProperties) throws FixMqException,JMSException
Initialize the FixServerSession from a properties file, the file should be the same one as is passed to the FixMQengine on the commands line. Note: this method does not start FixMQengine, you need to do that separately from the command line, then call this method to initialize your application's connection to FixMQengine.

public QueueReceiver start()throws JMSException, NamingException, IOException, FixMqException
After initialization, use this method to start the JMS connection and get a QueueReceiver that should be used to add a server message listener.

public static boolean isClientConnection(MapMessage mmsg) throws JMSException
Use this method from the server message listener to determine if an incoming message is a new Fix Client Session.

public FixSession accept(MapMessage clientConnectMsg)
throws JMSException, FixMqException, NamingException
Use this method from the server message listener to accept a new FixSession if isClientConnection() returns true.  This method returns a FixSession, which can then be used to manage the new Fix Connection.

public void close() throws JMSException
Close all local JMS resources associated with this FixServerSession

Class FixMsgType

This class lists all current Fix Message Types, use this when creating a Fix Message. To see the messages defined, refer to the source code supplied for the Application API. If the message type you want is not defined, just set it anyway, there is no restriction to the types defined in  FixMsgType.
 
Class FixTag

This class lists many Fix Message Tags, use this when creating Fix Messages. To see the message tags defined, refer to the source code supplied for the Application API. If the message tag you want is not defined, just set it anyway, there is no restriction to the tags defined in FixTag.

Class FixConst

This class lists internal message type constants, normally, you will not need to refer to this class.
 
Class Logger

This class is used internally for logging, you could use it in your applications is you wish. For further details, see the enclosed

Class AbstractFixSession

This class is the base class for the FixSession, for convenience all methods have bee documented under FixSession above.

Class AbstractFixServerSession

This class is the base class for the FixServerSession, for convenience all methods have bee documented under FixServerSession above.

Pluggable Validators

Basic validation is performed on each message as it arrives.  You can define your own 'pluggable' validators to be called after basic validation has passed. Basic validation does not validate that Business Messages have all the required tags, or that they don't have extra tags. You could do Business Message validation in your application or you could define a validator to be called in the Engine itself.

Basic validation covers such things as header fields, date/time fields checksums, message length and Fix Version.

In order to define a pluggable validator, you must write a class that implements the FixValidatorI interface

public interface FixValidatorI {
    public void  validate(Map fixmsg) throws FixValidationException;
    public void init(String targetId, String localId);
}

The init() method is called after loading and gives you the chance to perform any initialization required. Then validate(Map fixmsg)  is called for every message received. If the validation fails your validate method should throw a FixValidationException

In order to define a validator, set the property external.validator to the name of your class, and modify the FixMQengine startup script to include the classpath to your validator class.

Class FixValidationException

import  com.octatec.fixengine.FixValidationException; // found in fixmq-engine.jar

public FixValidationException(String msg, boolean fatal)
public  void set(String msg, boolean fatal)

In both methods, if fatal is true, the fix session will be terminated, otherwise, a session-level rejection message will be sent, and processing will continue (but the remote side may decide to logout, of course). If you want to send an application level rejection you must do the validation in the application (not in the engine) and build your own rejection message.

Example JMS Configurations

The following are the JBOSS and OpenJMS configurations to run the samples. The configuration files are included in the installation under run-samples\jms-config. We have found the performance of JBossMQ to be far superior to OpenJMS (using the config below).

The queues required by FixMQengine are details in the Configuration section. The large number of queues here is because FixMQengine requires one 'admin' queue when running in Client mode and two 'admin' queues when running in server mode, plus an IN and OUT 'session' queue for each connected Fix Session. So if we have a Server and a Client sample application we need 3 admin queues plus at least 4 session queues, in fact, to run the samples fully, we need 8 session queues, this is because there are 2 distinct session configurations to show the Samples handling multiple Fix Sessions. This gives rise to the 11 queues listed below.

The configurations define the following queues which are needed to run the sample applications

FixMQ_adminCmd_srv
FixMQ_adminReply_srv
These are 'admin' queues required by the FixMQengine in Server Mode. All initial commands are sent on the admin queue. When a new FIX client connects to FixMQengine, it sends a message on the 'admin reply' queue. They are referenced in the They are referenced in the client-jboss.properties and  client-openjms.properties files.
  
FixMQ_adminCmd_cli
This is an 'admin' queue required by the FixMQengine  - when in Client Mode, FixMQengine does not require an 'admin reply' queue. It is referenced in the testsrvr-jboss.properties and  testsrvr-openjms.properties files.

fix_in_cli1_testsrvr
fix_out_cli1_testsrvr
These 2 queues are used by FixMQengine when in Client Mode and when connected to 'client 1'. The sample application is configured to allow 2 client sessions to connect to one server session. These are the in/out queue pair used to access the 'client 1' session. They are referenced in the cli1-session.properties file.
 
fix_in_cli2_testsrvr
fix_out_cli2_testsrvr
These 2 queues are used by FixMQengine when in Client Mode and when connected to 'client 2'. They are referenced in the cli2-session.properties file

cli1_snd_q
cli1_rcv_q
These are the queues used by FixMQengine  when in Server Mode and when connected to 'client 1'. They are referenced in the testsrvr-jboss.properties and  testsrvr-openjms.properties files.

cli2_snd_q
cli2_rcv_q
These are the queues used by FixMQengine  when in Server Mode and when connected to 'client 2'. They are referenced in the testsrvr-jboss.properties and  testsrvr-openjms.properties files.

The following diagram summarizes how the queues are used in the sample applications
sample application queue assignments

JBOSS Config

copy to ...\jboss-3.2.2\server\default\deploy\jms

<?xml version="1.0" encoding="UTF-8"?>

<server>
    <!-- Test Queue  -->

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=FixMQ_adminCmd_cli">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    </mbean>


    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=FixMQ_adminCmd_srv">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    </mbean>

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=FixMQ_adminReply_srv">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    </mbean>


    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=fix_in_cli1_testsrvr">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=fix_out_cli1_testsrvr">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=fix_in_cli2_testsrvr">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=fix_out_cli2_testsrvr">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>


    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=cli2_snd_q">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>


    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=cli2_rcv_q">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    <MaxTimesRedelivered>10</MaxTimesRedelivered>   
    </mbean>


    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=cli1_snd_q">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <MaxTimesRedelivered>10</MaxTimesRedelivered>
    </mbean>

    <mbean code="org.jboss.mq.server.jmx.Queue"
        name="jboss.mq.destination:service=Queue,name=cli1_rcv_q">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    <MaxTimesRedelivered>10</MaxTimesRedelivered>   
    </mbean>

</server>


OpenJMS Config

copy to ...\openjms-0.7.6.1\config

<?xml version="1.0"?>

<!-- OpenJMS configuration:
     . RMI connectors 
     . JDBM persistency
     . embedded JNDI provider
     . embedded RMI registry, running on port 1099
     . preconfigured destinations

     NOTES: this configuration shows all configuration elements relevant
            when using an RMI connector.
 -->

<Configuration>

  <!-- Optional. This represents the default configuration  -->
  <ServerConfiguration host="localhost" embeddedJNDI="true" />
 
  <!-- Required when using an RMI connector -->
  <Connectors>
    <Connector scheme="tcp">
      <ConnectionFactories>
        <QueueConnectionFactory name="JmsQueueConnectionFactory" />
        <TopicConnectionFactory name="JmsTopicConnectionFactory" />
      </ConnectionFactories>
    </Connector>
  </Connectors>
   
  <TcpConfiguration port="3030" jndiPort="3035" />

  <!-- Required  -->
  <DatabaseConfiguration>
    <JdbmDatabaseConfiguration name="openjms.db" />
  </DatabaseConfiguration>

  <!-- Required -->   
  <AdminConfiguration script="${openjms.home}\bin\startup.bat" />
   
  <!-- Optional. If not specified, no destinations will be created -->
  <AdministeredDestinations>
 
    <AdministeredQueue name="FixMQ_adminCmd_srv" />
    <AdministeredQueue name="FixMQ_adminReply_srv" />
   
    <AdministeredQueue name="FixMQ_adminCmd_cli" />
   
    <AdministeredQueue name="fix_in_cli2_testsrvr" />
    <AdministeredQueue name="fix_out_cli2_testsrvr" />

    <AdministeredQueue name="fix_in_cli1_testsrvr" />
    <AdministeredQueue name="fix_out_cli1_testsrvr" />

    <AdministeredQueue name="cli1_snd_q" />
    <AdministeredQueue name="cli1_rcv_q" />

    <AdministeredQueue name="cli2_snd_q" />
    <AdministeredQueue name="cli2_rcv_q" />
       
  </AdministeredDestinations>

  <!-- Optional. If not specified, no users will be created -->
  <Users>
    <User name="admin" password="openjms" />
  </Users>

</Configuration>


SonicMQ Config

The configuration for Sonic MQ is included in the distribution under run-samples\jms-config\sonic-mq, it is not documented here.

WebsphereMQ Config

The configuration for WebsphereMQ is included in the distribution under run-samples\jms-config\WebSphereMQ, it is not documented here.

FioranoMQ

The configuration for FioranoMQ is included in the distribution under run-samples\jms-config\fiorano, it is not documented here.

Choosing a JMS Provider

If you are already using a JMS provider for other applications, it makes sense to use the same JMS provider for FixMQ applications, the FixMQ configuration should be flexible enough to support any JMS implementation. Similarly, if you are using a a J2EE container, it makes sense to use the JMS implementation provided by the container. If you are starting from scratch, you can consider any JMS provider equally. Of the ones we have tested, we were quite disappointed by OpenJMS, it was by far the slowest and also had a tendency to deadlock during the 'failure' tests. JBossMQ did an admirable job and can't be beaten for the money (its free). Of the 3 commercial implementations, we were disappointed with WebSphereMQ's MapMessage restrictions, but we did find it very fast; we didn't do explicit speed testing on any implementation but all 3 commercial providers 'seemed fast'.

Logfiles

A typical top-level log-directory will look as follows. This directory layout is create by the two samples included in the installation.

logfile directory

FixMQengine logs

E.fixmq-client.log
E.fixmq-server.log
These are the main FixMQengine logs. If you run more than one FixMQengine in server or client mode, you should give the instance a 'name' in the engine properties file, that name will be used to distinguish these log files.

C.cli1-testsrvr
S.testsrvr-cli1
These directories contain the session logs,  sequence number logs and message journals for the Client and Server sessions. The directories contain date-stamped sub-directories when the actual log files are located. These log directories are named based on the local and target fix-ids  of the session.

Within the date-stamped directories, there are the following log-files

YYYYMMDD_0/session.log
YYYYMMDD_0/seq-num-in.log
YYYYMMDD_0/send-jnl.log
YYYYMMDD_0/send-jnl.pos

The only one you are likely to be interested in is the session.log, which is a log of the individual FixEngine session

Application logfiles

Aa.cli1.log
This is the main log for the application resulting from a FixSession.openClientSession call (Ao. indicates Application-Opened session), i.e. a Client Session

Ao.cli1-testsrvr.log
This is the main log for the application resulting from a FixSession.acceptConnection call (Aa. indicates Application-Accepted session), i.e. a Server Session

As.testsrvr.log
This is the main log for the server session (As. indicates Application-Server session), it is typically a very short log

Ai.c.FixMQ_adminCmd_cli.log
Ai.s.FixMQ_adminCmd_srv.log
These are the application queue initialization logs, (Ai indicates Application Initialization), these are also typically a very short logs

Appendix I

Description of the Message Passing protocol. This protocol is encapsulated by the  com.octatec.fixmq  API, and so you don't really need to know this information at all if you stick to the com.octatec.fixmq  API. The the description below, adminq represent the admin queue and fixq represents the FIX message queue, tmpq and tmpq2 represent temporary queues passed in the JMS message

Client Application

open a client session
PING[tmpq] -> adminq

OPEN_CLIENT_SESSION
[tmpq] -> adminq


INIT -> fixq
(if an OK_REPLY results, the INIT message is sent)

tmpq <- PING

tmpq <- ERROR_REPLY or OK_REPLY
(an error will result if, for example there is no remote FixEngine listening at the address)



This is implemented in the  FixSession.openClientSession() method, see the sample code ClientTest.openClientFixSession() for an example.

running a session
FIX_MSG -> fixq

(any number of FIX message can be received and sent, eventually you will send a LOGOUT, unless you get a CLOSED first)

LOGOUT ->  fixq



fixq <- FIX_MSG
(you will expect to receive multiple FIX messages)

fixq <- ERROR_REPLY
(an error reply may result, this just needs to be logged)
   
fixq <- CLOSED
(eventually a CLOSED message will arrive, this indicates the session is closed either normally or due to an error - this will always be the last message on the queue)

You need to implement your own MessageListener and react accordingly, an example can be found in  the AbstractTest.onFixMessage() sample code.

processing a resend request
(you will get a RESEND_PERMISSION_REQUEST if you have set request.resend.permission=true, respond with a YES or NO after examining the FIX message in the resend request, if request.resend.permission is not present or false, all resend are automatically fulfilled by FixMQengine)


RESEND_YES or RESEND_NO -> tmpq





fixq <- [tmpq]RESEND_PERMISSION_REQUEST

An example of processing these messages can also be found in the AbstractTest.onFixMessage() sample code.

Server Application

initialization
PING[tmpq] -> adminq

START_SERVER -> adminq

tmpq <- PING

This procedure is encapsulated by the FixServerSession.start() method, see the sample code  ServerTest.startServerFixSession() for an example of its use.

accepting a connection


START_SERVER -> adminq

blank-message
[tmpq2] -> tmpq

INIT -> fixq

(once a session has been accepted
running a session and processing a resend request apply equally to the server application and the client application)
adminq <- [tmpq]OPEN_CLIENT_SESSION




You need to implement your own MessageListener and react accordingly, an example can be found in  the ServerTest.onServerMessage() sample code. The actual code to accept a connection can be seen in FixSessionServer.accept(). found  Once a session has been accepted, it is a FixSession and should be treated exactly as a FixSession created from a Client application.

listenin to the server

adminq <- ERROR_REPLY
(an error reply may result, this just needs to be logged)

adminq <- CLOSED_SERVER
(a server closed message will normally be received when the server is closed by a kill signal or Ctrl-C, this will cause all open fix sessions to be closed first)
Again see the sample code in ServerTest.onServerMessage().

m4_include(footer_hr.m4)