Home > Delphi, JavaScript, nodeJS, Object Pascal, OP4JS, Smart Mobile Studio > Message handling under HTML5 with Smart Mobile Studio

Message handling under HTML5 with Smart Mobile Studio

January 31, 2015 Leave a comment Go to comments

In my previous post I informed you that my latest addition to the QTX library is WinAPI like messages. It’s important to underline that this has nothing to do with SMS text-messages, push messages or anything like that; rather it deals with sending messages between forms, controls and routines on an application-wide scale.

This is a lot harder to achieve under JavaScript than you imagine. In a pointer based language you have the freedom of criss-crossing between memory boundaries inside your own program, but JavaScript has no such concept. It doesn’t even know what an object is (!) So being able to pass messages from Object A to Object B where none of them knows about each other is quite a task.

Thankfully HTML5 comes with a message stack built in, which we have made full use of in our API.

Why messages?

The Windows programming API is based on messages. In fact message-handling is the building block of any Microsoft Windows application. If you come from a .net or Visual Basic background you have been shielded from this – but C++ and Delphi programmers will know what I’m talking about. Native Windows programming is all about message dispatching and consumption.

Messages represents a very powerful technology. Actually there are some chores that can be said to be impossible to achieve without them. Being able to broadcast messages which every single class or component in an application, regardless of their relationship or knowledge of each other, are capable of receiving and processing.. well, it goes without saying that messages solves a lot of tough problems.

Note: Messages are great but they are also very easy to abuse! Always make sure you use messages with care, or you may risk turning your mobile app into a proverbial debugging nightmare.

Using messages

Before we look at how to use messages, let’s take a look at what exactly a message is. The message unit is names qtx.msgport.pas and can be found in the quartex library folder. Simply check this out from SVN and copy it to your libraries folder. There is a shortcut to this folder under the start-menu item for Smart Mobile Studio.

If you open up this file you will find the message defined as such:

  (* The TQTXMessageData represents the actual message-data which is sent
     internally by the system. Unlike Delphi or FPC, it is a class rather
     than a record. Also, it does not derive from TObject - and as such
     is suitable for 1:1 JSON mapping.

     Note:  You dont need to free TQTXMessageData objects, Javascript is
            garbage-collected. *)

  TQTXMessageData = class(JObject)
  public
    property    ID: Integer;
    property    Source: String;
    property    Data: String;

    function    Deserialize:String;
    procedure   Serialize(const value:String);

    Constructor Create;
  end;

Right, let’s step through the class field by field..

The ID field

The ID field of the message is just that, the message-id. This can be anything you want. I suggest you define your message ID’s using constants – and also that you start at some +1000 number. Please note that ID 0 through 999 is reserved for Smart Mobile Studio (!).

In the unit there is a constant called CNT_QTX_MESSAGES_BASEID which you can use to define the lower limit of your application specific messages. Below is how I typically define my own messages. Starting CNT (constant), then the name of my application – followed by the name of the functionality. And I always start from CNT_QTX_MESSAGES_BASEID;

const
  CNT_MYAPP_DATALOADING = CNT_QTX_MESSAGES_BASEID + 1;
  CNT_MYAPP_DATALOADED  = CNT_QTX_MESSAGES_BASEID + 2;
  CNT_MYAPP_CALCSTARTED = CNT_QTX_MESSAGES_BASEID + 3;

The source field

The source field is special. HTML5 messages require that you include the source-url from where the message came. This may seem odd, but it makes perfect sense when you realize that messages can be sent between open browser windows. The application running in one window may not come from the same server as the second window. Hence you have to populate this with the current URI.

If you dont care about checking the URI you can simply use “*”, this allows your message to pass though anyway. The security of URI checking is for your benefit, it’s not included against you. Keep that in mind.

The data field

This is where the fun stuff begins, because this string is all yours. This is where you place your message data. Now you may be tempted to think “what? Just a string? Thats not enough!” – but before you jump into that line of thinking, remember that all JavaScript objects serialize to JSON. Which means you can stuff any non TObject derived object into this field.

