Loading... (0%)

Building a request-response API

23 September 2015

This article will discuss how to build a real-time request-response API using ClearConnect.

Scenario

An example scenario that we will use is an electronic card checking system, such as one used on many undergrounds. There are many terminals controlling access to the underground and each terminal needs to scan a card, query a central system for details and then determine whether the card is valid for entry. In this article we will

  1. Work through defining the API used by the terminals to query the credentials of a scanned card.
  2. Implement the API using ClearConnect.
  3. Define the skeleton of the service that supports the API (we will not actually be building the full card checking system).

The diagram below illustrates the scenario

scenario

The API

The API is quite simple, we will have one method that is used to lookup the credentials of a card and an object that represents the card credentials:

public interface ICardTerminal
{
    ICardCredentials getCredentials(long cardId, long cardTerminalId);
}

public interface ICardCredentials extends Serializable
{
    double getCredit();
    boolean isValid();
}

 

Implementing the API

This is the code that provides the API implementation.

public class CardTerminal implements ICardTerminal
{
    final IPlatformRegistryAgent agent;
    final IPlatformServiceProxy serviceProxy;

    public CardTerminal(String registryHostOrIp, int registryTcpPort) throws IOException
    {
        // create the agent to connect to the ClearConnect platform
        agent = new PlatformRegistryAgent("TerminalAgent", new EndPointAddress(registryHostOrIp, registryTcpPort));
        // this is the proxy to the service that provides the RPC to get the card credentials
        serviceProxy = agent.getPlatformServiceProxy("CardTerminalService");
    }

    @Override
    public ICardCredentials getCredentials(long cardId, long cardTerminalId) throws TimeOutException,
        ExecutionException
    {
        final IValue rpcResult =
            PlatformUtils.executeRpc(serviceProxy, 5000, "getCredentials", LongValue.valueOf(cardId),
                LongValue.valueOf(cardTerminalId));
        return BlobValue.fromBlob(rpcResult);
    }
}

 

As you can see, with very little code the API (albeit a single method API) has been implemented for clients to call. Next we look at the server-side.

public class CardTerminalService
{
    final IPlatformRegistryAgent agent;

    public CardTerminalService(String registryHostOrIp, int registryTcpPort) throws IOException
    {
        // create the agent to connect to the ClearConnect platform
        agent = new PlatformRegistryAgent("TerminalAgent", new EndPointAddress(registryHostOrIp, registryTcpPort));
        // this is the service that provides the RPC to get the card credentials
        agent.createPlatformServiceInstance("CardTerminalService", "primary", TcpChannelUtils.LOCALHOST_IP,
            WireProtocolEnum.STRING, RedundancyModeEnum.FAULT_TOLERANT);

        final IPlatformServiceInstance service = agent.getPlatformServiceInstance("CardTerminalService", "primary");

        // this is the handler that will perform the RPC logic
        IRpcExecutionHandler getCredentialsHandler = new IRpcExecutionHandler()
        {
            @Override
            public IValue execute(IValue... args) throws TimeOutException, ExecutionException
            {
                long cardId = args[0].longValue();
                long terminalId = args[1].longValue();

                ICardCredentials result = null;
                // do the work to lookup the card credentials

                return BlobValue.toBlob(result);
            }
        };
        String[] argNames = new String[] { "cardId", "terminalId" };
        TypeEnum[] argTypes = new TypeEnum[] { TypeEnum.LONG, TypeEnum.LONG };

        // this publishes the RPC and makes it available for any CardTerminal clients
        service.publishRPC(new RpcInstance(getCredentialsHandler, TypeEnum.BLOB, "getCredentialsHandler", argNames,
            argTypes));
    }
}

 

What about threading?

ClearConnect manages a pool of threads dedicated for running RPC handler code. The number is fixed and scales with the number of available CPUs. This can be overridden using the system property dataFission.rpcThreadCount=[number of threads]

Summary

This article has shown how a request-response API can be implemented using the ClearConnect platform. The RPC mechanics are simple to use and provide a very transparent manner for writing logic that needs to be invoked remotely.

Ramon Servadei - post author

Ramon is a core architecture developer of the ClearConnect platform and has over 15 years experience designing and maintaining real-time data distribution systems.