HOME  | DEMO  |  BUY NOW



    Application Fix Interface  (c) 2003 Octatec Ltd
   


The Application Fix Interface is a FIX Engine with a very simple Application Programming Interface (API) that is designed to make adding Fix Connectivity to your applications very easy; it is very easy to use and requires the programmer to implement only a few methods of a FixHandler Java class. The system includes a sample fix server program that can read  files written in a simple scripting language and thus makes testing your application very easy. 

For more information about the FIX Protocol see http://www.fixprotocol.org

Contents


System Components

There are 3 system components, a Fix Engine that is started automatically when needed, and 2 API jars that must be available on your classpath in order to access the Fix Engine

The system  creates an AFI FixEngine session passing in the name of a properties file. This causes the AFI FixEngine process to start up and read the properties file. using information it finds in the  file, it will connect, using tcp/ip sockets to an external Fix Engine. It will communicate with the User Application via a local socket. The User Application enters a Fix Message loop receiving and sending messages.


Getting Started

The following is the basic structure of the afitest sample application and demonstrates the standard pattern of an AFI application.
// AfiTest...

import com.octatec.aficlient.*;
import com.octatec.jfixgw.*;

// implement a Fixhandler

class MyFixHandler extends FixHandler {

public void onPreOpen()
{
     m_session.enableAutoSetComplete();
          // doing this means you do never need to call
          // m_session.setComplete() yourself
}

public void onFixMsg(String type, FixString msg)
{
     if( type.equals( FixConst.FIX_MSG_SomeType ) )
     {

    ...process the message contained in msg...

        // E.G. Use... 
       String value = msg.GetField(FixConst.FIX_FLD_SomeFieldType);

       m_session.setComplete(); // indicates the message is fully processed

        // maybe you now want to send a message

        FixString myMsg = new FixString();

    myMsg.addField(FixConst.FIX_FLD_SomeFld, "some value");

    ...add more fields as required...

        m_session.sendMsg(FixConst.FIX_MSG_SomeOtherType, myMsg);
           // in an actual application you must catch 
             // any exception thrown by this method

}

}
}
/*
** from your application's main method...
*/

LPCTSTR propFileName = "loopback";
    // loopback is a standard properties file supplied with the distribution, it
    // allows a fix client (namely afitest) to connect to the afisrv application

AfiApp app = new AfiApp(propFileName);
FixHandler handler = new MyFixHandler();

int result = app.startApp(handler);
           // the system will now create a FixSession
           // and call your Fixhandler's methods
           // NB: there is NO RETURN from this method unil
           // the Fix Session has ended - to run a Fix Session
           // in a worker thread, see below

If you want your Fix Session to be created in a worker thread, just use an AfiThreadedApp object as follows
// afisrv
/* from the main thread... */

AfiThreadedApp app = new AfiThreadedApp(propFileName);
FixHandler handler = new MyFixHandler();
int result = app.startThread(handler);
        // the fix session is created in a worker thread and your 
        // FixHandler’s methods are call from the worker thread -
        // you can use methods on the AfiThreadedApp object to
        // send messages to your worker thread

/* still from the main thread… */

app.sendThreadFixMsg(FixConst.FIX_MSG_SomeOtherType, myMsg);
        // send a Fix Message via the worker thread - you
        // Don’t have to use this method to send fix messages
        // in a muti-threaded app, if the structure of your 
        // application permits it, you can send them directly 
        // from the worker thread using m_session.sendMsg() 
        // just as you would for a single threaded app

// at some point, close the session

app.closeThread();


FixEngine Properties File

This properties file describes the Fix Engine session, in particular what IP address and port number to use, as well as local optional settings. You pass the full pathname of a properties file into the constructor of the AfiApp or AfiThreadedApp. If you pass in a file name rather than a full pathname, the file is assumed to reside in  /Octatec/afi/Home/configs on UNIX-based systems and 
C:\Program Files\Octatec\afi\configs (or under whatever  directory you chose during the installation) on WIN32 systems.

The properties file contains a list of  names =values  entries, all entries are case sensitive

The following entries define the fix session

host = hostname
The host name to which the AFI Fix Engine will connect. The AFI Fix Engine will attempt to connect to hostname as a client. If the name is local, the local system is used. If the hostname is specified as an asterisk, *, the Fix Gateway will act as a server, i.e. it will listen for incoming calls and accept the first one. Only the first incoming call will be accepted - multiple connections to clients is not supported within a single gateway process, however multiple gateway process are permitted. For added security, you can specify a server using *N.N.N.N, in this case, the server will only accept calls from IPaddress N.N.N.N (note: you must use the actual IPaddress and not a hostname when restricting clients in this way.)

port = n
This is the port to used by the Fix Gateway.
FixVersion MAJ.MIN
This can be used to set the fix version, the default is 4.0. Currently MAJmust be 4. As of writing Fix 4.2 is the latest release release, so MIN should only be 0, 1 or 2.

localId = local
This is the name of the local fix session and is used in the outgoing fix header
LocalSubId local_sub
This is the sub-name of the local fix session and is used in the outgoing fix header

targetId = testsrvr
This is the expected name of the remote fix engine

targetSubId = testsrvr_sub
This is the expected sub-name of the remote fix engine
NB: these 4 IDs are not hostnames, they just strings chosen by the 2 sides of the fix conversation. Both sides must each know the others IDs and  specify them correctly in the config file. If SubId's are not being used, they can be left out of the config file, or given values starting with a '#' character. If the gateway detects a mismatch of IDs during logon, it will logout from the remote, unless checkLogonSubIDs is set to 0

gmtOffset = n
This parameter allows you to set a ‘virtual’ time zone for the fix gateway. The client application will still see the local time-zone as normal but the Fix Engine process will see the timezone as GMT+n (n can be +ve or –ve). The real implication of this is that Fix Message headers will leave with the Virtual Timezone in the time-stamp and midnight will also be dictated by the Virtual Timezone; midnight is important for FIX 4.0 and FIX 4.1 (and even FIX 4.2, when sessions are being re-set automatically) since the Fix Session is automatically reset when a session is restarted after midnight. The default value is 99, if GmtOffset is 99, the Virtual Timezone is the same as the system timezone.

bufferSize = n
By default, buffer size is 1024, and the system will not let you set it below 512. If you expect to receive particularly long Fix Messages (larger than 1012 bytes) you can increase the size of the buffer used to read incoming messages here.

FIXML_addhdr = n
If this is 1, a <Header>…</Header> section is automatically added to your outgoing XML. This duplicates the information in the standard FIX header, and is part of the FIXML specification. If you set this flag true, you don’t have to worry about adding te FIXML header yourself. If you set this flag to 0, you can either add FIXML header information yourself or leave it out if that is what has been agreed locally. In all cases the standard FIX header is automatically included by the Fix Engine process and you shold not attempt to add header fields using FixString::AddField() .The default value of this field is 0.

FIXML_addroot = n
If you set this to 1, your outgoing XML will be automatically enclosed in  <FIXML><FIXMLMessage> … </FIXML></FIXMLMessage> tags, so you don’t have to worry about adding them yourselves. (Of course this is only appropriate if your XML payload is actually FIXML) The default value of this field is 0.

preferNIO = n
The default value value is 1. Your should not normally change this – you will only want to change this if you are implementing your own SocketI and/or ServerSocketI in order to use a 3rd party SSL provider, and their implementation dos not support ‘nio’in which case you can set this value to 0.

The following entries control optional behaviour of the fix gateway

NB: there are quite a few parameters here, but mostly, the deault values will be what you want.

confirmResendSpec = List_of_Msg_Types
This setting allows your application program to decide is a message should be resent or not. List_of_Msg_Types is a colon-separated list of message type that you do not want to be resent automatically if a resend is requested by the remote side, e.g. D:E. When a message that appears in this list needs to be resent, your application is asked if the message is to be resent, if you say no, a gap fill is sent instead. List_of_Msg_Types can be a single asterisk (*), in which case, resend confirmation is requested for all non-admin messages. By default all messages are always resent automatically (except admin messages, of course, which are always replaced with GapFills)

forwardHeartbeat = n
If  n is 1, heartbeats will be received by the user application through the FixClient::GetFixMsg() method, if 0, heartbeats are not delivered to the user application. This might be useful if your application needs to perform housekeeping actions at regular intervals. It is also a useful way for the gateway to detect if your application has crashed or not - the gateway will only detect that your application has crashed when it tries to send data to it. The default value is 1.

forwardLogon = n
If n is 1, logon messages will be received by the user application through the FixClient::GetFixMsg() method, if 0, logon messages are not delivered to the user application. The default value is 0. This translates to a call to onLogon(FixMsg msg) on the Fix Handler.

forwardLogout = n
If n is 1, logout messages will be received by the user application through the FixClient::GetFixMsg() method, if 0, logon messages are not delivered to the user application. The default value is 0. This translates to a call to onRemoteLogout(FixMsg msg) on the Fix Handler.

ForwardRejection n
If n is 1, rejection messages will be received by the user application through the FixClient::GetFixMsg() method, if 0, rejections are not delivered to the user application. The default value is 0.

tolerateRejection = n
If n is 0 rejections are always allowed, if n is > 0, that number defines how many rejections will be received before the Fix Engine automatically closes. The default value is 1, i.e. the gateway automatically closes after receiving one session level rejection. 

heartBtInt = n
The heart beat interval, in seconds, passed in the login message, this is 15 by default
AlwaysUseOpenEndedResend n
If the value of n is 1, resend requests are always open-ended, if the value is 0,  resend requests are terminated with the current required sequence number. the default value is 1.

supressNestedResendRequests = n
If n is 1, the sending of resend requests after just issuing a resend are suppressed for a maximum of ResendSupressionTimeout seconds. This parameter is designed to avoid the situation where the sender has buffered up a lot of messages, but the first message triggers a resend. In this situation, the 2nd message would also trigger a resend, as would all the messages in the buffer, resulting in a lot of resend requests arriving at the sender. After ResendSupressionTimeout seconds have elapsed, normal resend requesting behaviour is resumed. The default value is 1.

resendSupressionTimeout = n
This parameter controls the number of seconds for which the special behaviour is performed. The default is 10 seconds.

honourOutOfSeqResend = n
This flag allows special action to be taken when a deadlock situation arises. When both fix engines start up, and both discover the Logon message contains an invalid sequence number, both sides will issue resend requests, but both sides will ignore the others resend because it contains an invalid sequence number. If this flag is 0, no special action is performed, if it is 1, a resend request with an invalid sequence number is still processed, and the requested messages are resent, if it is -1, a resend request with an invalid sequence number is rejected and a logout is initiated. The default value is 1.

journalIncoming = n
If n is 1, incoming messages are saved in a journal, if 0, incoming messages are not journaled (The default value is 1). Outgoing messages are always journaled. The Incoming (Receive Journal) plays a part in ensuring messages do not get lost, so read the section abount SetComplete() before switching this off.

logDir = path
This value defined the log directory. The first character may be a % as in %/logs, in which case the % is replaced by the Installation Directory under WIN32 and by /Octatec/fixgw/Home under UNIX/Linux. NB: the directory must exist. A sub directory with the name YYYYMMDD is created in the log directory, and logs and journal files are saved here. The fix gateway should close down at least once every 24 hours so that a new log directory is allocated. Ideally, the fix gateway will be closed sometime before midnight, and restarted sometime after; however, if you plan to use manual session resets, as permitted  under FIX 4.2, this is not required. NOTE: the path cannot contain spaces, if you are on a WIN32 system and you're path does contain spaces, use the short-form of the path, if you are on a UNIX system, you could create a symbolic link (that doesn't contain spaces) to the directory. NOTE: If you are entering a path-name on a WIN32 system, you must use \\ (two backslashes) as the path separator.

clientLogDir = path
This entry defines where the client logs are placed. Client logs are less important than server logs, but still useful if you encounter problems. If this entry is not present, if this entry is not present, the logDir (above) is used. If this directory doesn’t exists, the application will display an error message and exit – it is better to know straight away that there is a problem rather than try and search for the non-existent log at some later date 

logLevel = n
This defined the level of logging, 0 is the least verbose and 2 is the most verbose. The default value is 2.

__debug__ = n
If this value is 1, debug logging mode is switched on, in this mode all log files are closed after each entry is written, and opened again as needed, in this way, the log files can always be viewed in all environments. NOTE: setting this to 1 will slow the system down; the default value is 0.

