*VERY* busy time! RADSTUDIO XE, ITDevCon and other stuff

Embarcadero, Events, RAD STUDIO XE, Uncategorized, bit Time Software 4 Comments »

This is a very busy time.

Some news:

  • RAD STUDIO XE is out
  • The ITDevCon time table will be published ASAP. This year I’m working to create a Time Table even more interesting than the last year (not simple!). The speakers will talk about DELPHI XE, RADPHP XE and a*LOT* of DataSnap. Complete list of topic are available in the conference web site home page.
  • The italian RADSTUDIO XE events will be held in September, Tuesday 21 ROME and Wednesday 22 MILAN
  • Busy time also for this blog… I’m planning some really interesting stuff that I working on:
    • Nice stuff with the Delphi Language
    • MVC framework with scripting engine for web development in Delphi
    • DORM, the Delphi ORM
    • Some real-world samples for the new RAD STUDIO XE

What other to say?

Stay tuned

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

Delphi 2010, Delphi Dependency Injection, Design Patterns, MVC, MVP, Uncategorized 2 Comments »

Some month ago I wrote a simple article about an MVP variant called PassiveView.
That example was very simple. Now I’ll present a more “advanced” version of that example.

The main problem with first example was the following method:

  1. procedure TfrmCalculatorView.FormCreate(Sender: TObject);
  2. begin
  3.   //Link controls with related interface
  4.   IFirstOperand := TGUIEdit.Create(EditFirstOp);
  5.   ISecondOperand := TGUIEdit.Create(EditSecondOp);
  6.   ICalcResult := TGUIEdit.Create(EditResult);
  7.   IOperators := TGUISelectableList.Create(ComboOperators);
  8.   IError := TGUIEdit.Create(EditError);
  9.  
  10.   //link view and presenter
  11.   FPresenter := TCalculatorPresenter.Create(Self); //<<– THIS IS THE BAD LINE
  12. end;

The “BAD” line links the View with the Presenter but it’s in the view code, so this is meaning that View KNOWS the presenter… and this is not a good thing becouse the view is not so “passive”.

In a more advanced (and complex) version the View should be completely ignorant about the class that implement the presenter and the service.

In the main dpr file now the code now looks like the following.

  1. var
  2.   MainPresenter: ICalculatorPresenter;
  3.   CalculatorView: TForm;
  4. begin
  5.   Application.Initialize;
  6.   Application.MainFormOnTaskbar := True;
  7.   //SETUP THE MAIN APPLICATION FORM FOR VCL PURPOSE
  8.   Application.CreateForm(TfrmCalculatorView, CalculatorView);  
  9.   //SETUP ALL THE LINKS BETWEEN THE MVP TRIAD
  10.   MainPresenter := TCalculatorPresenter.Create(CalculatorView as ICalculatorView, TCalculatorService.Create);
  11.   //LETS START!
  12.   Application.Run;
  13. end.

Now the presenter take care about all links between the MVP triad.

  1. constructor TCalculatorPresenter.Create(CalculatorView: ICalculatorView;
  2.   CalculatorService: ICalculatorService);
  3. begin
  4.   inherited Create;
  5.   FCalculatorService := CalculatorService;
  6.   FCalculatorView := CalculatorView;
  7.   FCalculatorView.SetPresenter(self);
  8.   InitView;  //does the links
  9. end;

There is another addition to the previous example. Now there is only one constructor in the presenter, and using dependency injection take 2 interface for the view and the service.

  1.     constructor Create(CalculatorView: ICalculatorView; CalculatorService: ICalculatorService);

Another plus is the possibility to open the same form a number of times without change the code for create it.

This is the GUI for this simple application.

3 instance of the same view with different presenter and service

3 instance of the same view with different presenter and service

As bonus, unit tests and mock object arent changed.

As usual the source code is here.

JSON support in Delphi2010, a simple example

