RO Client with one _intf unit for every service

Hi,

in my app, client side, I use rocg4_helper tool to generate one file for every service since the server will expose many services (I use Hydra also on the client side) I would like to separate the interfaces for the exposed service on single files.

Every unit _intf generated (all services all inherited from DataAbstract) they have an initialization and finalization section. In these sections there are calls to register and unregister classes/enumerators etc. etc.

The question is that having each service on separate files I find that the same classes are registered multiple times (each unit has its own section with the same base classes registered).

This is a sample:

initialization
      RegisterROEnum('SimpleDataMode', System.TypeInfo(SimpleDataMode), DefaultNamespace);
      RegisterEnumMapping('SimpleDataMode', 'Insert', 'Insert', DefaultNamespace);
      RegisterEnumMapping('SimpleDataMode', 'Delete', 'Delete', DefaultNamespace);
      RegisterEnumMapping('SimpleDataMode', 'Update', 'Update', DefaultNamespace);
      RegisterROEnum('SimpleDataType', System.TypeInfo(SimpleDataType), DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'String', 'String', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Integer', 'Integer', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Double', 'Double', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'DateTime', 'DateTime', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Int64', 'Int64', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Currency', 'Currency', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Guid', 'Guid', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Binary', 'Binary', DefaultNamespace);
      RegisterEnumMapping('SimpleDataType', 'Boolean', 'Boolean', DefaultNamespace);
      RegisterROClass(TableRequestInfo, DefaultNamespace);
      RegisterROClass(DataParameter, DefaultNamespace);
      RegisterROClass(SimpleRequestInfo, DefaultNamespace);
      RegisterROClass(SimpleDataParameter, DefaultNamespace);
      RegisterROClass(SimpleDataResult, DefaultNamespace);
      RegisterROClass(SimpleFieldInfo, DefaultNamespace);
      RegisterROClass(SimpleDelta, DefaultNamespace);
      RegisterROClass(SimpleDeltaChange, DefaultNamespace);
      RegisterROClass(DataParameterArray, DefaultNamespace);
      RegisterROClass(SimpleDataParameterArray, DefaultNamespace);
      RegisterROClass(SimpleDataResultArray, DefaultNamespace);
      RegisterROClass(SimpleDeltaArray, DefaultNamespace);
      RegisterROClass(SimpleDeltaChangeArray, DefaultNamespace);
      RegisterROClass(SimpleFieldInfoArray, DefaultNamespace);
      RegisterROClass(SimpleRequestInfoArray, DefaultNamespace);
      RegisterROClass(StringArray, DefaultNamespace);
      RegisterROClass(StringArrayArray, DefaultNamespace);
      RegisterROClass(TableRequestInfoArray, DefaultNamespace);
      ...

I have no runtime errors and everything is working fine but I was wondering if this could be a problem.

Thank you very much.

Hi,
it will work correctly because these classes/enums were registered in personal namespace.
it was made for supporting multiply versions of RODL in one project. for example you can support in one project your RODL v1 and RODL v2.

list of namespaces can be specified in TROMessage.DefaultNamespaces.
if TROMessage.DefaultNamespaces isn’t set, it uses DefaultNamespaces for given _intf

Hi EvgenyK

thank you very much! I assumed it was so

So for each service I define a different NameSpace. Right?

Hi,

you can define it, but it isn’t necessary.

by default, if namespace is empty, name of Library if used as default namespace:

I use CodeFirst so If I, client side, create a unit for every services, all units will have the same namespace and therefore all “equal” classes will be registered with the same namespace because in my services I defined this:

type
  [ROService('CommonService', '{CCE18AD1-F304-49D4-80C8-2AC6B48190C6}')]
  [RONamespace('FujiFilm.SynapseWF')]
  [ROServiceGroup('Common')]
  [ROPooledClassFactoryAttribute(20)]

and this:

type
  [ROService('ExecutionService', '{DE548CA1-7416-42FB-8075-1FE007E41021}')]
  [RONamespace('FujiFilm.SynapseWF')]
  [ROServiceGroup('Execution')]
  [ROPooledClassFactoryAttribute(20)]

This work but every classes is registered in the same NameSpace

So what is the purpose of defining a NameSpace?

Conceptually all services are part of the same library but generating separate _intf units for each service I doubt that registering the same class several times on the same namespace is not correct. Among other things, I could extract the common part (all base classes) and define/register them on a dedicated unit that I no longer modify. I have to modify the generated units every time and import this “super unit” by hand but it would probably be the most correct logic. What do you think about it?

Thank you very much!

Hi EvgenyK

This is what I mean (I did it on the fly without testing it ;-))

I generate the _intf unit for a service. From this unit I extracted all base code and I generated Base_intf.pas unit (only the first time). After I deleted all base code and I added the Base_intf.pas in the initialization section of the service_intf.pas unit.

I attached all files.

Base_Intf.pas (148.6 KB) Execution_Intf.pas (116.2 KB)

Hi,

Have you tried to use the ServiceGroup attribute?
see more at Remoting SDK for Delphi vNext: New features

Yes, I use it to be able to export the services exposed by a group on a single unit. The “problem” is that each generated unit also extracts all base classes / structures. For example:

 type
  {Forward declarations}
  TableRequestInfo = class;
  TableRequestInfoCollection = class;
  DataParameter = class;
  DataParameterCollection = class;
  SimpleRequestInfo = class;
  SimpleRequestInfoCollection = class;
  SimpleDataParameter = class;
  SimpleDataParameterCollection = class;
  SimpleDataResult = class;
  SimpleDataResultCollection = class;
  SimpleFieldInfo = class;
  SimpleFieldInfoCollection = class;
  SimpleDelta = class;
  SimpleDeltaCollection = class;
  SimpleDeltaChange = class;
  SimpleDeltaChangeCollection = class;
  .....