checkLogonSubIDs = n
If any of the IDs (TargetSubID etc) in the config file are blank or start with a hash (#), then the ID is not added to the Fix message that is sent. When we process a logon, the TargetID must match the in-coming SenderID, and the target SubID must match the incoming sender SubID unless the TargetSubID is blank or starts with a hash (#), in which case, we are 'not' processing SubIDs.  If you want to send a TargetSubID, but not validate the returned SubID in the logon message, you must set this parameter to 0. The default value is 1.

manualSessionSwitch = n
This flag must be set to 1 if you are using fix version 4.2 or higher, and you want to use the ResetSession() method. The default value is 0. When this flag is 1, the log directories will have a 'version number' attached to the end of their name. Note: if this flag is set, the session will run until one side issues a ResetSession(). With this flag set to 0, a session is re-established at midnight local time  (or local 'virtual' time) - but further note: this only occurs when the fix gateway re-starts, hence, to cause a session reset when this flag is set to 0, you must close the fix gateway sometime before midnight, and re-start it after midnight.

CliSndBufSize n 
CliRecvBufSize n
These parameters specify the send and receive tcp/ip socket buffer size used within the client library when communicating with the FixGateway process, the default value is 0 which indicates the system-default is to be used. 

SrvInSndBufSize n 
SrvInRecvBufSize n 
These parameters specify the send and receive tcp/ip socket buffer size used within the FixGateway process when communicating with the client application, the default value is 0 which indicates the system-default is to be used. 

SrvOutSndBufSize n 
SrvOutRecvBufSize n 
These parameters specify the send and receive tcp/ip socket buffer size used within the FixGateway process when communicating with the remote Fix Engine, the default value is 0 which indicates the system-default is to be used. 

__useLCRP__ = n
See the implementation note at the end of this document. (The default value is 1)

String values can contain embedded spaces if they are surrounded by double or single quotes. Lines beginning with # are comments.


Client Library Properties File

fixgw.properties

This properties file must reside in the startup directory of your application that is using the aficlient.jar. This allows the client library to find the AFI Fix Engine. A suitable properties file is supplied with the installation and is located in the installation directory – normally you will just copy this and not change any of the entries. It contains the following entries which are all created during installation.

Home=C:\\Program Files\\Octatec\\AFI_J\\1.00
The installation directory, this will use single forward slashes if on UNIX, but if on Windows, it will use double backslashes.

Gateway=javaproc
Gateway process type. This entry tells the system to start the AFI Fix Engine in a new Java Virtual Machine, an alternative value is javathread, which will cause the Fix Engine to be started in a new thread in the current VM. (If you use javathread, you must ensure that afi.jar is on the classpath.)

Java=C:\\...\\bin\\java
The location of the java command

AFIsrv=C:\\...\\afi.jar
The location of the AFI Fix Engine classes

AFIcli=C:\\...\\JFixGW.jar
The location of additional Fix classes used by the Fix Engine


LogFiles and Journals

AFI's logfiles and journals

The location of these files is very important, and is controlled by the configuration file's LogDir entry.  These are created in a directory named YYYYMMDD_0  located in the Log Directory specified in the config file. Note: if  ManualSessionSwitch is set to 1 in the fix emgine properties file, the directories are named YYYYMMDD_N, where N is a version number that is incremented whenever a session is reset within any 24-hour period - if the reset takes place in a different 24 hour period, the YYYYMMDD part of the name will change and the N part will be 0.

One way of reseting the sequence number back to zero is simpley to delete these files.

The files created are as follows.

AFIserver.log
The general log file of the fix gateway, the LogLevel entry in the configuration file applies to this file only

FixJnl-TargetId.txt
The journal file - all outgoing messages are recorded here to enable resends of messages missed by the remote system.

FixRcv-TargetId.txt
The incoming journal - this is an optional file, and does not have any particular use.

SeqNo-TargetId.txt
A record of the current incoming and outgoing sequence numbers.

As already mentioned, you should endeavour to ensure that the fix gateway is closed down some time before midnight and started sometime after, so that the fix sequence numbers will restart at 0. It is the act of starting the fix gateway with an empty log directory that resets the sequence numbers to 0.
 

Client Library Log

The client library also creates a log file, FixGatewayClnt.log. The location of this log  is controlled by the fix engine properties file paramater cliLogDir. If this entry is not present, the logDir property is used instead. Once the base directory has been decided, a directory with the same name as the config file is created, and then a sub directory named YYYYMMDD_c is also created, finally the logfile is created in that directory. To summarize, the client library logfile is created as follows...

.../ConfigName/YYYYMMDD_c/FixGatewayClnt.log.

The sequence number of the last successfully processed fix message ( as defined by the FixSession.setComplete() method) is saved in .../ConfigName/YYYYMMDD_c/setcomplete.log

If the client application is using the output buffering mechanism, a buffer file is created in  .../ConfigName/buff.txt, this stores unflushed messages, when the buffer is flushed, it is renamed, .../ConfigName/buff.cmt.


FIXML Support

This package supports FIXML; it allows you to build ApplicationMessage FIXML sections using your favorite XML DOM implementation and pass these to the gateway, the gateway will add all the required FIXML headers around your ApplicationMessage.  To activate this functaionity, you need to set FIXML_addhdr andFIXML_addroot config parameters.

To make setting the XML payload of a standard FIX message slightly easier, the FixString.SetXmlPayload()method is provided.

You can find more details about FIXML support here.


The AfiClient Class library

This is an event-driven API and is extremely easy to use, it is the preferred method of accessing the AFI Fix Engine. It is built on top of  a low-level API which you can access, but are encouraged not to use.

Jar Files Needed: aficlient.jar, jfixgw.jar 

import com.octatec.aficlient.*;
import com.octatec.jfixgw.* ;
 

Abstract Class com.octatec.aficlient.FixHandler

You must derive your own class from the FixHandler class in order to process incoming FIX messages. The only method you really need to implement is onFixMsg(FixString s).

public void onPreCreate()
This method is called just before the fix session is created, it allows you to set low level options if you require them, mostly, you will not need to implement this method.

public void onOpenComplete()
This method is called just after a session is established with the remote FIX counterparty.

public void onLogon(FixString fixMsg)
If you have enabled notification of logon messages in the properties.file, [the default setting is to disable  logon notification] this method is called when the remote sends a logon message. You only need to implement this method if you are particularly interested in the remote’s logon message. This method will only be called if  the forwardLogon property is set to 1.

public void onHeartbeat (FixString fixMsg)
If you have enabled notification of heartbeat messages in the properties.file, [the default setting is to enable heartbeat notification] this method is called when the remote sends a heartbeat message. You only need to implement this method if you are particularly interested in heartbeat messages, (maybe you are using them as a timer?)

public void onRejection (FixString fixMsg)
If you have enabled notification of session protocol rejection messages in the properties.file, [the default setting is to disable  rejection notification]. This method is called when the remote sends a rejection message, the default behavioiur is for the fix engine to treat this as a ‘fatal’ error condition hence you will normally receive an onClose() notification not an onRejection(). You only need to implement this method is you have configured the fix engine to tolerate rejection messages sent from the remote side – something you will not normally want to do!

public void onRequestResend(FixString fixMsg)
If you have enabled confirmation of resend requests in the properties.file, [the default setting is to automatically fulfil all resend request] this method is called to ask permission to resend the specified message, if you return true the message is resent, if you return false a gap-fill is sent instead. You only need to implement this method if you do not want to automatically resend all requested messages

abstract public void onFixMsg(FixString)
This is the only method you really need to implement, it is called whenever an application-level fix message arrives. You should process the message as needed, a good first step is to put it in the database. You can use methods on the FixSession object (m_session)  to send response fix messages if required.

public void  onLogout()  DEPRECATED
This method is called when the fix session closes  normally. You do not need to implement this method, as the AfiApp.start() method will automatically return and no more messages will be received when the session closes. One reason you might want to implement this method is to call m_session.reopen(), if the reopen succeeds, the AfiApp.start() method will not return (at this juncture).
This method is now deprecated  and has been replaced by the following 2 methods.

public void onLocalLogout()
This is called is a local logout is issued within the application.

publi void onRemoteLogout(FixString msg)
This method is called when the remote logs out. The msg parameter will be null unless the forwardLogout property is set to 1.

public void  onError(int statuscode, boolean duringOpen)
This method is called when the fix session closes due to an error. Again, you do not need to implement this method, as the AfiApp.start() method will automatically return and no more messages will be received when the session closes. Again, one reason you might want to implement this method is to call m_session.reopen(), if the reopen succeeds, the AfiApp.start() method will not return (at this juncture). The duringOpen parameter will be true if the error occurred  during the attempt to open the session.

public void onClosed()
This method is called once the session is completely closed, for either of  the above 2 reasons or if you called m_session.logout(). (Note: It is too late to call m_session.reopen() from here.) NB - for every session you will either get an onError() or an onLogout(), this will cause the open session to close automatically, so you will then get an onClosed() event. If you call m_session.logout() you will get still get onLogout( ) followed by an onClosed(). If an error occurs during the attempt to open a session you will still get an onError() event but with duringOpen set to true, you will immediately get an onClosed() event to maintain consistent ordering and delivery of events.

onThreadMessageSent(String type, FixString sfix, int result)
This method will only be called if you used the AfiThreadedApp  object when creating your application: In this case your Fix session will be in a worker thread. If you call  AfiThreadedApp. sendThreadFixMsg(type, sfix), this method will be called immediately after the worker thread actually sends the message (. If result is not 0, it indicates an error, and to preserve consistency in the API, onError() will also be called immediately after this method. (Note: type and sfix could be null if a serious error occurs.) You don’t need to do anything in this method, but it may be important for you to know that the fix-message failed to be sent, remember the User Interface thread that used sendThreadFixMsg(type, sfix) will not know for sure that the message has been successfully sent to the remote fix engine - the return value of sendThreadFixMsg(type, sfix) only indicates that the message has been successfully sent on its way to the worker thread.
(NOTE: the actual sending of the message in response to AfiThreadedApp. sendThreadFixMsg(type, sfix) is performed  automatically by the frame-work, you don’t need to worry about that, and then once sent, ths method is called to inform you of the fact.)

public void onThreadCmd(short cmd, String text)
This method will only be called if you used the AfiThreadedApp  object when creating your application. In this case your Fix session will be in a worker thread, and the GUI or foreground thread can use AfiThreadedApp.sendThreadCmd() to send the Fix Worker Thread messages. NB: the text parameter may be null.

public void onUserError(Throwable t)
This method is called if an Exception (Throwable) is thrown from any of the above methods. For example, if you access a null reference or perform some other programing error in one of the above methods, unless you catch the exception yourself, this method will be called.

protected FixSession  m_session
This member contains the current FixSession object and is guaranteed never to be null. Your FixHandler class can call methods on this object, typically to send Fix messages or close the session.
 
 

Class com.octatec.aficlient.FixSession

This class is created automatically and is made available to your application via the FixHandler.m_session member.

public void sendMsg(String type, FixString fixMsg) throws AfiException;
Send a Fix message of the specified type. If you are in a loop sending fix messages, your application will not be able to receive any incoming messages until the loop completes.

Note: the correct thing to do when catching an AfiException thrown by any method is, after recording whatever information you want, call m_session.handleException(x), and then return immediately. Doing this allows the session to tidy up correctly and will also give rise to you handler’s onError() method being called.

public void sendMsgEx(String type, FixString fixMsg) throws AfiException;
Send a Fix message of the specified type. After the messages has been sent, the system will check for any incoming messages, and if there are any, they will be dispatched by the system. So your Fixhandler’s onFixMessage() or other methods may be called before this method returns. If you are in a loop sending fix messages, your application will still receive incoming messages while the loop is active.

public void logout()
Send a logout message and close the session.

public boolean reopen() 
You can call this method to attempt to re-open a closed session, typically, you will call it from your FixHandler’s onClose() method. The reopen() call will wait until a connection has been made or until an error occurs.

public void setComplete()
Use this method to indicate to the system that all messages received to-date have been fully processed (or saved in your database for latter processing). If this has not been called, and the application crashes (or exits in some other way), any messages received (since the last call to setComplete ) will be re-requested automatically when the application is next started. If you don’t want to have to call setComplete(), you can use the following method.

public boolean  enableAutoSetComplete()
If you are going to call this method, you MUST do so before the fix session is established, i.e. from you’re your FixHandler’s onPreCreate() method. If you call this method, all messages received are automatically marked as ‘fully’ processed, and there is no need to call setComplete().

public void beginBufferedOutput() throws AfiException;
public void abortBufferedOutput() throws AfiException;
public void flushBufferedOutput() throws AfiException;
If you call beginBufferdOutput(), all subsequent calls to sendMsg() or sendMsgEx() will merely add the message to a persistent buffer. The messages will not be sent until flushBufferdOutput() is called. If  abortBufferdOutput() is called the buffer is discarded. If you use this facility, and the application exits before you flush the buffer, the buffer is automatically flushed the next time your application runs. if you don't want to flush the buffer on application start-up, you can call, abortBufferdOutput() from your FixHandler’s onPreCreate() method, it is always safe to do this, even if there is no buffer to abort, (no exception will be thrown).

public void handleException(AfiException x)
This method should be called whenever you catch an AfiException; you will almost certainly be in a FixHandler method at the time - you should return immediately after calling this method. Calling handleException() allows the session to tidy up correctly and will also give rise to you FixHanler’s onError() method being called.

public FixClient getLowLevelApi();
You can call this method to access the ‘low-level api’, mostly you should not need to access the low-level api at all, but if you have special requirements, you can do this. One reason to use the low-level API is to send script file, the afisrv test program uses this facility,
 

Class com.octatec.aficlient.AfiApp

You should create one of these objects to run your application

public AfiApp(String propertiesFile);
Pass a properties file that defines the fix session connection parameters such as IPAddress and port.

public int  start(FixHandler handler);
Once you have created the AfiApp object, call this method to actually start the fix session, pass in your FixHandler-derriver object to this method.
 
 

Class com.octatec.aficlient.AfiThreadedApp

You can create an instance of this object instead of an AfiApp object if you want  your Fix session to run in a worker thread, perhaps your foreground thread will be presenting a GUI to a user. Internally, an AfiApp instance is created in its own thread. You could do this yourself if you wished, but the advantage of using the AfiThreadedApp  object is that you can use the sendThreadCmd() methods from te GUI thread to send ‘internal’ messages to your FixHandler class in the worker thread, in which case your FixHandler's onThreadCmd(short cmd, String text) method will be called

AfiThreadedApp(String propertiesFile)
Pass a properties file that defines the fix session connection parameters such as IPAddress and port.

public boolean startThread(FixHandler handler);
Create a new worker thread to run your fix session. The worker thread will automatically initiate the fix connection when this method is called.
This method will not return until a connection  has been made or an error has occurred.

public void startThreadNoWait(FixHandler handler);
Create a new worker thread to run your fix session. The worker thread will automatically initiate the fix connection when this method is called. This method will return immediately.

public boolean closeThread();
This will cause the worker thread to send a logout and close the session, if this method is called, any call to FixSession.reopen() will automatically fail.

public boolean sendThreadFixMsg(String type, FixString sfix)
You can call this method from the User Interface thread to cause the worker thread to send the specified fix message.  Your fix handlers onThreadMessageSent(type, sfix, result) will be called after the message has been sent in the worker thread, if result indicates an error, your fix handlers onError() will also be called. Of course, you don’t have to use this method to send fix messages – if your message can be generated entirely from the worker thread, e.g. in response to an incoming message, you can just use the m_session.sendMsg()  method from you fix handler. Note: this method will return false if you try and send an empty fix message.

public boolean sendThreadCmd(short cmd);
Send an arbitrary notification to the Fix session thread. The cmd parameter should be above 100, other than that, it can be any value you choose, and you can interpret it in any way you choose in your FixHandler’s  onThreadCmd(short cmd, String text) method, note the text parameter will be null.

public boolean sendThreadCmd(short cmd, String text);
This method allows you to also send an arbitrary notification and a text string to the worker thread. The cmd parameter should be above 100.

int getLastStatusCode();
You can use this method to ‘poll’ the status of the worker thread, however, you should probably implement some sort of notification send from the worker to the GUI thread if an important event occurs that the GUI needs to know about, e.g. using something like EventQueue.invokeLater()

The following class is actually found in the low-level API, but is used extensively by this class library, and encapsulates a fix message…
 
 

Class com.octatec.jfixgw.FixString

This class provides the functionality for building fix messages and accessing all the fields of the message. The class FixConst provides you with a list of current Fix Fields and Message Types. You can, however, use any value as a Fix Field ID, and any value for a Fix Field Type.

new FixString()
new FixString(String s)
Construct a fix message string, either empty, or from a string containing fix fields. Note: their is no validation of the string passed into the constructor.

void Set(String s)
Set the contents of the fix string to the specified value. Note: their is no validation of the string passed in.

String GetMsgType()
Return the type of a fix message. This will be one of the FIX_MSG_* values defined in FixConst

bool GetField(int tag, OutputString value)
bool GetField(int tag, OutputInt    value)
void AddField(int tag, int    value)
void AddField(int tag, String value)
void UpdateOrAddField(int tag, int value)
void UpdateOrAddField(int tag, String value)
bool RemoveField(int tag)
The above set of methods are likely to be the most useful. In all cases name is just the numerical value of the field (tag). It is most likely to be one of the FIX_FLD_* values in FixConst but could be any value. The methods treat the contents of fields as either strings or integers, if the field has a different type, e.g. date/time or floating point, you must extract it as a string and convert it.

String GetField(int tag)
A slightly more convenient method, if the field isn’t present, an empty string is returned.

void SetXmlPayload(String xmlText)
This method discards any tags you ay have already set, just sets the XmlDataLen and XmlData tags based on the xmlText parameter. You probably shoudn’t add any more tags to the message after this one, although you can if you want. You can then send the message using any ‘type’ you wish, it is up to the receiving end to be prepared to decode your XML payload if you use a traditional FIX-MSG-TYPE, or to understand any other type filed you may choose to use, such as “XML” or “FIXML”. It is up to you to serialize your XML into a flat sting before passing it to this method, this might be as easy as reading it into a buffer from an xml file. Note: if you are sending FIXML, there are a couple of config parameters to help you, and a further discussion here. 

String GetXmlPayload()
This method is realy the equivalent of calling GetField(FIX_FLD_XmlData) If there is no XML payload present, null is returned. 

void InitEnum()
boolean EnumNextField(OutputInt name, OutputString value);
These 2 methods enable the enumeration of all fields in a fix string. You should call InitEnum(), once then repeatedly call EnumNextField() until it returns false.

void EmptyString()
Clear the contents of a fix string

String GetString()
Get a reference to the actual string

static Calendar GetCurretTime() // implies gmtOffeset = Config.V_LOCAL_TIME
static Calendar GetCurretTime(short gmtOffeset) 
This is a convenience method to get the current time taking into account the GMT offset (virtual timezone) present in the Fix Gateway process. If the first version of the method is used, any GMT offset is ignored, and the current local time is returned.

static String FormatDate(Calendar cal) // implies format = FixString.FMT_LONG_MS
static String FormatTime(Calendar cal, int format);
Convert the date in cal into a fix format string. If cal is null, then  the current date/time is used. If format=FixString.FMT_LONG_MS, the output is in the form YYYYMMDD-HH:MM:SS.sss, if format=FixString.FMT_LONG, the output is in the form YYYYMMDD-HH:MM:SS and if format=FMT_SHORThe output is in the form YYYYMMDD

static Calendar ParseDate(String s); // YYYYMMDD  or   YYYYMMDD-HH:MM:SS.sss
Return a Calendar object that representd the date/time in the input fix date/time string.
 
 

Class com.octatec.jfixgw.OutputString

This is a class with a single public m_value String member. It is used to return output string values via parameters from various methods.

new OutpuString(String value);
new OutpuString();

boolean equals(Object o);
boolean equals(OutputString s);
boolean equals(String s);
These 2 methods compare the characters in the strings and not the object references.
 
 

Class com.octatec.jfixgw.OutputInt

This is a class with a single public m_value int member. It is used to return output int values via parameters from various methods.

new OutputInt(int value);
new OutputInt();
 
 

Class com.octatec.jfixgw.OutputShort

This is a class with a single public m_value short member. It is used to return output short values via parameters from various methods.

new OutputShort(short value);
new OutputShort();
 
 

Class com.octatec.jfixgw.OutputBool

This is a class with a single public m_value boolean member. It is used to return output boolean values via parameters from various methods.

new OutputBool(boolean value);
new OutputBool();
 
 

Class com.octatec.jfixgw.FixConst

This class defines all the Fix Message Types and most of the Fix Fields (tags) that can be used in the various messages. The FIX_MSG_ constants can be used as arguments to the FixSession.SendMsg() method, while the FIX_FLD_ constants can be used as the ‘name’ parameter to various methods in the FixString class.

  public  static final String FIX_Delimiter = "\001";

 public  static final String FIX_MSG_Heartbeat     ="0";
 public  static final String FIX_MSG_Test_Request    ="1";
 public  static final String FIX_MSG_Resend_Request    ="2";
 public  static final String FIX_MSG_Reject      ="3";
 public  static final String FIX_MSG_Sequence_Reset    ="4";
 public  static final String FIX_MSG_Logout      ="5";
 public  static final String FIX_MSG_Indication_of_Interest  ="6";
 public  static final String FIX_MSG_Advertisement    ="7";
 public  static final String FIX_MSG_Execution_Report   ="8";
 public  static final String FIX_MSG_Order_Cancel_Reject   ="9";
 public  static final String FIX_MSG_Logon      ="A";
 public  static final String FIX_MSG_News      ="B";
 public  static final String FIX_MSG_Email      ="C";
 public  static final String FIX_MSG_Order_Single    ="D";
 public  static final String FIX_MSG_Order_List     ="E";
 public  static final String FIX_MSG_Order_Cancel_Request  ="F";
 public  static final String FIX_MSG_Order_Cancel_Replace_Request="G";
 public  static final String FIX_MSG_Order_Status_Request  ="H";
 public  static final String FIX_MSG_Allocation     ="J";
 public  static final String FIX_MSG_List_Cancel_Request   ="K";
 public  static final String FIX_MSG_List_Execute    ="L";
 public  static final String FIX_MSG_List_Status_Request   ="M";
 public  static final String FIX_MSG_List_Status     ="N";
 public  static final String FIX_MSG_Allocation_ACK    ="P";
 public  static final String FIX_MSG_Dont_Know_Trade    ="Q";
 public  static final String FIX_MSG_Quote_Request    ="R";
 public  static final String FIX_MSG_Quote      ="S";
 public  static final String FIX_MSG_Settlement_Instructions  ="T";
 public  static final String FIX_MSG_Market_Data_Request   ="V";
 public  static final String FIX_MSG_Market_Data_Full_Refresh ="W";
 public  static final String FIX_MSG_Market_Data_Incremental_Refresh ="X";
 public  static final String FIX_MSG_Market_Data_Request_Reject  ="Y";
 public  static final String FIX_MSG_Quote_Cancel     ="Z";
 public  static final String FIX_MSG_Quote_Status_Request   ="a";
 public  static final String FIX_MSG_Quote_Acknowledgement   ="b";
 public  static final String FIX_MSG_Security_Definition_Request  ="c";
 public  static final String FIX_MSG_Security_Definition   ="d";
 public  static final String FIX_MSG_Security_Status_Request   ="e";
 public  static final String FIX_MSG_Security_Status     ="f";
 public  static final String FIX_MSG_Trading_Session_Status_Request ="g";
 public  static final String FIX_MSG_Trading_Session_Status   ="h";
 public  static final String FIX_MSG_Mass_Quote      ="i";
 public  static final String FIX_MSG_Business_Message_Reject   ="j";
 public  static final String FIX_MSG_Bid_Request      ="k";
 public  static final String FIX_MSG_Bid_Response     ="l";
 public  static final String FIX_MSG_List_Strike_Price    ="m";

 public static final String FIX_MSG_XML  = "XML";
 public  static final String FIX_MSG_FIXML = "FIXML";
   // you can use either of these or any other localy agreed
   // message type to indicate the FIX MESSAGE actually
   // contains FIXML or aome other XML payload, these are
   // just included as a sugestion

 public  static final int FIX_FLD_Account   =1;
 public  static final int FIX_FLD_AdvId    =2;
 public  static final int FIX_FLD_AdvRefID   =3;
 public  static final int FIX_FLD_AdvSide   =4;
 public  static final int FIX_FLD_AdvTransType  =5;
 public  static final int FIX_FLD_AvgPx    =6;
 public  static final int FIX_FLD_BeginSeqNo   =7;
 public  static final int FIX_FLD_BeginString  =8;
 public  static final int FIX_FLD_BodyLength   =9;
 public  static final int FIX_FLD_CheckSum   =10;
 public  static final int FIX_FLD_ClOrdID   =11;
 public  static final int FIX_FLD_Commission   =12;
 public  static final int FIX_FLD_CommType   =13;
 public  static final int FIX_FLD_CumQty    =14;
 public  static final int FIX_FLD_Currency   =15;
 public  static final int FIX_FLD_EndSeqNo   =16;
 public  static final int FIX_FLD_ExecID    =17;
 public  static final int FIX_FLD_ExecInst   =18;
 public  static final int FIX_FLD_ExecRefID   =19;
 public  static final int FIX_FLD_ExecTransType  =20;
 public  static final int FIX_FLD_HandlInst   =21;
 public  static final int FIX_FLD_IDSource   =22;
 public  static final int FIX_FLD_IOIid    =23;
 public  static final int FIX_FLD_IOIOthSvc   =24;
 public  static final int FIX_FLD_IOIQltyInd   =25;
 public  static final int FIX_FLD_IOIRefID   =26;
 public  static final int FIX_FLD_IOIShares   =27;
 public  static final int FIX_FLD_IOITransType  =28;
 public  static final int FIX_FLD_LastCapacity  =29;
 public  static final int FIX_FLD_LastMkt   =30;
 public  static final int FIX_FLD_LastPx    =31;
 public  static final int FIX_FLD_LastShares   =32;
 public  static final int FIX_FLD_LinesOfText  =33;
 public  static final int FIX_FLD_MsgSeqNum   =34;
 public  static final int FIX_FLD_MsgType   =35;
 public  static final int FIX_FLD_NewSeqNo   =36;
 public  static final int FIX_FLD_OrderID   =37;
 public  static final int FIX_FLD_OrderQty   =38;
 public  static final int FIX_FLD_OrdStatus   =39;
 public  static final int FIX_FLD_OrdType   =40;
 public  static final int FIX_FLD_OrigClOrdID  =41;
 public  static final int FIX_FLD_OrigTime   =42;
 public  static final int FIX_FLD_PossDupFlag  =43;
 public  static final int FIX_FLD_Price    =44;
 public  static final int FIX_FLD_RefSeqNum   =45;
 public  static final int FIX_FLD_RelatdSym   =46;
 public  static final int FIX_FLD_Rule80A   =47;
 public  static final int FIX_FLD_SecurityID   =48;
 public  static final int FIX_FLD_SenderCompID  =49;
 public  static final int FIX_FLD_SenderSubID  =50;
 public  static final int FIX_FLD_SendingDate  =51;
 public  static final int FIX_FLD_SendingTime  =52;
 public  static final int FIX_FLD_Shares    =53;
 public  static final int FIX_FLD_Side    =54;
 public  static final int FIX_FLD_Symbol    =55;
 public  static final int FIX_FLD_TargetCompID  =56;
 public  static final int FIX_FLD_TargetSubID  =57;
 public  static final int FIX_FLD_Text    =58;
 public  static final int FIX_FLD_TimeInForce  =59;
 public  static final int FIX_FLD_TransactTime  =60;
 public  static final int FIX_FLD_Urgency   =61;
 public  static final int FIX_FLD_ValidUntilTime  =62;
 public  static final int FIX_FLD_SettlmntTyp  =63;
 public  static final int FIX_FLD_FutSettDate  =64;
 public  static final int FIX_FLD_SymbolSfx   =65;
 public  static final int FIX_FLD_ListID    =66;
 public  static final int FIX_FLD_ListSeqNo   =67;
 public  static final int FIX_FLD_TotNoOrders  =68;
 public  static final int FIX_FLD_ListNoOrds   =68;
 public  static final int FIX_FLD_ListExecInst  =69;
 public  static final int FIX_FLD_AllocID   =70;
 public  static final int FIX_FLD_AllocTransType  =71;
 public  static final int FIX_FLD_RefAllocID   =72;
 public  static final int FIX_FLD_NoOrders   =73;
 public  static final int FIX_FLD_AvgPrxPrecision =74;
 public  static final int FIX_FLD_TradeDate   =75;
 public  static final int FIX_FLD_ExecBroker   =76;
 public  static final int FIX_FLD_OpenClose  =77;
 public  static final int FIX_FLD_NoAllocs   =78;
 public  static final int FIX_FLD_AllocAccount  =79;
 public  static final int FIX_FLD_AllocShares  =80;
 public  static final int FIX_FLD_ProcessCode  =81;
 public  static final int FIX_FLD_NoRpts    =82;
 public  static final int FIX_FLD_RptSeq    =83;
 public  static final int FIX_FLD_CxlQty    =84;
 public  static final int FIX_FLD_NoDlvyInst   =85;
 public  static final int FIX_FLD_DlvyInst   =86;
 public  static final int FIX_FLD_AllocStatus  =87;
 public  static final int FIX_FLD_AllocRejCode  =88;
 public  static final int FIX_FLD_Signature   =89;
 public  static final int FIX_FLD_SecureDataLen  =90;
 public  static final int FIX_FLD_SecureData   =91;
 public  static final int FIX_FLD_BrokerOfCredit  =92;
 public  static final int FIX_FLD_SignatureLength =93;
 public  static final int FIX_FLD_EmailType   =94;
 public  static final int FIX_FLD_RawDataLength  =95;
 public  static final int FIX_FLD_RawData   =96;
 public  static final int FIX_FLD_PossResend  =97;
 public  static final int FIX_FLD_EncryptMethod  =98;
 public  static final int FIX_FLD_StopPx    =99;
 public  static final int FIX_FLD_ExDestination  =100;
 public  static final int FIX_FLD___Not_Defined  =101;
 public  static final int FIX_FLD_CxlRejReason  =102;
 public  static final int FIX_FLD_OrdRejReason  =103;
 public  static final int FIX_FLD_IOIQualifier  =104;
 public  static final int FIX_FLD_WaveNo    =105;
 public  static final int FIX_FLD_Issuer    =106;
 public  static final int FIX_FLD_SecurityDesc  =107;
 public  static final int FIX_FLD_HeartBtInt   =108;
 public  static final int FIX_FLD_ClientID   =109;
 public  static final int FIX_FLD_MinQty    =110;
 public  static final int FIX_FLD_MaxFloor   =111;
 public  static final int FIX_FLD_TestReqID   =112;
 public  static final int FIX_FLD_ReportToExch  =113;
 public  static final int FIX_FLD_LocateReqd   =114;
 public  static final int FIX_FLD_OnBehalfOfCompID =115;
 public  static final int FIX_FLD_OnBehalfOfSubID =116;
 public  static final int FIX_FLD_QuoteID   =117;
 public  static final int FIX_FLD_NetMoney   =118;
 public  static final int FIX_FLD_SettlCurrAmt  =119;
 public  static final int FIX_FLD_SettlCurrency  =120;
 public  static final int FIX_FLD_ForexReq   =121;
 public  static final int FIX_FLD_OrigSendingTime =122;
 public  static final int FIX_FLD_GapFillFlag  =123;
 public  static final int FIX_FLD_NoExecs   =124;
 public  static final int FIX_FLD_CxlType   =125;
 public  static final int FIX_FLD_ExpireTime   =126;
 public  static final int FIX_FLD_DKReason   =127;
 public  static final int FIX_FLD_DeliverToCompID =128;
 public  static final int FIX_FLD_DeliverToSubID  =129;
 public  static final int FIX_FLD_IOINaturalFlag  =130;
 public  static final int FIX_FLD_QuoteReqID   =131;
 public  static final int FIX_FLD_BidPx    =132;
 public  static final int FIX_FLD_OfferPx   =133;
 public  static final int FIX_FLD_BidSize   =134;
 public  static final int FIX_FLD_OfferSize   =135;
 public  static final int FIX_FLD_NoMiscFees   =136;
 public  static final int FIX_FLD_MiscFeeAmt   =137;
 public  static final int FIX_FLD_MiscFeeCurr  =138;
 public  static final int FIX_FLD_MiscFeeType  =139;
 public  static final int FIX_FLD_PrevClosePx  =140;
 public  static final int FIX_FLD_ResetSeqNumFlag =141;
 public  static final int FIX_FLD_SenderLocationID =142;
 public  static final int FIX_FLD_TargetLocationID =143;
 public  static final int FIX_FLD_OnBehalfOfLocationID =144;
 public  static final int FIX_FLD_DeliverToLocationID =145;
 public  static final int FIX_FLD_NoRelatedSym   =146;
 public  static final int FIX_FLD_Subject    =147;
 public  static final int FIX_FLD_Headline    =148;
 public  static final int FIX_FLD_URLLink    =149;
 public  static final int FIX_FLD_ExecType    =150;
 public  static final int FIX_FLD_LeavesQty    =151;
 public  static final int FIX_FLD_CashOrderQty   =152;
 public  static final int FIX_FLD_AllocAvgPx    =153;
 public  static final int FIX_FLD_AllocNetMoney   =154;
 public  static final int FIX_FLD_SettlCurrFxRate  =155;
 public  static final int FIX_FLD_SettlCurrFxRateCalc =156;
 public  static final int FIX_FLD_NumDaysInterest  =157;
 public  static final int FIX_FLD_AccruedInterestRate =158;
 public  static final int FIX_FLD_AccruedInterestAmt  =159;
 public  static final int FIX_FLD_SettlInstMode   =160;
 public  static final int FIX_FLD_AllocText    =161;
 public  static final int FIX_FLD_SettlInstID   =162;
 public  static final int FIX_FLD_SettlInstTransType  =163;
 public  static final int FIX_FLD_EmailThreadID   =164;
 public  static final int FIX_FLD_SettlInstSource  =165;
 public  static final int FIX_FLD_SettlLocation   =166;
 public  static final int FIX_FLD_SecurityType   =167;
 public  static final int FIX_FLD_EffectiveTime   =168;
 public  static final int FIX_FLD_StandInstDbType  =169;
 public  static final int FIX_FLD_StandInstDbName  =170;
 public  static final int FIX_FLD_StandInstDbID   =171;
 public  static final int FIX_FLD_SettlDeliveryType  =172;
 public  static final int FIX_FLD_SettlDepositoryCode =173;
 public  static final int FIX_FLD_SettlBrkrCode   =174;
 public  static final int FIX_FLD_SettlInstCode   =175;
 public  static final int FIX_FLD_SecuritySettlAgentName =176;
 public  static final int FIX_FLD_SecuritySettlAgentCode =177;
 public  static final int FIX_FLD_SecuritySettlAgentAcctNum  =178;
 public  static final int FIX_FLD_SecuritySettlAgentAcctName  =179;
 public  static final int FIX_FLD_SecuritySettlAgentContactName =180;
 public  static final int FIX_FLD_SecuritySettlAgentContactPhone =181;
 public  static final int FIX_FLD_CashSettlAgentName    =182;
 public  static final int FIX_FLD_CashSettlAgentCode    =183;
 public  static final int FIX_FLD_CashSettlAgentAcctNum   =184;
 public  static final int FIX_FLD_CashSettlAgentAcctName   =185;
 public  static final int FIX_FLD_CashSettlAgentContactName  =186;
 public  static final int FIX_FLD_CashSettlAgentContactPhone  =187;
 public  static final int FIX_FLD_BidSpotRate     =188;
 public  static final int FIX_FLD_BidForwardPoints    =189;
 public  static final int FIX_FLD_OfferSpotRate     =190;
 public  static final int FIX_FLD_OfferForwardPoints    =191;
 public  static final int FIX_FLD_OrderQty2      =192;
 public  static final int FIX_FLD_FutSettDate2     =193;
 public  static final int FIX_FLD_LastSpotRate     =194;
 public  static final int FIX_FLD_LastForwardPoints    =195;
 public  static final int FIX_FLD_AllocLinkID     =196;
 public  static final int FIX_FLD_AllocLinkType   =197;
 public  static final int FIX_FLD_SecondaryOrderID  =198;
 public  static final int FIX_FLD_NoIOIQualifiers  =199;
 public  static final int FIX_FLD_MaturityMonthYear  =200;
 public  static final int FIX_FLD_PutOrCall    =201;
 public  static final int FIX_FLD_StrikePrice   =202;
 public  static final int FIX_FLD_CoveredOrUncovered  =203;
 public  static final int FIX_FLD_CustomerOrFirm   =204;
 public  static final int FIX_FLD_MaturityDay   =205;
 public  static final int FIX_FLD_OptAttribute   =206;
 public  static final int FIX_FLD_SecurityExchange  =207;
 public  static final int FIX_FLD_NotifyBrokerOfCredit =208;
 public  static final int FIX_FLD_AllocHandlInst   =209;
 public  static final int FIX_FLD_MaxShow    =210;
 public  static final int FIX_FLD_PegDifference   =211;
 public  static final int FIX_FLD_XmlDataLen    =212;
 public  static final int FIX_FLD_XmlData    =213;
 public  static final int FIX_FLD_SettlInstRefID   =214;
 public  static final int FIX_FLD_NoRoutingIDs   =215;
 public  static final int FIX_FLD_RoutingType   =216;
 public  static final int FIX_FLD_RoutingID    =217;
 public  static final int FIX_FLD_SpreadToBenchmark  =218;
 public  static final int FIX_FLD_Benchmark    =219;
 public  static final int FIX_FLD_CouponRate    =223;
 public  static final int FIX_FLD_ContractMultiplier  =231;
 public  static final int FIX_FLD_MDReqID    =262;
 public  static final int FIX_FLD_SubscriptionRequestType=263;
 public  static final int FIX_FLD_MarketDepth   =264;
 public  static final int FIX_FLD_MDUpdateType   =265;
 public  static final int FIX_FLD_AggregatedBook   =266;
 public  static final int FIX_FLD_NoMDEntryTypes   =267;
 public  static final int FIX_FLD_NoMDEntries   =268;
 public  static final int FIX_FLD_MDEntryType  =269;
 public  static final int FIX_FLD_MDEntryPx    =270;
 public  static final int FIX_FLD_MDEntrySize   =271;
 public  static final int FIX_FLD_MDEntryDate   =272;
 public  static final int FIX_FLD_MDEntryTime   =273;
 public  static final int FIX_FLD_TickDirection   =274;
 public  static final int FIX_FLD_MDMkt     =275;
 public  static final int FIX_FLD_QuoteCondition   =276;
 public  static final int FIX_FLD_TradeCondition   =277;
 public  static final int FIX_FLD_MDEntryID    =278;
 public  static final int FIX_FLD_MDUpdateAction   =279;
 public  static final int FIX_FLD_MDEntryRefID   =280;
 public  static final int FIX_FLD_MDReqRejReason   =281;
 public  static final int FIX_FLD_MDEntryOriginator  =282;
 public  static final int FIX_FLD_LocationID   =283;
 public  static final int FIX_FLD_DeskID     =284;
 public  static final int FIX_FLD_DeleteReason   =285;
 public  static final int FIX_FLD_OpenCloseSettleFlag =286;
 public  static final int FIX_FLD_SellerDays    =287;
 public  static final int FIX_FLD_MDEntryBuyer   =288;
 public  static final int FIX_FLD_MDEntrySeller   =289;
 public  static final int FIX_FLD_MDEntryPositionNo  =290;
 public  static final int FIX_FLD_FinancialStatus =291;
 public  static final int FIX_FLD_CorporateAction  =292;
 public  static final int FIX_FLD_DefBidSize    =293;
 public  static final int FIX_FLD_DefOfferSize   =294;
 public  static final int FIX_FLD_NoQuoteEntries   =295;
 public  static final int FIX_FLD_NoQuoteSets   =296;
 public  static final int FIX_FLD_QuoteAckStatus   =297;
 public  static final int FIX_FLD_QuoteCancelType  =298;
 public  static final int FIX_FLD_QuoteEntryID   =299;
 public  static final int FIX_FLD_QuoteRejectReason  =300;
 public  static final int FIX_FLD_QuoteResponseLevel  =301;
 public  static final int FIX_FLD_QuoteSetID    =302;
 public  static final int FIX_FLD_QuoteRequestType  =303;
 public  static final int FIX_FLD_TotQuoteEntries  =304;
 public  static final int FIX_FLD_UnderlyingIDSource  =305;
 public  static final int FIX_FLD_UnderlyingIssuer  =306;
 public  static final int FIX_FLD_UnderlyingSecurityDesc =307;
 public  static final int FIX_FLD_UnderlyingSecurityExchange =308;
 public  static final int FIX_FLD_UnderlyingSecurityID  =309;
 public  static final int FIX_FLD_UnderlyingSecurityType  =310;
 public  static final int FIX_FLD_UnderlyingSymbol   =311;
 public  static final int FIX_FLD_UnderlyingSymbolSfx  =312;
 public  static final int FIX_FLD_UnderlyingMaturityMonthYear=313;
 public  static final int FIX_FLD_UnderlyingMaturityDay  =314;
 public  static final int FIX_FLD_UnderlyingPutOrCall  =315;
 public  static final int FIX_FLD_UnderlyingStrikePrice  =316;
 public  static final int FIX_FLD_UnderlyingOptAttribute  =317;
 public  static final int FIX_FLD_Underlying     =318;
 public  static final int FIX_FLD_RatioQty     =319;
 public  static final int FIX_FLD_SecurityReqID    =320;
 public  static final int FIX_FLD_SecurityRequestType  =321;
 public  static final int FIX_FLD_SecurityResponseID   =322;
 public  static final int FIX_FLD_SecurityResponseType  =323;
 public  static final int FIX_FLD_SecurityStatusReqID  =324;
 public  static final int FIX_FLD_UnsolicitedIndicator  =325;
 public  static final int FIX_FLD_SecurityTradingStatus  =326;
 public  static final int FIX_FLD_HaltReason     =327;
 public  static final int FIX_FLD_InViewOfCommon    =328;
 public  static final int FIX_FLD_DueToRelated    =329;
 public  static final int FIX_FLD_BuyVolume      =330;
 public  static final int FIX_FLD_SellVolume     =331;
 public  static final int FIX_FLD_HighPx       =332;
 public  static final int FIX_FLD_LowPx       =333;
 public  static final int FIX_FLD_Adjustment     =334;
 public  static final int FIX_FLD_TradSesReqID    =335;
 public  static final int FIX_FLD_TradingSessionID   =336;
 public  static final int FIX_FLD_ContraTrader    =337;
 public  static final int FIX_FLD_TradSesMethod    =338;
 public  static final int FIX_FLD_TradSesMode    =339;
 public  static final int FIX_FLD_TradSesStatus    =340;
 public  static final int FIX_FLD_TradSesStartTime   =341;
 public  static final int FIX_FLD_TradSesOpenTime   =342;
 public  static final int FIX_FLD_TradSesPreCloseTime  =343;
 public  static final int FIX_FLD_TradSesCloseTime   =344;
 public  static final int FIX_FLD_TradSesEndTime    =345;
 public  static final int FIX_FLD_NumberOfOrders    =346;
 public  static final int FIX_FLD_MessageEncoding   =347;
 public  static final int FIX_FLD_EncodedIssuerLen   =348;
 public  static final int FIX_FLD_EncodedIssuer    =349;
 public  static final int FIX_FLD_EncodedSecurityDescLen  =350;
 public  static final int FIX_FLD_EncodedSecurityDesc  =351;
 public  static final int FIX_FLD_EncodedListExecInstLen  =352;
 public  static final int FIX_FLD_EncodedListExecInst  =353;
 public  static final int FIX_FLD_EncodedTextLen    =354;
 public  static final int FIX_FLD_EncodedText    =355;
 public  static final int FIX_FLD_EncodedSubjectLen   =356;
 public  static final int FIX_FLD_EncodedSubject    =357;
 public  static final int FIX_FLD_EncodedHeadlineLen   =358;
 public  static final int FIX_FLD_EncodedHeadline   =359;
 public  static final int FIX_FLD_EncodedAllocTextLen  =360;
 public  static final int FIX_FLD_EncodedAllocText   =361;
 public  static final int FIX_FLD_EncodedUnderlyingIssuerLen =362;
 public  static final int FIX_FLD_EncodedUnderlyingIssuer =363;
 public  static final int FIX_FLD_EncodedUnderlyingSecurityDescLen =364;
 public  static final int FIX_FLD_EncodedUnderlyingSecurityDesc  =365;
 public  static final int FIX_FLD_AllocPrice     =366;
 public  static final int FIX_FLD_QuoteSetValidUntilTime  =367;
 public  static final int FIX_FLD_QuoteEntryRejectReason  =368;
 public  static final int FIX_FLD_LastMsgSeqNumProcessed  =369;
 public  static final int FIX_FLD_OnBehalfOfSendingTime  =370;
 public  static final int FIX_FLD_RefTagID     =371;
 public  static final int FIX_FLD_RefMsgType     =372;
 public  static final int FIX_FLD_SessionRejectReason  =373;
 public  static final int FIX_FLD_BidRequestTransType  =374;
 public  static final int FIX_FLD_ContraBroker    =375;
 public  static final int FIX_FLD_ComplianceID    =376;
 public  static final int FIX_FLD_SolicitedFlag    =377;
 public  static final int FIX_FLD_ExecRestatementReason  =378;
 public  static final int FIX_FLD_BusinessRejectRefID  =379;
 public  static final int FIX_FLD_BusinessRejectReason  =380;
 public  static final int FIX_FLD_GrossTradeAmt    =381;
 public  static final int FIX_FLD_NoContraBrokers  =382;
 public  static final int FIX_FLD_MaxMessageSize    =383;
 public  static final int FIX_FLD_NoMsgTypes     =384;
 public  static final int FIX_FLD_MsgDirection    =385;
 public  static final int FIX_FLD_NoTradingSessions   =386;
 public  static final int FIX_FLD_TotalVolumeTraded   =387;
 public  static final int FIX_FLD_DiscretionInst    =388;
 public  static final int FIX_FLD_DiscretionOffset   =389;
 public  static final int FIX_FLD_BidID      =390;
 public  static final int FIX_FLD_ClientBidID    =391;
 public  static final int FIX_FLD_ListName     =392;
 public  static final int FIX_FLD_TotalNumSecurities   =393;
 public  static final int FIX_FLD_BidType     =394;
 public  static final int FIX_FLD_NumTickets     =395;
 public  static final int FIX_FLD_SideValue1     =396;
 public  static final int FIX_FLD_SideValue2     =397;
 public  static final int FIX_FLD_NoBidDescriptors   =398;
 public  static final int FIX_FLD_BidDescriptorType   =399;
 public  static final int FIX_FLD_BidDescriptor    =400;
 public  static final int FIX_FLD_SideValueInd    =401;
 public  static final int FIX_FLD_LiquidityPctLow   =402;
 public  static final int FIX_FLD_LiquidityPctHigh   =403;
 public  static final int FIX_FLD_LiquidityValue    =404;
 public  static final int FIX_FLD_EFPTrackingError   =405;
 public  static final int FIX_FLD_FairValue     =406;
 public  static final int FIX_FLD_OutsideIndexPct   =407;
 public  static final int FIX_FLD_ValueOfFutures    =408;
 public  static final int FIX_FLD_LiquidityIndType   =409;
 public  static final int FIX_FLD_WtAverageLiquidity   =410;
 public  static final int FIX_FLD_ExchangeForPhysical  =411;
 public  static final int FIX_FLD_OutMainCntryUIndex   =412;
 public  static final int FIX_FLD_CrossPercent    =413;
 public  static final int FIX_FLD_ProgRptReqs    =414;
 public  static final int FIX_FLD_ProgPeriodInterval   =415;
 public  static final int FIX_FLD_IncTaxInd     =416;
 public  static final int FIX_FLD_NumBidders     =417;
 public  static final int FIX_FLD_TradeType     =418;
 public  static final int FIX_FLD_BasisPxType    =419;
 public  static final int FIX_FLD_NoBidComponents   =420;
 public  static final int FIX_FLD_Country     =421;
 public  static final int FIX_FLD_TotNoStrikes    =422;
 public  static final int FIX_FLD_PriceType     =423;
 public  static final int FIX_FLD_DayOrderQty    =424;
 public  static final int FIX_FLD_DayCumQty     =425;
 public  static final int FIX_FLD_DayAvgPx     =426;
 public  static final int FIX_FLD_GTBookingInst    =427;
 public  static final int FIX_FLD_NoStrikes     =428;
 public  static final int FIX_FLD_ListStatusType    =429;
 public  static final int FIX_FLD_NetGrossInd    =430;
 public  static final int FIX_FLD_ListOrderStatus   =431;
 public  static final int FIX_FLD_ExpireDate     =432;
 public  static final int FIX_FLD_ListExecInstType   =433;
 public  static final int FIX_FLD_CxlRejResponseTo   =434;
 public  static final int FIX_FLD_UnderlyingCouponRate  =435;
 public  static final int FIX_FLD_UnderlyingContractMultiplier=436;
 public  static final int FIX_FLD_ContraTradeQty    =437;
 public  static final int FIX_FLD_ContraTradeTime   =438;
 public  static final int FIX_FLD_ClearingFirm    =439;
 public  static final int FIX_FLD_ClearingAccount   =440;
 public  static final int FIX_FLD_LiquidityNumSecurities  =441;
 public  static final int FIX_FLD_MultiLegReportingType  =442;


Resend Confirmation

With this facility you can specify a list of messge-types in the fix engine properties file, for which confirmation will be sought if a message of that type needs to be resent. 

E.G. if you place the following entry in the properties file 

confrimResend  B 

If a B (News) message needs to be re-sent because the remote Fix Engine has requested a resend, Your FixHandler’s  onRequestResend(FixString fixMsg) will be called with the message as a parameter; if you return true, the message will be resent, if you return false the message will be replaced with a gap-fill.

NB: under normal circumstances all resends occur transparently to the application, but in some circumstances, you may not want to resend a message if market conditions have changed significantly since the time that the message was originaly sent. 


FixGW Error Handling Strategies

The Fix Gateway is a separate process running the fix communication protocol with a remote Fix Engine. The user application communicates with the Fix Gateway via a socket. If the line drops between the Fix Gateway and the remote Fix Engine, the user application must be notified, and any messages that the User application has sent before the error notification must be guaranteed to arrive at the remote Fix Engine. This section explains how this is achieved. Note, the afitest and afisrv utilities can be used to test the system's terror handling capability.

Connection Errors While Sending Messages

When the FixSession.sendMsg() is called, the message is sent to the Fix Gateway via a socket,  provided no error occurs in the call to send the message on the socket, FixSession.sendMsg() returns successfully. The problem is, that the line between the Fix Gateway and the remote Fix Engine may have dropped, but the SendFixMsg method does not detect this. (NB: sendMsg could query the state of the FixEngine but this would slow things down too much).

In the Fix Gateway process, when a message is received via FixSession.sendMsg() it is sent to the remote Fix Engine - if the line to the remote Fix Engine is down, the message is added to the fix Journal file, and the outgoing sequence number is incremented so that when the connection is re-established, the message will be requested by the remote side. When this happens, an Out-Of-Band message is sent back to the User Application setting and error state flag. FixSession.sendMsg() checks  the error state flag, and if it finds it set, it returns an error. The consequence of this strategy is, some messages may be sent when the fix connection is down, but this should only be one or two messages before the User Application is detects the error, and these messages are not lost, they are transmitted as soon as the fix connection is re-established.

If the User Application is waiting for a Fix Message and the fix connection drops, an internal fix-admin messages is sent to the User Application to notify it of the error condition straight away.

Sending Messages Using Buffers

The fixgw library implements a buffering facility which enables your application to send messages to a local buffer rather than sending them to the gateway, then when happy with the current application state, the application can flush the buffer to the gate way. If the line goes down or the application is killed while flushing the buffer, the current position in the buffer is remembered when the application restarts, and by calling FixClient::SynchronizeOutputBuffer(), your application can being sending from the point at which it stopped. Once the buffer has been flushed you should call FixClient::SetComplete() (provided you haven't previously called FixClient::DisableAutoRecovery(), in which case you never need to call SetComplete(). )

The FixSession.setComplete() method

Once you receive a Fix Message, the fix protocol is done with it, your application should then store it into a database soon as   possible so that if your application is killed or crashes, the message is not lost. 

Imagine the situation where your application is slow (for whatever reason) to processes messages it received. The Fix Engine  process will continue to send you messages until your application (socket) buffers are full. If at this point your   application crashes the messages in the application buffer will be lost, but as far as the Fix protocol layer is concerned, the message   will have been received successfully and will not be re-requested. SetComplete() protects your from this  roblem. 

When the AFI Fix Engine starts, it checks its last received sequence number with the one specified in the last call to setComplete(). If the SetComplete sequence number is lower, it checks in the Receive Journal and if the missing messages are there, it sends them to the client app(with the Possible Dup flag set to Y), and all should be well. If the messages are not in the Receive Journal, the Fix Engine sets its own expected sequence number to the one specified by  setComplete() thus  forcing a re-send of any 'lost' messages. By the remote side. NOTE: the messages should only be missing from the Receive Journal if the Receive Journal has been switched off. (If you do switch the Receive Journal off, be   aware, that,  if the missing message was time-sensitive, the remote Fix engine may decide not to re-send the message, but rather, replace it with a gap fill.

The best way to use setComplete()is to save the message in the database as soon as your receive it, and then call   setComplete(). Then, when your application re-starts, it should check the database for received but un-processed messages first,  process these, and then create the Fix session and continue as normal. 

You may decide to only call setComplete() when you have fully processed the message, e.g, if you are collecting  messages in a list.  If your application crashes with unprocessed messages in its list, the SetComplete mechanism  will ensure that these messages are  not lost. Doing this removes the need to save the message immediately into the database.

You may call  setComplete() after each message has been processed, or after a sequence of messages have been processed,   once called, it applies to all messages received since the last call. It is, however, probably  safest to save each   message as you receive it and call setComplete() after each successful save. 

If you don’t want to use SetComplete()at all, just call DisableAutoRecovery(true) as soon as the session is created.
 


The Script File Format

The FixSession.RunScript() method accepts a script file that contains a set of fix messages and sends them to the Fix gateway. The script file should contain  lines in the following format

BEGIN fixMsgType
This defines the start of a fix message - fixMsgType can be either the actual value of a fix message or a symbolic name as defined in <fixconst.h>, but without the leading FIX_MSG_, i.e. fixMsgType could be E or Order_List

fixFieldId  value
This adds a field to the current fix message - fixFieldId can be the numeric or symbolic id, e.g. 38 or OrderQty, value can be any string, it can contain embedded spaces if it is surrounded by double or single quotes. If the value is a fix-time or fix-date, value can be @N, this is interpreted as the current time plus N seconds, or %N which is interpreted the current date plus N days. If a unique id is required for any value, a & can be used at the start of the string - the & is replaced by the Hour/ Minute/Second at the time the script file began to run, in the form of HHMMSS, the rest of the value is then appended to the HHMMSS - in this way & represents a different value each time a script runs, but the same value for the lifetime of the script. Note for & to be expanded into HHMMSS, it must appear at the start of the string.

If, however, more than one script runs in a second, the &  value will not change. For this reason there are several substitution characters that can be used, but note they must appear at the front of the string

& … substituted with HHMMSS
^  … substituted with HHMMSSmmm where mmm is the current milliseconds value, giving a unique value on a dily basis.
|   … substituted with the number of seconds since 10/10/2001 (in hex), thus | should give a
         unique  8 character value over time provided the script doesn’t run more than once per second.
~ …  substituted with  XXXXXXXmmm where XXXXXXX is the number of seconds since 10/10/2001 in hex and
         mmm is the current milliseconds value,  thus ~ should give a unique 10 character value over time 
         regardless of how quickly the scripts run.

SEND
Send the current fix message to the fix gateway.

RESET_AMPERSAND
Reset the value used when substituting &. This will be reset to the current hour/minute/second - note: the substitution values are automatically reset each time a script runs.

SET_AMPERSAND value
Set the value used when substituting &. The value parameters can be any string. Ampersand substitution is designed to enable the same script file to generate different ID's on each run, but you may, temporally, wish to test what happens when you get 2 runs with the same IDs, in this situation, you can use the SET_AMPERSAND at the top of the script to set a fixed value that will remain the same on each run of the script.

LOAD_AMPERSAND
This command loads a previously saved ampersand (&) value from persistent  storage. If there is not a previously saved value, the ampersand value  is set to 000000. Typically, you will LOAD_AMPERSAND and then INCR_AMPERSAND at the start of the script, and SAVE_AMPERSAND at the end, thus guaranteeing a unique value for ampersand on each script run. Values of ampersand loaded like this will be zero-padded to 6 character positions.

SAVE_AMPERSAND
You can save the current value of & to persistent  storage with this command.

INCR_AMPERSAND
Increment the value of the & substitution, if this is not a numeric value, a value of 0 will be used

DECR_AMPERSAND
Decrement  the value of the & substitution, if this is not a numeric value, a value of 0 will be used

RESET_HAT
Reset the value of the ^ substitution

RESET_BAR
Reset the value of the | substitution

RESET_TILDE
Reset the value of the ~ substitution

BEGIN_BUFFER
All subsequent messages are sent to the buffer, rather than the fix gateway.

FLUSH_BUFFER
Flush  the output buffer, sending buffered messages to the gateway. Subsequent messages are sent directly to the gateway unless BEGIN_BUFFER is called again.

#
This is a comment

A simple script file, to send 2 orders in a list would look like this...

# example script file
BEGIN Order_List
    ListID &4
    ListSeqNo 1
    ListNoOrds 2
    ClOrdID  &01
    ClientID ZCN0002
    Account xxxxxxxxx
    FutSettDate %2
    Symbol OCT.L
    SecurityID 12345678
    IDSource 2
    Side 2
    OrderQty 20000
    Price 987
    Currency GBP
    TransactTime @0
    TradeDate %0
SEND
BEGIN Order_List
    ListID &4
    ListSeqNo 2
    ListNoOrds 2
    ClOrdID  &02
    ClientID ZCN0002
    Account xxxxxxx
    FutSettDate %2
    Symbol OCT.L
    SecurityID 12345678
    IDSource 2
    Side 1
    OrderQty 20000
    Price 987
    Currency GBP
    TransactTime @0
    TradeDate %0
SEND

The afisrv Tool

This tool allows you to run fix client or server sessions with a minimum of effort. The tool understands a simple script format whereby you can send fix message to whoever is connected. The source code for this tool is included as a sample. The tool presents a character-based menu for simplicity and portability, and allows you to 'open' any config file you require. The program can act as a server and/or a client - two versions of the program can run on the same machine and communicate with each other. For testing purposes a configuration file named testsrvr is supplied, this configuration sets the fix gateway into server mode. A second configuration, loopback, is supplied for testing purposes, this config is used by the afitest sample program, which simply connects to the afisrv on the local machine. You can then send heartbeats and other fix messages to afitest from the afisrv menu, and watch them appear. This tool is particularly useful when testing your applications, you can create a script-file with a set of standard fix data and run afisrv as a dummy, replacing the actual Fix Engine you will want your application to connect to.

afisrv displays the following character based menu...

    o) Open Session         c) Close Session
    h) Send Heartbeat       t) Send Test Request
    s) Send Script File     n) Send Test News
        r) Reset Session        q) Test Reset Seq Num

    v) verbose mode

    x) exit