CodeGear, Delphi 2010, ITDevCon2009, Programming, Uncategorized 22 Comments »

During last ITDevCon in Verona (ITALY) I talked in a session with title “Marshal and UnMarshal in Delphi 2010″ (we have published some photos about this great conference here).
In the first part of the session I’ve talked about JSON and many attendees were very interested in JSON and his application in everyday programming. I’m a real JSON fan so I decided to write this post about JSON support in Delphi2010. In my session I talked about serialization and deserialization, in this post I’ll show an example of code to do some JSON generation.

  1. program JsonTypes;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.   SysUtils,
  5.   IOUtils,
  6.   DBXJSON;
  7. var
  8.   Obj, RestoredObject, JSON: TJSONObject;
  9.   arr: TJSONArray;
  10. begin
  11.   json := TJSONObject.Create;
  12.   try
  13.     WriteLn('Empty JSON Object: ' + sLineBreak,json.ToString);
  14.     json.AddPair('FirstName', TJSONString.Create('Daniele'));
  15.     WriteLn('Simple JSON Object with property: ' + sLineBreak, json.ToString);
  16.     json.AddPair(TJSONPair.Create('LastName', 'Teti'));
  17.     WriteLn('Simple JSON Object with 2 property: ' + sLineBreak, json.ToString);
  18.     arr := TJSONArray.Create;
  19.     arr.Add(9871238712);
  20.     arr.Add('peter.parker@bittime.it');
  21.     arr.Add('Via Roma, 12');
  22.     json.AddPair(TJSONPair.Create('Contacts', arr));
  23.     WriteLn('JSON Object with a property array: ' + sLineBreak, json.ToString);
  24.     obj := TJSONObject.Create;
  25.     obj.AddPair(TJSONPair.Create('John','Doe'));
  26.     json.AddPair('MyUndefinedPersonObject', obj);
  27.     WriteLn('JSON Object with a nested Object: ' + sLineBreak,json.ToString);
  28.     Write('Writing JSON object to file [jsonfile]…');
  29.     TFile.WriteAllText('jsonfile',json.ToString);
  30.     WriteLn('DONE!');
  31.     RestoredObject := TJSONObject.ParseJSONValue(
  32.       TEncoding.ASCII.GetBytes(TFile.ReadAllText('jsonfile')),0
  33.       ) as TJSONObject;
  34.     WriteLn('Readed JSON object from file: ' + sLineBreak, RestoredObject.ToString);
  35.   finally
  36.     json.Free;  //Every contained object is automatically freed
  37.   end;
  38.   readln; //If you want to see the output while in Delphi IDE
  39. end.

JSON is a lightweight data-interchange format and in Delphi 2010 you have full support for it with the built-in DBXJSON unit.
Enjoy!

DataSnap Filters Compendium

DataSnap Filters Compendium, Delphi 2010, Delphi for Win32, Uncategorized 27 Comments »

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 :-)

  1. == HASH FILTERS == 1000 iterations
  2. MD5             =  161ms (stream size:  8304 byte, filtered stream size:  4184 byte)
  3. MD4             =   99ms (stream size:  8304 byte, filtered stream size:  4184 byte)
  4. SHA1            =  145ms (stream size:  8304 byte, filtered stream size:  4192 byte)
  5. SHA512          =  344ms (stream size:  8304 byte, filtered stream size:  4280 byte)
  6.  
  7. == CIPHER FILTERS == 1000 iterations
  8. Blowfish        =  898ms (stream size:  8304 byte, filtered stream size:  8304 byte)
  9. Rijndael        =  941ms (stream size:  8304 byte, filtered stream size:  8304 byte)
  10. 3TDES           = 1729ms (stream size:  8304 byte, filtered stream size:  8304 byte)
  11. 3DES            = 1757ms (stream size:  8304 byte, filtered stream size:  8304 byte)
  12.  
  13. == COMPRESS FILTERS == 1000 iterations
  14. LZO             =   79ms (stream size:  8304 byte, filtered stream size:  1113 byte)
  15. 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

