DataSnap Filters Compendium

What’s DataSnap Filters Compendium

DataSnap Filters Compendium (DSFC) is a compendium of 9 filters for DataSnap 2010.
The filters are divided into 3 groups:

HASH
MD5
MD4
SHA1
SHA512

CIPHER
Blowfish
Rijndael
3TDES
3DES

COMPRESS
LZO

HASH filters
The HASH filters helps avoid to any spiteful person to modify datasnap message through an “Man in the middle” attack (http://en.wikipedia.org/wiki/Man-in-the-middle_attack).
Functioning is basing on an easy principle. After sending the message, the filter calculates the hash of the message and tags along it to the message. When the message gets to destination, the filter recovers the hash calculated by the client and recalculates it on the remaining part of the message.
If the part of the extrated hash (calculated at the beginning) and the hash recalculated to the end are equal, the message hasn’t change.
To avoid someone could modify the message and also recalculates the hash, after calculating the hash, a GUID is tagged along to the message, which just the sender and the receiver know.
This kind of filters DOES NOT AVOID THE UNAVOIDED READING OF DATA,it avoids just the modification.

CIPHER filters
The CIPHER filters are the most interesting filters. Many datasnap users have requested a built-in system to get the data transmission safe. This set of filters colud be the answer.
In the actual version I’ve implemented Symmetric-key algorithms. Maybe I’m going to develop of Asymmetric-key algorithms filters.
Implemented algorithms features are well known, I list them as follows just to be completed:

Blowfish
Blowfish has a 64-bit block size and a variable key length from 32 up to 448 bits.
The filter version has a keysize = 56 byte.

Rijndael
AES Round 2.
AES has a fixed block size of 128 bits and a key size of 128, 192, or 256 bits, whereas Rijndael can be specified with block and key sizes in any multiple of 32 bits, with a minimum of 128 bits and a maximum of 256 bits.
The filter version has a keysize = 32 byte.

3TDES
Triple DES with 24 byte Blocksize, 24 byte Keysize 168 bits relevant
The filter version has a keysize = 24 byte.

3DES
Triple DES with 8 byte Blocksize, 24 byte Keysize 168 bits relevant
The filter version has a keysize = 24 byte.

COMPRESS filters
Actually the LZO compression is the only one that exists, and is one of the faster compression algorithms.
The compression ratio compared to the ZLib is worse but about 3 times faster (as the table in next paragraph shows).

Tests
DSFC has a huge suite of unit tests and speed tests.
The speed tests show how filters are fast and how the data stream size is affected by their work. Follow table contains results of speed test execution (DSFCSpeedTest) on my workstation. If you want give a meaning to those numbers, see the code of the speed test 🙂

== HASH FILTERS == 1000 iterations
MD5             =  161ms (stream size:  8304 byte, filtered stream size:  4184 byte)
MD4             =   99ms (stream size:  8304 byte, filtered stream size:  4184 byte)
SHA1            =  145ms (stream size:  8304 byte, filtered stream size:  4192 byte)
SHA512          =  344ms (stream size:  8304 byte, filtered stream size:  4280 byte)

== CIPHER FILTERS == 1000 iterations
Blowfish        =  898ms (stream size:  8304 byte, filtered stream size:  8304 byte)
Rijndael        =  941ms (stream size:  8304 byte, filtered stream size:  8304 byte)
3TDES           = 1729ms (stream size:  8304 byte, filtered stream size:  8304 byte)
3DES            = 1757ms (stream size:  8304 byte, filtered stream size:  8304 byte)

== COMPRESS FILTERS == 1000 iterations
LZO             =   79ms (stream size:  8304 byte, filtered stream size:  1113 byte)
ZLibCompression =  295ms (stream size:  8304 byte, filtered stream size:   799 byte)

Last speed test is for the only filter included in Delphi2010. It’s included only for compare times and data stream size with the other filters.

After you install DataSnapFiltersCompendium.bpl you will see following filters into the “Filters” property

New filters registered by DSFC
New filters registered by DSFC

Cipher filters have only one property for the encription key

Encryption key for the cipher filters
Encryption key for the cipher filters

Project Source Contains

  • Full Filters Code
  • Unit Test
  • SpeedTest

Download DataSnap Filters Compendium

P.S. I’ll be at ITDevCon… and you? 🙂

Custom Marshalling/UnMarshalling in Delphi 2010

Introduction
Some days ago, Embarcadero has presented the new version of RAD Studio, 2010.
The are many new features, but you can find in a lot places around the web, so
I won’t repeat them here.

One of the things widely requested from all Delphi programmers all over the world over the past few years, including myself, is
certainly a new and more powerful RTTI.

The new system of RTTI has finally arrived, and pave the way for a large number of applications.
One area that has benefited from the new RTTI is for sure the marshaled objects.

Marshaling is defined as follows:

“In computer science, marshalling (similar to serialization) is the process of
transforming the memory representation of an object to a data format suitable for
storage or transmission. It is typically used when data must be moved between
different parts of a computer program or from one program to another.
The opposite, or reverse, of marshalling is called unmarshalling (demarshalling) (similar to deserialization).”
–WikiPedia

In Delphi 2010 the process of serialization and deserialization is handled respectively by a Marshaller and an Unmarshaller.

The built-in format for the serialization of any Delphi object is JSON.
There are 2 main classes responsible for serializing objects into JSON, both present in the unit DBXJSONReflect:
– TJSONMarshal
– TJSONUnMarshal

Let’s say you have an object defined as follow:

type
  TKid = class
    FirstName: String;
    LastName: String;
    Age: Integer;
  end;

To serialize and deserialize an instance of TKid it requires the following steps:

var
  Mar: TJSONMarshal;  //Serializer
  UnMar: TJSONUnMarshal;  //UnSerializer
  Kid: TKid;  //The Object to serialize
  SerializedKid: TJSONObject;  //Serialized for of object
begin
  Mar := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Kid := TKid.Create;
    try
      Kid.FirstName := 'Daniele';
      Kid.LastName := 'Teti';      
      Kid.Age := 29;      
      SerializedKid := Mar.Marshal(Kid) as TJSONObject;
    finally
      FreeAndNil(Kid);
    end;
  finally
    Mar.Free;
  end;
  //Output the JSON version of the Kid object
  WriteLn(SerializedKid.ToString);   
  // UnMarshalling Kid
  UnMar := TJSONUnMarshal.Create;
  try
    Kid := UnMar.UnMarshal(SerializedKid) as TKid;
    try
      //now kid is the same as before marshalling
      Assert(Kid.FirstName = 'Daniele');
      Assert(Kid.LastName = 'Teti');
      Assert(Kid.Age = 29);
    finally
      Kid.Free;
    end;
  finally
    UnMar.Free;
  end;
end;

Simple, isn’t it?
To access the JSON string that is our object, we must call the method ToString.
The JSON representation of this object SerializedKid can be saved to file,
sent to a remote server, used by a Web page from a web service, stored on a database or sent into space (!!!).
The Delphi application re-read the JSON string, you can recreate the object as it was at the time of serialization.
But anyone with a JSON parser can still read the data in our object, even non Delphi client.
These are the advantages of having used an open format and standard.

So far the simple part …
How serialize a field differently from the default?

Suppose we add the date of birth to our TKid:

type
  TKid = class
    FirstName: String;
    LastName: String;
    Age: Integer;
    BornDate: TDateTime;
  end; 

Serialize a TDateTime, localized and that I have in JSON string is a float, because for Delphi TDateTime is a decimal number.
If I read the data from another program Delphi, no problem, but if I wanted to read a script in JavaScript? or. NET? or Ruby?
Then I use a format “DATA” to understand, even for these languages.
The new engine provides the serialization too.
Is needed, however, to tell the Marshaller and UnMarsheller how to represent and reconstruct a particular
object field by two statements like the following:

//marshaller
Marshaller.RegisterConverter(TKid, 'BornDate', 
  function(Data: TObject; Field: string): string
  var
    ctx: TRttiContext; date : TDateTime;
  begin
    date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType<TDateTime>;
    Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
  end);
  
//UnMarshaller
UnMarshaller.RegisterReverter(TKid, 'BornDate', 
  procedure(Data: TObject; Field: string; Arg: string)
  var
    ctx: TRttiContext;
    datetime:TDateTime;
  begin
    datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), 
                               StrToInt(Copy(Arg, 6, 2)), 
                               StrToInt(Copy(Arg, 9, 2)), 
                               StrToInt(Copy(Arg, 12, 2)), 
                               StrToInt(Copy(Arg, 15, 2)), 
                               StrToInt(Copy(Arg, 18, 2)), 0);
    ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
  end);

