Serving blotter data with the Java Blotter API

The Java Blotter API (package com.caplin.datasource.blotter) provides a framework for the provision of data to front-end blotter components.

This API should be used in preference to the blotter API included in the Trading DataSource API (com.caplin.trading), the use of which is now deprecated.

Getting started

To get started building an integration adapter that provides data for a blotter, create a new adapter using the Blotter Adapter Template in the Caplin Project Templates hosted on GitHub. For more information, see Caplin Project Templates.

Features and concepts

This section provides an introduction to terms used throughout this page.

Blotters

A blotter is a record of trades and market orders, either live or completed, over a period of time. The time period is commonly a session, a day, or a specific historical period, such as the previous thirty days.

As an example of common blotter types in a trading application, the standard set of four blotters from FX Professional is shown below:

BlotterFXMotif

The blotters are contrasted in the table below. The differences between the blotters will affect how you implement the provision of their data.

Period Initial state Live feed Description

Activity

Client session

Empty

Yes

Displays a live feed of the user’s trades completed in the current browsing session.

The price of a trade in this blotter is the requested price, which may be different to the execution price.

Execution

Intraday

Trades completed so far

Yes

Displays a live feed of the user’s trades executed today.

The price of a trade in this blotter is the execution price, which may be different to the requested price.

Historic

Previous 7 days

Trades completed over the previous 7 days

No

Displays a record of the user’s trades executed during the previous seven days.

The price of a trade in this blotter is the execution price, which may be different to the requested price.

Order

N/A

All open orders

Yes

The user’s open orders

Channels

The Blotter API uses channels to provide blotter data to each subscribing user.

A channel is a private subscription between a user and the Caplin Platform. Channels are used for messaging (two-way communication), and for the provision of records to a single user or group of users. The Blotter Integration API uses channels to ensure that while every user subscribes to the same blotter subject, each user receives only the blotter items that they are permitted to see.

Channels are created by configuring Liberator to map a subject request to a new subject that contains either the subscribing user’s username or session identifier. The new subject is unique, and private, to that user or session. This private subject is only accessible through the mapping process; it is not possible for one user to subscribe to another user’s private subject.

Your integration adapter will receive blotter subscription requests in their mapped form. When you instantiate a BlotterProvider, you must pass the constructor two strings that describe the naming format of the blotter’s subjects.

To learn more about channels, see Channels.

To learn more about mapping one subject to another, see Liberator: Object mapping and Permissioning: Subject mapping.

Namespaces

In the Blotter Integration API, the word 'namespace' is used when referring to a string that describes the format of a blotter subjects or blotter item subject.

Load balancing and source affinity

Blotters that are served by a load-balanced set of adapters may require the use of the source affinity load-balancing option.

Adapters in a load-balanced set do not share their state. If the subjects in a blotter’s container have their origin in an adapter event rather than a backend source, then the blotter’s container and items will only be available on one adapter in the load balanced set. An example would be an Activity Blotter that records a user’s trading activity; the blotter container and items will only be available on the Trading Adapter instance that the user’s trade channel is subscribed to.

Source affinity ensures that all of a user’s channel subscriptions directed to a load-balanced set of adapters will be served by the same adapter in the set.

Configuring the Caplin Platform

To configure a blotter on the Caplin Platform, you must perform the following tasks:

Configure object mapping

In order to guarantee that blotters and their contents are private to each requesting user, all users subscribe to a common subject for the blotter, and Liberator is configured to map each request to an internal subject that includes the username of the requesting user.

As an example, here is the configuration required to map the subject for FX Suite’s Order Blotter to a subject with the user’s username appended to the end of the blotter’s subject:

object-map   /PRIVATE/FX/BLOTTER/ORDER   /PRIVATE/FX/BLOTTER/ORDER/%u

In the excerpt above, '%u' is a placeholder for the user’s username.

No mapping is usually required for blotter items, which are usually subscribed to via the blotter’s container and are not available outside of that container.

For more details on object-map syntax, see Liberator Object Configuration: object-map.