Delphi 2010, Programming, RTTI, Uncategorized 16 Comments »

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
  1.   TKid = class
  2.     FirstName: String;
  3.     LastName: String;
  4.     Age: Integer;
  5.   end;

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

var
  1.   Mar: TJSONMarshal;  //Serializer
  2.   UnMar: TJSONUnMarshal;  //UnSerializer
  3.   Kid: TKid;  //The Object to serialize
  4.   SerializedKid: TJSONObject;  //Serialized for of object
  5. begin
  6.   Mar := TJSONMarshal.Create(TJSONConverter.Create);
  7.   try
  8.     Kid := TKid.Create;
  9.     try
  10.       Kid.FirstName := 'Daniele';
  11.       Kid.LastName := 'Teti';      
  12.       Kid.Age := 29;      
  13.       SerializedKid := Mar.Marshal(Kid) as TJSONObject;
  14.     finally
  15.       FreeAndNil(Kid);
  16.     end;
  17.   finally
  18.     Mar.Free;
  19.   end;
  20.   //Output the JSON version of the Kid object
  21.   WriteLn(SerializedKid.ToString);  
  22.   // UnMarshalling Kid
  23.   UnMar := TJSONUnMarshal.Create;
  24.   try
  25.     Kid := UnMar.UnMarshal(SerializedKid) as TKid;
  26.     try
  27.       //now kid is the same as before marshalling
  28.       Assert(Kid.FirstName = 'Daniele');
  29.       Assert(Kid.LastName = 'Teti');
  30.       Assert(Kid.Age = 29);
  31.     finally
  32.       Kid.Free;
  33.     end;
  34.   finally
  35.     UnMar.Free;
  36.   end;
  37. 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
  1.   TKid = class
  2.     FirstName: String;
  3.     LastName: String;
  4.     Age: Integer;
  5.     BornDate: TDateTime;
  6.   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
  1. Marshaller.RegisterConverter(TKid, 'BornDate',
  2.   function(Data: TObject; Field: string): string
  3.   var
  4.     ctx: TRttiContext; date : TDateTime;
  5.   begin
  6.     date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
  7.     Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
  8.   end);
  9.  
  10. //UnMarshaller
  11. UnMarshaller.RegisterReverter(TKid, 'BornDate',
  12.   procedure(Data: TObject; Field: string; Arg: string)
  13.   var
  14.     ctx: TRttiContext;
  15.     datetime:TDateTime;
  16.   begin
  17.     datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)),
  18.                                StrToInt(Copy(Arg, 6, 2)),
  19.                                StrToInt(Copy(Arg, 9, 2)),
  20.                                StrToInt(Copy(Arg, 12, 2)),
  21.                                StrToInt(Copy(Arg, 15, 2)),
  22.                                StrToInt(Copy(Arg, 18, 2)), 0);
  23.     ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
  24.   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
  1.   TTeenager = class(TKid)
  2.     Phones: TStringList;
  3.     constructor Create; virtual;
  4.     destructor Destroy; virtual;
  5.   end;

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