o) open session
This option prompts for the name of a config file, the default value is testsrvr, this implements a server that will listen for incoming connections. The fix session runs in a separate thread leaving a user interface thread free to process menu commands. The c)close session option can be used to close the session.

h) send heart beat
Send a fix heartbeat to the remote fix engine.

t) send test request
Send a fix test request to the remote fix engine - we should get a heart beat in response, which will be seen if verbose mode is on.

s) run script file
Run a script file, 5LISTS.TXT is prompted for by default.

n) send test news
A test news message is sent

r) reset session
cause both sides to reset their sequence numbers back to 1. This will only work if both sides of the fix session are running protocol version 4.2 AND the fix gateway config file must have ManualSessionSwitch set to 0.

q) test reset sequence numbers
The sequence numbers are reset from 100.

v) set verbose mode
Verbose mode switches of the display of the menu, but displays all incoming fix messages as they are received. Menu commands are still processed, and entering v again will switch verbose mode off.

If you select the s) option, you will see the following sub menu

  2) 2 Orders Sample script
  5) 5 Orders Sample script
 OR  the name of a script file

This allows you to easily run the sample scripts or any script of your own. If you want to run your own script, just type its name.

The source code for this tool is included as a sample.


The afitest Sample

This is a simple test program, the source for which is included in the distribution. This program also display a simple menu, as follows...

afitest menu

0) normal mode
1) none buffered mode
2) local client crash-simulation testing mode
3) local gateway crash-simulation testing mode

4) test File fix-msg-source and fix-msg-destination

x) exit

To run the test, first start afisrv, and take the (o)open menu option and open the testsrv session - this is the default session to open, so you shouldn't have to type in its name, just accept the default. Now, from a different command line window, start the afitest program - it will give you a small menu, choose option 0. In order to give afitest some work to do, return to afisrv and take the (s) send script file menu - you will be able to chose from the pre-defined scripts 5LISTS.TXT (option 5), 2LISTS.TXT(option 2) or enter your own script file name. Running5LISTS.TXT script sends lists of orders to afitest, which simply compiles these lists into a file, and sends acknowledgements back to the sender. It is a relatively trivial test, but demonstrates many features of the fixgw lib. It can be used to test recovery features in the event of a system failure, as afitest validates the file it creates, and afisrv validates the replies it receives - the validation is based on the FIX_FLD_ClientID which is set in ascending order in 5LISTS.TXT.

The main point of interest in afitest is the ProcessFixMsg(FixString &sfix, FixClient &fixcli), where the messages are complied into lists. and void ProcessNews(FixString &sfix, FixClient &fixcli, StringType &orderList) where NEWS messages are handled - the 2 test programs use NEWS messages to trigger certain actions.