The anonymous method is called when the marshaller serializes the field ‘BornDate’ is called “Converter” while Unmarshaller anonymous method that calls when he has to reconstruct the object from the JSON string is the “Reverter”.
Thus serializing a TKid assure you that my object is readable both by Delphi from another language without loss of information.

But what happens when I have to serialize a complex type?

Suppose we extend TKid this:

type
  TTeenager = class(TKid)
    Phones: TStringList;
    constructor Create; virtual;
    destructor Destroy; virtual;
  end; 

We must define a Converter and a Reverter for the TStringList class.
We can do it this way:

var
  Marshaller: TJSONMarshal;
  UnMarshaller: TJSONUnMarshal;
  Teenager: TTeenager;
  Value, JSONTeenager: TJSONObject;
begin
  Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshaller.RegisterConverter(TTeenager, 'BornDate', 
      function(Data: TObject; Field: string): string
      var
        ctx: TRttiContext; date : TDateTime;
      begin
        date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType<TDateTime>;
        Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
      end);
      
    Marshaller.RegisterConverter(TStringList, function(Data: TObject): TListOfStrings
                                              var
                                                i, count: integer;
                                              begin
                                                count := TStringList(Data).count;
                                                SetLength(Result, count);
                                                for i := 0 to count - 1 do
                                                  Result[i] := TStringList(Data)[i];
                                              end);  //TStringList Converter 
    Teenager := TTeenager.CreateAndInitialize;
    try
      Value := Marshaller.Marshal(Teenager) as TJSONObject;
    finally
      Teenager.Free;
    end;
  finally
    Marshaller.Free;
  end;
  // UnMarshalling Teenager
  UnMarshaller := TJSONUnMarshal.Create;
  try
    UnMarshaller.RegisterReverter(TTeenager, 'BornDate', 
      procedure(Data: TObject; Field: string; Arg: string)
      var
        ctx: TRttiContext;
        datetime: TDateTime;
      begin
        datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), 
                                   StrToInt(Copy(Arg, 6, 2)), 
                                   StrToInt(Copy(Arg, 9, 2)), 
                                   StrToInt(Copy(Arg, 12, 2)), 
                                   StrToInt(Copy(Arg, 15, 2)), 
                                   StrToInt(Copy(Arg, 18, 2)), 0);
        ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
      end);
    UnMarshaller.RegisterReverter(TStringList, function(Data: TListOfStrings): TObject
                                               var
                                                 StrList: TStringList;
                                                 Str: string;
                                               begin
                                                 StrList := TStringList.Create;
                                                 for Str in Data do
                                                   StrList.Add(Str);
                                                 Result := StrList;
                                               end);  //TStringList Reverter

    Teenager := UnMarshaller.Unmarshal(Value) as TTeenager;
    try
      Assert('Daniele' = Teenager.FirstName);
      Assert('Teti' = Teenager.LastName);
      Assert(29 = Teenager.Age);
      Assert(EncodeDate(1979, 11, 4) = Teenager.BornDate);
      Assert(3 = Teenager.Phones.Count);
      Assert('NUMBER01'=Teenager.Phones[0]);
      Assert('NUMBER02'=Teenager.Phones[1]);
      Assert('NUMBER03'=Teenager.Phones[2]);
    finally
      Teenager.Free;
    end;
  finally
    UnMarshaller.Free;
  end;