var
  1.   Marshaller: TJSONMarshal;
  2.   UnMarshaller: TJSONUnMarshal;
  3.   Teenager: TTeenager;
  4.   Value, JSONTeenager: TJSONObject;
  5. begin
  6.   Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  7.   try
  8.     Marshaller.RegisterConverter(TTeenager, 'BornDate',
  9.       function(Data: TObject; Field: string): string
  10.       var
  11.         ctx: TRttiContext; date : TDateTime;
  12.       begin
  13.         date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
  14.         Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
  15.       end);
  16.      
  17.     Marshaller.RegisterConverter(TStringList, function(Data: TObject): TListOfStrings
  18.                                               var
  19.                                                 i, count: integer;
  20.                                               begin
  21.                                                 count := TStringList(Data).count;
  22.                                                 SetLength(Result, count);
  23.                                                 for i := 0 to count - 1 do
  24.                                                   Result[i] := TStringList(Data)[i];
  25.                                               end);  //TStringList Converter
  26.     Teenager := TTeenager.CreateAndInitialize;
  27.     try
  28.       Value := Marshaller.Marshal(Teenager) as TJSONObject;
  29.     finally
  30.       Teenager.Free;
  31.     end;
  32.   finally
  33.     Marshaller.Free;
  34.   end;
  35.   // UnMarshalling Teenager
  36.   UnMarshaller := TJSONUnMarshal.Create;
  37.   try
  38.     UnMarshaller.RegisterReverter(TTeenager, 'BornDate',
  39.       procedure(Data: TObject; Field: string; Arg: string)
  40.       var
  41.         ctx: TRttiContext;
  42.         datetime: TDateTime;
  43.       begin
  44.         datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)),
  45.                                    StrToInt(Copy(Arg, 6, 2)),
  46.                                    StrToInt(Copy(Arg, 9, 2)),
  47.                                    StrToInt(Copy(Arg, 12, 2)),
  48.                                    StrToInt(Copy(Arg, 15, 2)),
  49.                                    StrToInt(Copy(Arg, 18, 2)), 0);
  50.         ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
  51.       end);
  52.     UnMarshaller.RegisterReverter(TStringList, function(Data: TListOfStrings): TObject
  53.                                                var
  54.                                                  StrList: TStringList;
  55.                                                  Str: string;
  56.                                                begin
  57.                                                  StrList := TStringList.Create;
  58.                                                  for Str in Data do
  59.                                                    StrList.Add(Str);
  60.                                                  Result := StrList;
  61.                                                end);  //TStringList Reverter
  62.  
  63.     Teenager := UnMarshaller.Unmarshal(Value) as TTeenager;
  64.     try
  65.       Assert('Daniele' = Teenager.FirstName);
  66.       Assert('Teti' = Teenager.LastName);
  67.       Assert(29 = Teenager.Age);
  68.       Assert(EncodeDate(1979, 11, 4) = Teenager.BornDate);
  69.       Assert(3 = Teenager.Phones.Count);
  70.       Assert('NUMBER01'=Teenager.Phones[0]);
  71.       Assert('NUMBER02'=Teenager.Phones[1]);
  72.       Assert('NUMBER03'=Teenager.Phones[2]);
  73.     finally
  74.       Teenager.Free;
  75.     end;
  76.   finally
  77.     UnMarshaller.Free;
  78.   end;
  79. end;

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

  1.   //Convert a field in an object array
  2.   TObjectsConverter = reference to function(Data: TObject; Field: String): TListOfObjects;
  3.   //Convert a field in a strings array
  4.   TStringsConverter = reference to function(Data: TObject; Field: string): TListOfStrings;
  5.  
  6.   //Convert a type in an objects array
  7.   TTypeObjectsConverter = reference to function(Data: TObject): TListOfObjects;
  8.   //Convert a type in a strings array  
  9.   TTypeStringsConverter = reference to function(Data: TObject): TListOfStrings;
  10.  
  11.   //Convert a field in an object
  12.   TObjectConverter = reference to function(Data: TObject; Field: String): TObject;
  13.   //Convert a field in a string  
  14.   TStringConverter = reference to function(Data: TObject; Field: string): string;
  15.  
  16.   //Convert specified type in an object
  17.   TTypeObjectConverter = reference to function(Data: TObject): TObject;
  18.   //Convert specified type in a string  
  19.   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
  1.   TLaptop = class
  2.     Model: String;
  3.     Price: Currency;
  4.     constructor Create(AModel: String; APrice: Currency);
  5.   end;
  6.   TLaptops = TObjectList&lt;TLaptop&gt;;
  7.   TProgrammer = class(TTeenager)
  8.     Laptops: TLaptops;
  9.     constructor Create; override;
  10.     destructor Destroy; override;
  11.     class function CreateAndInitialize: TProgrammer;
  12.   end;
  13. // Implementation code…
  14. var
  15.   Marshaller: TJSONMarshal;
  16.   UnMarshaller: TJSONUnMarshal;
  17.   Programmer: TProgrammer;
  18.   Value, JSONProgrammer: TJSONObject;
  19. begin
  20.   Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  21.   try
  22.     Marshaller.RegisterConverter(TProgrammer, 'BornDate', ISODateTimeConverter);
  23.     Marshaller.RegisterConverter(TStringList, StringListConverter);
  24.     Marshaller.RegisterConverter(TProgrammer, 'Laptops', LaptopListConverter);
  25.     Programmer := TProgrammer.CreateAndInitialize;
  26.     try
  27.       Value := Marshaller.Marshal(Programmer) as TJSONObject;
  28.     finally
  29.       Programmer.Free;
  30.     end;
  31.  
  32.     // UnMarshalling Programmer
  33.     UnMarshaller := TJSONUnMarshal.Create;
  34.     try
  35.       UnMarshaller.RegisterReverter(TProgrammer, 'BornDate', ISODateTimeReverter);
  36.       UnMarshaller.RegisterReverter(TStringList, StringListReverter);
  37.       UnMarshaller.RegisterReverter(TProgrammer, 'Laptops', LaptopListReverter);
  38.  
  39.       Programmer := UnMarshaller.Unmarshal(Value) as TProgrammer;
  40.       try
  41.         Assert('Daniele' = Programmer.FirstName);
  42.         Assert('Teti' = Programmer.LastName);
  43.         Assert(29 = Programmer.Age);
  44.         Assert(EncodeDate(1979, 11, 4) = Programmer.BornDate);
  45.         Assert(3 = Programmer.Phones.Count);
  46.         Assert('NUMBER01' = Programmer.Phones[0]);
  47.         Assert('NUMBER02' = Programmer.Phones[1]);
  48.         Assert('NUMBER03' = Programmer.Phones[2]);
  49.         Assert('HP Presario C700' = Programmer.Laptops[0].Model);
  50.         Assert(1000 = Programmer.Laptops[0].Price);
  51.         Assert('Toshiba Satellite Pro' = Programmer.Laptops[1].Model);
  52.         Assert(800 = Programmer.Laptops[1].Price);
  53.         Assert('IBM Travelmate 500' = Programmer.Laptops[2].Model);
  54.         Assert(1300 = Programmer.Laptops[2].Price);
  55.       finally
  56.         Programmer.Free;
  57.       end;
  58.     finally
  59.       UnMarshaller.Free;
  60.     end;
  61.   finally
  62.     Marshaller.Free;
  63.   end;
  64. end;

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

