SDA SE Wiki

Software Engineering for Smart Data Analytics & Smart Data Analytics for Software Engineering

User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
research:pdt:connector:start [2014/09/09 14:26]
andreas.becker
research:pdt:connector:start [2018/05/09 01:59] (current)
Line 1: Line 1:
 +====== Prolog Connector ======
 +The Prolog Connector establishes the connection of a Java process and a Prolog process and can be used independently from the IDE part (see [[..:​contribute:​architecture]]).
 +
 +The Prolog Connector is based on sockets and implements a pure client-server relation: The Java processes send requests, the Prolog
 +processes answer. Communication from Prolog to Java is possible via a notification / observer mechanism:  ​
 +The Java side can declare to be listening for certain events and can explicitly call the Prolog side when notified that the respective events occurred. ​
 +
 +If you just want to run Prolog code from Java, without using the developement environment of the PDT, you can use the provided [[library|library]]. All you need is SWI-Prolog (no need for Eclipse or any other libraries).
 +
 +<​note>​
 +If you are using Windows, make sure that the “bin” directory of your SWI-Prolog installation is added to the system PATH.
 +</​note>​
 +
 +===== Getting an instance of a PrologProcess =====
 +
 +Each instance of a [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​process/​PrologProcess.html|PrologProcess]] corresponds to one Prolog process. There are two ways to retrieve an instance depending on how you use the connector ([[library|library]] or [[plugin|Eclipse plugin]]).
 +
 +=== Library ===
 +If you use the connector library you can get an instance via
 +<Code lang-java>​org.cs3.prolog.connector.Connector.newPrologProcess()</​Code>​
 +which uses SWI Prolog from the system PATH or you can use
 +<Code lang-java>​org.cs3.prolog.connector.Connector.newPrologProcess(executable)</​Code>​
 +which uses the specified SWI Prolog executable.
 +
 +=== Eclipse Plugin ===
 +If you want to use the connector within an Eclipse plugin that depends on the PDT we recommend to depend on the ''​org.cs3.pdt.connector''​ plugin and to use 
 +<Code lang-java>​
 +org.cs3.pdt.connector.PDTConnectorPlugin.getDefault().getPrologProcess(key)
 +</​Code>​
 +to get an instance.
 +
 +===== Executing queries and Processing Results =====
 +
 +Queries are passed as simple Java Strings to the responsible methods.
 +
 +One result of a query is a Java Map containing the bindings for all variables of the query. The variables are the keys of the map.\\
 +The type of the variable values differ, depending on the given flag. If not specified otherwise the [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​process/​PrologProcess.html#​DEFAULT|DEFAULT]] flag will be used. This means, that the values will be instances of ''​String''​ or instances of ''​java.util.List''​ (in case of Prolog lists). The elements in this list can also be of type ''​String''​ or ''​List''​. This is the recommended way if the results only consist of atoms, numbers and lists or if the string representation of a result is sufficient for the context of the program.
 +
 +
 +There are two methods that execute a query:\\
 +  * <Code lang-java>​org.cs3.prolog.connector.process.PrologProcess.queryOnce(query)</​Code>​ returns the first result of the query or ''​null''​ if the query fails.
 +  * <Code lang-java>​org.cs3.prolog.connector.process.PrologProcess.queryAll(query)</​Code>​ returns all results of the query. If the query fails the returned list will be empty.
 +
 +Each result is represented as a Map<​String,​ Object>. The String is the name of a variable in the query. The Object is the value of the variable generated by the query.  ​
 +The following listing shows an example.
 +
 +<Code lang-java>​
 +PrologProcess process = Connector.newPrologProcess();​
 +String query = "​father_of(Child,​ '​Peter'​)";​
 +
 +Map<​String,​ Object> result = process.queryOnce(query);​
 +List<​Map<​String,​ Object>>​ results = process.queryAll(query);​
 +</​Code>​
 +
 +To access the results (that is, the values of the variables from the query) you must know which kind of value to expect:
 +  * an atom -> a String (in the map)
 +  * a list -> a List of Objects (in the map)
 +  * a function term -> a [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​|CTerm]] instance (in the map)
 +
 +In the above example we expect the name of Peter'​s father to be an atom (-> String), so we access it via
 +
 +<Code lang-java>​
 +String firstChildOfPeter = result.get("​Child"​).toString();​
 +</​Code>​
 +
 +===== Utilities for queries =====
 +
 +The class [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​common/​QueryUtils.html|QueryUtils]] contains several utility methods which are useful for constructing queries. ​
 +
 +The most important one is <Code lang-java>​org.cs3.prolog.connector.common.QueryUtils.buildTerm(functor,​ args...)</​Code>​ which constructs a Prolog term for a functor and an arbitrary number of arguments. Using this method makes the code more readable and avoids String concatenations,​ especially when using Java variables in the term construction. There is also the method ''​QueryUtils.bT(functor,​ args...)''​ that forwards to ''​buildTerm''​ but has a shorter name.
 +
 +An example is:
 +<Code lang-java>​
 +String child = "​peter";​
 +String query = QueryUtils.buildTerm("​father_of",​ "​Father",​ child);
 +// this is the same as "​father_of(Father,​ peter)"​
 +</​Code>​
 +
 +===== Sessions =====
 +
 +Sessions are used to execute queries. For each session there is one corresponding thread in the Prolog process and one socket connection between Java and Prolog. There are two kinds of sessions:
 +
 +  * [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​session/​PrologSession.html|Synchronous sessions]] which wait for queries to finish.
 +  * [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​session/​AsyncPrologSession.html|Asynchronous sessions]] which do not wait for queries to finish. It is necessary to register an [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​session/​AsyncPrologSessionListener.html|AsyncPrologSessionListener]] to get notifications about results, errors, etc.
 +
 +Sessions can be obtained by the ''​getSession...''​ methods of a ''​PrologProcess''​ and need to be disposed when they are no longer needed. The ''​query...''​ methods of a ''​PrologProcess''​ create a session automatically and dispose it for each query. ​
 +
 +If you want to execute lots of queries in a short time it is recommended to create one session and execute the queries on this session instead of using the ''​query...''​ methods of a ''​PrologProcess''​. The following listing displays an example.
 +
 +<Code lang-java>​
 +PrologSession session = null;
 +try {
 +    // create a session for the current process
 +    session = process.getSession();​
 +    // execute a lot of queries in a short period
 +    for (int i = 0; i < 10000; i++) {
 +
 +        // use the queryOnce method from the session
 +        // this prevents the creation of a new session for every query
 +        session.queryOnce(bT("​assertz",​ "​p_"​ + i));
 +    }
 +} catch (PrologProcessException e) {
 +    e.printStackTrace();​
 +} finally {
 +    // make sure to close the session after the queries are finished
 +    if (session != null) {
 +        session.dispose();​
 +    }
 +}
 +</​Code>​
 +
 +===== Listen to events from Prolog =====
 +
 +
 +In addition to the message based interaction of Java and Prolog supported
 +by the ''​queryOnce''​ and ''​queryAll''​ methods, the PDT connector also supports
 +an event / observer / notification mechanism. ​
 +
 +The Java side does not need to poll the Prolog processes to find out
 +when some event occurred but can declare that it is listening for certain
 +events. The Prolog side triggers these events if something relevant happens ​
 +(e.g. the end of  a long running computation). Then the Java side can send 
 +a normal ''​queryOnce''​ / ''​queryAll''​ to retrieve the results. ​
 +
 +=== Create the listener ===
 +
 +First you need to create a [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​process/​PrologEventDispatcher.html|PrologEventDispatcher]] for a ''​PrologProcess''​. ​
 +Then add a [[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​process/​PrologEventListener.html|PrologEventListener]] to this dispatcher. ​
 +Every listener can be listening to one or more subjects.
 +
 +<Code lang-java>​
 +currentDispatcher = new PrologEventDispatcher(currentProcess);​
 +currentDispatcher.addPrologEventListener("​pdt_edit_hook",​ this);
 +</​Code>​
 +
 +The code above (excerpt from ''​org.cs3.pdt.editor.internal.editors.CurrentProcessListener''​) creates and registers a listener for the ''​pdt_edit_hook''​ event. ​
 +
 +When the related event is sent by the Prolog side, the ''​update''​ method of each
 +registered ''​PrologEventListener''​ will be called with a parameter of type 
 +[[http://​sewiki.iai.uni-bonn.de/​public-downloads/​docs/​prolog.connector_3.0/​index.html?​org/​cs3/​prolog/​connector/​process/​PrologEvent.html|PrologEvent]] that contains the event identifier (''​pdt_edit_hook''​ in our example)
 +and some arbitrary additional data from the second parameter of the ''​pif_notify/​2''​ call (see below).
 +
 +=== Sending Prolog events ===
 +
 +To send a notification from a Prolog process, call the ''​pif_notify/​2''​ predicate. ​
 +Its first argument is an even identifier (which must be an atom) and the second argument an 
 +arbitrary value that will be passed to the Java side along with the event.
 +<​Code>​
 +pif_observe:​pif_notify(pdt_edit_hook,​ '​l:​\test.pl 1')
 +</​Code>​
 +The above tells the Java side that the ''​pdt_edit_hook''​ event occurred for the file
 +'​l:​\test.pl'​. For an example see the module ''​pdt_editor_edit_hook''​.
 +
  

SEWiki, © 2019