Copyright (c) Prolog Developemnt Center SPb

Application Frame. Plugin mechanism

The plugins mechanism in ApplicationFrame is based on the concept of PzlSystem, which is a system of conventions for using DLLs to store part of an executable system.
The PzlSystem concept is described in more detail in the VpPuzzle document .

System packages are located in the   SpbVipTools\Packs\Logic\PzlSystem\OpenPzl directory.

Each of the AppFrame project variants in accordance with the concept of VpPuzzle is a pzl-Container, that is, it can contain pzl-Components. The AppFrame core does not use the properties of the pzl-Container, however, nothing prevents a particular project from using these properties.

The Plugins mechanism involves the use of the pzl-Component located in pzl-Containers, each of which is a DLL. Each pzl-Container may contain any number of pzl-Components.

Pzl-Components, the use of which is supposed to be in a project based on AppFrame, must be pre-registered by any of the methods provided by the pzl-Concept.

Each pzl-component can refer to any other registered pzl-components. The depth of the call hierarchy is unlimited.
However, the AppFrame only "knows" about the component it is accessing.

Call plugin

Since the AppFrame architecture assumes strict separation of FrontEnd and BackEnd, Plugins calls in the context of FrontEnd and BackEnd have their own characteristics.
In particular, this concerns the invocation of a component represented by its user interface, a command from the control panel.
In the xml description of the control panel for the AppFrame core, the agreement on the key combination
    ribbon.cmd.plugin. <Component name>

and the data for the 
category property of the command in the command identifier is significant. Moreover, the content of the category property data is determined only by the plugin component developer.

An example pzl call definition of pzlGame Components is given below

                 <cmd
                    id="ribbon.cmd.plugin.pzlGame"
                    label="Game_PLL14"
                    cmdstyle="image-and-text-vertical"
                    run="pzl-extension"
                    menu-label="Game_PLL14"
                    enabled="true"
                    visible="true"
                    category=""
                    >
                    <icon file="$(pdc-external)\categories\applications-games.ico"/>
                    <tooltip text="Polyline14 aggregated pzlComponent"/>
                </cmd>

Here is the category property shown for completeness, although it might be absent, since it has no practical value.
The definition of the run = "pzl-extension" attribute is important , which means that pzl-extension is the identifier of the predicate that will be called when the command with label = "Game_PLL14" is activated .

When determining the context for this case, the assignment must be

    setCommonPerformers(ContextObj):-
        ...
        ContextObj:setRunner("pzl-extention",fe_CoreTests():runPlugin),
        ...

And in the object
 fe_CoreTests() call of the pzl-Component may look like this:

clauses

    runPlugin ( Command ): -
        PluginID = fe_Command :: tryExtractCommandSuffix ( Command , "ribbon.cmd.plugin." ),
        !,
        ComponentObj = pzl :: newByName ( PluginID , fe_AppWindow ()),
        Component = convert ( pzlRun , ComponentObj ),
        Component : pzlRun ( toString (Command : category )).
    runPlugin ( Command ): -
        Msg = string :: format ( "Not pzl plugin invocation command [%] \ n " , Command : id ),
        log :: write ( log :: error , Msg ),
        exception :: raise_User ( Msg )

It uses the convention that components represented by the user interface can be invoked by calling the predicate pzlRun (...) with the transfer to him of the necessary data in text form. This example passes the contents of the category property of the command. The pzlRun interface (containing the predicate of the same name) is one of the interfaces of the pzl-System.

After calling the pzlRun predicate, the further behavior of Plugin is determined by its implementation. After the plugin completes, all its components will be automatically unloaded and the memory will be freed (when garbageCollector will run).