The non TObject derived object is important. The reason Smart Mobile Studio is better than any other JavaScript compiler out there, is because our compiler generates a VMT, which is short for “virtual method table”. It’s the VMT that gives you true OOP, inheritance, virtual and abstract procedures, interface support etc. etc.

But this also means that our generated code functions more or less like Delphi assembly. Every method in a TObject derived class expects to have a hidden parameter, namely the “self” parameter. Which is a reference to a structure in memory which represents the current object instance. This is not problematic for JSON, but the RTTI info which accompany each method is (!) because RTTI identifiers, which are unique each time you execute an application, will also be duplicated.

So the rule is, that whatever you want to serialize should inherit from JObject, which is a parent-less object without the OOP mechanisms we know and love from Delphi and C++ builder (read: without all that extra data).

But you dont need to know about all that technical mumbo-jumbo. Let’s define a hypotethical message you want to use in your application. It goes like this:

  TMyComplexMessage = class(JObject)
  public
    Property  FirstName:String;
    Property  LastName:String;
    Property  Age:Float;
    Property  Birth:TDateTime;

    function  Deserialize:String;
    procedure Serialize(value:String);

    procedure FromMessage(const msg:TQTXMessageData);
    function  ToMessage:TQTXMessageData;
  end;

The art of turning an object into a JSON structure (or XML for that matter) is called “deserialization”, and not unexpectedly the reverse, turning a JSON string into an object is cleverly called “serialization”. So for simplicity I decided to call our methods just that. What these methods do is take the current object and either turn that into JSON text or, take a JSON text and populate our object with it’s values.

You may think this is overkill, but I tell you, writing good software is all about structure, order and maintainability. The more time you spend on the infrastructure the better your software will be. That is a fact of life.

Next we have the FromMessage and ToMessage, these are just helper methods that allows us to skip the nitty-gritty in our program code, and enables us to send and handle messages with a single line.

The code for these methods looks like this:

procedure TMyComplexMessage.FromMessage(const msg:TQTXMessageData);
begin
  serialize(msg.Data)
end;

function  TMyComplexMessage.ToMessage:TQTXMessageData;
Begin
  result:=new TQTXMessageData();
  result.ID:=CNT_MYAPP_MyComplexMessage;
  result.source:="*";
  result.data:=Deserialize;
end;

function TMyComplexMessage.Deserialize:String;
begin
  result:=JSON.stringify(self);
end;

procedure TMyComplexMessage.Serialize(value:String);
var
  mData:  variant;
begin
  mData:=JSON.Parse(Value);
  self.FirstName:=TMyComplexMessage(mData).FirstName;
  self.LastName:=TMyComplexMessage(mData).LastName;
  self.Age:=TMyComplexMessage(mData).Age;
  self.Birth:=TMyComplexMessage(mData).Birth;
end;

As you can see, it’s all fairly straight forward code. You can even isolate these methods in a base-class and just override Serialize() in each derived type, since that’s where the differences will be.

Sending our message

We are now ready to send our message, but let’s start in reverse – by implementing the receiver first!

  FEventHandler:=TQTXMessageSubscription.Create;
  FEventHandler.SubScribe(CNT_MYAPP_MyComplexMessage,procedure (Message:TQTXMessageData)
    var
      mObj: TMyComplexMessage;
    begin
      mObj:=new TMyComplexMessage();
      mObj.serialize(message.data);
      // "mObj" is now ready to be used!
    end);

Sending a message is simplicity itself, especially with our serialization methods firmly implemented:

  var mMessage:TMyComplexMessage = new TMyComplexMessage();

  mMessage.firstname:="jon";
  mMessage.lastname:="aasenden";
  mMessage.age:="40.9";

  QTX_PostMessage(mMessage.toMessage);