Note: if you select option (0), you will be invited to "RELEASE VALIDATION FILES", if you are running a normal test you should enter Y and do this. You should  not do this if you are testing a recovery after a previously simulated crash.

Simple afitest / afisrv Test Session

This session will involve connecting the afitest program to the afisrv program via a fix session. They will exchange messages and verify that all messages have arrived successfully. afitest will use the loopback configuration file, and afisrv will use the testsrvr configuration file. Both thes config files are supplied with the distribution, in fact afisrvr can load any configuration file you choose, but afitest can only access the loopback config.
(afitest)...(FixGatwWay,cfg:loopback) -----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)
 Just follow the simple instructions bellow to run a test fix session...
  1. Start afisrv and afitest. These programs are both windows console applications.
  2. Select option (o) from afisrv and then just hit return at the next prompt.
  3. Select option(0) from afitest and enter Y at the next prompt
  4. In afitest, selectoption (s) and enter 5 at the next prompt
  5. You should see messages scrolling in the afitest window. After a few seconds you should see the message ORDER FILES VALIDATED AND SAVED in the afitest window, and [TEST LOG VERIFIED OK]in the afisrv window
  6. Enter x in the afisrv window to close the session.
  7. afitest will detect that afisrv has closed, enter a q to close afitest.

Using afitest and afisrv To Test The System's Error Recovery Capabilities