For more examples of object mapping in FX Motif, see Messages in the FX Motif: Subjects.

Configure a data service

Use the add-data-service configuration directive to configure Liberator to route requests for the blotter and its items to your integration adapter. The mapped container and blotter item subjects require a data service must be associated with a data service in order to populate them with data from an Integration Adapter. Use the include-pattern configuration option of the add-data-service configuration item to match the subject names of the blotter’s container and blotter items.

The example below shows an excerpt from a data-service that provides for an FX Motif Activity Blotter:

add-data-service
    service-name        OrderDataService
    include-pattern     "^/PRIVATE/FX/BLOTTER/ORDER/[^/]+"
    include-pattern     "^/FILTER/PRIVATE/FX/BLOTTER/ORDER/[^/]+"
    include-pattern     "^/PRIVATE/FX/BLOTTERITEM/[^/]+"
    .
    .
    .
end-data-service

To control the sensitivity of the blotter to network disconnection, change the discard-timeout for the blotter container’s data service.

For more information about data services, see Data Services and Data Services Configuration.

Configure blotter-item fields

This step is not required if you configure a blotter’s BlotterProvider to use generic messages instead of type 1 messages. For more information on how to do this, see Configuring a BlotterProvider below.

Include an add-field declaration to /Blade/blade_config/fields.conf for each field used in a blotter provided by your Integration Adapter. You only need one add-field declaration per field.

The FX Integration API includes configuration files for all the fields required by FX Professional blotters.

Configure permissioning

Users will need permission to read their blotter containers, and permission to read the items within those containers.

Blotter containers are permissioned using permissioning directives. Blotter items are permissioned, whenever possible, by using the auto-permit flag of their blotter container. You may use the auto-permit flag when blotter items require the same access privileges as the container that hosts them. Setting a container’s auto-permit flag reduces the load on Liberator by indicating that Liberator may waive permission checks for all items that are subscribed to via the container. For more information on the auto-permit flag, see BlotterConfiguration.setAutoPermit(boolean).

The example permissioning directives in this section are intended for use with the Permissioning Integration API, which supplies permissioning directives to Caplin’s Permissioning Auth Module. If you are using a custom Liberator auth module, consult the documentation for your auth module for instructions on how to grant permissions to containers and items.

Permissioning example

The following table shows the permissioning directives required for the FX Suite’s Order Blotter (/PRIVATE/FX/BLOTTER/ORDER). In this example, the integration adapter that publishes individual order blotters expects a username to be appended to the end of the blotter subject.

When writing the regular expression for a permissioning product-set, always include a character or a regular-expression anchor after a '%u' placeholder for a username.
Permissions for FX Suite’s Order Blotter
Product Set Permission namespace Action Authorisation Notes

/PRIVATE/FX/BLOTTER/ORDER/%u$

-

VIEW

ALLOW

Required.

/FILTER/PRIVATE/FX/BLOTTER/ORDER/%u\?.*

-

VIEW

ALLOW

Required, if you configure Transformer’s Refiner module to filter Order Blotter items.

Instantiating a BlotterProvider

The BlotterProvider class is your entry point to the Blotter API. Each type of blotter provided by your adapter requires its own instance of the BlotterProvider class. For example, if your integration adapter provides data for the Activity, Execution, Historic, and Order blotters in FX Professional, you will need four BlotterProvider instances: one for each type of blotter.

The BlotterProvider constructor requires three objects:

  • DataSource

    The DataSource object created during initialistation of your integration adapter.

  • BlotterConfiguration

    The BlotterConfiguration object specifies the blotter’s configuration. See Configuring a BlotterProvider, below.

  • BlotterApplicationListener

    Methods in this object are called when a blotter channel is opened and when it is closed. See BlotterApplicationListener, below.

Configuring a BlotterProvider

Each BlotterProvider you instantiate requires its own instance of BlotterConfiguration.

BlotterConfiguration constructor arguments
Argument Type Example Value Notes

blotterIdentifier

String

Order

A unique string that identifies your blotter. This string will be used in logs.