unit CustomConverter;
  1.  
  2. interface
  3.  
  4. uses
  5.   DBXJSONReflect,
  6.   MyObjects; //Needed by converter and reverter for TLaptops
  7.  
  8. var
  9.   ISODateTimeConverter: TStringConverter;
  10.   ISODateTimeReverter: TStringReverter;
  11.  
  12.   StringListConverter: TTypeStringsConverter;
  13.   StringListReverter: TTypeStringsReverter;
  14.  
  15.   LaptopListConverter: TObjectsConverter;
  16.   LaptopListReverter: TObjectsReverter;
  17.  
  18. implementation
  19.  
  20. uses
  21.   SysUtils, RTTI, DateUtils, Classes;
  22.  
  23. initialization
  24.  
  25. LaptopListConverter := function(Data: TObject; Field: String): TListOfObjects
  26. var
  27.   Laptops: TLaptops;
  28.   i: integer;
  29. begin
  30.   Laptops := TProgrammer(Data).Laptops;
  31.   SetLength(Result, Laptops.Count);
  32.   if Laptops.Count &gt; 0 then
  33.     for I := 0 to Laptops.Count - 1 do
  34.       Result[I] := Laptops[i];
  35. end;
  36.  
  37.  
  38. LaptopListReverter := procedure(Data: TObject; Field: String; Args: TListOfObjects)
  39. var
  40.   obj: TObject;
  41.   Laptops: TLaptops;
  42.   Laptop: TLaptop;
  43.   i: integer;
  44. begin
  45.   Laptops := TProgrammer(Data).Laptops;
  46.   Laptops.Clear;
  47.   for obj in Args do
  48.   begin
  49.     laptop := obj as TLaptop;
  50.     Laptops.Add(TLaptop.Create(laptop.Model, laptop.Price));
  51.   end;
  52. end;
  53.  
  54. StringListConverter := function(Data: TObject): TListOfStrings
  55. var
  56.   i, count: integer;
  57. begin
  58.   count := TStringList(Data).count;
  59.   SetLength(Result, count);
  60.   for i := 0 to count - 1 do
  61.     Result[i] := TStringList(Data)[i];
  62. end;
  63.  
  64.  
  65. StringListReverter := function(Data: TListOfStrings): TObject
  66. var
  67.   StrList: TStringList;
  68.   Str: string;
  69. begin
  70.   StrList := TStringList.Create;
  71.   for Str in Data do
  72.     StrList.Add(Str);
  73.   Result := StrList;
  74. end;
  75.  
  76. ISODateTimeConverter := function(Data: TObject; Field: string): string
  77. var
  78.   ctx: TRttiContext; date : TDateTime;
  79. begin
  80.   date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
  81.   Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
  82. end;
  83.  
  84. ISODateTimeReverter := procedure(Data: TObject; Field: string; Arg: string)
  85. var
  86.   ctx: TRttiContext;
  87.   datetime :
  88.   TDateTime;
  89. begin
  90.   datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), StrToInt(Copy(Arg, 6, 2)), StrToInt(Copy(Arg, 9, 2)), StrToInt
  91.       (Copy(Arg, 12, 2)), StrToInt(Copy(Arg, 15, 2)), StrToInt(Copy(Arg, 18, 2)), 0);
  92.   ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
  93. end;
  94.  
  95. 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

