Chapter 28. Implementing Custom Services

Custom services must be implemented in Java as implementations of the ServiceBlox Handler interface. The Handler interface is similar to the standard HttpServlet class.

28.1. Custom ProtoBuf Services

Custom ProtoBuf services have a ProtoBuf interface, but process the JSON or ProtoBuf messages in a different way than by importing them straight into a LogicBlox workspace, as the normal ProtoBuf services do. A few abstractions are available to help with the implementation of such services.

General Custom ProtoBuf Services

The ProtoBufHandler class helps with the input and output aspects of protobuf services. It was written with no assumptions about what is done with the messages. This class implements support for gzip compression and for handling JSON-formatted messages. It also logs requests and responses based on the configuration of the server, and handles error reporting of incorrect messages.

All ProtoBuf services should use this abstraction.

Subclasses of ProtoBufHandler must implement the method handle(Exchange, ProtoBufExchange). The ProtoBufExchange class is used to manage the parsing of the request message and communication of the response message. The goal of the ProtoBufExchange class is to make sure that messages do not get parsed repeatedly. The subclass of ProtoBufHandler can obtain the request message using protoExchange.getRequestMessage(). In return, the subclass is required to set the response message on the ProtoBufExchange. The response can be set in two ways:

protoExchange.setResponseMessage(msg)
protoExchange.setResponseBytes(bytes)

If implementations work with Message objects, then the preferred way of setting the response is via setResponseMessage, because this will avoid having to parse the bytes again in case a JSON response is needed, or if the message has to be logged. The setResponseBytes variant is preferred if subclasses do only a binary serialization of the message, since this will avoid parsing the message when it does not have to be logged and the response is not formatted as a JSON message.

By default, all Message objects are instances of DynamicMessage. The DynamicMessage objects are created using the descriptors that are in the workspace. This means that the message cannot be cast to classes generated by the ProtoBuf compiler (protoc). To address this, implementations can override two more methods on ProtoBufHandler:

protected Message.Builder getRequestBuilder()
protected Message.Builder getResponseBuilder()

This will help in the performance of the service, but it will also allow the subclass to cast messages to the generated message classes.

ProtoBuf Services using ConnectBlox

AbstractProtoBufHandler, which extends ProtoBufHandler, implements support for ProtoBuf services that are implemented by executing ConnectBlox requests. The subclasses determine what actual ConnectBlox requests to execute. This abstraction helps with the correct execution of ConnectBlox requests, handling of errors that might be triggered by the ConnectBlox request, and instrumenting ConnectBlox requests to handle correlation with database logs and monitoring predicate changes. Implementations based on AbstractProtoBufHandler must implement two methods: buildTransaction, to construct the ConnectBlox transaction to execute, and buildResponse, to extract a ProtoBuf response from a ConnectBlox response.

ProtoBuf services that use ConnectBlox should use this abstraction.