channelNamespace

String

/PRIVATE/FX/BLOTTER/ORDER/%u

The format of the blotter-container’s subject.

itemNamespace

String

/PRIVATE/FX/BLOTTERITEM/%i

The format of blotter-item subjects.

The channelNamespace and itemNamespace strings accept the following placeholders:

  • %u — the user’s username.

  • %U — the user’s session identifer.

  • %i — a blotter item identifer. Blotter item identifiers are prefixed with the blotter’s identifier.

The BlotterConfiguration object offers a range of additional configuration options. Enabling the following two options is recommended:

Recommended BlotterConfiguration options
Default Notes

setAutoPermit

false

Set to true to disable permission checking for blotter container items. This is a recommended performance optimisation when the blotter container can be trusted to contain only items the user is permitted to access.

setUseGenericMessages

false

Set to true to use generic messages instead of type 1 messages. If you use generic messages, then you do not need to configure fields.conf for blotter item fields.

Other blotter configuration options are used in the code examples towards the end of this page. See Examples.

Overview of the API’s interfaces and classes

This section provides an overview of following classes and interfaces:

Core model

There are three core interfaces in the Blotter Integration API:

Core interfaces
Notes

BlotterProvider

A blotter type. For example, an Activity Blotter.

Requires a BlotterConfiguration object.

BlotterChannel

A blotter instance. For example, the Activity Blotter instance for user bob@examplebank.com.

BlotterItem

An item in a blotter instance. For example, an item in the Activity Blotter instance for user bob@examplebank.com.

BlotterProvider

The BlotterProvider class is the entry point to the Blotter Integration API. One BlotterProvider must be instantiated for each type of blotter provided by your Integration Adapter.

The BlotterProvider class has two responsibilities:

  • Manage the DataProvider for the blotter’s container and the DataProvider for the blotter’s items

  • Instantiate and store a BlotterChannel instance for each subscribing user’s blotter. The BlotterChannel instances are passed to your code via events. It is your responsibility to manage your own store of BlotterChannel objects; the BlotterProvider’s internal store is not exposed through the API. BlotterChannel instances are stored by the BlotterProvider until the Integration Adapter is restarted, or the blotter’s container on Transformer is discarded.

BlotterChannel

The BlotterChannel class represents a user’s subscription to the blotter. It provides methods for the addition and removal of blotter items.

When a BlotterItem object is passed to BlotterChannel.sendBlotterItem or BlotterChannel.sendBlotterItems, the BlotterChannel instance performs the following two actions:

  1. Writes the subject of the BlotterItem to the blotter’s container

  2. Caches the BlotterItem’s data. This data will be used to respond to subsequent requests for the blotter item. A BlotterChannel’s cache of BlotterItem data persists for the lifetime of the BlotterChannel instance.

You do not instantiate a BlotterChannel. Objects of this class are created and managed by the BlotterProvider, and they enter your application code via the following three event handlers:

The event handlers are your only access to BlotterChannel instances; the BlotterProvider class does not expose methods to request a BlotterChannel for a specific user. For your Integration Adapter to have ready access to BlotterChannel instances, you must maintain your own store of BlotterChannel instances in parallel to the BlotterProvider’s.

The lifecycle of a BlotterChannel instance is outlined below, with programming tasks listed for each stage.

  1. Channel opened (BlotterApplicationListener.blotterChannelOpened)

    1. Send existing blotter items (if any) to the BlotterChannel instance. For example, for an Execution Blotter you would send the user’s executed intraday trades

    2. Register a BlotterChannelListener with the BlotterChannel instance to handle requests for blotter items that are not in the BlotterChannel’s cache. In the majority of blotter designs, the handler should simply call BlotterChannel.sendBlotterItemNotFound. In some blotter designs, the adapter should query the backend data source and send the item to the channel. See the third example on this page, Execution Blotter, for how an Historical Adapter can be programmed to respond to requests for blotter items that were originally published by a Trade Adapter.

    3. Store the BlotterChannel instance, keyed by username.

  2. Manage the channel’s contents over the lifetime of the channel

    1. When a workflow event occurs that should be recorded in the blotter, retrieve the user’s BlotterChannel instance from your BlotterChannel store, and add, update or remove blotter items.

  3. Channel closed (BlotterApplicationListener.blotterChannelClosed)

    1. Remove the user’s BlotterChannel instance from your BlotterChannel store.