That’s basically how easy it is to send complex messages. You can ofcourse send smaller stuff, if all you want to do is transport a text-string between two components, then creating a complex datatype (message class) is overkill. But if you are writing a serious application you really want to isolate everything in proper classes. It’s so much easier to maintain and extend later.

Messages to solve problems

If you have spent a couple of years in Delphi you know perfectly well that the VCL (Visual Component Library) which has been Delphi’s bread and butter for nearly two decades, is littered with message-use.

Everything from database states to refreshing a GUI elements is handled by messages. In fact, if you take a closer look at TCustomControl – which is the primary control that most visual controls inherit from, you will see that it functions, in company with it’s ancestor TWinControl, as the proverbial switch-box for messages. It catches all the relevant messages from the OS, like key-presses, redraw requests, movement – you name it, and isolates these in event procedures.

I have no desire for Smart Mobile studio to go the same way. It could, ofcourse, but there is little benefit in doing so since the difference between the browser environment and the WinAPI environment is like night and day.

But what the JVL (JavaScript Visual component Library) could be extended with, in order to solve some notification challenges, is messages. I am going to propose that we use messages, especially in the upcoming database component layer. Using messages to notify data-subscribers of updates (and even database aware controls in the future) is a cost effective, safe and elegant solution to an otherwise daunting task.

For example: You have 3 TW3Edit boxes connected to a database-field. Whenever the data in the table changes, all the visual controls should reflect that by changing as well.

Without messages all controls would have to register with the data-source and all types of updates would be represented by a call mechanism. This is perfectly valid, but it represents a lot more code (and potential errors) than using messages to solve the problem.

All connected controls could be notified with something as simple as:

mMsg.db := FDB.name;
mMsg.Table := FDB.Table.Name;
mMsg.FieldName := FDB.Table.Field[mChanged].Name;
mMsg.Value := FDB.Table.Field[mChanged].asVariant;
QTX_BroadcastMessage(mMsg.serialize);

The messages are automatically filtered out by it’s ID, and later by the content of the message. Each message handler only consume one particular type of message – hence the cost of broadcasting is minimal. The “sender” field in this case (as explained at the beginning of this article) would serve as the namespace. Hence different forms with the same name on their controls and listening to the same field would be clearly separated.

So if Form1 is set to receive updates on 3 controls, and Form2 is inactive but set to receive the same updates — then only Form1 will get the updates. This is controlled by the application dispatcher.

In short: You can expect some pretty cool controls in the future 🙂

Well, hope you found this little introduction helpful — now go download QTX 🙂

Advertisements
  1. February 1, 2015 at 1:28 pm

    This is Nice.

    I need to build a server in Delphi to send push notification messages to SmartMS app. I’m looking for some pointers to get started with this in Delphi. What would be a good library to use, do know of any example code to do something like this?

    • Jon Lennart Aasenden
      February 1, 2015 at 7:02 pm

      Google it, plenty of ready made services out there — then just wrap the JS client library as a smart class

  2. February 4, 2015 at 5:29 pm

    So basically I have JavaScript similar to: var a = {b:3};

    I have rendered an input element like using innerHTML:

    I’d like the input’s value to be a.b’s value (for example), and when the input text changes, I’d like a.b to change too. When a.b changes in SMS, the input changes.

    The Question:
    How would I implement bi-directional data-binding with SmartMS?

    • Jon Lennart Aasenden
      February 5, 2015 at 5:32 am

      I would use messages. In fact I am working on this now to provide context-free communication between elements and objects.
      You could also do it like jQuery does it, although it’s very costly to do so, and use tag-attributes (the Data- attributes) and store the connections there. Whenever a text-box (dbaware) changes, then it will check if it has data-source attributes set, and then fetch the data from the source.
      Whenever the dataset changes, it will collect all data- attributes from the document and populate those that match the changes.

      But I want to do it smarter! Hence I will introduce messages just like Delphi and C++ builder has, so we can target only those components that have a binding.

  3. February 5, 2015 at 7:31 pm

    This is totally awesome.

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: