This page describes a BSF (Bean Scripting Framework) engine for JLog, a Prolog-in-Java system. JLog is a full-featured Prolog interpreter that can be run as an applet, an application or embedded through an API. You can download the full package, which includes JLog-1.3.6, here: JLog-1.3.6-ulf.zip. It's licensed under the GPL.
BSF enables a Java host program to call scripts or programs written in other languages in a language-neutral way. That means that a BSF-enabled application can a) call scripts and programs written in other languages without knowing in advance in which language they might be (embedding), and b) that any language for which a BSF engine is available can be used to script a BSF-enabled Java application (scripting). Currently, BSF integration is available for JavaScript, XSLT, Jython, Python, Ruby, ObjectScript, NetRexx, TCL, Groovy and now for Prolog. BSF has been released under the Apache License and can be found at jakarta.apache.org/bsf/. It's also included in the download above.
The JLog/BSF integration library (or BSF engine) was developed by Ulf Dittmer. JLog itself is developed by Glendon Holst, and can be found at jlogic.sourceforge.net/. It's also licensed under the GPL.
Sections in this document:
Predicates
JLogBSFEngine defines a number of Prolog predicates that can be used for Prolog <--> Java interaction.
bsf_register (Name, Bean)
Stored the object in variable Bean under the given name in the registry.
Name
must be a string or a variable bound to a string. Bean
must be a bound variable.
bsf_lookup (Name, ResultVar)
Looks up the object of this name
in the registry, and binds it to the variable ResultVar
.
Name
must be a string or a variable bound to a string.
bsf_unregister (Name)
Removes the object with this name from the registry. Name
must be a
string or a variable bound to a string.
bsf_import (Package)
Adds the given package name to
the lists of imports, so that all Java objects in that package can be
referenced just by their classname, instead of by their fully qualified name. java.lang
is imported automatically. Package
must be a string or a variable bound to a string.
bsf_static (Class, ResultVar)
Retrieves a class and stores it in variable ResultVar
, so that static
methods can be invoked on it (e.g. Integer.valueOf
).
Can also be used to retrieve static fields of classes (e.g. java.lang.System.out
). Class
must be a string or a variable bound to a string.
bsf_create (ResultVar, Class, Parameters [, Types])
Prolog wrapper for a Java
constructor. The resulting object of class Class is put in the variable
ResultVar. Parameters is the list of parameters. The Java equivalent would be ResultVar = new Class(Parameters)
bsf_create/3
(w/o the Types
parameter) tries
to figure out the correct method signature based on the types of the given
parameters. This works in most cases, but not always. If it can't decide which
constructor to use, an exception is thrown that advises to use bsf_create/4
instead. That means that the
list of parameters is needed to select the correct one.
bsf_invoke (ResultVar, Bean, Method, Parameters [, Types])
Prolog wrapper for a Java method invocation. Its Java equivalent would be
ResultVar = Bean.Method(Parameters)
bsf_invoke/4
(w/o the Types
parameter) tries
to figure out the correct method signature based on the types of the given
parameters. This works in most cases, but not always. If it canβt decide which
method to use, an exception is thrown that advises to use bsf_invoke/5
instead. That means that the
list of parameters is needed to select the correct one.
bsf_addevent (Bean, Action, Script)
This causes the Prolog code in Script
to be executed whenever the Java
object Bean
fires an Action
event. The ScriptedUI example demonstrates this. Bean
must be bound to a Java object. Action
and Script
must be strings or bound to a string.
bsf_j2p (Object, Term)
Converts Object
-which must be bound to a Java object- to a Prolog term.
bsf_p2j (Term, Object)
Converts Term
-which must be bound to a Prolog term- to a Java object.
Examples
The following is a list of all examples that come with the distribution, with notes on how to run them and what they demonstrate.
PiApp
Demonstrates scripting use of JLogBSFEngine. The application is really just
a shell for running external scripts, which in this case calculates the
mathematical constant π. The pi.plog
script creates a piiterator
Object, and invokes its calcPi
method to do the calculation. Usage is:
java -classpath build/JLog.jar:lib/bsf-2.3.0-rc1.jar:Examples/bsf PiApp
Examples/bsf/bsf_pi.plog
Since the name of the script to run is passed as parameter to the program, this application can be used to run
any script, in any language supported by BSF. The language to use is inferred
from the file extension; for Prolog it's either .plog
or .prolog
.
ScriptedUI
Also demonstrates scripting use of JLogBSFEngine. The Java code sets up a simple
AWT application which is then modified by the Prolog code in the ui.plog
script. It demonstrates how to
create Java objects in Prolog, invoke methods on them, and how to register AWT
event handler that are called when buttons are clicked. One can play around
with the Prolog code in the file ui.plog
without
having to recompile the Java code. Usage is:
java -classpath build/JLog.jar:lib/bsf-2.3.0-rc1.jar:Examples/bsf ScriptedUI
Examples/bsf/bsf_ui.plog
Note that this is actually an
example that comes with BSF (where it demonstrates the use of JavaScript and
NetRexx), so the files ScriptedUI.java
and
ui.plog are licensed under the Apache License, not the GPL.
Ant <script> task
The Ant build file (build.xml
) also includes an example of how Ant
can be scripted via the <script>
task
that comes as part of Ant. For this to work, the various jar files that come
with JLog need to be in Ants CLASSPATH, which can be accomplished by copying
them into the lib
directory of your Ant installation.
Usage is "ant script
". Besides demonstrating how to
create Java objects and invoke methods on them, the Ant project
object is manipulated via its getProperty, setProperty, createTask
and log
methods. project
is put into the common object registry by the script
task precisely
for this reason: so that scripts can access it, and influence the way Ant executes.
Two examples can be found in the build.xml file that comes with JLog. The first calculates the n-th number of the Fibonacci sequence, with n being supplied on the command line.
% ant fib -Dn=15 Buildfile: build.xml ensure-fib-n: fib: 15 610 BUILD SUCCESSFUL
The second example has two parts: first, a property is read from Ant, incremented by 11, and stored in another Ant property. Then the current date is retrieved and printed to the console using the Ant projects' log method.
% ant script Buildfile: build.xml script: [echo] prop=42 [echo] prop2=53 Sun Jul 31 18:50:36 CEST 2005 BUILD SUCCESSFUL
Web Page Scripting
The Jakarta Taglibs project provides a JSP tag library that allows BSF-enabled languages to be used as scripting languages in a JSP page. The library is part of the Jakarta Taglibs project, and can be downloaded at jakarta.apache.org/taglibs
The library provides the <bsf:scriptlet> tag, which sources a Prolog script and evaluates its last term. The following is the adapted version of an example that ships with the tag library. It prints a table of Fahrenheit and Celsius temperatures.
This is not so much a practicable example, but rather a demonstration that wherever BSF is used, Prolog code can run.
<bsf:scriptlet language="prolog"> f2c(Start, End) :- Start =< End, bsf_lookup('out', OUT), bsf_static('Math', MATH), bsf_invoke(_, OUT, 'print', ['<tr><td>']), bsf_invoke(_, OUT, 'print', [Start]), bsf_invoke(_, OUT, 'print', ['</td><td>']), T is (Start-32) * 5/9, bsf_invoke(T1, MATH, 'round', [T]), bsf_invoke(_, OUT, 'print', [T1]), bsf_invoke(_, OUT, 'println', ['</td></tr>']), Start1 is Start + 10, f2c(Start1, End). f2c(30, 100). </bsf:scriptlet>
Restrictions And Problems
This section lists some of the restrictions one should be aware of.
Custom events are not supported by bsf_addevent/3
.
Only the events in java.awt.event
can
be used, as well as java.beans.VetoableChange
and java.beans.PropertyChange.
Array parameters can only be of type Object[]
or
String[]
, everything else is not
handled and will fail. Let me know if you run into this.
Declared beans are not supported, since Prolog has no notion of variables outside of predicates. Declaring beans simply registers them. Note that BSF allows engines not to support declared beans if they're not applicable to a specific language.
Changes
11/24/07: Updated to JLog 1.3.6
1/6/07: Fixed a bug in create/3
and invoke/4
that
would lead to the wrong constructors or methods being selected when matching the types of parameters.
9/18/05: Better handling of null parameters in method invocations:
Null
Parameters now match all formal parameters, except for primitive types.
7/13/05: Added Prolog <--> Java Object conversion predicates.
The BSF library no longer needs to be loaded explicitly; it's bootstrapped if necessary. Enhanced
type matching for bsf_create
and bsf_invoke
: Object and String can always be matched to Prolog terms.
4/10/05: Ported from JLog 1.1 to JLog 1.3. No longer 'kind of'
supports declaring beans; they're just not applicable in Prolog. Beans are now referred to as standard
Prolog variables, not by their name as a string. Phased out the generic 'bsf' predicate with its
action
dispatch parameters; all predicates start with 'bsf_
' followed
by their name. Note: If you have used the earlier version built upon
JLog-1.1.5, you will need to adapt your Prolog code, as the syntax has changed.
2/16/05: Methods can now be invoked on static fields (e.g. System.out
).
Added JUnit tests to check the array handling bugs and the static field functionality. java.lang
is now imported automatically. Verified and documented that this package works with the Jakarta BSF taglib.
Cleaned up code according to suggestions by various code checkers.
2/9/05: Fixed a problem that prevented array parameter types from being handled correctly.
1/30/05: Fixed a problem that prevented array return types with null objects from being handled correctly.