If a user disconnects and reconnects within the discard timeout of the blotter container, then the BlotterApplicationListener.blotterChannelClosed event will not fire and the user’s container and BlotterChannel instance will be reused. To control the sensitivity of the blotter to network disconnection, change the discard-timeout for the blotter container’s data service.

BlotterItem

The BlotterItem class represents data to send to a BlotterChannel instance.

When a blotter item is send over a blotter channel, the blotter item’s data is cached by the channel for automatic response to requests for the item. If the blotter channel receives a request for a blotter item that is not in its cache, the BlotterChannelListener.onBlotterItemRequest event is raised. As of version 6.2.1 of the Caplin Integration Suite (CIS), blotter items are cached by value; prior to version 6.2.1, blotter items were cached by reference. If using a version of CIS prior to 6.2.1, do not change a blotter item’s fields after sending it to a channel.

Configuration

BlotterConfiguration

The BlotterConfiguration class comprises all the configuration settings required to instantiate a BlotterProvider.

Event listeners

BlotterApplicationListener

An instance of a BlotterApplicationListener is required to instantiate a BlotterProvider. This interface has two methods:

  • blotterChannelOpened: called after the BlotterProvider has created a new BlotterChannel and added it to its internal store. Use this event to register a BlotterChannelListener with the BlotterChannel and store a reference to the BlotterChannel for future use.

  • blotterChannelClosed: called after the BlotterProvider has closed a BlotterChannel and removed it from its internal store, following a discard of the blotter’s container by Liberator. Use this event to clean up any references you hold to the BlotterChannel.

If a browser disconnects and reconnects within the active-discard timeout of Liberator and Transformer, the user’s blotter container will still exist on Liberator and Transformer, and so the BlotterChannel object cached by the blotter’s BlotterProvider will still be available. In such a scenario, the blotterChannelOpened event will not refire, even though the client has disconnected and reconnected.

BlotterChannelListener

A BlotterChannelListener should be registered with each BlotterChannel instance delivered to your code via BlotterApplicationListener.blotterChannelOpened. This interface has one method:

  • onBlotterItemRequest: called when a requested blotter item is not found in a BlotterChannel’s cache. In the majority of blotter designs, the handler should simply call BlotterChannel.sendBlotterItemNotFound. In some blotter designs, the adapter should query the backend data source and send the item to the channel.

Examples

This section contains examples of three blotter designs. The three designs all use variants of the template blotter-provider code below.