end;

There are different types of Converter and Reverter.
In the the DBXJSONReflect there are 8 types of converters:

  //Convert a field in an object array
  TObjectsConverter = reference to function(Data: TObject; Field: String): TListOfObjects;
  //Convert a field in a strings array
  TStringsConverter = reference to function(Data: TObject; Field: string): TListOfStrings;

  //Convert a type in an objects array
  TTypeObjectsConverter = reference to function(Data: TObject): TListOfObjects;
  //Convert a type in a strings array  
  TTypeStringsConverter = reference to function(Data: TObject): TListOfStrings;

  //Convert a field in an object
  TObjectConverter = reference to function(Data: TObject; Field: String): TObject;
  //Convert a field in a string  
  TStringConverter = reference to function(Data: TObject; Field: string): string;

  //Convert specified type in an object
  TTypeObjectConverter = reference to function(Data: TObject): TObject;
  //Convert specified type in a string  
  TTypeStringConverter = reference to function(Data: TObject): string;

Each of them deals with a particular conversion object representation in the final serialization, in our case we will use them to convert to JSON.

Also in the DBXJSONReflect unit are defined many “Reverter” dealing with retrieving
the serialized version of the data and use it to reconstruct the object previously serialized.
Because they are complementary to the Converter, I will not copy them here.

