blob: 241f122c6170770a4815c6ce04ee90b06df5f0ff [file]
= QuickFix Component
:doctitle: QuickFix
:shortname: quickfix
:artifactid: camel-quickfix
:description: Open a Financial Interchange (FIX) session using an embedded QuickFix/J engine.
:since: 2.1
:supportlevel: Stable
:tabs-sync-option:
:component-header: Both producer and consumer are supported
*Since Camel {since}*
*{component-header}*
The Quickfix component adapts the
http://www.quickfixj.org/[QuickFIX/J] FIX engine for using in Camel.
This component uses the standard http://www.fixprotocol.org/[Financial
Interchange (FIX) protocol] for message transport.
Maven users will need to add the following dependency to their `pom.xml`
for this component:
[source,xml]
----
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-quickfix</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
----
== URI format
----
quickfix:configFile[?sessionID=sessionID&lazyCreateEngine=true|false]
----
The `configFile` is the name of the QuickFIX/J configuration to use for
the FIX engine (located as a resource found in your classpath). The
optional `sessionID` identifies a specific FIX session. The format of
the sessionID is:
----
(BeginString):(SenderCompID)[/(SenderSubID)[/(SenderLocationID)]]->(TargetCompID)[/(TargetSubID)[/(TargetLocationID)]]
----
The optional `lazyCreateEngine` parameter allows
creating QuickFIX/J engine on demand:
* The value `true` means the engine is
started when the first message is sent or there's consumer configured in
route definition.
* When the value `false` is used, the engine is started at
the endpoint creation.
When this parameter is missing, the value of
component's property `lazyCreateEngines` is being used.
.Example URIs:
----
quickfix:config.cfg
quickfix:config.cfg?sessionID=FIX.4.2:MyTradingCompany->SomeExchange
quickfix:config.cfg?sessionID=FIX.4.2:MyTradingCompany->SomeExchange&lazyCreateEngine=true
----
== Endpoints
FIX sessions are endpoints for the quickfix component. An endpoint URI
may specify a single session or all sessions managed by a specific
QuickFIX/J engine. Typical applications will use only one FIX engine, but
advanced users may create multiple FIX engines by referencing different
configuration files in quickfix component endpoint URIs.
When a consumer does not include a session ID in the endpoint URI, it
will receive exchanges for all sessions managed by the FIX engine
associated with the configuration file specified in the URI. If a
producer does not specify a session in the endpoint URI, then it must
include the session-related fields in the FIX message being sent. If a
session is specified in the URI, then the component will automatically
inject the session-related fields into the FIX message.
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
include::partial$component-endpoint-headers.adoc[]
// component options: END
== Usage
The `DataDictionary` exchange property is useful if string messages are
being received and need to be parsed in a route. QuickFIX/J requires a
data dictionary to parse certain types of messages (with repeating
groups, for example). By setting the `DataDictionary` exchange property
(`QuickfixjEndpoint.DATA_DICTIONARY_KEY`) in the route after receiving a
message string, the FIX engine can properly parse the data. The property
can hold a `quickfix.DataDictionary` instance or the name of a data
dictionary resource, such as `FIX44.xml`. When the property is not set,
the data dictionary of the session identified by the `SessionID` header
is used, if that session exists.
=== QuickFIX/J Configuration Extensions
When using QuickFIX/J directly, one typically writes code to create
instances of logging adapters, message stores, and communication
connectors. The quickfix component will automatically create instances
of these classes based on information in the configuration file. It also
provides defaults for many of the commonly required settings and adds
additional capabilities (like the ability to activate JMX support).
The following sections describe how the quickfix component processes
the QuickFIX/J configuration. For comprehensive information about
QuickFIX/J configuration, see the
http://www.quickfixj.org/quickfixj/usermanual/usage/configuration.html[user manual].
==== Communication Connectors
When the component detects an initiator or acceptor session setting in
the QuickFIX/J configuration file, it will automatically create the
corresponding initiator and/or acceptor connector. These settings can be
in the default or in a specific session section of the configuration
file.
[width="100%",cols="10%,90%",options="header",]
|=========================================================
|Session Setting |Component Action
|`ConnectionType=initiator` |Create an initiator connector
|`ConnectionType=acceptor` |Create an acceptor connector
|=========================================================
The threading model for the QuickFIX/J session connectors can also be
specified. These settings affect all sessions in the configuration file
and must be placed in the settings default section.
[width="100%",cols="10%,90%",options="header",]
|=======================================================================
|Default/Global Setting |Component Action
|`ThreadModel=ThreadPerConnector` |Use `SocketInitiator` or
`SocketAcceptor` (default)
|`ThreadModel=ThreadPerSession` |Use `ThreadedSocketInitiator` or
`ThreadedSocketAcceptor`
|=======================================================================
==== Logging
The QuickFIX/J logger implementation can be specified by including the
following settings in the default section of the configuration file. The
`ScreenLog` is the default if none of the following settings are present
in the configuration. It's an error to include settings that imply more
than one log implementation. The log factory implementation can also be
set directly on the Quickfix component. This will override any related
values in the QuickFIX/J settings file.
[width="100%",cols="10%,90%",options="header",]
|=======================================================================
|Default/Global Setting |Component Action
|`ScreenLogShowEvents` |Use a `ScreenLog`
|`ScreenLogShowIncoming` |Use a `ScreenLog`
|`ScreenLogShowOutgoing` |Use a `ScreenLog`
|`SLF4J*` |Use a `SLF4JLog`. Any of the SLF4J settings
will cause this log to be used.
|`FileLogPath` |Use a `FileLog`
|`JdbcDriver` |Use a `JdbcLog`
|=======================================================================
==== Message Store
The QuickFIX/J message store implementation can be specified by
including the following settings in the default section of the
configuration file. The `MemoryStore` is the default if none of the
following settings are present in the configuration. It's an error to
include settings that imply more than one message store implementation.
The message store factory implementation can also be set directly on the
Quickfix component. This will override any related values in the
QuickFIX/J settings file.
[width="100%",cols="10%,90%",options="header",]
|=============================================
|Default/Global Setting |Component Action
|`JdbcDriver` |Use a `JdbcStore`
|`FileStorePath` |Use a `FileStore`
|`SleepycatDatabaseDir` |Use a `SleepcatStore`
|=============================================
==== Message Factory
A message factory is used to construct domain objects from raw FIX
messages. The default message factory is `DefaultMessageFactory`.
However, advanced applications may require a custom message factory.
This can be set on the QuickFIX/J component.
==== JMX
[width="100%",cols="10%,90%",options="header",]
|============================================
|Default/Global Setting |Component Action
|`UseJmx` |if `Y`, then enable QuickFIX/J JMX
|============================================
==== Other Defaults
The component provides some default settings for what are normally
required settings in QuickFIX/J configuration files. `SessionStartTime`
and `SessionEndTime` default to "00:00:00", meaning the session will not
be automatically started and stopped. The `HeartBtInt` (heartbeat
interval) defaults to 30 seconds.
==== Minimal Initiator Configuration Example
----
[SESSION]
ConnectionType=initiator
BeginString=FIX.4.4
SenderCompID=YOUR_SENDER
TargetCompID=YOUR_TARGET
----
=== Using the InOut Message Exchange Pattern
Although the FIX protocol is event-driven and asynchronous, there are
specific pairs of messages
that represent a request-reply message exchange. To use an InOut
exchange pattern, there should
be a single request message and single reply message to the request.
Examples include an
OrderStatusRequest message and UserRequest.
==== Implementing InOut Exchanges for Consumers
Add `exchangePattern=InOut` to the QuickFIX/J endpoint URI. The
`MessageOrderStatusService` in
the example below is a bean with a synchronous service method. The
method returns the response
to the request (an ExecutionReport in this case) which is then sent back
to the requestor session.
[tabs]
====
Java::
+
[source,java]
----
from("quickfix:examples/inprocess.qf.cfg?sessionID=FIX.4.2:MARKET->TRADER&exchangePattern=InOut")
.filter(header(QuickfixjEndpoint.MESSAGE_TYPE_KEY).isEqualTo(MsgType.ORDER_STATUS_REQUEST))
.bean(new MarketOrderStatusService());
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: quickfix:examples/inprocess.qf.cfg
parameters:
sessionID: "FIX.4.2:MARKET->TRADER"
exchangePattern: InOut
steps:
- filter:
expression:
simple:
expression: "${header.MessageType} == 'H'"
steps:
- bean:
beanType: com.example.MarketOrderStatusService
----
====
In YAML, the headers are written by name: `MessageType` is `QuickfixjEndpoint.MESSAGE_TYPE_KEY`, and the type of an
OrderStatusRequest is `H`.
The reply is always sent on the session the request was received on.
Changing the `SessionID` header while routing does not change where the
reply goes. To send a message to another session, use a QuickFIX/J
producer endpoint with the `sessionID` option.
==== Implementing InOut Exchanges for Producers
For producers, sending a message will block until a reply is received or
a timeout occurs. There
is no standard way to correlate reply messages in FIX. Therefore, a
correlation criteria must be
defined for each type of InOut exchange. The correlation criteria and
timeout can be specified
using `Exchange` properties.
[width="100%",cols="60%,10%,20%,10%",options="header",]
|=======================================================================
|Description |Key String |Key Constant |Default
|Correlation Criteria |`CorrelationCriteria`
|`QuickfixjProducer.CORRELATION_CRITERIA_KEY` |None
|Correlation Timeout in Milliseconds |`CorrelationTimeout`
|`QuickfixjProducer.CORRELATION_TIMEOUT_KEY` |1000
|=======================================================================
The correlation criteria is defined with a `MessagePredicate` object.
The following example will treat
a FIX `ExecutionReport` from the specified session where the transaction
type is STATUS and the Order ID
matches our request. The session ID should be for the __requestor__, the
sender and target CompID fields
will be reversed when looking for the reply.
._Java-only: programmatic correlation criteria setup using QuickFIX/J API_
[source,java]
----
exchange.setProperty(QuickfixjProducer.CORRELATION_CRITERIA_KEY,
new MessagePredicate(new SessionID(sessionID), MsgType.EXECUTION_REPORT)
.withField(ExecTransType.FIELD, Integer.toString(ExecTransType.STATUS))
.withField(OrderID.FIELD, request.getString(OrderID.FIELD)));
----
=== Spring Configuration
The QuickFIX/J component includes a Spring `FactoryBean` for configuring
the session settings within a Spring context. A type converter for
QuickFIX/J session ID strings is also included. The following example
shows a simple configuration of an acceptor and initiator session with
default settings for both sessions.
._XML-only: Spring XML configuration with QuickFIX/J component and session settings_
[source,xml]
----
<!-- camel route -->
<camelContext xmlns="http://camel.apache.org/schema/spring" id="quickfixjContext">
<route>
<from uri="quickfix:example"/>
<filter>
<simple>${in.header.EventCategory} == 'AppMessageReceived'</simple>
<to uri="log:test"/>
</filter>
</route>
</camelContext>
<!-- quickfix component -->
<bean id="quickfix" class="org.apache.camel.component.quickfixj.QuickfixjComponent">
<property name="engineSettings">
<util:map>
<entry key="quickfix:example" value-ref="quickfixjSettings"/>
</util:map>
</property>
<property name="messageFactory">
<bean class="org.apache.camel.component.quickfixj.QuickfixjSpringTest.CustomMessageFactory"/>
</property>
</bean>
<!-- quickfix settings -->
<bean id="quickfixjSettings" class="org.apache.camel.component.quickfixj.QuickfixjSettingsFactory">
<property name="defaultSettings">
<util:map>
<entry key="SocketConnectProtocol" value="VM_PIPE"/>
<entry key="SocketAcceptProtocol" value="VM_PIPE"/>
<entry key="UseDataDictionary" value="N"/>
</util:map>
</property>
<property name="sessionSettings">
<util:map>
<entry key="FIX.4.2:INITIATOR->ACCEPTOR">
<util:map>
<entry key="ConnectionType" value="initiator"/>
<entry key="SocketConnectHost" value="localhost"/>
<entry key="SocketConnectPort" value="5000"/>
</util:map>
</entry>
<entry key="FIX.4.2:ACCEPTOR->INITIATOR">
<util:map>
<entry key="ConnectionType" value="acceptor"/>
<entry key="SocketAcceptPort" value="5000"/>
</util:map>
</entry>
</util:map>
</property>
</bean>
----
The QuickFIX/J component includes a `QuickfixjConfiguration` class for
configuring the session settings. A type converter for QuickFIX/J
session ID strings is also included. The following example shows a
simple configuration of an acceptor and initiator session with default
settings for both sessions.
[source,xml]
----
include::{examplesdir}/components/camel-quickfix/src/test/resources/org/apache/camel/component/quickfixj/QuickfixjSpringTest-context.xml[tags=e1]
----
=== Exception handling
QuickFIX/J behavior can be modified if certain exceptions are thrown
during processing of a message. If a `RejectLogon` exception is thrown
while processing an incoming logon administrative message, then the
logon will be rejected.
Normally, QuickFIX/J handles the logon process automatically. However,
sometimes an outgoing logon message must be modified to include
credentials required by a FIX counterparty. If the FIX logon message
body is modified when sending a logon message
(`EventCategory=AdminMessageSent` the modified message will be sent to
the counterparty. It is important that the outgoing logon message is
being processed __synchronously__. If it is processed asynchronously (on
another thread), the FIX engine will immediately send the unmodified
outgoing message when its callback method returns.
=== FIX Sequence Number Management
If an application exception is thrown during _synchronous_ exchange
processing, this will cause QuickFIX/J to not increment incoming FIX
message sequence numbers and will cause a resend of the counterparty
message. This FIX protocol behavior is primarily intended to handle
_transport_ errors rather than application errors. There are risks
associated with using this mechanism to handle application errors. The
primary risk is that the message will repeatedly cause application
errors each time it's re-received. A better solution is to persist the
incoming message (database, JMS queue) immediately before processing it.
This also allows the application to process messages asynchronously
without losing messages when errors occur.
Although it's possible to send messages to a FIX session before it's
logged on (the messages will be sent at logon time), it is usually a
better practice to wait until the session is logged on. This eliminates
the required sequence number resynchronization steps at logon. Waiting
for session logon can be done by setting up a route that processes the
`SessionLogon` event category and signals the application to start
sending messages.
See the FIX protocol specifications and the QuickFIX/J documentation for
more details about FIX sequence number management.
== Examples
=== Route Examples
Several examples are included in the QuickFIX/J component source code
(test subdirectories). One of these examples implements a trivial trade
execution simulation. The example defines an application component that
uses the URI scheme "trade-executor".
The following route receives messages for the trade executor session and
passes application messages to the trade executor component.
[tabs]
====
Java::
+
[source,java]
----
from("quickfix:examples/inprocess.qf.cfg?sessionID=FIX.4.2:MARKET->TRADER").
filter(header(QuickfixjEndpoint.EVENT_CATEGORY_KEY).isEqualTo(QuickfixjEventCategory.AppMessageReceived)).
to("trade-executor:market");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: quickfix:examples/inprocess.qf.cfg
parameters:
sessionID: "FIX.4.2:MARKET->TRADER"
steps:
- filter:
expression:
simple:
expression: "${header.EventCategory} == 'AppMessageReceived'"
steps:
- to:
uri: trade-executor:market
----
====
The trade executor component generates messages that are routed back to
the trade session. The session ID must be set in the FIX message itself
since no session ID is specified in the endpoint URI.
[tabs]
====
Java::
+
[source,java]
----
from("trade-executor:market").to("quickfix:examples/inprocess.qf.cfg");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: trade-executor:market
steps:
- to:
uri: quickfix:examples/inprocess.qf.cfg
----
====
The trader session consumes execution report messages from the market
and processes them.
[tabs]
====
Java::
+
[source,java]
----
from("quickfix:examples/inprocess.qf.cfg?sessionID=FIX.4.2:TRADER->MARKET").
filter(header(QuickfixjEndpoint.MESSAGE_TYPE_KEY).isEqualTo(MsgType.EXECUTION_REPORT)).
bean(new MyTradeExecutionProcessor());
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: quickfix:examples/inprocess.qf.cfg
parameters:
sessionID: "FIX.4.2:TRADER->MARKET"
steps:
- filter:
expression:
simple:
expression: "${header.MessageType} == '8'"
steps:
- bean:
beanType: com.example.MyTradeExecutionProcessor
----
====
The type of an ExecutionReport is `8`.
=== Additional Examples
The source code contains an example called `RequestReplyExample` that
demonstrates the InOut exchanges
for a consumer and producer. This example creates a simple HTTP server
endpoint that accepts order
status requests. The HTTP request is converted to a FIX
`OrderStatusRequestMessage`, is augmented with a
correlation criteria, and is then routed to a quickfix endpoint. The
response is then converted to a
JSON-formatted string and sent back to the HTTP server endpoint to be
provided as the web response.