To implement the jess.Userfunction interface, you need to implement only two methods: getName() and call(). Here's an example of a class called 'MyUpcase' that implements the Jess function my-upcase, which expects a String as an argument, and returns the string in uppercase.
import jess.*; public class ExMyUpcase implements Userfunction { // The name method returns the name by which the function will appear in Jess code. public String getName() { return "my-upcase"; } public Value call(ValueVector vv, Context context) throws JessException { return new Value(vv.get(1).stringValue(context).toUpperCase(), RU.STRING); } } C:\> java ExMyUpcaseThe call() method does the business of your Userfunction. When call() is invoked, the first argument will be a ValueVector representation of the Jess code that evoked your function. For example, if the following Jess function calls were made,
Jess> (load-function ExMyUpcase) Jess> (my-upcase foo) "FOO"the first argument to call() would be a ValueVector of length two. The first element would be a Value containing the symbol (type RU.ATOM) my-upcase, and the second argument would be a Value containing the string (RU.STRING) "foo".
Note that we use vv.get(1).stringValue(context) to get the first argument to my-upcase as a Java String. If the argument doesn't contain a string, or something convertible to a string, stringValue() will throw a JessException describing the problem; hence you don't need to worry about incorrect argument types if you don't want to. vv.get(0) will always return the symbol my-upcase, the name of the function being called (the clever programmer will note that this would let you construct multiple objects of the same class, implementing different functions based on the name of the function passed in as a constructor argument). If you want, you can check how many arguments your function was called with and throw a JessException if it was the wrong number by using the vv.size() method. In any case, our simple implementation extracts a single argument and uses the Java toUpperCase() method to do its work. call() must wrap its return value in a jess.Value object, specifying the type (here it is RU.STRING).
Having written this class, you can then, in your Java main program, simply call Rete.addUserfunction() with an instance of your new class as an argument, and the function will be available from Jess code. So, we could have
import jess.*; public class ExAddUF { public static void main(String[] argv) throws JessException { // Add the 'my-upcase' command to Jess Rete r = new Rete(); r.addUserfunction(new ExMyUpcase()); // This will print "FOO". r.executeCommand("(printout t (my-upcase foo) crlf)"); } } C:\> java ExAddUF FOOAlternatively, the Jess language command load-function could be used to load my-upcase from Jess:
Jess> (load-function ExMyUpcase) Jess> (printout t (my-upcase foo) crlf) FOO
import jess.*; public class ExMyStringFunctions implements Userpackage { public void add(Rete engine) { engine.addUserfunction(new ExMyUpcase()); // Other similar statements } } C:\> java ExMyStringFunctionsNow in your Java code, you can call
import jess.*; public class ExAddUP { public static void main(String[] argv) throws JessException { // Add the 'my-upcase' command to Jess Rete r = new Rete(); r.addUserpackage(new ExMyStringFunctions()); // This will still print FOO. r.executeCommand("(printout t (my-upcase foo) crlf)"); } } C:\> java ExAddUP FOOor from your Jess code, you can call
Jess> (load-package ExMyStringFunctions) Jess> (printout t (my-upcase foo) crlf) FOOto load these functions in. After either of these snippets, Jess language code could call my-upcase, my-downcase, etc.
Userpackages are a great place to assemble a collection of interrelated functions which potentially can share data or maintain references to other function objects. You can also use Userpackages to make sure that your Userfunctions are constructed with the correct constructor arguments.
All of Jess's "built-in" functions are simply Userfunctions, albeit ones which have special access to Jess' innards. Most of them are automatically loaded by code in the jess.Funcall class. You can use these as examples for writing your own Jess extensions.