As a final example, we derive from TProgrammer by TTeenager adding a list of Laptops in the properties.

Is therefore necessary to introduce a new pair of Converter / Reverter.
In this example I have defined all the converter and reverter in another unit in
order to have more readable code:

type
  TLaptop = class
    Model: String;
    Price: Currency;
    constructor Create(AModel: String; APrice: Currency);
  end;
  TLaptops = TObjectList<TLaptop>;
  TProgrammer = class(TTeenager)
    Laptops: TLaptops;
    constructor Create; override;
    destructor Destroy; override;
    class function CreateAndInitialize: TProgrammer;
  end;
// Implementation code...
var
  Marshaller: TJSONMarshal;
  UnMarshaller: TJSONUnMarshal;
  Programmer: TProgrammer;
  Value, JSONProgrammer: TJSONObject;
begin
  Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshaller.RegisterConverter(TProgrammer, 'BornDate', ISODateTimeConverter);
    Marshaller.RegisterConverter(TStringList, StringListConverter);
    Marshaller.RegisterConverter(TProgrammer, 'Laptops', LaptopListConverter);
    Programmer := TProgrammer.CreateAndInitialize;
    try
      Value := Marshaller.Marshal(Programmer) as TJSONObject;
    finally
      Programmer.Free;
    end;

    // UnMarshalling Programmer
    UnMarshaller := TJSONUnMarshal.Create;
    try
      UnMarshaller.RegisterReverter(TProgrammer, 'BornDate', ISODateTimeReverter);
      UnMarshaller.RegisterReverter(TStringList, StringListReverter);
      UnMarshaller.RegisterReverter(TProgrammer, 'Laptops', LaptopListReverter);

      Programmer := UnMarshaller.Unmarshal(Value) as TProgrammer;
      try
        Assert('Daniele' = Programmer.FirstName);
        Assert('Teti' = Programmer.LastName);
        Assert(29 = Programmer.Age);
        Assert(EncodeDate(1979, 11, 4) = Programmer.BornDate);
        Assert(3 = Programmer.Phones.Count);
        Assert('NUMBER01' = Programmer.Phones[0]);
        Assert('NUMBER02' = Programmer.Phones[1]);
        Assert('NUMBER03' = Programmer.Phones[2]);
        Assert('HP Presario C700' = Programmer.Laptops[0].Model);
        Assert(1000 = Programmer.Laptops[0].Price);
        Assert('Toshiba Satellite Pro' = Programmer.Laptops[1].Model);
        Assert(800 = Programmer.Laptops[1].Price);
        Assert('IBM Travelmate 500' = Programmer.Laptops[2].Model);
        Assert(1300 = Programmer.Laptops[2].Price);
      finally
        Programmer.Free;
      end;
    finally
      UnMarshaller.Free;
    end;
  finally
    Marshaller.Free;
  end;
