A Basic Demo for Beginners #3
Robert-Koifman
started this conversation in
Basic Examples
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
By tradition, demos on a software technology begin with a "Hello World" application. We continue this tradition and start a series of basic examples with a simple greeting application. Guided by this demo, you’ll create a service application that accepts a greeting message and answers with “Hello! I'm a service”. Then you’ll create a client application that sends a “Hello! I'm a client” message to the service and receives the response. To exchange the messages, you'll use the built-in RPC.
When explaining the development steps for this example, I refer to the following guides:
Before getting started
In order to run this example, you should have a Softnet MS account and be in the “Provider” role. For the purpose of learning Softnet Free we offer you a free registration on http://ts.softnet-iot.org/.
You can run this example in any of well-known IDEs including Geany, Eclipse and IntelliJ IDEA. For setting up the endpoint library in your project, see “Setting up the endpoint library”.
The platform has no special requirements for the network infrastructure. The only requirement is that outgoing connections to a specific set of TCP and UDP ports must not be blocked. For details, see Requirements for the network infrastructure.
Creating the service application
First, we go to the http://ts.softnet-iot.org/ and sign in to Softnet MS. Then, we create a new domain and name it “A Basic Demo for Beginners”. A newly created domain contains two built-in users and no sites:
Then, we create a new site in the domain. A newly created site has a status “site blank” and contains a blank service registration with status “service type undefined”:
Now open your favorite Java IDE and create a console application named "Greeter". Add a class named “ServiceApp” and insert the method main into the class. Then, import the following packages:
The softnet.service.ServiceEndpoint class of the platform provides the networking functionality for service applications. It has a static method to create an instance of the class:
The first parameter of the method is an object that implements the SiteStructure interface. ServiceEndpoint has a static method to create the required object:
<serviceType> and <contractAuthor> are the minimum data required to create a SiteStructure object, so the method accepts these two mandatory parameters. Set the Service Type as “Greeter” and the Contract Author as “Softnet Guide”.
The second parameter of the create method is <version>. Assume the service’s API version is “1.0”. The method has two more parameters: <serviceUri> and <password>. Take their values on the site you have created in the beginning:
In my case, I had the following values for the <serviceUri> and <password>:
In real applications, this data might be stored in the application's config file.
At this point your code may look like the following:
Important note! Do not forget to close the service endpoint in the end!
The above code creates the “serviceEndpoint” object through which the application will be performing all network operations. If your host does not support a secure hash algorithm SHA-1, the ServiceEndpoint.create method throws an exception, so enclose the code in a try-catch block. All Softnet exceptions are derived from SoftnetException.
There is a set of the service's state parameters controlled by the platform that you might want to monitor. For each of these parameters, the platform generates an event when its value changes. To intercept these events, ServiceEndpoint has a listener method called addEventListener:
This method accepts an object that implements the ServiceEventListener interface with appropriate event handlers. Instead of implementing all the methods of ServiceEventListener, you can extend an abstract class ServiceEventAdapter which has empty implementations of these methods. In this case, you can just override the methods you need.
This example demonstrates monitoring the service status and the service connectivity status:
The first method, onConnectivityChanged, is called whenever the service’s connectivity changes. It reflects the status of a physical connection with the Softnet server and the result of authentication. After the connection is established, Softnet examines the status of the service and calls the listener’s method onStatusChanged. If your service’s status is <Online>, it is ready to serve clients.
Up to this point we described the standard development steps typical for service apps in the Basic Examples section. And next we will look at how to implement a message exchange using Softnet RPC.
The Application-specific Steps
ServiceEndpoint has a method registerProcedure for registering procedures that clients call remotely:
The first parameter is the procedure’s name that clients use to call it. The second one is an object that implements the RPCRequestHandler interface. And, the third parameter limits the number of concurrent calls to the procedure. If the execution of your procedure is resource intensive, this number is important. However, in a given case you can specify any number greater than 0. The procedure registration code may look like the following:
The RPC-procedure is named as “Hello”. The second parameter is an anonymous class that implements the only method execute of the RPCRequestHandler interface. Let’s consider the method in more detail. Its body is left empty so that you could concentrate on the parameters. The first parameter is <context> of type RequestContext. We do not use this parameter in the example, so we skip it. The second parameter, <parameters>, is an ASN.1 Sequence decoder that contains structured data from the client. In our case, we expect it to contain a welcome message from the client. The procedure fetches it out and prints on the screen. The third parameter, <result>, is an ASN.1 Sequence encoder that allows you to encode the result data in the ASN.1 format and send it back to the client. In our case, the procedure responds to the client with a welcome message. Finally, the last parameter, <error>, allows you to send back structured information about an error that might occur while executing the procedure. In case of an error, don’t forget to return a non-zero value. If the procedure completes without an error, the procedure must return 0.
Let's write the necessary code in the body of the procedure:
Now we just need to write the code for connecting to the Softnet server:
In the end, the "serviceEndpoint" should be closed by calling the close method.
The following is the entire code of the service application:
Now, we can run the application. If the service endpoint establishes connection with the Softnet server, you application will print out something like this:
The meaning of these messages is as follows: on the first connection of the service endpoint, the server constructs the site, and then the server demands the service endpoint to re-establish the connection. When connecting to the server for the second time, the service is assigned the status Online.
The site, which was originally blank, will be constructed in accordance with the "siteStructure" object attached to the "serviceEndpoint". In case of our example, it has the following view:
The platform adds the Owner user to the site by default. Now we can create clients associated with this user.
Creating the client application
Ok, we have developed a simple service application. Now, it’s time to develop the client application. In your favorite Java IDE create a console application. Add a class named “ClientApp” and insert the main method into the class. Then, import the following packages:
The softnet.client.ClientSEndpoint class provides the network functionality to a client application to communicate with a single remote service. It has a static method to create an instance of the class, i.e. a client endpoint:
We set the first two parameters,<serviceType> and <contractAuthor>, as “Greeter” and “Softnet Guide”. This ensures that the client will be able to communicate only with a service which Service Type and Contract Author are the same. The third parameter is <clientURI>. We get it from the account section of the client registration. But, first, we have to create the client registration on the site. Let's open the example’s domain we have created in the beginning. Then we open the site in which we’ve registered the service. Clicking the clients button opens the client management section of the site:
Clicking the add client button to the right of the Owner creates an empty client registration:
Clicking the generate password button generates the password:
In my case, I had the following values for the <clientURI> and <password>:
In real applications, this data might be stored in the application's config file.
Now, we have all the required data. The following code shows how the client endpoint creation code may look like:
As with the service application, we want to monitor the client status and the client connectivity status. To intercept the platform events related to a client, ClientSEndpoint has a method addEventListener:
This method accepts an object that implements the ClientEventListener interface with appropriate event handlers. As with the service application, instead of implementing all the ClientEventListener methods, you can extend an abstract class ClientEventAdapter which has empty implementations of these methods. This allows you just to override the methods you want to implement.
Along with two events related to the status parameters described above, we need to intercept the ServiceOnline event, which notifies the client when the remote service goes online. To do so, we'll override the onServiceOnline handler of ClientEventAdapter. The code snapshot for the event handlers might look like this:
The way onServiceOnline works requires some explanation. Before making an RPC request to a remote service (or making a request to establish a TCP or UDP connection) your client app must be able to check its own online status and the online status of the remote service. If one or both of them are offline, the client should wait until the communication platform notifies that both are online. The onServiceOnline method serves this purpose. The platform calls it in one of the following two cases:
It follows that in the case of our single-service client, if the onServiceOnline method is called, both the client and the service are online, and the client can make a request.
As with the service application, up to this point we described the standard development steps typical for client apps in the Basic Examples section. And next we'll describe the steps specific for this application.
The Application-specific Steps
Let's write the code to call the remote procedure "Hello" that we defined in the service application. ClientSEndpoint has two overloaded methods call to make an RPC call. We're going to use the first one with two parameters:
Here're the parameter descriptions:
Note that ClientSEndpoint is a class derived from ClientEndpoint, which is a multi-service endpoint class. ClientEndpoint also has two overloaded methods call similar to those of ClientSEndpoint, but these methods each has an additional parameter RemoteService used to specify the target remote service. See «Making RPC requests» for more details.
Let's consider the RemoteProcedure class. It has the following public members:
When instantiating this class, your application provides the remote procedure’s name to the constructor. In our case, it is "Hello". RemoteProcedure has an arguments field in which the client provides arguments to the method. It is of type softnet.asn.SequenceEncoder and its maximum data size is limited by the platform to 64 kilobytes. The following code creates the remoteProcedure object and puts a message "Hello! I'm a client." into the arguments:
Let's consider the second parameter of the ClientSEndpoint's method call. This is an implementation of the RPCResponseHandler interface:
The interface has three methods to implement. Each request ends with a callback to one of these methods. In case of success, the onSuccess method is called back. Its first parameter, context, is provided by the platform. Any response handler has this type of parameter. It is well-described in Making TCP connection requests. The second parameter, result, is an object of type softnet.asn.SequenceDecoder that contains the ASN.1 DER encoded data returned as a result by the remote procedure.
The interface has two overloaded onError methods to handle an error response. The first overload is called back if the error code returned by the remote procedure is not 0. The first parameter, as usual, is the context. The second parameter, errorCode, is the error code itself. And the third parameter, error, of type softnet.asn.SequenceDecoder is a structured description of the error provided by the remote procedure.
The second overload of onError is called back when an error is detected by the platform. It provides the error in the second parameter of type SoftnetException. The possible exceptions are described in Making RPC requests.
We can implement the RPCResponseHandler by anonymous class. Then, it might look like the following:
Right after the code calling the method call, we can place the following code to show us that the RPC request has been sent:
We can place the code for calling the RPC procedure and handling the response in the body of onServiceOnline. Now, let's put everything together. The following is the entire code of the application:
Running the example
Now, it’s time to run the example. Let's first run the client applications. If everything is ok, you will see the following output:
From this output we can see that the client has connected to the server and it is assigned the Online status. Since the service is still offline, the onServiceOnline handler has not yet been called by the platform.
Now we run the service application and if everything is ok, we can see the following output:
Then, the client application prints this:
This output indicates that by calling the onServiceOnline handler, the platform has notified the client app that the service came online. In the handler's body, the RPC response handler has been established and the RPC request has been sent. Right after this, the service application prints the following:
At this point, the service application received the message from the client, printed it, and sent the response back to the client. Right after this, the client app, in turn, receives the RPC response and prints the following:
That's all!
Beta Was this translation helpful? Give feedback.
All reactions