Using AMQP from Delphi with ZeroMQ

Delphi for Win32, Design Patterns, Programming, Uncategorized 8 Comments »

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:

  1. zmq := TZeroMQ.Create;
  2. try
  3. zmq.Open('localhost');
  4. ex := zmq.CreateLocalExchange('MyExchange', zmqStyleDataDistribution);
  5. zmq.Bind('MyExchange', 'GlobalQueue');
  6. zmq.Send(ex, 'Hello World From Delphi');
  7. finally
  8. zmq.Free;
  9. end;

And a simple receiver is simple as follow:

  1. zmq := TZeroMQ.Create;
  2. try
  3. zmq.Open('localhost');
  4. ex := zmq.CreateLocalQueue('LocalQueue');
  5. zmq.Bind('GlobalExchange', 'LocalQueue');
  6. zmq.Receive(msg, msgtype, msgsize, zmqBlocking);
  7. WriteLn(msg);  //we are in a console application
  8. finally
  9. zmq.Free;
  10. 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!

CodeGear, Delphi for Win32, Programming, Uncategorized 5 Comments »

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″

Delphi for PHP, Design Patterns, Programming, Uncategorized, bit Time Software 3 Comments »

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

CodeGear, Delphi for Win32, Design Patterns, MVC, MVP, Programming, Uncategorized 10 Comments »

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:

  1. ICalculatorView = interface
  2.   ['{471E3657-C6CE-49A3-BCB4-8FA6AF611DAD}']
  3.   function FirstOperand: String;
  4.   function SecondOperand: String;
  5.   procedure SetFirstOperand(Value :String);
  6.   procedure SetSecondOperand(Value :String);
  7.   function GetOperator: IGUISelectableList;
  8.   procedure SetCalcResult(const Value: String);
  9.   procedure SetCalcResultReadOnly(const Value: Boolean);
  10.   function Error: IGUIEdit;
  11. end;

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

  1.   function FirstOperand: String;
  2.   function SecondOperand: String;
  3.   procedure SetFirstOperand(Value :String);
  4.   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:

  1.   IGUIBaseInterface = interface
  2.     ['{F0B7F031-9302-415E-8545-1FE20A365840}']
  3.   end;
  4.  
  5.   IGUIEdit = interface(IGUIBaseInterface)
  6.     ['{FE2D56FB-0CFB-4B33-9B56-0A523B235D37}']
  7.     procedure SetText(const Value: String);
  8.     function GetText: String;
  9.     function GetAsInteger: Integer;
  10.     function GetAsFloat: Extended;
  11.     procedure SetReadOnly(const AValue: boolean);
  12.     procedure SetVisible(const Value: Boolean);
  13.     function GetTextAsInteger: Integer;
  14.     procedure SetTextAsinteger(const Value: Integer);
  15.     function GetTextAsFloat: Extended;
  16.   end;
  17.  
  18.   IGUISelectableList = interface(IGUIBaseInterface)
  19.     ['{EEFE5C52-94C3-464B-80F2-05E443B0F0F6}']
  20.     procedure SetText(const Value: String);
  21.     function GetText: String;
  22.     procedure SetValue(const Value: String);
  23.     function GetValue: String;
  24.     function GetSelected: ISSKeyValue;
  25.     procedure AddPair(AKey, AValue: String);
  26.     procedure Clear;
  27.   end;