import com.caplin.datasource.DataSource;
import com.caplin.datasource.blotter.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExampleBlotterProvider
{
    public static final String BLOTTER_NAME = "ExampleBlotter";
    public static final String CHANNEL_NAMESPACE = "/PRIVATE/%u/EXAMPLEBLOTTER";
    public static final String ITEM_NAMESPACE = "/PRIVATE/%u/EXAMPLEBLOTTERITEM/%i";

    private BlotterProvider provider = null;
    private final Map<String,BlotterChannel> channels = new HashMap<>();

    private BlotterChannelListener channelListener = null;

    /**
     * Constructor
     *
     * @param dataSource An unstarted DataSource
     */
    public ExampleBlotterProvider(final DataSource dataSource)
    {
        final BlotterConfiguration configuration = new BlotterConfiguration(BLOTTER_NAME, CHANNEL_NAMESPACE, ITEM_NAMESPACE);

        // Create the channel listener.
        channelListener = new ExampleBlotterProvider.ChannelListener();

        // Set to 'false' if the blotter's container is written to by
        // multiple adapters and their subjects should be aggregated.
        configuration.setChannelUsingImageFlag(true);

        // Set to 'false' if the data for each blotter item is provided by multiple
        // adapters and the data for each blotter item should be merged.
        configuration.setItemUsingImageFlag(true);

        // Tells the API to use generic objects instead of Type1 records.
        configuration.setUseGenericObjects(true);

        // Configures whether Liberator should automatically allow subscriptions to every Blotter item within a BlotterChannel
        // or it should check the permissions for every BlotterItem. If the DataSource is trusted, it should only send out updates
        // that that user is permissioned for so checking isn't strictly necessary.
        configuration.setAutoPermit(true);

        provider = new BlotterProvider(dataSource, configuration,
                new ExampleBlotterProvider.ApplicationListener());
    }

    /**
     * Retrieves the channel for a specified user's blotter.
     *
     * @param username
     * @return the channel to the specified user's blotter or null if no such channel exists
     */
    public BlotterChannel getBlotterChannel(final String username)
    {
        if (channels.containsKey(username)) {
            return channels.get(username);
        } else {
            return null;
        }
    }

    /**
     * Get the Blotter API version
     *
     * @return Version string
     */
    public String getVersion()
    {
        return provider.getVersion();
    }

    /**
     * Handler for channel creation and discard events
     */
    private class ApplicationListener implements BlotterApplicationListener
    {
        @Override
        public void blotterChannelOpened(final BlotterChannel channel)
        {
            // Add channel listener
            channel.setBlotterChannelListener(channelListener);

            // Send initial items to container
            channel.sendBlotterItems(getInitialContainerLoad(channel.getUsername()));

            // Store channel
            channels.put(channel.getUsername(), channel);
        }

        @Override
        public void blotterChannelClosed(final BlotterChannel channel)
        {
            // Remove channel from store
            channels.remove(channel.getUsername());
        }
    }

    /**
     * Handler for requests for blotter-items not in a BlotterChannel's cache.
     * A cache miss occurs when an adapter receives a request for a blotter item
     * that was added to the blotter container by a different adapter.
     */
    private class ChannelListener implements BlotterChannelListener
    {
        @Override
        public void onBlotterItemRequest(final BlotterChannel channel, final String uniqueId)
        {
            final BlotterItem item = getBlotterItem(uniqueId);
            if (item != null) {
                channel.sendBlotterItem(item);
            } else {
                channel.sendBlotterItemNotFound(uniqueId);
            }
        }
    }

    /**
     * Placeholder method. Query the backend data source and return
     * a list of blotter items to send to the blotter on opening.
     *
     * Typically used by adapters that provide intraday and historical blotters.
     *
     * @return List of BlotterItem objects
     */
    private List getInitialContainerLoad(final String username)
    {
        return new ArrayList();
    }

    /**
     * Placeholder method. Query the backend data source for an
     * individual BlotterItem.
     *
     * Typically used by adapters that serve requests for blotter items added
     * to a blotter container by another adapter.
     *
     * @param uniqueId
     * @return BlotterItem or null
     */
    private BlotterItem getBlotterItem(final String uniqueId)
    {
        return null;
    }
}

This section contains three examples of three different designs:

  • a blotter provided by one adapter

  • a blotter provided by two adapters (aggregation)

  • a blotter provided by two adapters (one adapter provides the container, the other adapter provides the items)

Blotter provided by one adapter

This example is for an activity blotter provided by one adapter.

Configure object mapping

Map the Activity Blotter’s container and records to a private namespace based on the client’s username. Include the following lines of configuration in /Blade/liberator/etc/rttpd.conf.

object-map /PRIVATE/FX/BLOTTER/ACTIVITY   /PRIVATE/%u/FX/BLOTTER/ACTIVITY
object-map /PRIVATE/FX/BLOTTER/ITEM/%1    /PRIVATE/%u/FX/BLOTTER/ITEM/%1

Configure data services

Route the mapped subjects to your Integration Adapter. Include the following lines of configuration in /Blade/liberator/etc/rttpd.conf.

add-data-service
    service-name        ActivityBlotterSvc
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/ACTIVITY"
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/ITEM"

    add-source-group
        required
        add-priority
            label   TradingAdapter
        end-priority
    end-source-group
