Getting Started with Java Android DataSnap Mobile Connector

From RAD Studio
Jump to: navigation, search

Go Up to Getting Started with DataSnap Mobile Connectors


This topic is a guide for getting started with generating and using the Java Android DataSnap proxy, for use with Android mobile development. The Java proxy supports all the same data types that DataSnap itself supports. Special Java classes have been created to wrap those DBX and Delphi types, and their usage is similar to usage in Delphi.

When requested, the DataSnap REST server generates and dispatches the proxy class used to invoke the methods on the server. This is very similar to the proxy generation you might already be familiar with, but also includes the process of zipping up the proxy and all dependencies, and sending this zip file to the requester. For more information on this process, see Getting Started with DataSnap Mobile Connectors.

The DSProxy class and all the run-time files are contained in the com.embarcadero.javaandroid package, and its structure is as follow:

Javadroidfiles.png

Note: Version 2.1 of the Android SDK is required.

How to Download Android Proxy Files from a DataSnap REST Server

First you need to obtain a copy of Win32ProxyDownloader.exe, available in the \bin directory of your product installation. This file and where to obtain a copy is further discussed in Getting Started with DataSnap Mobile Connectors. The downloader is a simple utility that helps with asking the server for the proxy and other files needed for communication with the server.

To use the proxy downloader, you need to provide the following parameters:

  • -language (required): Specifies the mobile platform/language of the requested proxy. For Android development, use java_android.
  • -protocol: Specifies the connection protocol to use: http or https. The default is http.
  • -host: Specifies the port and host name or IP address to connect to. Default is localhost with port 80. If a different name or port is needed, the name must be fully qualified with the port number included, separated by a colon (":").
  • -output: Specifies the folder to download the proxy files into. If not specified, the current folder is used.

The following example uses most of the parameters mentioned above:

C:\Win32ProxyDownloader.exe -language java_android -host 127.0.0.1:8080 -output C:\test

After executing the downloader, the Android proxy files are copied into the output folder that was specified. These files include the following:

  • Static Java source files required by the proxy
  • DSProxy.java, the generated proxy

The main file is DSProxy.java, which declares the class that contains all the methods defined on the server.

After importing the files into your project, you have a setup that looks like this:

AndroidDemofiles.png

How to Use the DSProxy Class

The code below shows the DSProxy.java file generated by the server. The code contains a TServerMethods1 class, which encapsulates the server methods. Our server has only one method (EchoString), and the Java Class TServerMethods1 implements it accordingly. The proxy generator has automatically generated all the Java code for connecting to the server and executing the methods:

public class DSProxy {
  public static class TServerMethods1 extends DSAdmin {
    public TServerMethods1(DSRESTConnection Connection) {
      super(Connection);
    }
    
    private DSRESTParameterMetaData[] TServerMethods1_EchoString_Metadata;
    private DSRESTParameterMetaData[] get_TServerMethods1_EchoString_Metadata() {
      if (TServerMethods1_EchoString_Metadata == null) {
        TServerMethods1_EchoString_Metadata = new DSRESTParameterMetaData[]{
          new DSRESTParameterMetaData("Value", DSRESTParamDirection.Input, 
                                               DBXDataTypes.WideStringType, "string"),
          new DSRESTParameterMetaData("", DSRESTParamDirection.ReturnValue, 
                                          DBXDataTypes.WideStringType, "string"),
        };
      }
      return TServerMethods1_EchoString_Metadata;
    }

    /**
     * @param Value [in] - Type on server: string
     * @return result - Type on server: string
     */
    public String EchoString(String Value) throws DBXException {
      DSRESTCommand cmd = getConnection().CreateCommand();
      cmd.setRequestType(DSHTTPRequestType.GET);
      cmd.setText("TServerMethods1.EchoString");
      cmd.prepare(get_TServerMethods1_EchoString_Metadata());
      cmd.getParameter(0).getValue().SetAsString(Value);
      getConnection().execute(cmd);
      return cmd.getParameter(1).getValue().GetAsString();
    }
    
    
    private DSRESTParameterMetaData[] TServerMethods1_ReverseString_Metadata;
    private DSRESTParameterMetaData[] get_TServerMethods1_ReverseString_Metadata() {
      if (TServerMethods1_ReverseString_Metadata == null) {
        TServerMethods1_ReverseString_Metadata = new DSRESTParameterMetaData[]{
          new DSRESTParameterMetaData("Value", DSRESTParamDirection.Input, 
                                               DBXDataTypes.WideStringType, "string"),
          new DSRESTParameterMetaData("", DSRESTParamDirection.ReturnValue, 
                                          DBXDataTypes.WideStringType, "string"),
        };
      }
      return TServerMethods1_ReverseString_Metadata;
    }
}

The first step to using the proxy class is to create and setup a connection to the server. Class DSRESTConnection encapsulates all the properties and methods needed for connecting to the server. Just create the connection and set up the properties as shown below (Java code):

import com.embarcadero.javaandroid.DSRESTConnection;
// ...

DSRESTConnection conn = new DSRESTConnection();
conn.setHost("host");
conn.setPort(port);
conn.setProtocol("http");
  • The host property is the host name or IP address.
  • The port property is the port that the server is listening on.
  • The protocol property is the protocol to use for the connection. Specifically: either http or https.

To remotely invoke the server methods, just create the proxy class, passing the connection, and then call the method (Java code):

DSRESTConnection conn = new DSRESTConnection();
conn.setHost("10.40.30.24");
conn.setPort(8080); 

TServerMethods1 proxy = new TServerMethods1(conn);
String Result = proxy.EchoString("Hello, World!");

Example of a Server Method with a var Parameter

The following example illustrates the code that gets generated when your server method contains a var parameter or returns multiple results.

This is what the Delphi code looks like for the server method:

function TServerMethods1.VarParamTest(var Value: string): string;
begin
  Value := StrUtils.ReverseString(Value);
  Result := Value;
end;

And here is the generated proxy code to invoke that server method:

private DSRESTParameterMetaData[] TServerMethods1_VarParamTest_Metadata;
private DSRESTParameterMetaData[] get_TServerMethods1_VarParamTest_Metadata() {
  if (TServerMethods1_VarParamTest_Metadata == null) {
    TServerMethods1_VarParamTest_Metadata = new DSRESTParameterMetaData[]{
      new DSRESTParameterMetaData("Value", DSRESTParamDirection.InputOutput, 
                                           DBXDataTypes.WideStringType, "string"),
      new DSRESTParameterMetaData("", DSRESTParamDirection.ReturnValue, 
                                      DBXDataTypes.WideStringType, "string"),
    };
  }
  return TServerMethods1_VarParamTest_Metadata;
}

/**
 * @param Value [in/out] - Type on server: string
 * @return result - Type on server: string
 */
public static class VarParamTestReturns {
  public String Value;
  public String returnValue;
}

public VarParamTestReturns VarParamTest(String Value) throws DBXException {
  DSRESTCommand cmd = getConnection().CreateCommand();
  cmd.setRequestType(DSHTTPRequestType.GET);
  cmd.setText("TServerMethods1.VarParamTest");
  cmd.prepare(get_TServerMethods1_VarParamTest_Metadata());
  cmd.getParameter(0).getValue().SetAsString(Value);
  getConnection().execute(cmd);
  VarParamTestReturns ret = new VarParamTestReturns();
  ret.Value = cmd.getParameter(0).getValue().GetAsString();
  ret.returnValue = cmd.getParameter(1).getValue().GetAsString();
  return ret;
}

Please note that the method returns an instance of VarParamTestReturns. This special class holds the information about var (in/out) parameters as well as the result.

The example below shows how to invoke the method and read the resulting values:

TServerMethods1 proxy = new TServerMethods1(conn);
VarParamTestReturns Result = proxy.VarParamTest("Hello, World!");
System.out.println(Result.Value);
System.out.println(Result.returnValue);

Both the new value of the parameter passed in and the result value are held by the Result instance. The value for Result.Value is "!dlroW ,olleH", and Result.returnValue is "Hello, World!".

How to Use Heavyweight Callbacks

Heavyweight callbacks provide a way for DataSnap Servers to send nearly instantaneous notifications to REST clients. A client can register a callback for a specific topic on the server that interests him, then whenever that topic is updated, the client receives a notification. This is, of course, a very simplified description of what heavyweight callbacks accomplish, but is sufficient for the purposes of this task.

The first step towards using callbacks in your application is to create a custom callback class that is inherited from the abstract DBXCallback class and override the abstract "Execute" method. An example implementation of this class is shown below:

public class MyCallback extends DBXCallback { 
    public TJSONValue execute(TJSONArray params) { 
        System.out.println(params.toString());
        return new TJSONTrue();
  }
}

The DSClientCallbackChannelManager class manages the client's callbacks. It provides methods for registering and unregistering the callbacks, and closing one or all of them. Its constructor accepts 3 parameters:

  1. DSRESTConnection, specifying the server connection information
  2. A String that contains the name of the server channel to register with
  3. A String that contains the manager's ID (unique to the server)

Here is the code that creates the manager:

DSCallbackChannelManager manager  = 
 new DSCallbackChannelManager(conn,"chname",DSCallbackChannelManager.getNewManagerID());

Registering and Unregistering a Callback

The following is an example of registering a callback and then broadcasting to the same channel it is registered on:

manager.registercallback("mycb01", new MyCallback());

The example above registers a callback with the name "mycb01". The first parameter to the 'registerCallback' method is an ID for the callback (the ID must be unique to the client channel). The second parameter is the actual callback instance to register. If this is the first callback being registered, then when the call to registerCallback returns, you are not guaranteed that the callback manager is ready, as initial registration is done asynchronously. However, after the initial call to registerCallback, any subsequent calls do not return until the registration is complete.

The connection stays open until you close it or until it is closed by the server. To stop the connection, you can unregister the callback and close the channel as shown below:

manager.unregisterCallback("mycb01");
manager.closeClientChannel();

See Also