end;


Unit CustomConverter.pas contains all needed Converters/Reverts as anon methods.

unit CustomConverter;

interface

uses
  DBXJSONReflect,
  MyObjects; //Needed by converter and reverter for TLaptops

var
  ISODateTimeConverter: TStringConverter;
  ISODateTimeReverter: TStringReverter;

  StringListConverter: TTypeStringsConverter;
  StringListReverter: TTypeStringsReverter;

  LaptopListConverter: TObjectsConverter;
  LaptopListReverter: TObjectsReverter;

implementation

uses
  SysUtils, RTTI, DateUtils, Classes;

initialization

LaptopListConverter := function(Data: TObject; Field: String): TListOfObjects
var
  Laptops: TLaptops;
  i: integer;
begin
  Laptops := TProgrammer(Data).Laptops;
  SetLength(Result, Laptops.Count);
  if Laptops.Count > 0 then
    for I := 0 to Laptops.Count - 1 do
      Result[I] := Laptops[i];
end;


LaptopListReverter := procedure(Data: TObject; Field: String; Args: TListOfObjects)
var
  obj: TObject;
  Laptops: TLaptops;
  Laptop: TLaptop;
  i: integer;
begin
  Laptops := TProgrammer(Data).Laptops;
  Laptops.Clear;
  for obj in Args do
  begin
    laptop := obj as TLaptop;
    Laptops.Add(TLaptop.Create(laptop.Model, laptop.Price));
  end;
end;

StringListConverter := function(Data: TObject): TListOfStrings
var
  i, count: integer;
begin
  count := TStringList(Data).count;
  SetLength(Result, count);
  for i := 0 to count - 1 do
    Result[i] := TStringList(Data)[i];
end;


StringListReverter := function(Data: TListOfStrings): TObject
var
  StrList: TStringList;
  Str: string;
begin
  StrList := TStringList.Create;
  for Str in Data do
    StrList.Add(Str);
  Result := StrList;
end;

ISODateTimeConverter := function(Data: TObject; Field: string): string
var
  ctx: TRttiContext; date : TDateTime;
begin
  date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType<TDateTime>;
  Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
end;

ISODateTimeReverter := procedure(Data: TObject; Field: string; Arg: string)
var
  ctx: TRttiContext;
  datetime :
  TDateTime;
begin
  datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), StrToInt(Copy(Arg, 6, 2)), StrToInt(Copy(Arg, 9, 2)), StrToInt
      (Copy(Arg, 12, 2)), StrToInt(Copy(Arg, 15, 2)), StrToInt(Copy(Arg, 18, 2)), 0);
  ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
end;

end.

Last hint…
Every serialization/unserialization process can create “warnings”.
Those warnings are collected into the “Warnings” property of the Ser/UnSer Object.

Conclusions
In this post I tried to introduce the basics of the new serialization engine in Delphi 2010.
During the next ITDevCon to be held in Italy next November 11.12, I’ll have a talk in which I will extensively talk about serialization and RTTI.
All interested smart developers are invited 🙂

ITALIAN P.S.
Se qualche programmatore italiano volesse avere la versione in italiano di questo post può lasciare un commento e vedrò di accontentarlo 🙂

You can find the DUnit project Source Code

My AMQP Delphi wrapper is in the standard 0MQ distribution

Yes, this is a nice news!
My AMQP Delphi wrapper for 0MQ is officially included into the distribution of 0MQ.
Now sources are managed into the main svn trunk.
You can read the news in the project’s main page.
You can see the code here.

In the upcoming greatest Delphi conference ITDevCon, I’ll have a talk about MoM (Message oriented middleware) and I’ll talk about ZeroMQ too.

Using AMQP from Delphi with ZeroMQ

The Advanced Message Queuing Protocol (AMQP) is an open standard application layer protocol for Message Oriented Middleware (MoM).