Note: in following discussion afitest is used to refer to the afitest client application and the associated fixgw process, and similarly afisrv refers to the afisrv client application and the associated fixgw processes. Remember, self validation during these tests rely on the fact that 5LISTS.TXT script files supplied with the distribution has a pre-defined format that allows afitest and afisrv to determine if all messages have arrived successfully.

Testing Recovery from failure in the User Application

(afitest)...(FixGatwWay,cfg:loopback) ----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)
this side will crash                              this side will wait for a reconnect

Firstly start afisrv and open a session. Start afitest in crash-simulation testing mode (menu option 2). Use afisrv to run the  5LISTS.TXT script file (option S and option 5), afitest will crash half way through, it will either exit directly or give you the option to quit or reconnect, you should quit.   The afisrv program will wait for a reconnection, and then continue sending from where it left off, hence you should restart afitest in normal mode (option 0) Depending on the situation, it may take up to 30 seconds for the 2 fix engines to re-synchronize, so please be patient. Eventually, messages will flow from where they left off, and afisrv and afitest should print out a messages indicating that validation has completed successfully.

Restart afitest in normal mode, it will re-received the orders already sent (but not processed) , and then continue to receive the rest of the messages. afitest and afisrv will both validate the files they have created, and should report no errors. NB: it may take up to 30 seconds for the 2 fix engines to re-synchronize themselves during error recovery in this and the next test.

Testing Recovery from failure in the Fix Gateway

The assumption is that the gateway process dies because of user intervention, i.e. someone kills it, it will not, of course, crash on its own.

(afitest)...(FixGatwWay,cfg:loopback) ----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)

            this side dies

Firstly start afisrv and open a session. Start afitest in local gateway crash-simulation testing mode(menu option 3). Again, use afisrv to run the  5LISTS.TXT script file (option S and option 5). The gateway used by afitest will die and afitest will detect this it will either exit directly or give you the option to quit or reconnect, you should quit, The remote gateway server(afisrv) will detect that its fix client(afitest) has died, it will close down and  inform the user application(afisrv), afisrv will then wait for a reconnection. When afitest is restarted in normal mode (option 0), it will restart its gateway, which will request a resend of any messages that either it or the user application has lost. Once again, depending on the situation, it may take up to 30 seconds for the 2 fix engines to re-synchronize, so please be patient. Eventually, messages will flow from where they left off, and afisrv and afitest should print out a messages indicating that validation has completed successfully.

Disclaimer

These tests demonstrates the systems reliability in failure situations. The likely causes of failure are

  1. user application crash
  2. computer failure due to power loss or hardware fault
  3. user intervention to kill the gateway process
The above tests show good recovery in the face of a user application crash, however, the behaviour of the user application is entirely the responsibility of the user. Similarly, if the system fails due to hardware errors, the gateway behaves well, but again, it is the users responsibility to minimize the likelihood of hardware failure, using uninteruptable power supplies and fault tolerant hardware.

