An LPI plug-in ("logic plug-in") is essentially a small Prolog program that is attached to the CBserver at startup-time. It extends the functionality of the CBserver, for example for user-defined builtin queries. A plug-in can also interface to the services of the operating system.
You can create a file like myplugin.swi.lpi to provide the implementation for your user-defined builtin queries or for action calls in active rules (see section 4). You can use the full range of functions provided by the underlying Prolog system (here: SWI-Prolog, link) and the functions of the CBserver to realize your implementation. You may consult the the CB-Forum for some examples at link. You find there examples for sending emails from active rules, and for extending the set of builtin queries and functions.
Once you have coded your file myplugin.swi.lpi, there are two ways to plug it into the CBserver. The first way is to copy the file into an existing database directory created by the CBserver.
cbserver -g exit -d MYDB cp myplugin.swi.lpi MYDB
This option makes the definitions only visible to a CBserver that loads the database MYDB. The second option is to instruct ConceptBase to load your LPI code to any database created by the CBserver. To do so, you just have to copy the LPI file into the directory with the system definitions:
cp myplugin.swi.lpi <CB_HOME>/lib/SystemDB
where CB_HOME is the directory into which you installed ConceptBase. The number of LPI files is not limited. You may code zero, one or any number of plug-in files.
A couple of useful LPI plug-ins are published via the CB-Forum, see link. Note that these plugins are copyrighted typically come with their own license conditions that may be different to the license conditions of ConceptBase. If you plan to use the plugins for commercial purposes, you may have to acquire appropriate licenses from the plugin’s authors.
There are two ways to trigger the call of a procedure implemented by an LPI plugin.
If the code of an LPI plugin realizes a ConceptBase function, e.g. selecting the first instance of a class, then you can use that function whereever functions are allowed. As an example, consider the definition of the LPI plugin selectfirst.swi.lpi from link:
compute_selectfirst(_res,_class,_c1) :- nonvar(_class), cbserver:ask([In(_res,_class)]), !. tell: 'selectfirst in Function isA Proposition with parameter class: Proposition end'.
The first clause is the Prolog code. The predicate must start with the prefix compute_ followed by the name of the function. The first argument is for the result of the function. Subsequently, each input parameter is represented by two arguments, one for the input parameter itself and a second as a placeholder of the type of the input parameter. The second clause tells the new function as ConceptBase object so that it can be used like any other ConceptBase function. For technical reasons, the ’tell’ clause may not span over more than 5 lines. Use long lines if the object to be defined is large.
If you just want to invoke the procedure defined in an LPI plugin via the CALL clause of an active rule, you do not need to include a ’tell’ clause. Consider for example the SENDMAIL plugin from link.
You need to be very careful with testing your code. Only use this feature for functions that cannot be realized by a regular query class or by active rules. LPI code has the full expressiveness of a programming language. Program errors may lead to crashes of the CBserver or to infinite loops or to harmful behavior such as deletion of files. Query classes, deductive rules and integrity constraints can never loop infinitely and can (to the best of our knowledge) only produce answer, not changes to your file system or interact with the operating system. Active rules could loop infinitely but also shall not change your file system and shall not interact with the operating system unless you call such code explicitely in the active rule.
You can disable the loading of LPI plugins with the CBserver option -g nolpi. The CBserver will then not load LPI plugins upon startup. This option might be useful for debugging or for disabling loading LPI plugins that are configured in the lib/SystemDB sub-directory of your ConceptBase installation.
The CBserver plug-ins need to interface to the functionalities of the CBserver, the Prolog runtime, and possibly the operating system. To simplify the programming of the CBserver plug-ins, we document here the interface of the module cbserver. We assume that the code for the plug-ins is written in SWI-Prolog and the user is familiar with the SWI-Prolog system.
Note that ConceptBase internally manages concepts by their object identifier. The programming interface instead addresses concepts (and objects) by their name, i.e. the label of the object or the Prolog value corresponding to the label. You may have to use the procedure makeName and makeId to switch between the two representations. The two procedures arg2val and val2arg are useful for defining new builtin functions on the basis of Prolog’s arithmetic functions. Assume for example, that the object identifier id123 has been created to correspond to the real number 1.5. Then, the following relations hold: makeName(id123,’1.5’), arg2val(id123,1.5). Hence, makeName returns the label ’1.5’ whereas arg2val returns the number 1.5.
The interface shall be extended in the future to provide more functionality. Be sure that you only use this feature if user-defined query classes cannot realize your requirements!