The defining features of AMQP are message orientation, queuing, routing (including point-to-point and publish-and-subscribe), reliability and security.

The good news about AMQP is that AMQP mandates the behaviour of the messaging provider and client to the extent that implementations from different vendors are truly interoperable, in the same way as SMTP, HTTP, FTP, etc. have created interoperable systems.

In a so “Open” market, live an interesting project called ZeroMQ.

In a my recent Delphi project, I must choice a thin and fast messaging system, ZeroMQ has been the choice.

However, ZeroMQ has not the Delphi client for talking with the broker, so I decided to write my own.

ZeroMQ is very fast but doesn’t support some enteprise features like users management and message persistence, but is very simple to use and to intergate in a legacy system.

For example, with my wrapper, a simple “sender” is like following:

zmq := TZeroMQ.Create;
try
zmq.Open('localhost');
ex := zmq.CreateLocalExchange('MyExchange', zmqStyleDataDistribution);
zmq.Bind('MyExchange', 'GlobalQueue');
zmq.Send(ex, 'Hello World From Delphi');
finally
zmq.Free;
end;

And a simple receiver is simple as follow:

zmq := TZeroMQ.Create;
try
zmq.Open('localhost');
ex := zmq.CreateLocalQueue('LocalQueue');
zmq.Bind('GlobalExchange', 'LocalQueue');
zmq.Receive(msg, msgtype, msgsize, zmqBlocking);
WriteLn(msg);  //we are in a console application
finally
zmq.Free;
end;

In the distribution there are a complete set of examples including a simple “Chat” application.

ZeroMQ is primarily intended to power stock trading business, this is the reason becouse is very fast.

To use ZeroMQ you need the ZeroMQ server downloadable from http://www.zeromq.org/ where you can find additional info about Exchange and Queue configuration and binding.

Wrapper (beta) can be downloaded from the ZeroMQ section.

Comments and fix for the wrapper are very apreciated.

Have fun and happy messaging 🙂

Delphi profiling made simple… really simple!

Many users asked Embarcadero to include a profiler in the next Delphi for Win32.

Waiting for this, there are some interesting tools for profile a Delphi program.

For example, AsmProfile is an Open Source sampling profiler wich is very simple to use.

UPDATE:

Actually AsmProfile is an “Instrumenting” profiler. It uses runtime function detouring and assembly to profile any selected function.

If you dont know differences between Instrumenting profiler and Sampling profiler, you can go here or here and read about it.

So, Suppose to have a slow code like this:

Download AsmProfiler from SVN or project home page (see the end of the article).

Now you can put 2 unit in your uses clause and initialize profiler interface directly in your dpr

So far so good… compile your app with following settings:
Delphi -> Project Options:

  • Linker -> Map file = detailed
  • Compiler -> Optimization = off
  • Compiler -> Stack frames = on

In this way, the profiler can reach procedures address for profiling phase.
Run your application and a small form will show up. In this form your must select the profiled methods and then click “Start”.

Now stress your application, click “Stop” and then “Show Results”.
In the “results” form will be shown detailed information about program execution.

Every call timing is splitted in “Calls”, “Parent Calls” and “Child calls” and some stats has been calculated too.

AsmProfiler It’s not complete like AQTime from AutomatedQA, but it’s a very usefull tool for every Delphi programmer.

You can find AsmProfiler here but I suggest to download the updated SVN version.

UPDATE:

AsmProfile can also profile your code without change source using DllInjection.

When you only have an executable:

  • Start your executable
  • Start “dllinject.exe” (will show up a console window)
  • Get the PID of your executable via Windows Task Manager or Sysinternal Process Exlorer
  • Enter this number in the console black
  • Start profiling

My speech at “PHPCon Italia 2009”

I will talk at the italian PHPCon in Rome on March 18-20 2009.

I will talk about “Data Access Design Patterns” showing many PHP examples.

PHPCon Italia 2009
Holiday Inn Eur Parco dei Medici
Viale Castello Della Magliana 65
ROME, 00148
ITALIA
Web Site

