RemObjects SDK Services Sample (Delphi)
The RemObjects SDK Services sample demonstrates how to use Hydra to enhance RemObjects SDK services. In this sample we will show how to use Hydra SDK service plugins to dynamically extend server functionality and also use local services.
Please note that you will need the RO SDK for Delphi and the Hydra RO SDK integration package installed in order to build and run this application.
Examine the Server
The server application is a regular RemObjects SDK VCL server application that exposes two simple test services. If you need more information on how to create an RO SDK server, please refer to the RemObjects SDK docs.
Let's examine the most important part of the server:
TServerForm = class(TForm, ISessionProvider) [...] ModuleManager: THYModuleManager; RODLReader: THYRODLReader; [...] end; procedure TServerForm.Button2Click(Sender: TObject); begin with ModuleManager do if ModuleCount>0 then UnloadModules else LoadModules('*.dll'); end; procedure TServerForm.ROServerGetRODLReader(Sender: TROServer; var aRODLReader: TROCustomRODLReader); begin aRODLReader := RODLReader; end; procedure TServerForm.DisplayServiceCount; var i, cnt : integer; begin if (csDestroying in ComponentState) then Exit; ListBox1.Items.Clear; cnt := 0; with ModuleManager do for i := 0 to (PluginDescriptorCount-1) do if (PluginDescriptors[i].PluginType=ptService) then begin Inc(cnt); ListBox1.Items.Add(PluginDescriptors[i].Name) end; lbServiceCount.Caption := IntToStr(cnt)+' Dynamic Services Loaded'; end;
Button2Click method- Using module manager, we are loading all existing dll's in a server directory or unloading all loaded plugins. This allows us to extend server functionality dynamically in runtime.
OnGetRODLReader event handler- This handler assigns Hydra's THYRODLReader component as a custom RODL reader. This component allows our server to merge rodls from plugins into the main rodl.
DisplayServiceCount method- This method uses a plugin descriptor to detect the number of service plugins.
As mentioned earlier, the server also demonstrates how to use local services. The key component here is the THYLocalService class. This component is used for accessing any local service implemented in either the host application itself or in the Hydra module loaded by the host application.
Let's take a look at how this is done in the sample:
procedure TServerForm.bInvokeLocalServiceClick(Sender: TObject); var mainsvc : IMainService; begin try mainsvc := (svcMainService as IMainService); ShowMessage('The result is '+IntToStr(mainsvc.Sum(1,2))); finally if svcMainService.HoldsInstance then svcMainService.ReleaseInstance; end; end; procedure TServerForm.bInvokeHydraServiceClick(Sender: TObject); var hydrasvc : IHydraService; begin try hydrasvc := (svcHydraService as IHydraService); ShowMessage(hydrasvc.GetRandomSentence); finally if svcHydraService.HoldsInstance then svcHydraService.ReleaseInstance; end; end;
The first method works with a service that is exposed by the host itself; the second one is trying to access the dynamic service that is located in the Hydra plugin.
As you can see, we are simply casting our svcHydraService and svcMainService, which are THYLocalService components, to the desired service interface and can then use this interface like a regular service.
Also please note that THYLocalService provides the HoldsInstance property, which can show if we already created an instance of the service, as well as the ReleaseInstance method that can release a previously created instance.
Examine the Plugin
Our plugin is a Hydra module that holds an RO SDK service. If you need more information on how to create an RO SDK server, please refer to this article.
Note: We are using a shared package to avoid possible issues with multiple types initialization. If the _Intf file is placed in a package that is loaded by the host, they will be initialized only once.
Let's take a look at one of the services:
THydraService = class(TRORemoteDataModule, IHydraService) protected function GetRandomSentence: AnsiString; end; [..] function THydraService.GetRandomSentence: AnsiString; const Sentences : array[0..3] of Ansistring = ( 'It is a beautiful day', 'I would love to speak Japanese', 'I am a RemObjects SDK Service', 'RemObjects'' stuff is really cool!'); begin Randomize; result := Sentences[Random(Length(Sentences))]; end; initialization THYServicePluginFactory.Create(HInstance, TROClassFactory.Create('HydraService', Create_HydraService, THydraService_Invoker));
As you can see, this is a regular RO SDK service, the only difference lies in the registration procedure – it creates a THYServicePluginFactory on top of the regular RO factory. Everything else is the same as in server: the services plugins can have multiple services, structures, etc.
Examine the Client
The client is an application that is able to access services exposed by our server. If you need more information on how to create an RO SDK client, please refer to the RemObjects SDK docs.
There is no difference between the server's own services and the dynamic services from a client perspective, so you can work with them as with any other services:
procedure TClientForm.Button1Click(Sender: TObject); begin ShowMessage('The result is '+IntToStr((RORemoteService as IMainService).Sum(1,2))); end; procedure TClientForm.Button2Click(Sender: TObject); begin ShowMessage((svcHydraService as IHydraService).GetRandomSentence); end;
The only difference occurs when the plugin that contains the service is not loaded; in this case the server will return an exception:
Putting It All Together
Now that we've examined all major parts of the sample, we can build both plugin and host. And after we launch the sample, we should get the following results:
The server is started but the plugin is not loaded. This is the result of the Parse RODL command – as you can see, the server exposes only its own services:
After the plugin is loaded:
Client accessing the dynamic service: