vrijdag 13 februari 2009

RemObjects SDK voor Delphi

RemObjects SDK is een Remoting Framework, waar onder andere eenvoudig WebServices mee gemaakt kunnen worden. Het is van het gelijknamige RemObjects.com . De laatste tijd is het vooral bekend geworden door Delphi Prism , omdat zij de Oxygene compiler geschreven hebben. RemObjects maakt nog meer mooie software: Hydra (.Net assemblies in Win32 gebruiken), Data Abstract , Pascal Script, etc. Niet alleen Delphi maar ook .Net (Visual Studio) wordt ondersteunt.
Ik heb geluk gehad dat ik bij mijn huidige detacheringsopdracht met deze mooie software in aanraking mocht komen :-).

De RO SDK is een beetje te vergelijken met WCF van .Net en DataSnap van Delphi. Maar het vooral veelzijdiger dan deze 2! Het is in principe taal onafhankelijk (C++, C#, php, Delphi maar ook FPC), meerdere platformen (Windows, Linux en MacOs!), ondersteunt verschillende formaten (binair, SOAP, JSON, XML, etc) en allerlei transporten (TCP, UDP, HTTP, mail, IPC, Messages, dll(!) etc). Daarnaast ondersteunt het verschillende vormen van encryptie en compressie. Juist deze brede ondersteuning biedt heel veel mogelijkheden, waarbij WebServices maar een van de vele is.

Ontwikkelen met de RO SDK is eenvoudig, globaal te verdelen in 4 stappen:

  1. Interface definieren in een aparte grafische tool
  2. Code wordt automatisch gegenereerd door de SDK
  3. Implementatie maken aan de server kant
  4. De interface aanroepen aan de client kant

Doordat de software mooi integreert met oa Delphi wordt je stap voor stap geholpen door middel van een wizard. Zo kan automatisch een server en client project aangemaakt worden, zodat je snel er mee kunt werken. Ook worden vele demos (inclusief handleiding en uitleg!) meegeleverd, zodat wat geavanceerde technieken eenvoudig geleerd kunnen worden. Ook de gegenereerde code is netjes gedocumenteerd. Alles is gewoon heel netjes afgewerkt!

Demonstratie

Om het een en ander toe te lichten, zal ik de stappen tonen waarmee je een nieuwe RO applicatie maakt.
Als eerste maken een nieuw project via File -> New -> Other:

Vervolgens kiezen we voor een VCL Standalone server (dit is het makkelijkst te testen):

Na het drukken op OK verschijnt een mooie wizard van RO:

Via de "Advanced Project Options" knop kunnen wat meer instellingen aangepast worden:

Na het drukken op OK hebben we een nieuwe Project Group met een server en client project.

Cliënt

De client bestaat uit een channel (in dit geval een TCP client), een message (binair formaat) en een remote service waarmee we de functies aan de server kant mee kunnen aanroepen:

Server

De server bestaat uit een TCP server en message component (binair formaat):

Standaard staat alles al goed ingesteld, tijd om de "service interface" te bekijken.

Service Interface

Om de interface te bekijken of aan te passen, klikken we op "Edit Service Library" in het "RemObjects SDK" menu:

Vervolgens verschijnt de Service Builder, met default de volgende interface:

Zoals je ziet in de bovenstaande screenshot, kun je hier je eigen structures, enumerations en arrays maken. Deze types kunnen als parameter of result van een functie gebruikt worden. Ook kunnen custom exceptions gedefinieerd worden en asynchrone events gemaakt worden. Het mooie van deze types en definities is dat deze ook als fixed types in code gebruikt kunnen worden!

Server Code

Zodra het project gecompileerd wordt (of via het RO menu) wordt vanuit de Service Definitie de code gegenereerd. Voor elke "service" wordt een RO Datamodule aangemaakt:

Verder wordt een "invoker" unit, "interface" unit (met alle types) en een "implementation" unit gemaakt. De eerste 2 units worden elke keer automatisch ververst en hoeven niet aangepast te worden. Alleen de implementatie moet uiteraard zelf gemaakt worden, zoals in dit geval voor de "Sum" en "GetServerTime" functies:

Client Code

Het enige wat we nu nog moeten doen is een paar knoppen toevoegen aan de client, zodat we server functies kunnen aanroepen:

procedure TClientForm.btnServerTimeClick(Sender: TObject);
var dtServer: TDateTime;
begin
dtServer := (RORemoteService as INewService).GetServerTime;
lblServerTime.Caption := DateTimeToStr( dtServer );
end;

procedure TClientForm.btnSumClick(Sender: TObject);
var iSum: integer;
begin
iSum := (RORemoteService as INewService).Sum( edtA.Value, edtB.Value );
edtSum.Text := IntToStr( iSum );
end;

Als laatste builden we de beide projecten.

Uitvoeren

Om onze code te testen, starten we als eerste via het RO menu de server:

Het eenvoudige scherm van de server verschijnt, waarna we de client kunnen starten (zie onder voor server en client):

Zoals je ziet werkt de code uitstekend :-). En dat met maar 6 regels code!

maandag 9 februari 2009

Dephi Prism: Aspect Oriented Programming

Vorige week heeft CodeGear de Delphi Prism Roadmap vrijgegeven. 1 onderdeel wat me opviel was de support voor "Aspect Oriented Programming" (AOP). Ik heb deze term opgezocht bij Wikipedia (AOP [nl] en AOP [en] ) en simpel gezegd komt het erop neer dat het een uitbreiding is van "Object Oriented Programming", waarbij de nadruk ligt in het verdelen van functionaliteit in "aspecten". Leuk, maar hoe werkt dit in de praktijk?

Gelukkig verscheen eind vorige week een interesante blog op de blogsite van RemObjects (makers van de Oxygene compiler in Delphi Prism): Delphi Prism AOP - Cirrus

Cirrus is de code naam voor de AOP implementatie. Het is een onderdeel van de compiler: tijdens het compileren worden de "aspecten" aan de classes toegevoegd. Het is een beetje te vergelijken met "class c.q. extensions methods" en "partial classes". Maar AOP gaat veel verder, doordat je de aspecten kun hergebruiken en toe kunt passen op alle classes!
Erg interesant, maar de bovenstaande blog was vooral een simpel voorbeeld hoe het technisch werkt, wat ook bleek uit de reacties in de trant van: "Leuk, maar wat kun je er nou mee?". Hierop werd de volgende uitleg gegeven:

The reason this is cool is it allows you to separate your concerns. When you are writing code you don't need mix your concerns by including logging code in your main business logic classes, and you don't need to duplicate the calls to logging in each method.

Keep in mind this is the simplest example. You can use AOP to add multi-threading support, security, logging, etc. to a class. You implement the logging, security, threading, etc. code in one class, and the business logic in another class. Then it is injected for you.

It makes code easier to write and maintain. Less duplication of code so less bugs.

Later verscheen de volgende blog met een specifiek partijk voorbeeld hoe je AOP kunt gebruiken: Prism Aspects to Help with Monobjc Development

AOP is niet de oplossing voor alle problemen, maar zeker een nuttige feature om te gebruiken! Sommige C# programmeurs werden al jalours toen ze die blog lazen... ;-)