end-data-service

Write the blotter provider

Base the blotter class on the template code. Only minimal changes are required for this example:

  1. Change the classname to ActivityBlotterProvider

  2. Change the following class constants:

    public static final BLOTTER_NAME = "ActivityBlotter";
    public static final CHANNEL_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/ACTIVITY";
    public static final ITEM_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/ITEM/%i";

Blotter provided by two adapters (aggregation)

This example modifies the Activity Blotter in the first example so that it aggregates blotter items from a Trading Adapter and an Orders Adapter. There is no overlap in provision of blotter items: one adapter provides trade items and the other provides order items.

Configuring data services

Configure data services so that requests for the blotter’s container and items are sent in parallel to the two Integration Adapters. A simple example that illustrates the principle is given below.

add-data-service
    service-name        ActivityBlotterSvc
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/ACTIVITY"
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/ITEM"

    add-source-group
        required
        add-priority
                label   TradingAdapter
        end-priority
    end-source-group

    add-source-group
        required
        add-priority
                label   OrdersAdapter
        end-priority
    end-source-group
end-data-service

Write the blotter providers

Write a blotter provider class for both the trading adapter and the orders adapter. Base the code on the template included at the beginning of this examples section.

Make the following changes to the template code for both blotter provider classes:

  1. Change the classname to ActivityBlotterProvider

  2. Change the following class constants:

    public static final BLOTTER_NAME = "ActivityBlotter";
    public static final CHANNEL_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/ACTIVITY";
    public static final ITEM_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/ITEM/%i";
  3. In the ActivityBlotterProvider constructor, set the image flag for the blotter container’s channel to false. By default, the first subject written to the blotter container by an adapter is written as an 'image' and will reset the container. By disabling the image flag in the blotter code for both adapters, the second adapter to write a subject to the container will not delete the subjects written to the container by the first adapter.

    configuration.setChannelUsingImageFlag(false);
  4. In the ActivityBlotterProvider constructor, confirm that the image flag for the blotter’s items is set to true. By default, the first provision of data for a blotter item by an adapter is provided as an 'image'. It is necessary to disable the blotter-item image flag if data for individual blotter items will be merged from multiple adapters. In the current example, the image flag should remain set to true. Although two adapters provide blotter items for the blotter, trade items are provided exclusively by the trading adapter and order items are provided exclusively by the orders adapter.

    configuration.setItemUsingImageFlag(true);

Blotter provided by two adapters (separate adapters for the container and items)

A good example of this design is an Execution Blotter, which displays a live, intraday history of executed trades. The most efficient design would be to provide the blotter with a live feed from the historical adapter, but not all backend historical sources are able to push live updates to the adapter. The solution is to supplement the data from the historical adapter with a live feed of newly executed trades from the trading adapter.

The table below describes the responsibilities of both adapters:

Adapter responsibilities
Responsibilities

Historical Adapter

Populate the blotter with the subjects of the day’s trades executed so far (intraday history).

Respond to requests for blotter items, including requests for blotter items added to the blotter’s container by the Trading Adapter.

Trading Adapter

Populate the blotter container with the subjects of requested trades.

Data services configuration

Two data services are configured:

  • ExecutionBlotterSvc: provides the Execution Blotter’s container. The container is populated by both the historical adapter and the trading adapter. The historical adapter provides the initial content; the trading adapter provides new content. The subjects listed in the container use the same format as items in the historical blotter (not shown).

  • HistoricalItemSvc: provides blotter items to both the Execution Blotter and the Historical Blotter (not shown).

add-data-service
    service-name        ExecutionBlotterSvc
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/EXECUTION"

    add-source-group
        required
        add-priority
            label   TradingAdapter
        end-priority
    end-source-group

    add-source-group
        required
        add-priority
            label   HistoricalAdapter
        end-priority
    end-source-group
end-data-service