For implementation details see attached sample code.

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

  1. TfrmCalculatorView = class(TForm, ICalculatorView)
  2.   //code
  3. end;
  4.   //interface section
  5. procedure TfrmCalculatorView.FormCreate(Sender: TObject);
  6. begin
  7.   //Link controls with related interface
  8.   IOperators := TGUISelectableList.Create(ComboOperators);
  9.   IError := TGUIEdit.Create(EditError);
  10.  
  11.   //link view and presenter
  12.   //In this version VIEW know PRESENTER
  13.   FPresenter := TCalculatorPresenter.Create(Self);
  14. 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.

  1. procedure TfrmCalculatorView.Button1Click(Sender: TObject);
  2. begin
  3.   FPresenter.DoCalc;
  4. 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

CodeGear, Delphi for Win32, Design Patterns, MVP, Programming, Uncategorized 1 Comment »

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.

  1. 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.

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

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

  1. procedure TForm3.FormCreate(Sender: TObject);
  2. var
  3. binder: TDataBinder;
  4. begin
  5. //Create your "BO"
  6. Person := TPerson.Create;
  7. //read data from "database"
  8. Person.Load;
  9.  
  10. //Setup databinding…
  11. binder := TDataBinder.Create(self);
  12. binder.Add(Person, 'FirstName'   ,      Edit1,     'Text');
  13. binder.Add(Person, 'LastName',          Edit2,     'Text');
  14.  
  15. //The same attribute binded to 3 controls
  16. binder.Add(Person, 'Married',     CheckBox1, 'Checked');
  17. binder.Add(Person, 'Married'   , Edit1,     'Ctl3D');
  18. binder.Add(Person, 'Married',     Edit2,     'Ctl3D');
  19.  
  20. //The same attribute binded to 2 controls
  21. binder.Add(Person, 'SomeInteger', ComboBox1, 'ItemIndex');
  22. binder.Add(Person, 'SomeInteger',     TrackBar1, 'Position');
  23.  
  24. //A derived property
  25. binder.Add(Person, 'FullName',     Panel1, 'Caption');
  26.  
  27. //let start…
  28. binder.Bind;
  29. end;

Other info asap so, stay tuned.

Download Code and compiled sample

(Source code require Delphi 2009)

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in