CIS Trade-Model Code Generator
To help you integrate your XML trade model into your trading application, CIS 6 provides a code generator that creates the necessary Java code from a single command line instruction.
Purpose and location
The code generator, like the CIS Command Line Toolkit, is a jar file that can be found in the tools directory of the unzipped CIS Toolkit. The name of the file will change from time to time, but it will always use the following structure:
trading-datasource-code-generator-[version number]-[build number].jar
For example:
trading-datasource-code-generator-6.0.1-253872.jar
If you’ve got an XML trade model set up, you can simply run the Generator, and it will parse the XML and set up all the necessary interfaces, classes and methods to write the bridging code for it (such as listeners and event-handlers, with getters and setters for any field values defined in the XML <transition>
tags).
Running the code generator
To run the Code Generator, you’ll need to have an XML file set up, containing one or more trade models. If the XML contains more than one trade model, you can either nominate a particular model to generate code for, or you can allow the Generator to create code for all the trade models in the file. From the command line, enter a command with the following structure:
java -jar code-generator-jar src package templates-dir model-file [model-name]
This command is composed of the following:
If any of the file paths included in these arguments are relative paths, they will be calculated from the location of the command prompt. If an argument contains spaces, that argument should be in quotation marks. |
Parameter | Description | ||
---|---|---|---|
|
The name of the Code Generator jar file, including the path to it from the command prompt if necessary. |
||
|
The location of the root directory in which the code will be generated. |
||
|
The name of the Java package to be used for the generated code. |
||
|
The directory containing the code templates that the generator uses; usually the CIS Toolkit’s tools/templates/java directory.
|
||
|
The name and location of the XML file that contains the trade model for which you are generating the code. |
||
|
Optional. The name of a particular trade model within the model-file you specified (i.e. the name attribute of the |
Code generation example
Let’s assume that we have a trade model called models.xml, located in the tools/xml directory of the CIS Toolkit, which looks like this:
/tools/xml/models.xml
<tradeModels>
<tradeModel name="ESP" initialState="Initial">
<state name="Initial">
<transition target="OpenSent" trigger="Open" source="client">
<field name="StateModelName" description="ESP model name" required="true" />
<field name="RequestID" description="Request ID" required="true" />
<field name="QuoteID" description="Quote ID" required="true" />
<field name="InstrumentName" description="Instrument Name" required="true" />
<field name="DealtCurrency" description="Dealt currency" required="true" />
<field name="BuySell" description="BuySell indicator" required="true" />
<field name="Price" description="Price" />
</transition>
</state>
<state name="Timeout" />
<state name="OpenSent" timeout="10" timeoutState="Timeout">
<transition target="Opened" trigger="OpenAck" source="server">
<field name="RequestID" description="Request ID" required="true" />
<field name="StateModelName" description="ESP model name" required="true" default="ESP" />
<field name="BuySell" description="BuySell indicator" required="true" default="BUY" />
</transition>
</state>
<state name="Opened" timeout="10" timeoutState="Timeout">
<transition target="TradeConfirmed" trigger="TradeConfirmation" source="server">
<field name="RequestID" description="Request ID" required="true" />
<field name="TradeID" description="Request ID" required="true" />
</transition>
<transition target="TradePassed" trigger="Pass" source="server" />
<transition target="TradeExpired" trigger="Expired" source="server" />
</state>
<state name="TradeConfirmed" />
<state name="TradePassed" />
<state name="TradeExpired" />
</tradeModel>
</tradeModels>
Because the Generator will use the name and trigger attributes to create Java classes, it’s important to ensure that they conform to Java class naming conventions; i.e. alphanumeric characters only, with an initial capital letter and using "CamelCase".
|
You might then use the following command, entered from the tools directory of the unzipped CIS Toolkit:
java -jar trading-datasource-code-generator-6.0.1-253872.jar samplesrc example.generated templates/java xml/model.xml ESP
Breaking this down into its component parts, this would do the following:
Command component | Description |
---|---|
|
Runs the Trade Model Code Generator script. |
|
Specifies that the name of the root directory in which our new code will be created is called samplesrc. It will be created (if it doesn’t exist already) in the command line’s working directory. |
|
Defines a Java package in which the code will be generated. Combined with the samplesrc parameter above, this means that the code will be generated in the samplesrc/example/generated directory. |
|
The location of the Generator’s code templates, relative to the working directory. |
|
The name and location of the XML file containing the trade model (again, relative to the working directory). |
|
The name of the trade model for which we want to generate code. As our XML contains only one |
What code is generated?
The Code Generator creates all necessary interfaces, classes and methods needed for your trade model, and includes the generic classes and interfaces from the Caplin Trading API, to integrate your trade model with a fully functional trading system. You’ll be happy to hear that all the code created by the Generator contains extensive comments to help you understand what the various interfaces, classes and methods are doing.
Code shared between trade models
In the directory you specified in the [package]
argument of your command (in our example this is the example/generated directory), there will be two files that are common to all the trade models for which you’ve generated code:
TradingAdapter.java
This defines the TradingAdapter
class, which implements the TradingApplicationListener
and TradeChannelListener
interfaces, and acts as a wrapper for the whole trading library.
CleanupListener.java
This file defines the CleanupListener
interface, which is used to initiate clean-up operations after a trade (whether or not the trade has completed successfully).
Code specific to the trade model
Within the [package]
directory will be a separate directory with the name of each trade model for which code has been generated. In our case, there’s only one: example/generated/esp. These contain four java files that are specific to the trade models themselves, and an additional java file for each <transition>
element in the trade model that contains one or more <field>
tags.
Filename Format | Filenames in this Example |
---|---|
[ModelName]Trade.java |
ESPTrade.java |
[ModelName]TradeListener.java |
ESPTradeListener.java |
[ModelName]TradeListenerAdapter.java |
ESPTradeListenerAdapter.java |
[ModelName]TradeListenerFactory.java |
ESPTradeListenerFactory.java |
[TransitionTriggerName]TradeEvent.java |
OpenTradeEvent.java, OpenAckTradeEvent.java, TradeConfirmationTradeEvent.java |
[ModelName]Trade.java
This defines the [ModelName]Trade
class (ESPTrade
in our example), which implements the Trade
interface and represents a particular trade. It also imports the valid responder
classes that have been created for this trade model (see below).
[ModelName]TradeListener.java
This defines a TradeListener
interface for this trade model, which in our example, would be: ESPTradeListener
.
A class that implements it would "listen" for the client action that initiates the trade process, based on the <transition>
tag’s trigger
attribute, and would then use that action’s TradeEvent
to create a new trade.
The interface identifies the methods called if invalid transitions or fields occur, and defines the CleanUp()
method for this trade model.
For Example:
The first client action defined in the ESP trade model is "Open", as shown in the XML below:
xml/model.xml
<transition target="OpenSent" trigger="Open" source="client">
The ESPTradeListener
interface listens for the Open
trigger, and then calls the TradeEvent
associated with that transition (OpenTradeEvent
), as shown here:
samplesrc/example/generated/esp/ESPTradeListener.java
public interface ESPTradeListener
{
public void onOpen(OpenTradeEvent event);
...
}
[ModelName]TradeListenerAdapter.java
This defines a TradeListenerAdapter
class for this trade model, implementing the TradeListener
and CleanUpListener
interfaces.
[ModelName]TradeListenerFactory.java
This defines a TradeListenerFactory
interface, which enables you to use a factory class for this trade model, giving you a simple way to create new instances of TradeListener
classes for it.
In our example, this would be: ESPTradeListenerFactory
.
[TransitionTrigger]TradeEvent.java
Each <transition>
element that contains one or more <field>
tags will produce a class that implements the TradeEvent
interface, with get()
and set()
methods for the defined fields. If any of the fields have default values, they will be included in the generated code. The class will be named after the trigger attribute of the <transition>
it describes.
In our example, this would generate three classes, OpenTradeEvent
, OpenAckTradeEvent
and TradeConfirmationTradeEvent
.
It’s possible for a trade model to have more than one transition with the same trigger name, but if so, all such transitions must have the same fields. If you want one transition to have different fields, you’ll have to give it a different name! Transitions that don’t contain any fields don’t have a custom class generated for them, and are handled using the generic TradeEvent class.
|
Responders
[StateName]Responder.java
Each trade model also has a responders directory generated for it. This contains a java file for each <state>
element in the trade model that contains at least one <transition>
tag. Each of these files contains a class called [StateName]Responder
, which defines a method for each valid transition from that state, as defined in the trade model. These methods will be named after the trigger attributes of the applicable <transition>
tags.
In our example, the states containing transitions are Initial
, Opened
and OpenSent
, so the responder classes generated are InitialResponder
, OpenedResponder
and OpenSentResponder
.
For Example:
The OpenSent
state contains a single transition, the trigger of which is OpenAck
, as we can see here:
xml/model.xml
<state name="OpenSent" timeout="10" timeoutState="Timeout"> <transition source="server" target="Opened" trigger="OpenAck"> <field description="Request ID" name="RequestID" required="true"/> </transition> </state>
The Code Generator therefore creates a class called OpenSentResponder
, which, since there’s only one valid transition from this state, contains only one method: sendOpenAckTradeEvent()
, which calls the OpenAckTradeEvent
class generated to handle that transition type, as shown below:
samplesrc/example/generated/esp/responders/OpenSentResponder.java
public class OpenSentResponder { Trade trade; public OpenSentResponder(Trade trade) { this.trade = trade; } public void sendOpenAckEvent(OpenAckTradeEvent event) throws TradeException { trade.sendEvent(event); } }
A point to remember about generated code
The thing about generated code, is that it’s… well… generated. The interfaces, classes and methods are there to make your life easier, because they are designed to let you integrate trade models into your trading system, keeping the need for manually produced code and the likelihood of errors to a minimum.
It’s strongly recommended though, that you don’t actually edit the generated code, not least because if you generate code using the same parameters again (maybe because you’ve added an extra field to your trade model), the Code Generator will overwrite any existing files with new versions.
That’s not to say that you won’t have to write a bit of your own code in order to implement the trade model into your own application, but we’d strongly advise you to keep it separate from the code produced by the Generator.
So what code do I have to write myself?
Once the Generator has done its stuff, you’ll still have to write a small amount of code yourself, to serve as an entry point into the trade and to create implementations of some of the classes that have been generated. The code you’ll need is going to vary depending on the nature of your application (not to mention your trade model), but some examples are provided to give you an idea of what you’ll need. The examples given fit in with the ESP trade model shown earlier, and the code that the Generator produced for it. Note that the ESP trade model is a very simple example, and almost anything else you do will be more complicated!
As an example, we’ve produced three files that would implement the ESP trade model, using the generated files, and which we’ve given similar names to the classes they implement or instantiate. We’ve put them in the example folder, within the generated directory structure, but above the level of any of the generated files themselves.
MyTradingAdapter
samplesrc/example/MyTradingAdapter.java
package example; import com.caplin.datasource.DataSource; import example.generated.TradingAdapter; import java.io.IOException; public class MyTradingAdapter { public MyTradingAdapter(DataSource datasource) throws IOException { TradingAdapter adapter = new TradingAdapter(datasource); adapter.registerTradeListenerFactory(new MyESPTradeListenerFactory()); } }
This would be the entry point for the trade, and includes the generated TradingAdapter
class, as well as Caplin’s DataSource
interface. It creates a new instance of TradingAdapter
, and registers MyESPTradeListenerFactory
- the second of the three implementation classes we’ve written - as a new ESPTradeListenerFactory
, using the registerTradeListenerFactory()
method from the TradingAdapter
class.
MyESPTradeListenerFactory
samplesrc/example/ MyESPTradeListenerFactory.java
package example;
import com.caplin.trading.TradeException;
import example.generated.esp.ESPTrade;
import example.generated.esp.ESPTradeListener;
import example.generated.esp.ESPTradeListenerFactory;
public class MyESPTradeListenerFactory implements ESPTradeListenerFactory {
@Override
public ESPTradeListener createESPTradeListener(ESPTrade trade) throws TradeException
{
return new MyESPTradeListener();
}
}
The MyESPTradeListenerFactory
class (which has been registered by MyTradingAdapter
) implements the ESPTradeListenerFactory
interface. It uses the generated ESPTradeListener
and ESPTrade
classes in order to create a new instance of MyESPTradeListener
.
MyESPTradeListener
Now our trading adapter has registered the factory class, which in turn has created an instance of MyESPTradeListener
, this is really where it all happens.
First, we import all of the classes generated for the ESP trade model, as well as a couple of classes from the Caplin Trading API to handle invalid fields or transitions, and then we create our MyESPTradeListener
class, implementing the ESPTradeListener
interface that the Code Generator conveniently created for us.
samplesrc/example/MyESPTradeListener.java
package example;
import com.caplin.trading.InvalidFieldsEvent;
import com.caplin.trading.InvalidTransitionEvent;
import example.generated.esp.*;
public class MyESPTradeListener implements ESPTradeListener {
public MyESPTradeListener()
{
}
We then need an event-handler to pick up when a user initiates an ESP trade. As we established earlier, there’s only one actual event in the ESP trade model that comes from the client, which is initiated by the Open
trigger. Having detected it, we then want to call the appropriate class for this kind of trade event; in this case an OpenTradeEvent
.
samplesrc/example/MyESPTradeListener.java (continued...)
@Override
public void onOpen(OpenTradeEvent event) {
Once a user has triggered the OpenTradeEvent
, we need to be able to handle the trade events that might come back from the server, and we’ll also want to make sure that the trade was in the correct state when those events occur. As the Code Generator has already given us a TradeEvent
class for each event that can occur in our trade model, get()
and set()
methods for all the fields associated with those events, and responder classes to ensure that we know which events are valid from which states, this is all quite easy to do:
samplesrc/example/MyESPTradeListener.java (continued...)
try { OpenAckTradeEvent ackEvent = new OpenAckTradeEvent(event.getESPTrade()); // Fields for OpenAckTradeEvent ackEvent.setRequestID(event.getRequestID()); event.getESPTrade().getOpenSentResponder().sendOpenAckEvent(ackEvent); TradeConfirmationTradeEvent confirmEvent = new TradeConfirmationTradeEvent(event.getESPTrade()); // Fields for TradeConfirmationTradeEvent confirmEvent.setRequestID(event.getRequestID()); confirmEvent.setTradeID(event.getTradeID()); event.getESPTrade().getOpenedResponder().sendTradeConfirmationEvent(confirmEvent); } catch (Exception e) { } }
Finally, if we do catch any invalid transitions, or events that don’t have the required fields, we can use the classes we imported from the Caplin Trading API in order to handle them, and also clean up afterwards.
samplesrc/example/MyESPTradeListener.java (continued...)
@Override
public void receiveInvalidTransitionEvent(InvalidTransitionEvent event) {
// An invalid transition has been received from the client
}
@Override
public void receiveInvalidFieldsEvent(InvalidFieldsEvent event) {
// An event from the client has been received without the required fields
}
@Override
public void doCleanup(ESPTrade trade) {
// Cleanup after the trade. This doesn't necessarily mean that the trade has completed!
}
}
Remember that ESP is a very simple, one-click trade model. Most trades will require more user interaction than this, and would therefore need to capture more than one client-sourced event, not to mention quite a few more states, transitions and fields.