Click here for discount on ticket (italian web site)

And this is the “Speaker Button”

My Speaker Button
My Speaker Button

A Simple start with MVP in Delphi for Win32, Part 1

As GUI framework such as VCL become more and more powerful, it’s common practice to let the UI layer do more than it should. Without a clear separation of responsibilities, the UI layer can often become an integral part of application and businness logic, but… this kind of responsabilities belongs to other layers of the application.
A design pattern (and his numberless variants), is especially well suited to solving this problem.

In this article I want to build a simple application using MVP pattern. Actually, pattern used is not “clear” MVP but his variation called Passive View.

Using Fowler words:

A perennial problem with building rich client systems is the complication of testing them. Most rich client frameworks were not built with automated testing in mind. Controlling these frameworks programaticly is often very difficult.

A Passive View handles this by reducing the behavior of the UI components to the absolute minimum by using a controller that not just handles responses to user events, but also does all the updating of the view. This allows testing to be focused on the controller with little risk of problems in the view.

Passive View ensures no dependecies between Model and View.

Passive View has no dependencies between view and model (Unlike most MVC-style triad)
Passive View has no dependencies between view and model (Unlike most MVC-style triad)

In this sample, “model” is a simple layer for application logic. In real world, “service layer” should incapsulate “application service” and “domain model“.

Application looks like following:

The Calculator
The Calculator
Div operator with result
Div operator with result
Div operator with a EDivByZero Exception
Div operator with a EDivByZero Exception

Connect View and Presenter
The view (the Form in VCL application) must implement an interface.

This interface should provide all method to interact with GUI:

ICalculatorView = interface
  ['{471E3657-C6CE-49A3-BCB4-8FA6AF611DAD}']
  function FirstOperand: String;
  function SecondOperand: String;
  procedure SetFirstOperand(Value :String);
  procedure SetSecondOperand(Value :String);
  function GetOperator: IGUISelectableList;
  procedure SetCalcResult(const Value: String);
  procedure SetCalcResultReadOnly(const Value: Boolean);
  function Error: IGUIEdit;
end;

For simple interacting with GUI widget (in our example are EditFirstOperand, EditSecondoperand and EditCalcResult) we use a simple methods like following

  function FirstOperand: String;
  function SecondOperand: String;
  procedure SetFirstOperand(Value :String);
  procedure SetSecondOperand(Value :String);

But, if we need more by our widget (like populating combo box or change font color in the EditError or set ReadOnly to true) we should use another interface for a family of component.
In this sample I wrote 3 general interface:

  IGUIBaseInterface = interface
    ['{F0B7F031-9302-415E-8545-1FE20A365840}']
  end;

  IGUIEdit = interface(IGUIBaseInterface)
    ['{FE2D56FB-0CFB-4B33-9B56-0A523B235D37}']
    procedure SetText(const Value: String);
    function GetText: String;
    function GetAsInteger: Integer;
    function GetAsFloat: Extended;
    procedure SetReadOnly(const AValue: boolean);
    procedure SetVisible(const Value: Boolean);
    function GetTextAsInteger: Integer;
    procedure SetTextAsinteger(const Value: Integer);
    function GetTextAsFloat: Extended;
  end;

  IGUISelectableList = interface(IGUIBaseInterface)
    ['{EEFE5C52-94C3-464B-80F2-05E443B0F0F6}']
    procedure SetText(const Value: String);
    function GetText: String;
    procedure SetValue(const Value: String);
    function GetValue: String;
    function GetSelected: ISSKeyValue;
    procedure AddPair(AKey, AValue: String);
    procedure Clear;
  end;

For implementation details see attached sample code.

Finally in FormCreate of our form we can wire Presenter and View:

TfrmCalculatorView = class(TForm, ICalculatorView)
  //code 
end;
  //interface section