add-data-service
    service-name        HistoricalItemSvc
    include-pattern     "^/PRIVATE/[^/]+/FX/BLOTTER/HISTORIC-ITEM"

    add-source-group
        required
        add-priority
            label  HistoricalAdapter
        end-priority
    end-source-group
end-data-service

Writing the Trading Adapter

Base the code on the template code at the beginning of the examples section.

Make the following changes to the template code:

  1. Change the classname to ExecutionBlotterProvider

  2. Change the following class constants:

    public static final String BLOTTER_NAME = "ExecutionBlotter";
    public static final String CHANNEL_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/EXECUTION";
    public static final String ITEM_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/HISTORIC-ITEM/%i";
  3. In the ExecutionBlotterProvider constructor, set the image flag for the blotter container’s channel to false. By default, the first subject written to the blotter container by an adapter is written as an 'image' and will reset the container. By disabling the image flag in the blotter code for both adapters, the second adapter to write a subject to the container will not delete the subjects written to the container by the first adapter.

    configuration.setChannelUsingImageFlag(false);
  4. In the ExecutionBlotterProvider constructor, confirm that the image flag for the blotter’s items is set to true. By default, the first provision of data for a blotter item by an adapter is provided as an 'image'. It is necessary to disable the blotter-item image flag if data for individual blotter items will be merged from multiple adapters. In the current example, the image flag should remain set to true. Although both adapters add subjects to the blotter’s container, only the Historical Adapter responds to requests for blotter items.

    configuration.setItemUsingImageFlag(true);

Within the main body of code for the Trading Adapter, write the subject of each new trade to the Execution Blotter’s container. This is achieved by sending an empty (no fields) BlotterItem instance to the trading user’s BlotterChannel instance. It does not matter that the BlotterItem is empty; it will never be served. Execution Blotter items have the same subject namespace as Historical Blotter items, and so they are served by the Historical Adapter, not the Trading Adapter.

// Retrieve the channel to the user's Execution Blotter
BlotterChannel channel = executionBlotterProvider.getBlotterChannel(username);

// Create an empty Blotter Item, specifying the unique ID for the item's
// record. Send it to the user's Execution Blotter. This will write the item's
// subject name to the blotter's container.
if (channel != null) {
    BlotterItem item = new BlotterItem(itemId);
    channel.sendBlotterItem(item);
}

Writing the Historical Adapter

Base the code on the template code at the begining of the examples section.

Make the following changes to the template code:

  1. Change the classname to ExecutionBlotterProvider

  2. Change the following class constants:

    public static final String BLOTTER_NAME = "ExecutionBlotter";
    public static final String CHANNEL_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/EXECUTION";
    public static final String ITEM_NAMESPACE = "/PRIVATE/%u/FX/BLOTTER/HISTORIC-ITEM/%i";
  3. In the ExecutionBlotterProvider constructor, set the image flag for the blotter container’s channel to false. By default, the first subject written to the blotter container by an adapter is written as an 'image' and will reset the container. By disabling the image flag in the blotter code for both adapters, the second adapter to write a subject to the container will not delete the subjects written to the container by the first adapter.

    configuration.setChannelUsingImageFlag(false);
  4. In the ExecutionBlotterProvider constructor, confirm that the image flag for the blotter’s items is set to true. By default, the first provision of data for a blotter item by an adapter is provided as an 'image'. It is necessary to disable the blotter-item image flag if data for individual blotter items will be merged from multiple adapters. In the current example, the image flag should remain set to true. Although both adapters add subjects to the blotter’s container, only the Historical Adapter responds to requests for blotter items.

    configuration.setItemUsingImageFlag(true);
  5. Edit the method getInitialContainerLoad. Include code to query the backend historical source for the user’s intraday trading activity, and return a list of blotter items to write to the user’s Execution Blotter. Unlike the blotter items created by the Trading Adapter for the Execution Blotter, these items should contain populated fields.

  6. Edit the method getBlotterItem. Include code to query the backend historical source for the blotter item with the supplied ID. Return a blotter item, populated with details of the trade. This method will be called when the Historical Adapter receives a request for an item added to a blotter’s container by the Trading Adapter.


See also: