donderdag 21 juni 2012

RemObjects integration in Smart Mobile Studio (part 2)

In part 1, I explained how to create a very basic RemObjects service. In this post (part 2), I will show how easy it is to create a fancy looking mobile and web front-end for this service.
In the mean time, Smart Mobile Studio is updated(!), so get this new version to use the nice RO integration :).

First, we create a new project in Smart Mobile Studio (SMS):
Just choose a nice project name and press OK.

Now we can use the brand new RemObjects wizard to import our previous created RO service file:
(Smart Mobile Studio -> Tools -> Import Remobject SDK library)

In the wizard that pops up, we select our .rodl file (created by the "RemObjects Service Builder" tool):

We press the "import" button, and then we have a generated unit for our service!

As you see, it has a "{$R 'file:TestLibrary_intf.js'}" line in it. This javascript file contains the real client implementation, generated by the integrated RemObjects template engine in the wizard. This file is the same as you can generate with the "RemObjects Service Builder" tool. The magic is in some lines below. First we have our callback definitions (remember: everything is async! so no functions with a result, but you get the result async when the http call returns the value via the callback):
  TBasicService_Sum_Result = procedure(aResult: Integer);
  TBasicService_GetServerTime_Result = procedure(aResult: DateTime);
 Then the service class definition:

  { Service definition }
  TBasicService = class external 'BasicService'
    constructor Create(aChannel: TROHTTPClientChannel;
                                 aMessage: TROMessage;
                                 aServiceName: string = "BasicService");
    procedure Sum(
               A: Integer;
               B: Integer;
               aCallback: TBasicService_Sum_Result;
               aOnError: TErrorResult);
    procedure GetServerTime(aCallback: TBasicService_GetServerTime_Result;
                                            aOnError: TErrorResult);
  end;

You see the "external" keyword? This means our "BasicService" class maps directly to the javascript "BasicService" object (defined in the included $R TestLibrary_intf.js). We have a constructor with 3 params, which maps to the JS constructor. And we have 2 procedures (not functions!): Sum and GetServerTime. These are the same as defined in the .rodl file and implemented on the server side. Both procedures have a least a result callback and an error callback (in case the connection gets lost etc).

Before we can call these functions, we will make a simple form with some components on it. We place some labels and textboxes and a button on the form:

We can preview how it looks like using the preview button:

Looks nice isn't it?


Code

Now some real code and fun :). We go to the source ("Source" tab or press F12), create a button click event, and attach it to the button OnClick:
type
  TForm1=class(TW3form)
  private
    { Private methods }
    {$I 'Form1:intf'}
  protected
    { Protected methods }
    Procedure InitializeObject;override;
    Procedure FinalizeObject;override;
    Procedure StyleTagObject;reintroduce;virtual;
    Procedure Resize;override; 
    procedure btnSumClick(Sender: TObject);
  end;
Procedure TForm1.InitializeObject;
Begin
  inherited;
  {$I 'Form1:impl'}
  btnSum.OnClick := btnSumClick;
End;

procedure TForm1.btnSumClick(Sender: TObject);
begin
end;
To be able to call our RO service, we have to add the following uses clause:
uses
  RemObjectsSDK,
  TestLibrary_intf;
Now we can create a http channel, a JSON message, attach this to our client side TBasicService object and then call the Sum function:
procedure TForm1.btnSumClick(Sender: TObject);
begin
  var chn := TROHTTPClientChannel.Create("http://localhost:8099/JSON");
  var msg := TROJSONMessage.Create; 
  var srv := TBasicService.Create(chn, msg);
  srv.Sum(
    edtValue1.Text.ToInteger, edtValue2.Text.ToInteger,
    procedure(aResult: Integer)
    begin
      edtResult.Text := aResult.ToString;
    end,
    ROErrorCallback);
end;
We supply the 2 values of the 2 editboxes, and when calculation is done (on the server), we put it in the 3rd editbox (using an inline anonymous method).

Run

Now compile this and run it! ("Execute" or F9 in SMS). Oh, and don't forget to run the server we made in part 1!
We click on the "Sum" button and.... hmmm, not exactly what I wanted...

The reason is, I forgot something in the server project (in part 1): I must set the property "WrapResult" of the TROJSONMessage to True (see "Tips & Tricks" in this RemObjects wiki item). Now we recompile our server, run it, and click on the "Sum" button again:

That's better :).
And this is how it looks on an android smartphone (Samsung Mini, Android 2.3):

Now, is this very cool or not!? :)
It is of course a very simple example, I hope to blog more about this in the future.

Demo

If you want to run this demo yourself:

Note: string/integer helper classes

Note: I added 2 helper classes for "string" and "integer" to be able to use ToInteger and ToString on these basic types (like "edtValue1.Text.ToInteger"):
type
  TString_helper = helper for string
    function  ToInteger: Integer;
  end;
  TInteger_helper = helper for integer
    function  ToString: string;
  end;
function TString_helper.ToInteger: Integer;
begin
  Result := StrToInt(Self);
end;
function TInteger_helper.ToString: string;
begin
  Result := IntToStr(Self);
end;




Geen opmerkingen: