Copyright (c) Prolog Developemnt Center SPb

Application Frame. Information exchange between modules

All application core modules (both FE and BE) are objects and, therefore, simple calls to them as class modules cannot be used.
Applicaiton Frame uses a single object registrar, which is a repository of named objects. An object is added to the registrar programmatically by the user when this object is created. The object in the registrar is stored until it is deleted from there by the user programmatically.

If you use a configuration in which FrontEnd and BackEnd are separate applications and they are connected via Http, then each of the applications has its own object registrar, that is, FE and BE cannot "see" each other's object modules. However, in the configuration of the mono-applications, FE and BE do not take advantage of the opportunity to contact each other's module-objects through a common object registrar.

Object Register Operations

The object registrar is an integral part of the  SpbVipTools\Packs\Logic\PzlSystem\OpenPzl\Packs\pzl.pack package. The
predicates for manipulating object registration are (in the pzl.cl class ):

predicates  % Object registration
    register :( string  ObjectName , object  Object ).
    registerMulti :( string  ObjectName , object  Object ).
    getObjectByName_nd :( string  ObjectName ) -> object  Object  nondeterm .
    getNameByObject_nd :( object Object ) -> string  ObjectNameLow  nondeterm .
    getNameAndObject_nd :( string  ObjectName , object  Object )  nondeterm  ( o , o ).
    unRegister :( string  ObjectName , object  Object ).
    unRegisterByName :( string  ObjectName ).
    unRegisterAllByNamePrefix :( string  EntityPrefix ).  % unregister all entities with the Prefixed names
    unRegisterByObject :( object Object ).
    unRegisterAll :().

Registration is simple by assigning a name to the

        pzl :: register object ( <object name>, <object>),

for example, like this:

    ...
   Tasks = fe_CoreTasks :: new ( This ),
   pzl :: register (fe_CoreTasks_C ,  Tasks ),
    ...

Wherefe_CoreTasks_C - the name of the object by agreement.

Getting the registered object for subsequent calls is also easy:
    ...
    TasksObj = pzl :: getObjectByName_nd (fe_CoreTasks_C )),
    the Tasks = tryConvert ( fe_CoreTasks , TasksObj ) , ! ,

    Tasks:
 foo (),    
     ...


Of course, one should pay attention to the determinism of such a transformation. 
Removing an object from the registrar is a simple operation    
    ...
    pzl::unRegisterByName(fe_CoreTasks_C),
    ...

Using the object register in the plugin components

The mechanism for registering objects can be easily built using any approach to organizing data storage, and not just using the pzl.pack package .
Using the pzl.pack package is remarkable in that the plugin components also use the pzl.pack package to work with registered objects. But the most important thing is that plug-in components, being DLLs in their essence, have access to the repository of objects of the main application.
This means that plug-in components can access each other’s objects and the main application’s objects using a single database of registered objects.

Using fe_Connector and be_Connector object modules

The main modules of the kernel access each other using the described mechanism for registering objects.
To reduce the size of the code, operations to obtain objects are placed
Registration of kernel objects is performed at application startup in the classes Common\AppFrontEnd\frontEnd.pro and Common\AppBackEnd\backEnd.pro, respectively.
The following trick is used (using the fe_CoreTasks module object as an example ).

        pzl 
:: register ( string :: concat ( toString ( This ), fe_CoreTasks_C ), Tasks )

That is, the name of the object during registration consists of the string name of the class in the form of the constant 
fe_CoreTasks_C

to which the string representation of the object is assigned to the left (frontEnd or backEnd).

Within the AppFrame, this is not a significant trick. However, the name means that any of the ApplFrame parts can itself be a plug-in component in some application (including those built on the basis of AppFrame), adding such a prefix makes the name of each object unique within one application.

Finally, in the xe_Connector class, which is the parent class of application kernel modules, accessing any application kernel object is made simple by using predicates

for FrontEnd
predicates
    fe_AppWindow : () -> fe_MainWindow .
    fe_CoreTasks : () -> fe_CoreTasks .
    fe_Tasks : () -> fe_Tasks .
    fe_Tests : () -> fe_Tests .
    be_Responses : () -> be_Responses .
    fe_Dictionary : () -> fe_Dictionary .

for BackEnd
predicates
    be_CoreTasks : () -> be_CoreTasks .
    be_Tasks : () -> be_Tasks .
    be_Tests : () -> be_Tests .
    fe_Requests : () -> fe_Requests .
    be_Options : () -> be_Options .
    be_Dictionary : () -> be_Dictionary .

At the same time, obtaining and converting the object to fe_Connector and be_Connector are done as described above, as shown below for the object of class fe_CoreTasks

clauses
    fe_CoreTasks () = convert ( fe_CoreTasks , GuiTasks ): -
        GuiTasks = pzl :: getObjectByName_nd ( string :: concat ( toString ( frontEnd_P ), fe_CoreTasks_C )),!.
    fe_CoreTasks () = _ : -
        exception :: raise_User ( string :: format( "Component% not Registered!" , Fe_CoreTasks_C )).

Hence it can be understood by recording the next track code

    setRibbonScriptFilesAndNameSpace ( Dialog ): -
        Future = be_Responses () : createResponseReciever_async ( be_TakeRibbonScriptFiles_C ),
        fe_CoreTasks () : getRibbonScriptFiles (),
        ...

Where 
be_Responses () and fe_CoreTasks () prepared in the manner described objects.