procedure TfrmCalculatorView.FormCreate(Sender: TObject);
begin
  //Link controls with related interface
  IOperators := TGUISelectableList.Create(ComboOperators);
  IError := TGUIEdit.Create(EditError);

  //link view and presenter
  //In this version VIEW know PRESENTER
  FPresenter := TCalculatorPresenter.Create(Self);
end;

This is a very simple example, so not all looks like real world. In a real world application, for example, view should not known the presenter class. With dependency injection you can do that (Next article in this serie will talk about this).

Every event generated by View (our Form) must be redirected to Presenter.

procedure TfrmCalculatorView.Button1Click(Sender: TObject);
begin
  FPresenter.DoCalc;
end;

Another approach is to publish some events in view interface and let presenter to bind them via standard event handler or anonimous methods (but this is for another post).

In attached sample code there is a sample application and unit test for Service Layer and View.
Required Mock Library is included in the zip file.

Simple Passive View, Sample Code

In 2nd part I’ll talk about unit test and mock object in Passive View.

.NET databinding in Delphi for Win32

Databinding is defined as: “General technique that binds two data/information sources together and maintains them in sync. This is usually done with two data/information sources with different types as in XML data binding. However in UI data binding, we bind data and information objects of the same type together (e.g. Java objects to Java UI elements).”

Databinding is common technique in VCL. Since Delphi 1 we have TDataset class for bind data and UI controls (DB Aware) in a GUI application.

In .NET world, instead, databinding is very different.

So, I’m starting to write (actually for fun) a DataBinder component to use .NET “like” databinding (or something similar to) in Delphi for Win32 too.

All the code has been written in about 2 hours.

TDataBinder

With this component you can “bind” an object property to another object property in a declarative mode.

e.g.

DataBinder.Add(Person, 'FirstName', Edit1, 'Text');

and then, every update to Person.FirstName property, will be reflected in the Edit1.Text property.

You can bind different control properties to different BO properties.

e.g.

//Text = FirstName
DataBinder.Add(Person, 'FirstName', Edit1, 'Text');
//If Person is not married, TEdit become flat
DataBinder.Add(Person, 'IsMarried', Edit1, 'Ctl3D');

So in your initialization code (e.g. FormCreate) you can write somethig similat to following:

procedure TForm3.FormCreate(Sender: TObject);
var
binder: TDataBinder;
begin
//Create your "BO"
Person := TPerson.Create;
//read data from "database"
Person.Load;

//Setup databinding...
binder := TDataBinder.Create(self);
binder.Add(Person, 'FirstName'   ,      Edit1,     'Text');
binder.Add(Person, 'LastName',          Edit2,     'Text');

//The same attribute binded to 3 controls
binder.Add(Person, 'Married',     CheckBox1, 'Checked');
binder.Add(Person, 'Married'   , Edit1,     'Ctl3D');
binder.Add(Person, 'Married',     Edit2,     'Ctl3D');

//The same attribute binded to 2 controls
binder.Add(Person, 'SomeInteger', ComboBox1, 'ItemIndex');
binder.Add(Person, 'SomeInteger',     TrackBar1, 'Position');

//A derived property
binder.Add(Person, 'FullName',     Panel1, 'Caption');

//let start...
binder.Bind;
end;

Other info asap so, stay tuned.

Download Code and compiled sample

(Source code require Delphi 2009)

Value Object vs Data Transfer Object

One of the main goals of design patterns is to have a names dictionary shared among professionals.
This dictionary, sometimes, has some trouble.

It’s the case of two well known design patterns: Value Object and Data Transfer Object.

Value Object, according to Martin Fowler, is defined as:
“A small simple object, like money or a date range, whose equality isn’t based on identity.”

But Value Object, according to SUN, was for some time defined as follows: “An object that carries data between processes in order to reduce the number of method calls.”

In the words of Fowler: “Many people in the Sun community use the term “Value Object” for this pattern. I use it to mean something else.” (Talking about Data Transfer Object)

Some time ago, Value Object pattern (SUN version), has been renamed to “Transfer Object” according to Fowler.

Question is exposed in a few lines by Fowler at following address: http://martinfowler.com/bliki/ValueObject.html