Troubleshooting

The main source of information when troubleshooting are the log files. If, however, the problem is related to log-file location  specification, or occurs before the log-file name has been initialised, there are 2 additional log-files that can help. Both files are located in the start-up directory of your application.

.fgwtemp.log – This logfile is created by the client library
.AFItmp.log –  This logfile is created by the actual Fix Engine

NOTE: You cannot copy AFI/J to another computer and expect it to run, it must be correctly installed and licensed. Further, if you rename you computer, you will have to reinstall AFI/J, you can, however, change the IP address and not have to reinstall.


Appendix I - Implementation Notes

The Local Client Reliable Protocol

Before reading this refer to the system diagram.

Now, when the client sends a message and the return code indicates success, as far as the client is concerned the messages has gone and will be received. Under normal circumstances the messages reaches the gateway and is then sent, using the FIX protocol to the remote fix engine. This is all very well, but if the machine crashes, or if someone kills the fixgw process after the message has left the client lib but before it arrives at the gateway, the message is lost, but the client thinks it has been sent. This potential problem is overcome by the ‘Local Client Reliable Protocol’ (LCRP) which is a very simple protocol used between the clientg lib and the fix gateway. Basically every message has its own LCRP number. When the client opens a gateway session, the gateway sends the the client the last LRCP number it received, and the client then checks a local journal file, and re-sends any messages that it previously sent whose LRCP is bellow the number sent by the gateway. Remember, this isn’t the FIX protocol at work here, this is just a mechanism to ensure that if the client lib sends a message, that message is guaranteed to reach the fix gateway regardless.

The mechanism is implemented by a file called jnl.txt, in which outgoing messages are saved. When the library opens a session, it renames jnl.txt, (if it exists), to jnl.wrk and then checks the last LCRP number received from the gateway with records in jnl.wrk and resends missing messages. The jnl.txt/jnl.wrk file is located in a 'session' sub-directory of a directory with the same named as the config file, either located in the system temp directory, in the directory specified by the environment variable FIXGWLOG, or in the directory specified by the CliLogDir config parameter. It follows from this, that if you open a config and each time have FIXGWLOG set to different values or sometimes not set at all, the client lib will behave inconsistently with regard to the LRCP, since it will not be checking the correct journal files against the correct LRCP number - previously sent messages may well get sent again.

Note: one source of problems in this area is if the a config is opened by different users that don’t have FIXGWLOG set consistently.

If for any reason you don’t want this protocol to operate, set UseLCRP  to 0 in the config file
 

Client Buffering Support


This is provided by the methods...

  FixSession.beginBufferedOutput();
 FixSession.abortOutputBuffer();
 FixSession.flushOutputBuffer();
The buffer is persisted in a file located in a directory with the same named as the config file, either located in the system temp directory or in the directory specified by the environment variable FIXGWLOG. It follows from this, that if you open a config file and have FIXGWLOG set to different values or not set at all, the client lib will behave inconsistently with regard to buffering.  Buffered records are stored in a file buff.txt until the buffer is flushed, the file is then renamed buff.cmt, and each record is actually sent, as a record is sent it is marked as  sent  within the file.
 

The Implementation of FixSession.setComplete()

When setComplete() is called, the sequence number of the current message is saved in a file setcomplete.log is located in a directory with the same named as the config file, either located in the place specifed by the CliLogDirconfig parameter or system temp directory or in the directory specified by the environment variable FIXGWLOG. It follows from this, that if you open a config file and have FIXGWLOG set to different values or not set at all, the client lib will behave inconsistently with regard to processing setComplete() data. When the client starts a new session, it passes the last processed sequence number to the gateway, if this is lower than the last sequence number the gateway received from the remote fix engine, it firstly searches the Receive Journal for the missing messages and, if found, passes them to the client app with the Possible Dup flag set to Y, but if the messages are not found, the gateway uses the sequence number defined by SetComplete so that the missing messages are re-requested from the remote Fix Engine. Note a value of –1 in the setcomplete.log file  is an ‘initial value’ flag, and is ignored.

Appendix II - Recovery from total sequence number failure

Firstly, you should never be in a situation of total sequence number failure unless you have suffered some sort of hardware failure.

Note: you will have to use methods on the low level API to achieve this.

Now, how could this situation arise. We’ll, if your machine suffers total failure and you move your application onto a backup machine, depending on how things are configured, your backup system won’t know the last sequence number sent, so it can only send 0, the receiving system will likely reject this message as a duplicate and then you’re stuck  - the only thing you can do is phone up the 3rd party and get them to reset their sequence numbers to 0.

We’ll, there is an alternative to phoning up if you are running Fix 4.2 or higher. If you are in this situation, you can use the FixClient.SetRecoverySeqNos() to set the outgoing sequence number to a high value, maybe 899999. How will this help? Well, the 3rd party won’t reject your message, but it will ask for a resend of the sequence number it has missed. Your system won’t of course, have these number, but the AFI Fix Engine will know that it is trying to recover a connection from an error condition, so it will respond with a GapFill to the remote site, and then, it will issue a session reset. Thus everything will be working again. Of course, you will have to manually investigate what might have been lost due to the failure of your machine. If you don’t want to suffer this sort of problem in the first place, you should run your application on fault-tolerant hardware, at the very least, you should have a UPS and probably disk-mirroring as well. 


Appendix III: The low level API

This API can be used on its own or accessed via the high-level API. In general, you should not use this API. This API is encapsulated by the High Level API. You should always use the High Level API, and use the FixSession.getLowLevelApi() to access the underlying FixClient object if you need low level API methods. It is extremely unlikely you will need to access this API, so if you think you need it, take another look at the high level API, the functionality you need is probably there!

Note: Ths API is compatible with the FixGateway API used in in Octatec's C++ based FIX Engine.

Jar File: jfixgw.jar

import com.octatec.jfixgw.*
 

Class com.octatec.jfixgw.FixClient

new FixClient()
Create and initialize a FixClient object. The object is not connected to the fix gateway until Open() is called.

Destruct()
You can call this method to close the connection  and release any resources. If you just call Close(), some resources are held in case you want to Open() the connection again. If you don't call Destruct(), the resources will be released when the garbage collector runs and calls the objects finalize() method.

int Open(LPCTSTR configFile)
int Open(LPCTSTR configFile, CntrlInterface ctrl)
Open a fix session. The parameters of the fix session, e.g. IP address, port etc., are held in the configFile. The config file can be a full pathname, but more usually, it is just the filename, without extension - given such a value, the fix gateway will look (under UNIX) in /Octatec/fixgw/Home/configs(and under WIN32) in C:/Program File/Octatec/fixgw/configs  for a file of the same name and a .cfg extension. If you choose to use the full path specification for config files, the path length must be less than 128 characters. (You should try and keep config names (not path names) less than 32 characters, as the config file name will be truncated to 32  when the log-directory is created). Use the ctrl parameter if you want to send control mesages to a worker thread in a Fix Message loop.

The same application can have many FixClient objects, and open multiple fix sessions if it wishes, however, it should only OpenconfigFile once, i.e. if you wish to open 2 or more sessions to the same client, you must create separate config files for each session, the files can just be copies but must have different names, e.g. MyBroker_1, MyBroker_2 etc. The reason for this is that the configFile name defines where the fix log files are created. Attempts to open the same configFile more than once in the same process or even in a different process will fail.

int WaitForConnection()
You may use this method to wait until a connection has been established with the remote fix engine. The method only returns when (a) the Local Fix Gateway makes a connection to a remote Fix Engine, or (b) if an error occurs, or (c) if the CntrlInterface is in use and a Control Message has been sent by another thread. You do not need to make this call, you can go straight into reading messages or sending messages, (if messages are sent and no connection is ever established, they are not lost, they are stored in the local Fix Gateway, if you try to read before the connection is established you will just wait until the connection is made). This method is, perhaps, of most use when the local Fix Gateway is acting as a server.

boolean IsConnected()
This method returns true if the local Fix Gateway is connected to a remote Fix Engine.

int GetFixMsg(FixString str)
This is the main method of the object. Your program should enter a loop calling GetFixMsg() until it returns an error. When the method returns without an error, the str parameter contains a fix message. You should query the returned FixError object to see if the message returned was a Fix Message, or a Control Message. Mostly, it will be a Fix Message. If it is not a fix message, the str parameter is meaningless and you must use  GetControlMsg() to get the  ControlMessage information.

int SendFixMsg(String type, FixString str)
This method is used to send a FixMessage to the remote fix engine. You should set the fix-fields of the str parameter and then send the message. The type parameter should be one of the FIX_MSG_  values defined in the  in FixConst class, or any other string value denoting a locally agreed fix message type.
 

int ResetSession()
This resets sequences numbers back to 1 on both sides of the conversation, using the Reset Session mechanism introduced in protocol version 4.2. If the protocol version is bellow 4.2, this method returns an error. When the session is reset, a new log directory is created. For this method to work, ManualSessionSwitch must be set to 1 in the config file.

int ResetLogLevel(int n, boolean gatewayOnly)
This method can be used once a connection is established to reset the log level, valid values are 1 2 or 3. If gatewayOnly if false, then the client log level is also reset.

int ResetForwardHtBtFlag(boolean flag)
This method can be used once a connection is established to reset the heartbeat forwarding strategy, if flag istrue, heartbeat messages are passd to the client app.

int ResetRejectionTolerationLevel(ingt value)
This method can be used once a connection is established to reset the rejection toleration level. If the value is 0, rejections are always allowed, otherwise, the gateway will close down after receiving the specified number of rejections. A value of 1causes the gateway to close immediately it receives a rejection from the remote Fix Engine.

int ResetForwardRejectionFlag(boolean flag)
This method can be used once a connection is established to reset the rejection forwarding strategy, if flag istrue, fix-protocol rejection messages are passd to the client app.

int ResetManualSessionSwitchFlag(boolean flag)
This method can be used once a connection is established to reset the ManulSessionReset flag (see the FixGateway documentation for more details about this flag.) If  flag is true, and the fix version is 4.2 or above, a new fix session will only be started if either side initiates a new session (using ResetSession).

int BeginBufferedOutput()
After this method has been called, SendFixMsg() merely records the message in a local persistent buffer.

int AbortOutputBuffer()
This method closes and discards the local buffer.

int FlushOutputBuffer()
This method closes the local buffer, and then sends all messages to the fix gateway. As each message is sent, it is marked as processed, so that if your application fails or is killed, when it restarts, you can use SynchronizeOutputBuffer() to send any pending messages to the gateway. Once FlushOutputBuffer()or AbortOutputBuffer() is called subsequent calls to SendFixMsg() sends messages directly to the gateway, until BeginBufferedOutput() is called again.

int SynchronizeOutputBuffer()
You can use this method when your application starts, it will send any pending messages in the local buffer to the gateway. You should only have pending messages if your application failed or was killed.  If you make use of the buffering mechanism, you should call this method immediately after Open() returns success.

boolean SetComplete()
This method tells the system that all messages received since the last call to SetComplete() (or since the 1st message was received if SetComplete() has not yet been called) are fully processed. Until SetComplete() is called, all messages currently received will be received again should your application crash or be killed. Depending on how your application is structured, you may call SetComplete() after each message has been processed or wait until a group of messages, i.e. a list, have been processed. SetComplete() is implemented by saving the sequence number of the last completed message, and then passing this to the gateway at startup - the gateway compares this to the last application-level message received, and if it is lower, the gateway requests a resend from the remote fix engine. If you call DisableAutoRecovery() there is then no need to use  Setcomplete(), but this is not recommended.

boolean SetComplete(int lastProcesedSeqNum)
This form of SetComplete() allows you to set which sequence number you are 'happy' with. You can extract the sequence number from the Fix Message.

void DisableAutoRecovery() // implies mode==true
void DisableAutoRecovery(boolean mode)
This method disables the SetComplete() mechanism. However, doing this is dangerous, since if your application (not the fix gateway) crashed or was kill after it received the message but before it was processed, the message would be lost, as the fix gate will have received it successfully and passed it to your application successfully as well. It must be called before Open() if it is to be effective.

int Close() // implies grace=15
int Close(int grace)
Close the fix session. If you do not close an open session, it will be closed eventually by the finalize method, but because you don't know when this will run, you    should always Close sessions explicitly. If you open a 'server session', and try to close it  before a client has connected to it, you will hit a snag - the gateway is   'busy' waiting for a connection, and will not see the 'close' command, consequently, the Close() method will wait up to grace seconds before forcibly  closing a    'server' GateWay if it doesn't close naturally. The Close method keeps some resources allocated in case you want to Open the connection again. If you don't want to open the session again, you   can call Destruct() after Close(), or just call Destruct() without calling Close().

int Reopen()
If you get an error from GetFixMsg() or WaitForConnection() you can either call Close() and Open() or just call Reopen(). If you get an error from Reopen(), then you should call Close() and Open(). If you call Close(), Reopen() will not work and you must call Open(). Any additional login or header tags you have set will still be active after a Reopen(), but will not be active after a Close(). NB:  Reopen() will return an error if no connection has ever been established, i.e. it should be used after a connection has been established and then closed by the other side.

