10. Service Status Detection
This chapter describes a mechanism called Service Status Detection, as well as the Service Group API that clients use to access this functionality.
Clients, in order to interact with services registered on the site, must know the service’s interface, which is indicated by the two main properties of the site: Service Type and Contract Author. These properties are static and never change until the owner does it manually. But there are a number of additional service properties that may change over time and that clients need to be aware of. These are the version of the service’s primary API, hostname, service ID, and online/offline status. The API version may change with software updates. The hostname can be changed by the owner. The service ID never changes for a given service instance, but the list of services on a multi-service site can change. Finally, the online/offline status of the service can change at any time. Clients, in order to make a request to the service, must know some of these features in advance. The platform’s ability to provide clients with access to the service status is known as Service Status Detection. Softnet uses a dynamic structure called Service Group to implement this functionality. Hosted on the site, this structure contains a record for each service with properties necessary for clients, including the online/offline status. If the site is single-service, the Service Group is trivial and always contains one record for the only service. It is called a single-service group. And if the site is multi-service, then the Service Group is multi-service, accordingly.
As with User Membership, when a client application hosted on a device connects to the site, Softnet loads the Service Group into the application and keeps it synchronized with the site. Any change to the service properties made on the site is immediately propagated to the application’s copy. The Service Group also keeps track of the online/offline status of the services.
The application’s copy of the Service Group contains RemoteService objects – one for each remote service. RemoteService is an interface with the following members:
public interface RemoteService {
long getId();
String getHostname();
String getVersion();
boolean isOnline();
boolean isRemoved();
}
The first method, getId, returns the service ID of the service. It is mostly used by Softnet internally. If the service group is single-service, this method always returns 0. The getHostname method returns the service’s hostname. The getVersion method returns the version of the service’s primary API. It has already been discussed in the chapter “Client Endpoint”. isOnline returns the online/offline status. Use it to check the online status of the service before making a request to it.
The RemoteService object is used in remote service request methods as the destination. For example, the method for making an RPC call has the following parameters:
public void call(
RemoteService remoteService,
RemoteProcedure remoteProcedure,
RPCResponseHandler responseHandler,
Object attachment)
And the following is a method for establishing a TCP connection:
public void tcpConnect(
RemoteService remoteService,
int virtualPort,
TCPOptions tcpOptions,
TCPResponseHandler responseHandler,
Object attachment)
Both methods have a RemoteService object as the first parameter. Note that at the moment of making the request, the service is supposed to be online. The method RemoteService.isOnline allows the app to check this status in advance. The checking is not required, if a client makes a request on receiving a ServiceOnline event from the platform. The “Interface ClientEventListener” section gives more details on this topic.
A single-service group contains only one object of the type RemoteService, while a multi-service group contains multiple objects – one for each remote service. This is where ClientEndpoint and ClientSEndpoint differ from each other. Let’s see those differences. The following is a view of the ClientEndpoint class that shows signatures of the methods for accessing elements of a multi-service group:
public class ClientEndpoint {
public RemoteService findService(long serviceId)
public RemoteService findService(String hostname)
public RemoteService[] getServices()
// the rest of the members are omitted
}
The class provides methods to find a RemoteService object by ID or by hostname. And the getServices method returns the entire list of objects.
The ClientSEndpoint class is derived from ClientEndpoint. It has two more methods for making manipulations with the only RemoteService object easier. Below is the class with the method signatures:
public class ClientSEndpoint extends ClientEndpoint {
public boolean isServiceOnline()
public RemoteService getService()
// the rest of the members are omitted
}
Since this is a single-service endpoint class, the getService method returns the only RemoteService object. If you only need to check its online status, you can call the isServiceOnline method. As for three methods of the parent class, the way they work with a single-service group is trivial. The findService method that finds an object by the service ID returns the only RemoteService object if the argument is 0, otherwise it returns null; the findService overload that finds an object by the hostname returns the only RemoteService object if the argument’s value is equal to the service’s hostname; the method getServices always returns an array of a single item, that is, the only RemoteService object.
The ClientSEndpoint class also overloads all parent methods for making requests to the remote services. The overloaded methods lack the first parameter of type RemoteService. For example, the overloaded call method has the following view:
public void call(
RemoteProcedure remoteProcedure,
RPCResponseHandler responseHandler,
Object attachment)
And the tcpConnect method also lack the first parameter:
public void tcpConnect(
int virtualPort,
TCPOptions tcpOptions,
TCPResponseHandler responseHandler,
Object attachment)
In your code, if you have a reference of type ClientEndpoint and you want to cast it to ClientSEndpoint in order to use its overloaded methods, check the return value of the isSingleService method and if it is true, make the type casting:
if(clientEndpoint.isSingleService()) {
ClientSEndpoint clientSEndpoint = (ClientSEndpoint)clientEndpoint;
clientSEndpoint.call(remoteProcedure, responseHandler);
// the rest of your code
}
If you do not want to make the type casting, there is a simple way to use a reference of type ClientEndpoint to work with a single-service endpoint. As in the previous example, you can check whether the reference points to a single-service endpoint by calling isSingleService and if it is true, you can get the only RemoteService object by calling the findService method with 0 as an argument. Then you can use the RemoteService object as the first argument in the request methods. For example:
if(clientEndpoint.isSingleService()) {
RemoteService remoteService = clientEndpoint.findService(0);
clientEndpoint.call(remoteService, remoteProcedure, responseHandler);
// the rest of your code
}