And the related registrations

initialization

RegisterROEnum('SimpleDataMode', System.TypeInfo(SimpleDataMode), DefaultNamespace);
RegisterEnumMapping('SimpleDataMode', 'Insert', 'Insert', DefaultNamespace);
RegisterEnumMapping('SimpleDataMode', 'Delete', 'Delete', DefaultNamespace);
RegisterEnumMapping('SimpleDataMode', 'Update', 'Update', DefaultNamespace);
RegisterROEnum('SimpleDataType', System.TypeInfo(SimpleDataType), DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'String', 'String', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Integer', 'Integer', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Double', 'Double', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'DateTime', 'DateTime', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Int64', 'Int64', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Currency', 'Currency', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Guid', 'Guid', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Binary', 'Binary', DefaultNamespace);
RegisterEnumMapping('SimpleDataType', 'Boolean', 'Boolean', DefaultNamespace);
RegisterROClass(TableRequestInfo, DefaultNamespace);
RegisterROClass(DataParameter, DefaultNamespace);
RegisterROClass(SimpleRequestInfo, DefaultNamespace);
RegisterROClass(SimpleDataParameter, DefaultNamespace);
RegisterROClass(SimpleDataResult, DefaultNamespace);
RegisterROClass(SimpleFieldInfo, DefaultNamespace);
RegisterROClass(SimpleDelta, DefaultNamespace);
RegisterROClass(SimpleDeltaChange, DefaultNamespace);
RegisterROClass(DataParameterArray, DefaultNamespace)

As I wrote you before, I’d like to extract all these base classes / types and expose them to a base unit to import into each generated _intf (clearly making all the necessary modifications) so that these classes are defined only once.

See this units :wink:

Hi,

try to use this trick:

  • create a .RODL like
DA_Shared
<?xml version="1.0" encoding="utf-8"?>
<Library Name="DA_Shared" UID="{D344508D-06C3-4868-9BEF-1E1758B0B6A4}" Version="3.0">
<Services>
</Services>
<EventSinks>
</EventSinks>
<Structs>
</Structs>
<Enums>
</Enums>
<Arrays>
</Arrays>
<Uses>
<Use Name="DataAbstract4" UID="{54C5870B-A89D-4DB4-A13F-6E2D183D7503}" Rodl="$(Data Abstract for Delphi)\Source\DataAbstract4.RODL" AbsoluteRodl="C:\Program Files (x86)\RemObjects Software\Data Abstract for Delphi\Source\DataAbstract4.RODL" UsedRodlUID="{DC8B7BE2-14AF-402D-B1F8-E1008B6FA4F6}" DontCodeGen="1">
<Includes UID="{ECE5910F-040B-4BDF-9502-EDF7F95642CF}" Delphi="DataAbstract4" DotNet="RemObjects.DataAbstract.Server" ObjC="DataAbstract/DataAbstract4_Intf" Java="com.remobjects.dataabstract.intf" Cocoa="DataAbstract"/>
</Use>
<Use Name="DataAbstract_Simple" UID="{47785532-48BB-4486-8A00-6430819E2A96}" Rodl="$(Data Abstract for Delphi)\Source\DataAbstract-Simple.RODL" AbsoluteRodl="C:\Program Files (x86)\RemObjects Software\Data Abstract for Delphi\Source\DataAbstract-Simple.RODL" UsedRodlUID="{367FA81F-09B7-4294-85AD-68C140EF1FA7}" DontCodeGen="1">
<Includes UID="{19A60D98-4AC7-49CC-B172-5528DE83DAEC}" Delphi="DataAbstractSimple" DotNet="RemObjects.DataAbstract.Server" ObjC="DataAbstract/DataAbstractSimple_Intf" Java="com.remobjects.dataabstract.intf" Cocoa="DataAbstract"/>
</Use>
</Uses>
<Exceptions>
</Exceptions>
</Library>
  • create .RES from it
  • include DA_Shared.RES to your server project
  • regenerate _Intf

after this, all your _intf will use types/enums from DataAbstract4_Intf.pas/DataAbstractSimple_Intf.pas accordingly and content of _Intf will be simplified

Hi EvgenyK

I tried but it doesn’t work.

I create a new server project with your RODL. Compiled and copied the DASharedLibrary.res in my server project.

In .dpr I added this

{$R ..\Common\Resources\DASharedLibrary.res}

I also did the same thing on the Hydra service plugin.

Compile and run, extract a _intf service but the generated file it’s the same as before.

But be aware that on the server side I use CodeFirst and not RODL. Same logic for RO Hydra services.

Maybe I’m doing something wrong. Could you send me a small example?

Thank you very much!!

Hi,

something like this: testcase.zip (182.2 KB)
check _Intf unit - it doesn’t contain DA/DA_Simple declarations.

it was generated from DA_Shared.remoteRODL

1 Like

Hi EvgenyK

your test work fine!!!

You are my hero!

I tried to modified my server importing DA_SHARED.res

{$R ..\Common\Resources\DA_SHARED.res}

but not work.

Now I have to understand why as your solution is exactly what I want!

Thank you EvgenyK, I really appreciate your invaluable and always top support!

Hi EvgenyK

IT WORKS!!!

I found where was my problem.

Since I use runtime packages I imported the DA_SHARED.res resource into the package and now it works correctly !!!

THANK YOU VERY MUCH!!!