int RunScript(final String path, OutputInt numberOfMessages) // implies reconnect=0 maxretries=0
int RunScript(final String path, OutputInt numberOfMessages, int reconnect, int maxretries)
Run a script, the number of messages processed is returned in numberOfMessages. See the FixGateway documentationfor the format of a script file. If reconnect is specified,the fix session is automatically reconnected after waitingreconnect seconds - this process is repeated for maxretries times (or forever if maxretries is 0). Note: if the configuration specifies the fix gateway is in server mode, the reconnect will cause the gateway to wait for another connection. You may pass -1 as the reconnect parameter, in which case their is no delay before the reconnection attempt - you may want this if your fix gateway is acting as a server. (see the configuration file section for how to configure the gateway as a server)

int OverrideTargetSubId(final String newId) // implies permanent=true
int OverrideTargetSubId(final String newId, boolean permanent)
You can use this method once a connection has been established to override the TargetSubID defined in the config file. If permanent is false, the change is only applied to the next message you send, otherwise it is applied to all subsequent messages (resent messages are, of course, resent with their original TargetSubID)

int SetAddionalLoginTags(final FixString tags)
This method can be used before the FixClient::Open() call to define some additional fields to be sent in the Login message - i.e. this can be used to support non-standard login tags.

int SetAddionalMsgTags(final FixString tags)
This method can be used before the FixClient::Open() call to define some additional fields to be sent in all outgoing messages  - i.e. this can be used to support non-standard header/trailer tags (actually the tags are always added to the end of the message, but before the standard fix trailer).

int ResetSessionAtLogon();
This method van only be used before a connection is established, i.e. before the Open() call has been made. This instructs the system to include a reset-sequence-number directive with the initial logon. The sequence numbers will be reset to zero on both sides. This can only be used, of course, if the sequence numbers are already ‘in-sync’ to start with. This method can only be used with Fix 4.1 and higher.

int ResetSequenceNumber(int num)
This method provides an interface to the Fix Protocol RESET SEQUENCE NUMBER message, sequence numbers can only be increased in value, so the num parameter is added to the current value of the outgoing sequence  number. NOTE: you shoukld not attempt to send this FIX message yourself, if you want to send the message, use this method, however you are very very unlikely to actually want to do this, you are very very unlikely to find this method useful for any  purpose!

void  GetControlMsg(OutputShort &msg, OutputString &s)
String  GetControlMsgString()
short GetControlMsg()
These methods return the value of the control message (and it's string parameter, if one was present)

OutputStream GetControlInterface()
This can be used if a ControlInterface is in use  and you wish to send a response back using  CntrlInterface.SendResponse() - the control messages  values/contents are chosen entirely by you, but the  intention is that they be used for simple queries  and shutdown commands.

public Object [] DetachControlInterface()
Detach the ‘raw’ Control Interface. The purpose of doing this is so that the socket used by the Control Interface is not closed by the FixClient::Close() method. You can then close the FixClient and the Control Interface held by the UI thread remains valid. Thus if you decide to open another FixClient object, you can ‘reuse’ the Control Interface without having to inform the GUI client.

public  boolean AttachControlInterface(Object [] rawCtlIf)
Attach a previous detached ‘raw’ Control Interface. This call MUST be made before FixClient::Open() is called, otherwise it will fail. (If you pass a Control Interface Object in the Open()call, then that is the interface that will be used, and the previously attached ‘raw’ interface will be ignored.)

int SetRecoverySeqNos(long out) // implies  in = -1 
int SetRecoverySeqNos(long out, long in) 
This method can be used to recover a connection after complete sequence number failure. To achieve this you must call this method before Open(), probably with out = 899999 and the default in parameter. After the connection has been established, the session will be automatically reset, and both sides will have sequence numbers of 0. IMPORTANT: do not use this method as a 'matter -of-course' - only use it to recover the situation described here. This method can only be used with Fix 4.2 and higher. 

boolean IsGmtOffsetInUse()
If a Virtual Timezone is being used in the Gateway process, this method returns true. (To find out more about Virtual Timezones, see the FixGateway documentation)

short GetGmtOffset() 
If a Virtual Timezone is being used in the Gateway process, this method returns the offset from GMT of the Virtual Timezone.  If no Virtual Timezone is in use, a value of Config.V_LOCAL_TIME is returned. To find the time as viewed by the gateway process, use the FixString.GetCurrentTime() method.

int ConfirmResend(bool okToResend)
Call this method in response to a Resend Confirmation Request. You can configure the system to ask for confirmation when resending time-sensitive messages. (To find out more about Confirmation Requests, see the FixGateway documentation)

FixString queryOutwardSeqNum(int outwardSeqNum)
Given a sequence number, this method finds the outbound message that was sent with the given sequence number. It will return null if no message can be found.
 

Class com.octatec.jfixgw.FixError

FixError Static Constant Values

FIX_OK (0)
    no error

FIX_LOGOUT (-1)
    the remote side logged out
FIX_DROPPED (-2)
    the remote side droppend the line
FIX_CANT_CONNECT (-3)
    can't connect to the remote
FIX_NO_CFG (-4)
    the config file specified does not exist
FIX_NO_GTWY (-5)
    the gateway process cannot be started
FILE_OPEN_ERROR(-6)
    couldn't open the config file or an inpuit/output file
FIX_IN_USE(-7)
    the configFile specified in the open call is already opened in this or another process.
FIX_BAD_DYN_CFG (-8)
        you passed a DynamicFixCfg object to  FixClient::Open(), and DynamicFixCfg::Save() failed.
FIX_BAD_ID (-9)
        the other side of the Fix Conversation has an unexpected ID or SubID, the IDs of the sender are specified in the config file, and are called
        the TaregetID and TargetSubID, these must match what the Sender actually sends, similarly our IDs may well be checked by the Sender,
        these are called the LocalID and the LocalSubID in the config file.
FIX_OUT_OF_SYNC (-10)
        The gateway process is issuing resend requests but the remote fix engine is rejecting these requests
FIX_BAD_FIX_VER (-11)
        The gateway process detected an incompatible Fix Version specified in the config files.
FIX_NEVER_OPENED (-12)
        you are trying to call methods on the FixClient that require an open session, and one is not open
FIX_EMPTY_MSG (-13)
        you are attempting to send an empty Fix message.
NO_ADMIN_INTERFACE (-1000)
    this error can only occur when trying to 'run' a script
        or journal file, and the session is not correctly initialized
NO_FILE (-1001)
    the script or journal file you are trying to run does not exits
WRONG_PROTOCOL_VERSION (-1003)
    a session reset was attempted but this is not allowed in the current protocol version

FIX_CLT_IF_ERROR (-992)
FIX_2MANY (-993)
FIX_DISCONNECT_WHILE_LISTENING (-994)
FIX_SELECT_ERROR1 (-995)
FIX_INIT (-996)
    internal errors

FIX_ERROR (-999)
    a general error

FIX_CONTROL_MSG (1)
    not an error, and indication that the message is a control message, not a FIX message

Methods
boolean IsControlMsg(int errorCode)
Returns true if the input errorCode represents a control message. (I.e. errorCode==FixError.FIX_CONTROL_MSG).

boolean IsFixMsg(int errorCode)
Returns true if the input errorCode represents a FIX message. (I.e. errorCode==FixError.FIX_OK).

boolean IsError(int value)
Returns true if the input errorCode represents a an error state.
 
 

Class com.octatec.jfixgw.CntrlInterface

Note: the functionality discussed below is encapsulated by the AfiThreadedApp class, which you should use if you wish to create a FIX session in a worker thread, and send commands to it from a GUI (or similar) thread.

This class allows you to pass messages from a controlling thread, e.g. a user interface thread into the fix message loop of a fix worker thread. Once in a Fix Message Loop, the thread is waiting for messages from the Fix Gateway and/or messages from the Control Interface. Unless you use the Control Interface, their will be no way for you to control the Fix Message Loop except when a Fix Message arrives. The main reason for implementing the Control Interface object is so that a GUI thread can tell the FIX thread to shut down. The JFixSrv program shows how the Control Interface can be used.

new CntrlInterface()
Create a new CntrlInterface object (in the UI thread)

boolean InitControlSide();
Call this method first in the control (GUI) thread

boolean WaitForActivation() // implies sendStartMsg=true
boolean WaitForActivation(bool sendStartMsg);
Call this method in the Control (GUI) thread after the worker thread has been created, it will wait  for the worker (FIX) thread to become 'ready'. Once the worker thread is ready, provided sendStartMsg was true, WaitForActivation() will send a start message allowing the worker thread to continue and connect to the remote fix engine. If sendStartMsg was false, you must manually send a start message when the time is right.

boolean SendStartMsg()
You only need send a Start Message after if you passed in false to WaitForActivation(), if you did, you must call this method at some point after WaitForActivation() returns true.  This allows you to control when the Fix Message Loop actually begins.

boolean SendMsg(short iparam) // implies sparam=null
boolean SendMsg(short iparam, String sparam);
You can use this method to send messages to a thread in a Fix Message Loop, the messages are entirely under your own control but should all have values above 100, values below 100 are reserve for internal use. It is intended that this mechanism be used for simple  queries and commands, e.g. to shutdown the gateway. The messages will be received in the Fix Message Loop via FixClient.GetFixMessage(), a return of FixError.FIX_CONTROL_MSG fromFixClient.GetFixMessage() indicates that you should call FixClient.GetControlMsg() and optionally FixClient.GetControlMsgString() to examine the message and any parameter. Normally, SendMsg() will be called from the Control (GUI) thread to send a message to the worker (FIX) thread, possibly to shut down, it is unlikely, but possible, you may want to send a response to the message, to do this, use the SendResponse() method

static boolean SendResponse(OutputStream sd, short iparam) // implies sparam=null
static boolean SendResponse(OutputStream sd, short iparam, String sparam)
Call this method in the worker (FIX) thread to send a response back to the Control (GUI) thread if you know one is required.

bool GetResponse(OutputShort iparam, OutputString s)
If you are expecting a response to the message, you can use this method in the Control (GUI) thread to wait for it. Mostly, messages you send to the fix thread will not give rise to a response.


Appendix IV - Installation Guide

AFI/J is a 100% pure Java application, and so should be able to run on any operating system that has Java installed. However, to make installation easier, the application comes with 2 alternative installation programs, one for UNIX and one for Windows. These are discussed here.

Appendix V - Suport for SSL

SSL is not supported directly by AFI/J. However, you can ‘plug in’ your own or a 3rd party SSL provider into the Engine.

You must specify the fully qualified name of a Socket class and a ServerSocket class in the properties file. (you only need to specify a ServerSocket class if you are running AFI/J as a server)

Use the properties socketClass and serverSocketClass in session configuration properties file to do this. If these classes begin with a #, they will be ignored, otherwise they should specify a valid class. Your class should be packaged in a .jar file, and the jar should be specified in the client application properties file (fixgw.properties) by the SocketJar property. NOTE you specify the class names in the session properties file and the jar file that contains the classes in the client application properties file – you use 2 different properties files.

The class you specify as a ServerSocket must implement the ServerSocketI interface
 

public interface ServerSocketI {
   public void init(int port) throws IOException;
   public SocketI accept() throws IOException;
   public void close() throws IOException;
}
And the class you specify as a Socket must implement the SocketI interface.
public interface SocketI {
   public void connect(InetAddress address, int port) throws IOException;
   public InputStream getInputStream() throws IOException ;
   public OutputStream getOutputStream() throws IOException;
   public void shutdownInput() throws IOException;
   public void shutdownOutput() throws IOException;
   public void close() throws IOException;
}
If you don’t specify any Socket/ServerSocket class in the properties file, default implementations are used that just delegate to the standard Java Socket and ServerSocket classes. The following is the code of the default implementations and can be used as a guide to creating your own implementations.
import java.io.*;
import java.net.*;

public class DefaultServerSocket implements ServerSocketI {

   private ServerSocket m_sd = null;

   public void init(int port) throws IOException
   {
      m_sd = new ServerSocket(port);
   }

   public SocketI accept() throws IOException
   {
      Socket sd = m_sd.accept();
      DefaultSocket dsd = new DefaultSocket(sd);
      return dsd;
   }

   public void close() throws IOException { m_sd.close(); }
}
 

import java.io.*;
import java.net.*;

public class DefaultSocket implements SocketI {

   private Socket m_sd = null;

   DefaultSocket(Socket sd) {m_sd = sd; }

   public void connect(InetAddress address, int port) throws IOException { m_sd = new Socket(address, port);  }
   public InputStream getInputStream() throws IOException { return m_sd.getInputStream(); }
   public OutputStream getOutputStream() throws IOException { return m_sd.getOutputStream(); }
   public void shutdownInput() throws IOException { m_sd.shutdownInput(); }
   public void shutdownOutput()throws IOException { m_sd.shutdownOutput(); }
   public void close()throws IOException { m_sd.close(); }
}

NIO Issues

If you are running using java version 1.4 or above, AFI/J will, by default, use NIO. So if you are implementing these interfaces, you should endeavour to create your sockets in an NIO compatible manner. If you are using a 3rd party SSL socket library, this may not be possible. If your SSL providers socket sub-system does not support NIO, you can still use it, but your must set the preferNIO parameter to 0 in the configuration file.


Home | FixGateway | AFI/J | SimpleGrid | SBpayroll | SXAzip | InstallScript | DiskUsage/DiskClean | Virtual Desktop Manager | ComBridge | Demos | Purchase