Distribution
Category UC-411
SAND98-8206 (revised)
Unlimited Release
First Printed November 1997

Jess, The Java Expert System Shell

http://herzberg.ca.sandia.gov/jess
Ernest J. Friedman-Hill
Distributed Computing Systems
Sandia National Laboratories
Livermore, CA
Version 4.5 (May 3rd, 2001)

ABSTRACT

This report describes Jess, an expert system shell written entirely in Java. Jess supports the development of rule-based expert systems which can be tightly coupled to code written in the powerful, portable Java language. The syntax of the Jess language is discussed, and a comprehensive list of supported functions is presented. A guide to calling Java functions from Jess, and to extending Jess by writing Java code, is also included.

Note: this version of Jess is no longer being actively developed. It is provided for download because it was the last version of Jess to be Java 1.0 compatible. Note that this manual was written a number of years ago and does not accurately describe the current Jess software.

1 Introduction

Jess is an expert system shell written entirely in Java. Jess was originally a clone of the essential core of CLIPS, but has begun to acquire a Java-influenced flavor of its own. With Jess, you can conveniently give your Java applets and applications the ability to "reason." In describing Jess, I am going to describe much of CLIPS itself, but the reader may want to have a copy of the CLIPS manuals at hand. See the CLIPS site for more information.

Jess 4.5 is compatible with all versions of Java starting with version 1.0.2. It is compatible with version 1.1, although while compiling you will see warnings about deprecated methods. Such is the price of compatibility! Note: Jess 4.5 is the last version that will be compatible with Java 1.0.2; future versions of Jess will not work with anything less than Java 1.1. That means that the "deprecated" warnings will disappear.

Jess is a work in progress; more features are constantly being added. The order will be determined in part by what folks seem to want most, what I need Jess to do, and how much time I have to spend on it. See Version History for a list of what's new in this version of Jess and see What's New in This Release for a quick overview.

There is a Jess email discussion list you can join. To get information about the jess-users list, send a message to majordomo@sandia.gov containing the text

  help
  info jess-users
  end
as the body of the message.

This is the final release of Jess 4.5. Although this version has undergone extensive testing, It's always possible that there are bugs. Please report any that you find to me at ejfried@ca.sandia.gov so I can fix them for a later release.

Jess is copyrighted software. See the file LICENSE for details.

1.1 Getting Started With Jess

1.1.1 Unpacking the Distribution
If you download Jess for UNIX, you can extract the files using tar and gunzip
        gunzip Jess45.tgz
        tar xf Jess45.tar
If you downloaded Jess for Windows, you get a .zip file which should be unzipped using a Win32-aware unzip program like WinZip. Don't use PKUNZIP since it cannot handle long file names.

When Jess is unpacked, you should have a directory named Jess45/. Inside this directory may be the following files:
README.html This file
jess/ If you have a source distribution, this is a directory containing the jess package. There are many source files in here that implement Jess's inference engine. Others implement a number of Jess GUIs and command-line interfaces. Main.java implements the Jess command-line interface. Console.java is a very simple GUI console for Jess; ConsoleApplet.java is an applet version of the same. If you have a binary distribution, this directory contains .class files instead of .java files.
jess/view This directory contains Java source or .class files implementing the optional Jess view command.
jess/reflect This directory contains Java source or .class files implementing the optional Jess commands that let you create and manipulate Java objects from Jess.
examples/ A directory of tiny example Jess files.
jess/examples A directory of more complicated examples, containing example Java source files.
examples/index.html A web page containing the Jess example applet. It may need to be edited.
Makefile A simple makefile for Jess.

1.1.2 Compiling Jess
If you have a source distribution of Jess, you have a set of Java source files. To use Jess, you'll need to compile them first. If you have a make utility (any UNIX make; or nmake or GNU make on Win32), you can just run make and the enclosed makefile will build everything. You might have to edit it a bit first. Otherwise the commands:
  javac jess/*.java (UNIX)
or
  javac jess\*.java (Win32)
would work just fine, given that you have a Java compiler like Sun's JDK, and that Jess45/ is your current directory. If you have problems, be sure that the directory in which the jess subdirectory appears is on your CLASSPATH; this may mean including . (dot). Don't try to compile from inside the Jess45/jess/ directory; it won't work. You can use either a Java 1.0.2 or a Java 1.1 compiler to compile Jess. The resulting code runs on either 1.0 or 1.1 VMs. Note that if you use a 1.1 compiler, you will see some warning about deprecated methods. It is safe to ignore these warnings. Jess also seems to work with Java 1.2.

There are a number of optional source files in the subdirectories Jess45/jess/view/, Jess45/jess/reflect/ and Jess45/jess/examples/ that aren't compiled if you follow the instructions above. These files define the optional debugging command view, the reflection commands new, call, set, get, set-member, and get-member, and the Java object matching commands defclass and definstance. They can be compiled only with Java 1.1 or later. If you have such a compiler, then you can issue a set of commands like:

  javac jess/*.java jess/view/*.java jess/reflect/*.java jess/examples/*/*.java (Unix)
or
  javac jess\*.java
       javac jess\view\*.java
       javac jess\reflect\*.java
       javac jess\examples\pumps\*.java
       javac jess\examples\simple\*.java (Win32)
to compile everything (or use the Makefile, of course).
Again, don't set your current directory to, for example, Jess45/jess/examples/pumps/ to compile the pumps example: it will not work. The compiler will report all sorts of errors about classes not being found and the jess package not being found. Compile everything from the Jess45 directory. I can't stress this enough: this is by far the most common problem people have in getting started with Jess!

1.1.3 Jess Example Programs
There are several example programs for you to try, including fullmab.clp, zebra.clp, and wordgame.clp. fullmab.clp is a version of the classic Monkey and Bananas problem. To run it yourself from the command line, just type:
  java jess.Main examples/fullmab.clp (Unix)
or
  java jess.Main examples\fullmab.clp (Win32)
and the problem should run, producing a few screens of output. Any file of Jess code can be run this way. Many simple CLIPS programs will also run unchanged in Jess. Note that giving Jess a file name on the command line is like using the batch command in CLIPS. Therefore, you need to make sure that the file ends with:
  (reset)  
  (run)
or nothing will happen. The zebra.clp and wordgame.clp programs are two classic CLIPS examples selected to show how Jess deals with tough situations. These examples both generate huge numbers of partial pattern matches, so they are slow and use up a lot of memory. They each can take some time to run, depending on your computer. Other examples include sticks.clp (an interactive game) and frame.clp (a demo of building a graphical interface using Jess's Java integration capabilities).

In the jess/examples/* subdirectories, you will find some more complex examples, all of which contain both Java and Jess code. As such, these are generally examples of how to tie Jess and Java together. The Pumps examples is a full working program that demonstrates how Jess rules can react to the properties of Java Beans.

1.1.4 Command-line Interface
Jess has an interactive command-line interface. Just type java jess.Main to get a Jess> prompt. To execute a file of CLIPS code from the command prompt, use the batch command:
  Jess> (batch myfile.clp)
    (lots of output)
You can use the Jess system command to invoke an editor from the Jess command line to edit a file of Jess code before reading it in with batch. system also helps to allow non-Java programmers to integrate Jess with other applications. Given that you have an editor named notepad on your system, try:
  Jess> (system notepad README &)
    TRUE
The & character makes the editor run in the background. Omitting it will keep the system command from returning until the called program exits.

The class jess.Console is a graphical verison of the Jess command-line interface. Output appears in a scrolling window. Type java jess.Console to try it.

1.1.5 Jess as an Applet
The class jess.ConsoleApplet is a generic Jess applet that uses the same display as the jess.Console class. It can be used in general question-and-answer situations simply by embedding the applet class on a Web page. The applet accepts two applet parameters. The value of an INPUT parameter will be interpreted as a Jess program to run when starting up. Note that when this program halts, the Jess prompt will appear in the applet window. The applet also accept a COMPACT parameter. If present, ConsoleApplet will contain only a bare-bones version of Jess (no optional functions will be loaded).

1.2 What's New in This Release

If you've used Jess before, this section will help you get started quickly with this version. Jess 4.5 offers quite a few new features and user-visible changes:

2 The Jess Language

Jess is an interpreter for a rule language borrowed from CLIPS. Given CLIPS's heritage (strongly influenced by systems written in LISP), this rule language is basically a small, idiosyncratic version of LISP, making Jess a LISP interpreter written in Java. I will briefly describe this language here; more information can be gotten from the CLIPS manuals themselves.

I'm using an extremely informal notation to describe syntax. Basically strings in <angle-brackets> are some kind of data that must be supplied; things in [square brackets] are optional, things ending with + can appear one or more times, and things ending with * can appear zero or more times.

In general, input to Jess is free-format. Newlines are generally not significant and are treated as whitespace.

In the example dialogs, you type what appears after the Jess> prompt. The system responds with the text in bold.

2.1 Atoms

The atom or symbol is a core concept of the Jess language. Atoms are very much like identifiers in other languages. A Jess atom can contain letters, numbers, and the following punctuation: $*=+/<>_?#. . An atom may not begin with a number; it may begin with some punctuation marks (some have special meanings as operators when they appear at the start of an atom). The best atoms consist of letters, numbers, underscores, and dashes; dashes are traditional word separators. The following are all valid atoms:
  foo first-value contestant#1 _abc

2.2 Numbers

Jess parses numbers using the Java StreamTokenizer class. Therefore, it accepts only simple floating point and integer numbers. It does not accept scientific or engineering notation. The following are all valid numbers:
  3 4. 5.643

2.3 Strings

Character strings in Jess are denoted using double quotes (""). Backslashes (\) can be used to escape embedded quote symbols. The following are all valid strings:
  "foo" "Hello, World" "\"Nonsense,\" he said firmly."

2.4 Lists

The fundamental unit of syntax in Jess is the list. A list always consists of an enclosing set of parentheses and zero or more atoms, numbers, strings, or other lists. The following are valid lists:
  (+ 3 2) (a b c) ("Hello, World") () (deftemplate foo (slot bar))
The first element of a list (the car of the list in LISP parlance) is often called the list's head in Jess.

2.5 Comments

Programmer's comments in Jess begin with a semicolon (;) and extend to the end of the line of text. Here is an example of a comment:
  ; This is a list
  (a b c)

2.6 Functions

Jess contains a large number of built-in functions that you may call. More functions are provided as extensions. You can write your own functions in the Jess language (see Deffunctions) or in Java (see Extending Jess with Java).

Function calls in Jess use a prefix notation. A list whose head is an atom that is the name of an existing function can be evaluated as an expression. For example, an expression that uses the + function to add the numbers 2 and 3 would be written (+ 2 3). When evaluated, the value of this expression is the number 5 (not a list containing the single element 5!). In general, expressions are recognized as such and evaluated in context when appropriate. You can type expressions at the Jess> prompt. Jess evaluates the expression and prints the result:

  Jess> (+ 2 3)
    5
  Jess> (+ (+ 2 3) (* 3 3))
    14
Note that arithmetic results may be returned as floating-point numbers or as integers, depending on the types of the arguments.

Jess implements only a small subset of CLIPS functions as intrinsic functions that are built into Jess and cannot be removed. All of these have been designed to function as much like their CLIPS counterparts as possible. On the other hand, I'm supplying implementations for many more CLIPS functions, and lots of functionality specific to Jess, as 'Userfunctions' - external functions written in Java that you can plug into Jess. All of the included Userfunctions are installed into the command-line version of Jess by default; you can pick and choose in your own applications. In applets, in particular, you may want to include only the Userfunctions you need, to keep the size of the applet down. (see Extending Jess with Java for information about doing this.)

Here is the complete list of functions shipped with Jess 4.5, both intrinsic and optional:

* ** + - / < <= <> = > >= abs agenda and assert assert-string bag batch bind build call clear close complement$ create$ defclass definstance delete$ div e engine eq eq* eval evenp exit exp explode$ external-addressp facts fetch first$ float floatp foreach format gensym* get get-member get-reset-globals get-salience-evaluation get-var halt if implode$ insert$ integer integerp intersection$ jess-version-number jess-version-string length$ lexemep list-function$ load-facts load-function load-package log log10 lowcase max member$ min mod modify multifieldp neq new not nth$ numberp oddp open or pi ppdefrule printout random read readline replace$ reset rest$ retract retract-string return round rules run save-facts set set-member set-reset-globals set-salience-evaluation set-strategy setgen socket sqrt store str-cat str-compare str-index str-length stringp sub-string subseq$ subsetp sym-cat symbolp system time try undefinstance undefrule union$ unwatch upcase view watch while
All these functions are described in detail in the Jess Function Guide. Note that the distinction between intrinsic functions and Userfunctions is mostly an academic one; intrinsic functions are all written as Java classes that implement the same Userfunction interface that user-supplied classes do. The only real difference is whether Jess will start up without them; the intrinsics are required because they're loaded in by code in the jess.Funcall class. To find out if a function is intrinsic, see its entry in the Function Guide below.

2.7 Variables

Programming variables in Jess are atoms that begin with the question mark (?) character. The question mark is part of the variable's name. A normal variable can refer to a single atom, number, or string. A variable whose first character is instead a $ (for example, $?X) is a multivariable, which can refer to a special kind of list called multifield. You assign to any variable using the bind function:
  (bind ?x "The value")
Multifields are generally created using special multifield functions like create$ and can then be bound to multivariables:
  (bind $?grocery-list (create$ eggs bread milk))
Variables need not (and cannot) be declared before their first use (except for Defglobals).

2.8 Constructs

Besides expressions and multifields, the Jess language includes another kind of special list called a construct. A construct is a list that defines something to the Jess system itself. For example, the deffunction construct is used to define functions (see Deffunctions). A construct evaluates to TRUE if it was accepted by Jess or FALSE if it was not.

2.9 Deffunctions

The deffunction construct is used to define functions that you can then call from Jess. A deffunction construct looks like this:
  (deffunction <function-name> [<doc-comment>] (<parameter>*)
  <expr>* 
  [<return-specifier>])
The <function-name> must be an atom. Each <parameter> must be a variable name (all functions use pass-by-value semantics). The optional <doc-comment> is a double-quoted string that can describe the purpose of the function. There may be an arbitrary number of <expr> expressions. The optional <return-specifier> gives the return value of the function. It can either be an explicit use of the return function or it can be any value or expression. Control flow in deffunctions is achieved via the special control-flow expressions foreach, if, and while. The following is a deffunction that returns the numerically larger of its two numeric arguments:
  (deffunction max (?a ?b)
    (if (> ?a ?b) then
        (return ?a)
     else
        (return ?b)))
Note that this could have also been written as:
  (deffunction max (?a ?b)
    (if (> ?a ?b) then
        ?a
     else
        ?b))

2.10 Facts

Jess maintains a list of facts or information about the current state of the system. Facts may be ordered or unordered. Ordered facts are merely lists whose head must be an atom:
  (temperature 98.6)
  (shopping-list bread milk paper-towels)
  (start-processing)
Unordered facts are structured. They contain a definite set of slots which must be accessed by name. While ordered facts can be used without prior definition, unordered facts must be defined using the deftemplate construct (see Deftemplates).

Facts are placed on the fact list by the assert function. You can see the current fact list using the facts function. You can remove (retract) a fact from the fact list if you know its fact ID. For example:

  Jess> (assert (foo bar))
    <Fact-0>
 
  Jess> (facts) 
    f-0   (foo bar)
    For a total of 1 facts.
    TRUE
  Jess> (retract 0)
    TRUE
  Jess> (facts)
    For a total of 0 facts.
    TRUE

2.11 Deftemplates

To define an unordered fact, use the deftemplate construct:
  (deftemplate <deftemplate-name> [<doc-comment>] 
    [(slot <slot-name> [(default <value>)]
                          [(default-dynamic <value>)]
                          [(type <typespec>)])]+)
The <deftemplate-name> is the head of the facts that will be created using this deftemplate. There may be an arbitrary number of slots. The <slot-name> must be an atom. The default slot qualifier states that the default value of a slot in a new fact is given by <value>; the default is the atom nil. The 'default-dynamic' version will evaluate the given function each time a new fact using this template is asserted. The 'type' slot qualifier is accepted (for compatibility with CLIPS) but is ignored by Jess.

As an example, defining the following deftemplate:

  (deftemplate automobile
    "A specific car."
    (slot make)
    (slot model)
    (slot year)
    (slot color (default white)))
would allow you to define facts like this:
  Jess> (assert (automobile (make Chrysler) (model LeBaron) (year 1997)))
    <Fact-0>
  Jess> (facts)    
    f-0   (automobile (make Chrysler) (model LeBaron) (year 1997) (color white))
    For a total of 1 facts.
    TRUE
Note that the car is white by default. Also note that any number of additional automobiles could also be simultaneously asserted onto the fact list using this deftemplate.

A given slot in a deftemplate fact can normally hold only one value. If you want a slot that can hold multiple values, use the multislot keyword instead:

  (deftemplate box
    (slot location)
    (multislot contents))

  (assert (box (location kitchen) (contents spatula sponge frying-pan)))

2.12 Defclasses

A defclass construct basically lets you use a Java Bean as a deftemplate. Almost any Java object can be made into a Bean. This is a very powerful feature of Jess that lets it reason about the state of objects connected to the physical world. defclass will be documented later, after we've explained some of the prerequisites.

2.13 Deffacts

The deffacts construct is a handy way to define a list of facts that should be made true when the Jess system is started or reset.
  (deffacts <deffacts-name>
    [<doc-comment>]   
    <fact>+)
The primary purpose of the <deffacts-name> is documentation. A deffacts instance can contain any number of facts. Any unordered facts in a deffacts instance must have previously been defined via a deftemplate construct when the deffacts is parsed. The following is a valid deffacts construct:
  (deffacts automobiles
    (automobile (make Chrysler) (model LeBaron) (year 1997))
    (automobile (make Ford) (model Contour) (year 1996))
    (automobile (make Nash) (model Rambler) (year 1948)))

2.14 Definstances

What deffacts are to deftemplates, definstances are to defclasses. While a deffacts construct defines an initial set of facts to the Rete engine, the definstance construct tells Jess that one particular Java object should be treated as if it were a fact and be matched by deftemplate patterns defined in defclass constructs. Again, we'll defer discussion until we're in a better position to understand the mechanics involved.

2.15 Defrules

The main purpose of an expert shell like Jess is to support the execution of rules. Rules in Jess are somewhat like the IF...THEN... statements of other programming languages. In operation, Jess constantly tests to see if any of the IFs become true, and executes the corresponding THENs. (Actually, it doesn't work quite this way, but this is a good way to imagine things. See How Jess Works for an explanation closer to the truth.) The intelligence embedded in an intelligent rule-based system is encoded in the rules. The defrule construct is used to define a rule to Jess:
  (defrule <defrule-name>
    [<doc-comment>]
    [<salience-declaration>]
    [[<pattern-binding> <- ] <pattern>]*
    =>
    <action>*)
Basically, a rule consists of a list of patterns (the IF part on the rule's left-hand-side or LHS) and a list of actions (the THEN part on the rule's right-hand-side or RHS). The patterns are matched against the fact list. When facts are found that match all the patterns of a rule, the rule becomes activated, meaning it may be fired (have its actions executed).
Note: The patterns on rule LHSs are matched against the fact-list as if they were facts - they are NOT function calls! The following rule does NOT work:
   (defrule wrong-rule
      (eq (+ 2 2) 4)
      =>
      (printout t "Just as I thought, 2 + 2 = 4!" crlf))      
This rule will NOT fire just because the function call (eq (+ 2 2) 4) would evaluate to true. Instead, Jess will try to find a fact on the fact-list that looks like (eq 4 4). Unless you have previously asserted such a fact, this rule will NOT be activated and will not fire. If you want to fire a rule based on the evaluation of a function, you can use the test CE.
An activated rule may become deactivated before firing if the facts that matched its patterns are retracted, or removed from the fact list, while it is waiting to be fired. Here is an example of a simple rule:
  (defrule example-1
    "Announce 'a b c' facts"
    (a b c)
     =>
    (printout t "Saw 'a b c'!" crlf))
To see this rule in action, enter it at the Jess> prompt, assert the fact (a b c), then the run command to start the Jess engine. You'll get some interesting additional information by first issuing the watch all command:
  Jess> (clear)
    TRUE
  Jess> (watch all)
    TRUE
  Jess> (defrule example-1
            "Announce 'a b c' facts"
            (a b c)
           =>
            (printout t "Saw 'a b c'!" crlf))
    example-1: +1+1+1+1+t
    TRUE
  Jess> (assert (a b c))
     ==> Activation: example-1 : f-0
     ==> (a b c)
     <Fact-0>
  Jess>  (run)
    FIRE example-1 f-0
    Saw 'a b c'!
    TRUE
  Jess>
When you enter the rule, you see the sequence of symbols +1+1+1+1+t. This tells you something about the way that Jess compiled the rule you wrote into the internal rule representation. Then when you assert the fact, Jess responds by telling you that the new fact was assigned the numeric fact identifier 0 (f-0), and that it is an ordered fact with head a and additional fields b and c. Then it tells you that the rule example-1 is activated by the fact f-0, that fact you just entered. When you type the run command, you see an indication that your rule has been fired, including a list of the relevant fact IDs. The line "Saw 'a b c'!" is the result the execution of your rule.

Multiple activated rules are fired in order of salience (see Salience). Within a given salience value, the order in which rules will fire is given by the current conflict resolution strategy. See the set-strategy command for details. You can see the list of activated, but not yet fired, rules with the command.

If all the patterns of a rule had to be given literally as above, Jess would not be very powerful. However, patterns can also include wildcards and various kinds of predicates (comparisons and boolean functions). You can specify a variable name instead of a value for a field in any of a rule's patterns (but not the pattern's head). A variable matches any value in that position within a rule. For example, the rule:

  (defrule example-2
    (a ?x ?y)
    =>
    (printout t "Saw 'a " ?x " " ?y "'" crlf))
will be activated each time any fact with head a having two fields is asserted: (a b c), (a 1 2), (a a a), and so forth. As in the example, the variables thus matched in the patterns (or LHS) of a rule are available in the actions (RHS) of the same rule.

Each such variable field in a pattern can also include any number of tests to qualify what it will match. Tests follow the variable name and are separated from it and from each other by ampersands. (The variable name itself is actually optional.) Tests can be:

Here's an example of a rule that uses several kinds of tests:
  (defrule example-3
    (not-b-and-c ?n1&~b ?n2&~c) 
    (different ?d1 ?d2&~?d1)
    (same ?s ?s)
    (more-than-one-hundred ?m&:(> ?m 100))
    =>
    (printout t "Found what I wanted!" crlf))
The first pattern will match a fact with head not-b-and-c with exactly two fields such that the first is not b and the second is not c. The second pattern will match any fact with head different and two fields such that the two fields have different values. The third pattern will match a fact with head same and two fields with identical values. The last pattern matches a fact with head more-than-one-hundred and a single field with a numeric value greater than 100.

A few more details about patterns: you can match a field without binding it to a variable by omitting the variable name and using just a question mark (?) as a placeholder. You can match any number of fields using a multivariable (one starting with $?):

  Jess> (defrule example-4
    (grocery-list $?list)
    =>
    (printout t "I need to buy " $?list crlf))
    TRUE
  Jess> (assert (grocery-list eggs milk bacon))
    TRUE
  Jess> (run)
    I need to buy (eggs milk bacon)
    TRUE
And finally, to access a global variable on the left-hand side of a rule, you must use the get-var function.
2.15.1 Pattern bindings.
Sometimes you need a handle to an actual fact that helped to activate a rule. For example, when the rule fires, you may need to retract or modify the fact. To do this, you use a pattern-binding variable:
  (defrule example-5
    ?fact <- (command "retract me")
    =>
    (retract ?fact))
The variable (?fact, in this case) is assigned the fact ID of the particular fact that activated the rule.
2.15.2 Salience.
Rules normally fire in an order related to which rules were most recently activated. See the set-strategy command for details. To force certain rules to always fire first or last, rules can include a salience declaration:
  (defrule example-6
    (declare (salience -100))
    (command exit-when-idle)
    =>
    (printout t "exiting..." crlf))
Declaring a low salience value for a rule makes it fire after all other rules of higher salience. A high value makes a rule fire before all rules of lower salience. The default salience value is zero. Salience values can be integers, global variables, or function calls. See the set-salience-evaluation command for details about when such function calls will be evaluated.
2.15.3 Not patterns.
A pattern can be enclosed in a list with not as the head. In this case, the pattern is considered to match if a fact which matches the pattern is not found. For example:
  (defrule example-7
     (person ?x)
     (not (married ?x))
     =>
     (printout t ?x " is not married!" crlf))
Note that a not pattern cannot contain any variables that are not bound before that pattern (since a not pattern does not match any facts, it cannot be used to define the values of any variables!) You can use blank variables, however (a blank variable is a bare ? or $?). A not pattern can similarly not have a pattern binding.
2.15.4 The test conditional element (CE).
A pattern with test as the head is special; the body consists not of slot tests but of a single function which is evaluated and whose truth determines whether the pattern matches. For example:
  (defrule example-8
     (person (age ?x))
     (test (> ?x 30))
     =>
     (printout t ?x " is over 30!" crlf))
Note that a test pattern, like a not, cannot contain any variables that are not bound before that pattern. test and not may be combined:
          (not (test (eq ?X 3)))
is equivalent to:
          (test (neq ?X 3))
2.15.5 The unique conditional element.
A pattern can be enclosed in a list with unique as the head. This is a hint to Jess that only one fact could possibly satisfy a given pattern, given matches for the preceding patterns in that rule. Here's an example:
(defrule unique-demo
   (tax-form (social-security-number ?num))
   (unique (person (social-security-number ?num) (name ?name)))
   =>
   (printout t "Auditing " ?name "..." crlf))
Here the unique CE is providing a hint to Jess that only one person can have a given Social Security number. Given this knowledge, Jess knows that once it has found the person that matches a given tax form, it doesn't need to look any further. In practice, this can result in performance gains of 20-30% on real problems!

unique may not be combined in the same patten with either test or not CEs.

unique was new in Jess 4.1, and is my own invention. I'm interested in hearing any feedback related to this feature.

2.16 Defglobals

Jess can support global variables that are visible from the command-prompt or inside any rule or deffunction. You can define them using the defglobal construct:
    (defglobal
         [<varname1> = <value1>]*)
Note that defglobals are reset to their assigned values by the (reset) command. If the <value> is a function call, this function will be evaluated each time (reset) is called. You can change this behaviour with the set-reset-globals command.

2.17 Things Not Implemented In Jess

Jess does not implement all features of all CLIPS constructs. This list tries to explain some of what's missing from Jess to those who know CLIPS. If you're not already a CLIPS user, you can skip this section.
2.17.1 Defrules
2.17.2 Deffunctions.
Forward declarations of mutually recursive functions are not needed in Jess and will not parse.
2.17.3 Deftemplates.
The only supported slot attribute in Jess are the default and default-dynamic attributes. In particular, type will parse, but is ignored at runtime.
2.17.4 COOL, FuzzyCLIPS, wxCLIPS, etc.
Jess does not implement any features of these CLIPS extensions. Note that defclass and definstance are keywords in CLIPS that form part of COOL. Although these keywords exist in Jess, their syntax and precise meaning is different. You should find that the functionality they provide (pattern matching on Java Beans) is a satisfactory replacement for COOL.
2.17.5 Modules.
Jess does not implement CLIPS modules. However, since Jess itself is object-oriented, you can instantiate multiple Jess systems and get them to communicate via the external function interface.


3 Jess Function Guide

In this section, every Jess language function shipped with Jess version 4.5 is described. Some of these functions are intrinsic functions while others are Userfunctions and may not be available to all Jess code. All of these functions are installed into the command-line version of Jess; to use a function not marked (built-in) in your own programs, you need to add the appropriate Userpackage using Rete.addUserpackage(new <pkgname>()). The package for each function is listed below.

Note: many functions documented as requiring a specific minimum number of arguments will actually return sensible results with fewer; for example, the + function will return the value of a single argument as its result. This behavior is to be regarded as undocumented and unsupported. In addition, all functions documented as requiring a specific number of arguments will not report an error if invoked with more than that number; extra rguments are simply ignored.

(* <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Number
Description:
Returns the products of its arguments. The return value is an INTEGER unless any of the arguments are FLOAT, in which case it is a FLOAT.

(** <numeric-expression> <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
Two numeric expressions
Returns:
Number
Description:
Raises its first argument to the power of its second argument (using Java's Math.pow() function). Note: the return value is NaN (not a number) if both arguments are negative.

(+ <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Number
Description:
Returns the sum of its arguments. The return value is an INTEGER unless any of the arguments are FLOAT, in which case it is a FLOAT. Note: the return value is the value of the single numeric expression if only one argument is supplied.

(- <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Number
Description:
Returns the first argument minus all subsequent arguments. The return value is an INTEGER unless any of the arguments are FLOAT, in which case it is a FLOAT.

(/ <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Number
Description:
Returns the first argument divided by all subsequent arguments. The return value is a FLOAT.

(< <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if each argument is less in value than the argument following it; otherwise, returns FALSE.

(<= <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if the value of each argument is less than or equal to the value of the argument following it; otherwise, returns FALSE.

(<> <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if the value of the first argument is not equal in value to all subsequent arguments; otherwise returns FALSE.

(= <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if the value of the first argument is equal in value to all subsequent arguments; otherwise, returns FALSE. The integer 2 and the float 2.0 are =, but not eq.

(> <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if the value of each argument is less than that of the argument following it; otherwise, returns FALSE.

(>= <numeric-expression> <numeric-expression>+)

Package:
(built-in)
Arguments:
Two or more numeric expressions
Returns:
Boolean
Description:
Returns TRUE if the value of each argument is greater than or equal to that of the argument following it; otherwise, returns FALSE.

(abs <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Number
Description:
Returns the absolute value of its only argument.

(agenda)

Package:
jess.MiscFunctions
Arguments:
None
Returns:
NIL
Description:
Displays a list of rule activations to the WSTDOUT router.

(and <expression>+)

Package:
(built-in)
Arguments:
One or more expressions
Returns:
Boolean
Description:

Returns TRUE if all arguments evaluate to a non-FALSE value; otherwise, returns FALSE.

(assert <RHS-pattern>+)

Package:
(built-in)
Arguments:
One or more facts (not fact-IDs)
Returns:
Fact-ID or FALSE
Description:
Adds a fact to the fact list. Asserts all facts onto the fact list; returns the fact-ID of last fact asserted or FALSE if no facts were successfully asserted (for example, if all facts given are duplicates of existing facts.)

(assert-string <string-expression>)

Package:
(built-in)
Arguments:
One string representing a fact
Returns:
Fact-ID or FALSE
Description:
Converts a string into a fact and asserts it. Attempts to parse string as a fact, and if successful, returns the value returned by assert with the same fact. Note that the string must contain the fact's enclosing parentheses.

(bag <bag-command> <bag-arguments>+)

Package:
jess.BagFunctions
Arguments:
An atom (a sub-command) and one or more additional arguments
Returns:
(Varies)
Description:
The bag command lets you manipulate Java hashtables from Jess. The net result is that you can create any number of associative arrays or property lists. Each such array or list has a name by which it can be looked up. The lists can contain other lists as properties, or any other Jess data type.

The bag command does different things based on its first argument. It's really seven commands in one:

(batch)

Package:
jess.Miscfunctions
Arguments:
One string or atom representing the name of a file
Returns:
(Varies)
Description:
Attempts to parse and evaluate the given file as Jess code. If successful, returns the return value of the last expression in the file.

Note: the argument must follow Jess' rules for valid atoms or strings. On UNIX systems, this presents no particular problems, but Win32 filenames may need special treatment. In particular: pathnames should use either '\\' (double backslash) or '/' (forward slash) instead of '\' (single backslash) as directory separators; and pathnames which include a colon (':') or a space character (' ') must be enclosed in double quotes.

(bind <variable> <expression>*)

Package:
(built-in)
Arguments:
A variable name and any value
Returns:
(Varies)
Description:
Binds a variable to a new value. Assigns the given value to the given variable, creating the variable if necessary. Note that (as in CLIPS) this works best in rules and deffunctions, and not from the command prompt. Returns the given value.

(build <lexeme-expression>)

Package:
jess.Miscfunctions
Arguments:
One string representing some Jess code
Returns:
(Varies)
Description:
Evaluates a string as though it were entered at the command prompt. Only allows constructs to be evaluated. Attempts to parse and evaluate the given string as Jess code. If successful, returns the return value of the last expression in the string. This is typically used to define rules from Jess code. For instance:

(build "(defrule foo (foo) => (bar))")

(call (<external-address> | <string-expression>) <string-expression> <call-arguments>+)

Package:
jess.reflect.ReflectFunctions
Arguments:
an external address or String, a String, and any number of additional arguments (see below)
Returns:
(Varies)
Description:
Calls a Java method on the given object, or a static method of the class named by the first argument. The second argument is the name of the method, and subsequent arguments are passed to the method. Arguments are promoted and overloaded methods selected precisely as for new. The return value is converted to a suitable Jess value before being returned. Array return values are converted to multifields.

The functor call may be omitted if the method being called is non-static and the object is represented by a simple variable. The following two method calls are equivalent:

        
        ;; These are legal and equivalent
        (call ?vector addElement (new java.lang.String "Foo"))
        (?vector addElement (new java.lang.String "Foo"))
call may not be omitted if the object comes from the return value of another function call:
        ;; This is illegal
        ((new java.lang.Vector 10) addElement (new java.lang.String "Foo"))

(clear)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Clears Jess. Deletes all rules, deffacts, defglobals, deftemplates, facts, activations, and so forth. Userfunctions are not deleted.

(close [<router-identifier>])

Package:
(built-in)
Arguments:
One or more router identifiers (atoms)
Returns:
TRUE
Description:
Closes any I/O routers associated with the given name by calling close() on the underlying stream, then removes the routers. Any subsequent attempt to use a closed router will report bad router. See open.

(complement$ <multifield-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
Two multifields
Returns:
Multifield
Description:
Returns a new multifield consisting of all elements of the second multifield not appearing in the first multifield.

(create$ <expression>*)

Package:
jess.MultiFunctions
Arguments:
Zero or more expressions
Returns:
Multifield
Description:
Appends its arguments together to create a multifield value. Returns a new multifield containing all the given arguments. Note: multifields must be created explicitly using this function or others that return them. Multifields cannot be directly parsed from Jess input.

(delete$ <multifield-expression> <begin-integer-expression> <end-integer-expression>)

Package:
jess.MultiFunctions
Arguments:
A multifield and two integer expressions
Returns:
Multifield
Description:
Deletes the specified range from a multifield value. The first numeric expression is the 1-based index of the first element to remove; the second is the 1-based index of the last element to remove.

(div <numeric-expression> <numeric-expression>+)

Package:
jess.MathFunctions
Arguments:
Two or more numeric expressions
Returns:
Numbers
Description:
Returns the first argument divided by all subsequent arguments using integer division. Quotient of the values of the two numeric expressions rounded to the nearest integer.

(e)

Package:
jess.MathFunctions
Arguments:
None
Returns:
Number
Description:
Returns the transcendental number e.

(engine)

Package:
jess.MiscFunctions
Arguments:
None
Returns:
External address
Description:
Returns an external-address object containing the Rete engine in which the function in called.

(eq <expression> <expression>+)

Package:
(built-in)
Arguments:
Two or more arbitrary arguments
Returns:
Boolean
Description:
Returns TRUE if the first argument is equal in type and value to all subsequent arguments. For strings, this means identical contents. Uses the Java Object.equals() function, so can be redefined for external types. Note that the integer 2 and the floating-point number 2.0 are not eq, but they are eq* and =.

(eq* <expression> <expression>+)

Package:
(built-in)
Arguments:
Two or more arbitrary arguments
Returns:
Boolean
Description:
Returns TRUE if the first argument is equivalent to all the others. Uses numeric equality for numeric types, unlike eq. Note that the integer 2 and the floating-point number 2.0 are not eq, but they are eq* and =.

(eval <lexeme-expression>)

Package:
(built-in)
Arguments:
One string containing a valid Jess expression
Returns:
(Varies)
Description:
Evaluates a string as though it were entered at a command prompt. Only allows functions to be evaluated. Evaluates the string as if entered at the command line and returns the result.

(evenp <expression>)

Package:
jess.PredFunctions
Arguments:
One numeric expression
Returns:
Boolean
Description:
Returns TRUE for even numbers; otherwise, returns FALSE. Results with non-integers may be unpredictable.

(exit)

Package:
(built-in)
Arguments:
None
Returns:
Nothing
Description:
Exits Jess and halts Java.

(exp <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Number
Description:
Raises the value e to the power of its only argument.

(explode$ <string-expression>)

Package:
jess.MultiFunctions
Arguments:
One string
Returns:
Multifield
Description:
Creates a multifield value from a string. Parses the string as if by a succession of read calls, then returns these individual values as the elements of a multifield.

(external-addressp <expression>)

Package:
jess.PredFunctions
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE or FALSE as the given expression is an external-address.

(facts)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Prints a list of all facts on the fact list.

(fetch <string or atom>)

Package:
(built-in)
Arguments:
One string or atom
Returns:
(varies)
Description:
Retrieves and returns any value previously stored by the store function under the given name, or nil if there is none. Analogous to the fetch() member function of the Rete class. See the section "Using store and fetch" for details.

(first$ <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
One multifield
Returns:
Multifield
Description:
Returns the first field of a multifield.as a new 1-element multifield.

(float <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Floating-point number
Description:
Converts its only argument to a float.

(floatp <expression>)

Package:
jess.PredFunctions
Arguments:
One numeric expression
Returns:
Boolean
Description:
Returns TRUE for floats; otherwise, returns FALSE.

(foreach <variable> <multifield-expression> <action>*)

Package:
(built-in)
Arguments:
A variable, a multifield expression, and zero or more arguments
Returns:
Varies
Description:
The named variable is set to each of the values in the multifield in turn; for each value, all of the other arguments are evaluated in order. The return function can be used to break the iteration.

Example:

(foreach ?x (create$ a b c d) (printout t ?x crlf))

(format <router-identifier> <string-expression> <expression>*)

Package:
jess.MiscFunctions
Arguments:
A router identifier, a format string, and zero or more arguments
Returns:
A string
Description:
Sends formatted output to the specified logical name. Formats the arguments into a string according to the format string, which is identical to that used by printf in the C language (find a C book for more information). Returns the string, and optionally prints the string to the named router. If you pass nil for the router name, no printing is done.

(get <external-address> <string-expression>)

Package:
jess.reflect.ReflectFunctions
Arguments:
An external address and a string.
Returns:
(Varies)
Description:
Retrieves the value of a Java Bean's property. The first argument is the object and the second argument is the name of the property. The return value is converted to a suitable Jess value exactly as for call.

(get-member (<external-address> | <string-expression>) <string-expression>)

Package:
jess.reflect,ReflectFunctions
Arguments:
An external address or a string, and a string.
Returns:
(Varies)
Description:
Retrieves the value of a Java object's data member. The first argument is the object (or the name of a class, for a static member) and the second argument is the name of the field. The return value is converted to a suitable Jess value exactly as for call.

(get-reset-globals)

Package:
jess.MiscFunctions
Arguments:
None
Returns:
Boolean
Description:
Indicates the current setting of global variable reset behavior. See set-reset-globals for an explanation of this property.

get-salience-evaluation

Package:
jess.MiscFunctions
Arguments:
None
Returns:
Atom
Description:
Indicates the current setting of salience evaluation behavior. See set-salience-evaluation for an explanation of this property.

(gensym*)

Package:
(built-in)
Arguments:
None
Returns:
Atom
Description:
Returns an atom which consists of the letters gen plus an integer. Use setgen to set the value of the integer to be used by the next gensym call. Note that, unlike in CLIPS, these symbols are not guaranteed to be unique. This will change in a future release.

(get-var <lexeme-expression>)

Package:
(built-in)
Arguments:
A string or atom
Returns:
(Varies)
Description:
Fetches the value of a variable, given the name of the variable as a string or atom. (Rarely needed, but when you need it, you'll know.) Most commonly, get-var is used to fetch the value of a global variable on the LHS of a rule.

(halt)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Halts rule execution. No effect unless called from the RHS of a rule.

(if <expression> then <action>* [else <action>*])

Package:
(built-in)
Arguments:
A Boolean variable or function call returning Boolean, the atom then, and any number of additional expressions; optionally followed by the atom else another list of expression.
Returns:
(Varies)
Description:
Allows conditional execution of a group of actions. The boolean expression is evaluated. If it does not evaluate to FALSE, the first list of expressions is evaluated, and the return value is that returned by the last expression of that list. If it does evaluate to FALSE, and the optional second list of expressions is supplied, those expressions are evaluated and the value of the last is returned.
Example:
(if (> ?x 100)
        then
          (printout t "X is big" crlf)
        else
          (printout t "X is small" crlf))

(implode$ <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
One multifield
Returns:
String
Description:
Creates a string from a multifield value. Converts each element of the multifield to a string, and returns these strings concatenated with single intervening spaces.

(insert$ <multifield-expression> <integer-expression> <single-or-multifield-expression>+)

Package:
jess.MultiFunctions
Arguments:
A multifield, an integer, and one more more multifields
Returns:
A multifield
Description:
Inserts one or more values in a multifield. Inserts the elements of the one or more multifields so that they appear starting at the given 1-based index of the first multifield.

(integer <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Integer
Description:
Converts its only argument to an integer. Truncates any fractional component of the value of the given numeric expression and returns the integral part.

(integerp <expression>)

Package:
jess.PredFunctions
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE for integers; otherwise, returns FALSE.

(intersection$ <multifield-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
Two multifields
Returns:
Multifield
Description:
Returns the intersection of two multifields. Returns a multifield consisting of the elements the two argument multifields have in common.

(jess-version-number)

Package:
(built-in)
Arguments:
None
Returns:
Float
Description:
Returns a version number for Jess; currently 4.5 .

(jess-version-string)

Package:
(built-in)
Arguments:
None
Returns:
String
Description:
Returns a human-readable string descriptive of this version of Jess.

(length$ <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
Multifield
Returns:
Integer
Description:
Returns the number of fields in a multifield value.

(lexemep <expression>)

Package:
jess.PredFunctions
Arguments:
Any expression
Returns:
Boolean
Description:
Returns TRUE for symbols and strings; otherwise, returns FALSE.

(list-function$)

Package:
(built-in)
Arguments:
None
Returns:
Multifield
Description:
Returns a multifield list of all the functions currently callable, including intrinsics, deffunctions, and Userfunctions. Each function name is an atom. The names are sorted in alphabetical order.

(load-facts <file-name>)

Package:
(built-in)
Arguments:
A string or atom representing the name of a file of facts
Returns:
Boolean
Description:
Asserts facts loaded from a file. The argument should name a file containing a list of facts (not deffacts constructs, and no other commands or constructs). Jess will parse the file and assert each fact. The return value is the return value of assert when asserting the last fact. In an applet, load-facts will use getDocumentBase() to find the named file.

Note: See the batch command for a discussion about specifying filenames in Jess.

(load-function <class-name>)

Package:
jess.MiscFunctions
Arguments:
One string or atom representing the name of a Java class
Returns:
Boolean
Description:
The argument must be the fully-qualified name of a Java class that implements the Userfunction interface. The class is loaded in to Jess and added to the engine, thus making the corresponding command available. See Extending Jess with Java for more information.

(load-package <class-name>)

Package:
jess.MiscFunctions
Arguments:
One string or atom, the name of a Java class
Returns:
Boolean
Description:
The argument must be the fully-qualified name of a Java class that implements the Userpackage interface. The class is loaded in to Jess and added to the engine, thus making the corresponding package of commands available. See Extending Jess with Java for more information.

(log <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Number
Description:
Returns the logarithm base e of its only argument.

(log10 <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Number
Description:
Returns the logarithm base-10 of its only argument.

(lowcase <lexeme-expression>)

Package:
jess.StringFunctions
Arguments:
One atom or string.
Returns:
String
Description:
Converts uppercase characters in a string or symbol to lowercase. Returns the argument as an all-lowercase string.

(max <numeric-expression>+)

Package:
jess.MathFunctions
Arguments:
One or more numerical expressions
Returns:
Number
Description:
Returns the value of its largest numeric argument

(member$ <single-field-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
A value and a multifield
Returns:
Integer or FALSE
Description:
Returns the position (1-based index) of a single-field value within a multifield value; otherwise, returns FALSE.

(min <numeric-expression>+)

Package:
jess.MathFunctions
Arguments:
One or more numeric expressions
Returns:
Number
Description:
Returns the value of its smallest numeric argument.

(mod <numeric-expression> <numeric-expression>)

Package:
(built-in)
Arguments:
Two integer expressions
Returns:
Integer
Description:
Returns the remainder of the result of dividing the first argument by its second (assuming that the result of the division must be an integer).

(modify <fact-specified> <RHS-slot>*)

Package:
(built-in)
Arguments:
A fact-ID and zero or more two-element lists
Returns:
Fact-ID
Description:
Modifies the deftemplate fact in the fact list. The fact-ID must belong to an unordered fact. Each list is taken as the name of a slot in this fact and a new value to assign to the slot. A new fact is asserted which is similar to the given fact but which has the specified slots replaced with new values. The original fact is retracted. The fact-ID of the new fact is returned. Modifying a definstance fact will cause the appropriate object properties to be set as well.

(multifieldp <expression>)

Package:
jess.PredFunctions
Arguments:
Any value
Returns:
Boolean
Description:
Returns TRUE for multifield values; otherwise, returns FALSE.

(neq <expression> <expression>+)

Package:
(built-in)
Arguments:
Two or more values
Returns:
Boolean
Description:
Returns TRUE if the first argument is not equal in type and value to all subsequent arguments (see eq).

(new <string-expression> <new-arguments>+)

Package:
jess.reflect.ReflectFunctions
Arguments:
A string and one or more arguments
Returns:
Boolean
Description:
Creates a new Java object and returns an EXTERNAL_ADDRESS value containing it. The first argument is the fully-qualified class name: java.util.Vector, for example. The second and later arguments are constructor arguments. The constructor will be chosen from among all constuctors for the named class based on a first-best fit algorithm. Built-in Jess types are converted as necessary to match available constructors. See the text for more details.

(not <expression>)

Package:
(built-in)
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE if its only arguments evaluates to FALSE; otherwise, returns FALSE.

(nth$ <integer-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
A number and a multifield
Returns:
(Varies)
Description:
Returns the value of the specified (1-based index) field of a multifield value.

(numberp <expression>)

Package:
jess.PredFunctions
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE for numbers; otherwise, returns FALSE.

(oddp <integer-expression>)

Package:
jess.PredFunctions
Arguments:
One integer expression
Returns:
Boolean
Description:
Returns TRUE for odd numbers; otherwise, returns FALSE; see evenp.

(open <file-name> <router-identifier> ["r"|"w"|"a"])

Package:
(built-in)
Arguments:
A file name, an identifier for the file (an atom), and optionally a mode string: one of r, w, a.
Returns:
The file identifier
Description:
Opens a file. Subsequently, the given router identifier can be passed to printout, read, readline, or any other functions that accept I/O routers as arguments. By default, the file is opened for reading; if a mode string is given, it may be opened for reading only (r), writing only (w), or appending (a).

Note: See the batch command for a discussion about specifying filenames in Jess.

(or <expression>+)

Package:
(built-in)
Arguments:
One or more expressions
Returns:
Boolean
Description:
Returns TRUE if any of the arguments evaluates to a non-FALSE value; otherwise, returns FALSE.

(pi)

Package:
jess.MathFunctions
Arguments:
None
Returns:
Number
Description:
Returns the number pi.

(ppdefrule <rule-name>)

Package:
jess.MiscFunctions
Arguments:
A string or atom representing the name of a rule
Returns:
String containing rule's text
Description:
Displays the text of a given rule in a pretty-print representation.

(printout <router-identifier> <expression>*)

Package:
(built-in)
Arguments:
A router identifier followed by zero or more expressions
Returns:
nil
Description:
Sends unformatted output to the specified logical name. Prints its arguments to the named router, which must be open for output. No spaces are added between arguments. The special atom crlf prints as a newline. The special router name t can be used to signify standard output.

(random)

Package:
jess.MathFunctions
Arguments:
None
Returns:
Number
Description:
Returns a pseudo-random integer between 0 and 65536.

(read [<router-identifier>])

Package:
(built-in)
Arguments:
An optional input router identifier (when omitted t is the default)
Returns:
(Varies)
Description:
Reads a single-field value from a specified logical name. Read a single atom, string, or number from the named router, returns this value. The router t means standard input. Newlines are treated as ordinary whitespace; this behaviour is different than in CLIPS, which returns newlines as tokens. If you need to parse text line-by-line, use readline and explode$.

(readline [<router-identifier>])

Package:
(built-in)
Arguments:
An optional input router identifier (when omitted t is the default)
Returns:
String
Description:
Reads an entire line as a string from the specified logical name (router). The router t means standard input.

(replace$ <multifield-expression> <begin-integer-expression> <end-integer-expression> <single-or-multifield-expression>+)

Package:
jess.MultiFunctions
Arguments:
A multifield, two numeric expressions, and one or more multifields
Returns:
Multifield
Description:
Replaces the specified range of a multifield value with a set of values. The last one more more multifields are inserted into the first multifield, replacing elements between the 1-based indices given by the two numeric arguments, inclusive.
Example:
 Jess> (replace$ (create$ a b c) 2 2 (create$ x y z))
     (a x y z c)

(reset)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Removes all facts from the fact list, removes all activations, then asserts the fact (initial-fact), then asserts all facts found in deffacts, asserts a fact representing each registered definstance, and (if the set-reset-globals property is TRUE) initializes all defglobals.

(rest$ <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
One multifield
Returns:
Multifield
Description:
Returns all but the first field of a multifield as a new multifield.

(retract <integer-expression>+)

Package:
(built-in)
Arguments:
One or more fact-IDs
Returns:
TRUE
Description:
Retracts the facts whose IDs are given. Retracting a definstance fact will result in an implict call to undefinstance for the corresponding object (the object will no longer be pattern-matched).

(return [<expression>])

Package:
(built-in)
Arguments:
An optional expression
Returns:
(Varies)
Description:
Returns the given value from a deffunction. Exits the deffunction immediately.

(round <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
One numeric expression
Returns:
Integer
Description:
Rounds its argument toward the closest integer or negative infinity if exactly between two integers.

(rules)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Prints a list of all defrules.

(run)

Package:
(built-in)
Arguments:
None
Returns:
TRUE
Description:
Starts the inference engine. Jess will keep running until no more activations remain or halt is called.

(save-facts <file-name> [<deftemplate-name>])

Package:
(built-in)
Arguments:
A filename, and optionally an atom
Returns:
Boolean
Description:
Saves facts to a file. Attempts to open the named file for writing, and then writes a list of all facts on the fact list to the file. This file is suitable for reading with load-facts. If the optional second argument is given, only facts whose head matches this atom will be saved. Does not work in applets.

Note: See the batch command for a discussion about specifying filenames in Jess.

(set <external-address> <string-expression> <expression>)

Package:
jess.reflect.ReflectFunctions
Arguments:
An external address, a string, and an expression
Returns:
The last argument
Description:
Sets a Java Bean's property to the given value. The first argument is the Bean object; the second argument is the name of the property. The third value is the new value for the property; the same conversions are applied as for new and call.

(set-member (<external-address> | <string-expression>) <string> <expression>+)

Package: jess.reflect.ReflectFunctions
Arguments:
An external address or a string, a string, and one or more expressions
Returns:
The last argument
Description:
Sets a Java object's member variable to the given value. The first argument is the object (or the name of the class, in the case of a static member variable). The second argument is the name of the variable. The third value is the new value for the variable; the same conversions are applied as for new and call.

(set-reset-globals (TRUE | FALSE | nil))

Package:
jess.MiscFunctions
Arguments:
One boolean value (TRUE or FALSE or nil)
Returns:
Boolean
Description:
Changes the current setting of the global variable reset behavior. If this property is set to TRUE (the default), then the (reset) command reinitializes the values of global variables to their initial values (if the initial value was a function call, the function call is reexecuted.) If the property is set to FALSE or nil, then (reset) will not affect global variables. Note that in previous versions of Jess, defglobals were always reset; but if the initial value was set with a fucntion call, the function was not reevaluated. Now it is.

(set-salience-evaluation (when-defined | when-activated | every-cycle))

Package:
jess.MiscFunctions
Arguments:
One of the atoms when-defined, when-activated, or every-cycle
Returns:
One of the potential arguments (the previous value of this property)
Description:
Changes the current setting of the salience evaluation behavior. By default, a rule's salience will be determined once, when the rule is defined (when-defined.) If this property is set to when-activated, then the salience of each rule will be redetermined immediately before each time it is placed on the agenda. If the property is set to every-cycle, then the salience of every rule is redetermined immediately after each time any rule fires.

(set-strategy (depth | breadth))

Package:
jess.MiscFunctions
Arguments:
An atom or string representing the name of a strategy (can be a fully-qualified Java class name). You can use depth and breadth to represent the two built-in strategies.
Returns:
The previous strategy as an atom
Description:
Lets you specify the conflict resolution strategy Jess uses to order the firing of rules of equal salience. Currently, there are two strategies available: depth (LIFO) and breadth (FIFO). When the depth strategy is in effect (the default), more recently activated rules are fired before less recently activated rules of the same salience. When the breadth strategy is active, rules of the same salience fire in the order in which they are activated. Note that in either case, if several rules are activated simultaneously (i.e., by the same fact-assertion event) the order in which these several rules fire is unspecified, implementation-dependent and subject to change. More built-in strategies may be added in the future. You can (perhaps) implement your own strategies in Java by creating a class that implements the jess.Strategy interface and then specifying its fully-qualified classname as the argument to set-strategy. Details can be gleaned from the source. At this time, though, I think some of the methods you'd need to call are package-protected.

(setgen <numeric-expression>)

Package:
jess.MiscFunctions
Arguments:
A numeric expression
Returns:
TRUE
Description:
Sets the starting number used by gensym*. Note that if this number has already been used, gensym* uses the next larger number that has not been used.

(socket <Internet-hostname> <TCP-port-number> <router-identifier>)

Package:
jess.MiscFunctions
Arguments:
An Internet hostname, a TCP port number, and a router identifier
Returns:
The router identifier
Description:
Somewhat equivalent to open, except that instead of opening a file, opens an unbuffered TCP network connection to the named host at the named port, and installs it as a pair of read and write routers under the given name.

(sqrt <numeric-expression>)

Package:
jess.MathFunctions
Arguments:
A numeric expression
Returns:
Number
Description:
Returns the square root of its only argument.

(store <string or atom> <expression>)

Package:
(built-in)
Arguments:
A string or atom and any other value
Returns:
(varies)
Description:
Associates the expression with the name given by the first argument, such that later calls to the fetch will retrieve it. Analagous to the store() member function of the jess.Rete class. See section on Using store and fetch for more details.

(str-cat <expression>*)

Package:
jess.StringFunctions
Arguments:
Zero or more expressions
Returns:
String
Description:
Concatenates its arguments as strings to form a single string.

(str-compare <string-expression> <string-expression>)

Package:
jess.StringFunctions
Arguments:
Two strings
Returns:
Integer
Description:
Lexicographically compares two strings. Returns 0 if the strings are identical, a negative integer if the first is lexicographically less than the second, a positive integer if lexicographically greater.

(str-index <lexeme-expression> <lexeme-expression>)

Package:
jess.StringFunctions
Arguments:
Two atoms
Returns:
Integer or FALSE
Description:
Returns the position of the first argument within the second argument. This is the 1-based index at which the first string first appears in the second; otherwise, returns FALSE.

(str-length <lexeme-expression>)

Package:
jess.StringFunctions
Arguments:
An atom
Returns:
Integer
Description:
Returns the length of an atom in characters.

(stringp <expression>)

Package:
jess.PredFunctions
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE for strings; otherwise, returns FALSE.

(sub-string <begin-integer-expression> <end-integer-expression> <string-expression>)

Package:
jess.StringFunctions
Arguments:
Two numbers and a string
Returns:
String
Description:
Retrieves a subportion from a string. Returns the string consisting of the characters between the two 1-based indices of the given string, inclusive.

(subseq$ <multifield-expression> <begin-integer-expression> <end-integer-expression>)

Package:
jess.MultiFunctions
Arguments:
A multifield and two numeric expressions
Returns:
Multifield
Description:
Extracts the specified range from a multifield value consisting of the elements between the two 1-based indices of the given multifield, inclusive.

(subsetp <multifield-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
Two multifields
Returns:
Boolean
Description:
Returns TRUE if the first argument is a subset of the second (i.e., all the elements of the first multifield appear in the second multifield); otherwise, returns FALSE.

(sym-cat <expression>*)

Package:
(built-in)
Arguments:
Zero or more expressions
Returns:
Atom
Description:
Concatenates its arguments as strings to form a single symbol.

(symbolp <expression>)

Package:
jess.PredFunctions
Arguments:
One expression
Returns:
Boolean
Description:
Returns TRUE for symbols; otherwise, returns FALSE.

(system <lexeme-expression>*)

Package:
jess.MiscFunctions
Arguments:
Zero or more atoms
Returns:
TRUE
Description:
Appends its arguments to form a command which is then sent to the operating system. Executes the operating-system command-line constructed by converting each argument to a string. Normally blocks (i.e., Jess stops until the applet returns), but if the last argument is an ampersand (&), the program will run in the background.

(time)

Package:
jess.MiscFunctions
Arguments:
None
Returns:
Number
Description:
Returns the number of seconds since 12:00 AM, Jan 1, 1970.

(try <expression>* catch <expression>*)

Package:
(built-in)
Arguments:
One or more expressions, followed by the atom catch, followed by zero or more expressions
Returns:
(Varies)
Description:
This command works something like Java try with a few simplifications. The biggest difference is that the catch clause can specify neither a type of exception nor a variable to receive the exception object. All exceptions occurring in a try block are routed to the single required catch block. The variable ?ERROR is made to point to the exception object as an EXTERNAL_ADDRESS. For example:
(try
(open NoSuchFile.txt r)
catch

(printout t (call ?ERROR toString) crlf))

prints

Rete Exception in routine _open::call.
Message: I/O Exception java.io.FileNotFoundException: NoSuchFile.txt.

An empty catch block is fine. It just signifies ignoring possible errors.

(undefrule <rule-name>)

Package:
(built-in)
Arguments:
An atom representing the name of a rule
Returns:
Boolean
Description:
Deletes a defrule. Removes the named rule from the Rete network and returns TRUE if the rule existed.. This rule will never fire again.

(union$ <multifield-expression> <multifield-expression>)

Package:
jess.MultiFunctions
Arguments:
Two multifields
Returns:
Multifield
Description:
Returns a new multifield consisting of the union of its two multifield arguments (i.e., of all the elements that appear in the two arguments with duplicates removed).

(unwatch <watch-item>)

Package:
(built-in)
Arguments:
One of the atoms all, rules, compilations, activations, facts
Returns:
TRUE
Description:
Causes trace output to not be printed for the given indicator. See watch.

(upcase <lexeme-expression>)

Package:
jess.StringFunctions
Arguments:
A string or atom
Returns:
A string
Description:
Converts lowercase characters in a string or symbol to uppercase. Returns the argument as an all-uppercase string.

(view)

Package:
jess.view.ViewFunctions
Arguments:
None
Returns:
TRUE
Description:
This Userfunction is included in the Jess distribution but is not normally installed. It requires Java 1.1. You must load it using load-package (the class name is jess.view.ViewFunctions). When invoked, it displays a live snapshot of the Rete network in a graphical window. See How Jess Works.

(watch (all | rules | compilations | activations | facts))

Package:
(built-in)
Arguments:
One of the atoms all, rules, compilations, activations, facts
Returns:
TRUE
Description:
Produces additional debug output when specific events happen in Jess, depending on the argument. Any number of different watches can be active simultaneously:

(while <expression> [do] <action>*)

Package:
(built-in)
Arguments:
A Boolean value or a function call returning Boolean, the atom do, and zero or more expressions
Returns:
(Varies)
Description:
Allows conditional looping. Evaluates the boolean expression repeatedly. As long as it does not equal FALSE, the list of other expressions are evaluated. The value of the last expression evaluated is the return value.

4 Writing Jess Code

Many useful expert systems can be written using only the Jess language as presented above. I won't present a tutorial on writing such systems here (maybe someday!), but I do want to share a few useful hints and ideas.

4.1 Using an External Editor

Jess allows you to enter rules directly at its interactive prompt. While this is fine for experimenting, Jess doesn't yet have the ability to remember the source text for all the rules and constructs you enter. Therefore, you will typically enter your rules and other data into a separate script file and read it into Jess using the batch command. Jess does offer the ppdefrule and save-facts commands, both of which can be very helpful in interactively building up a system definition and them storing it in a file. And as described in a previous section, you can use the system command to start the external editor form within Jess, if desired.

4.2 Efficiency

The single biggest determinant of Jess performance is the number of partial matches generated by your rules. You should always try to obey the following (sometimes contradictory) guidelines while writing your rules: You can use the view command to find out how many partial matches your rules generate. See How Jess Works.

4.3 Error Reporting and Debugging

I've tried hard to improve Jess's syntax error reporting in this release, but it is still not as detailed as it could be. When you get an error from Jess (during parsing or at runtime) it is generally delivered as a Java exception. The exception will contain an explanation of the problem and the stack trace of the exception will help you understand what went wrong. For this reason, it is very important that, if you're embedding Jess in a Java application, you don't write code like this:
        try
        {
          Rete engine;
          ...
          engine.executeCommand("(gibberish!)");
        }
        catch (ReteException re) { /* ignore errors */ }
If you ignore the Java exceptions, you will miss Jess's explanations of what's wrong with your code. Don't laugh - more people code this way than you'd think!

Anyway, if you attempt to load the folowing rule in the standard Jess command-line executable,

        Jess> (defrule foo-1
                (foo bar)
                ->
                (printout "Found Foo Bar" crlf))
You'll get the following printout:
        Rete Exception in routine Jesp::parseDefrule.
          Message: Expected '=>' at line 2:  ( defrule foo-1 ( foo bar ) -> .
                at jess.Jesp.parseError(Compiled Code)
                at jess.Jesp.doParseDefrule(Compiled Code)
                at jess.Jesp.parseDefrule(Compiled Code)
                at jess.Jesp.parseSexp(Compiled Code)
                at jess.Jesp.parse(Compiled Code)
                at jess.Main.main(Compiled Code)
Looking at the routine names listed in the stack trace make it fairly clear that a defrule was being parsed, and the detail message explains that the position of the . was reached in the input without finding the expected => symbol (we accidentally typed -> instead).

Runtime errors can be more puzzling, but the stack trace will give you a lot of information. Here's a rule where we erroneously try to add the number 3.0 to the word four:

        Jess> (defrule foo-2
              =>
                (printout t (+ 3.0 four) crlf))
When we (reset) and (run) we'll see:
       Rete Exception in routine Value::intValue while executing defrule foo-2.
          Message: Not a number: four type = 1 at line 8:  ( run ) .
                at jess.Value.typeError(Compiled Code)
                at jess.Value.numericValue(Compiled Code)
                at jess.Plus.call(Compiled Code)
                at jess.Funcall.simpleExecute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Defrule.fire(Compiled Code)
                at jess.Activation.fire(Compiled Code)
                at jess.Rete.run(Compiled Code)
                at jess.Rete.run(Compiled Code)
                at jess.HaltEtc.call(Compiled Code)
                at jess.Funcall.simpleExecute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Jesp.parseAndExecuteFuncall(Compiled Code)
                at jess.Jesp.parseSexp(Compiled Code)
                at jess.Jesp.parse(Compiled Code)
                at jess.Main.main(Compiled Code)
In this case, the error message is pretty clear except for the claim that the offending statement is run. To find out what was really happening, we have to look at the stack trace. Starting from the top down, we find Value.numericValue() was called by Plus.call(). A few levels down, we see Defrule.fire(). Taken together, this means that an addition operation on the RHS of the rule foo-2 (from the first line of the trace) found the symbol four as one of its operands when it expected a number.

The notation type = 1 in the error message, by the way, refers to a set of constants in the class jess.RU. The values of these constants are presented in section 5.4.1, The class jess.Value. Consulting that table, we see that type 1 is RU.ATOM, a symbol, which is indeed not a number.

If we make a similar mistake on the LHS of a rule:

        Jess> (defrule foo-3
                (test (eq 3 (+ 2 one)))
                 =>
                )
We see the following after a reset:
        Rete Exception in routine Value::intValue while executing 'test' CE:
        [NodeTest ntests=1 [Test1: test=EQ;slot_idx=3;sub_idx=-1;
                  slot_value=eq 3 + 2 one] ;usecount = 1].
            Message: Not a number: one type = 1 at line 11: ( reset ) .
                at jess.Value.typeError(Compiled Code)
                at jess.Value.numericValue(Compiled Code)
                at jess.Plus.call(Compiled Code)
                at jess.Funcall.simpleExecute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.Funcall.execute(Compiled Code)
                at jess.NodeTest.runTests(Compiled Code)
                at jess.NodeTest.callNode(Compiled Code)
                at jess.Node.passAlong(Compiled Code)
                at jess.Node1TELN.callNode(Compiled Code)
                at jess.Node.passAlong(Compiled Code)
                at jess.Node1TECT.callNode(Compiled Code)
                at jess.Rete.processTokenOneNode(Compiled Code)
                at jess.Rete.updateNodes(Compiled Code)
                at jess.ReteCompiler.addRule(Compiled Code)
                at jess.Rete.addDefrule(Compiled Code)
                at jess.Jesp.doParseDefrule(Compiled Code)
                at jess.Jesp.parseDefrule(Compiled Code)
                at jess.Jesp.parseSexp(Compiled Code)
                at jess.Jesp.parse(Compiled Code)
                at jess.Main.main(Compiled Code)
Again, the error message is somewhat but not completely helpful (it says the error was in the function reset, but it also says that a (test) CE was being executed, and it prints out a stylized version of the test CE itself) and the stack trace contains additional information. Here we see our old friends Value.numericValue() and Plus.call() being called, but we don't see the Defrule being fired. Instead we see lots of oddly named classes and functions with names containing Node and Token. This is always a tip-off that the error happened on Defrule LHS processing, as are both the fact that the error happened during a reset and the message at the top of the trace. Way down the stack we see Rete.assert() being called by Rete.reset(), which also indicates that LHS processing was in progress when the exception happened.

The funny string starting with [NodeTest ntests=1; ... is Jess's internal representation for a single node in the Rete network that encodes the test CE from the rule above. Looking at it, you can see that it includes the function call (+ 2 one), which should help you track it down. Note that in this case, Jess can't tell you which rule this node belongs to, as it theoretically could be shared by several rules (see How Jess Works for details.)


5 Embedding Jess in a Java Program

There are three different ways to use Jess and Java code together:

5.1 The jess.Rete Class

5.1.1 Executing a File of Jess Code
Using Jess from Java code is simple. The jess.Rete class contains the expert system engine. The jess.Jesp class contains the Jess parser. To execute a file of CLIPS code in Jess (like the Jess batch command), simply create a Rete object and a Jesp object, tell the Jesp object about the file, and call Jesp.parse(boolean prompt):
  
import jess.*;

  // ...

  // See info about the ReteDisplay classes below
  NullDisplay nd = new NullDisplay();

  // Create a Jess engine
  Rete rete = new Rete(nd);

  // Open the file test.clp
  FileInputStream fis = new FileInputStream("test.clp");

  // Create a parser for the file, telling it where to take input
  // from and which engine to send the results to
  Jesp j = new Jesp(fis, rete);
  do
    {
      try
      {
        // parse and execute one construct, without printing a prompt
        j.parse(false);
      }
      catch (ReteException re)
      {
        // All Jess errors are reported as 'ReteException's.
        re.printStackTrace(nd.stderr());
      }
    } while (fis.available() > 0);
Note that if the file test.clp contains the CLIPS reset and run commands, the Jess engine will run to completion during the parse() calls. Also note that Jess will throw jess.ReteException exceptions to signal errors.
5.1.2 Adding Optional Commands
The code above will create only a minimal Jess engine, including a relatively small number of functions (the intrinsic functions). Many of the functions packaged with Jess are actually implemented as optional jess.Userpackage classes. You can choose to load some or all of these into your Jess applications. Omitting unneeded functions may be especially important in applets, where a small footprint is important.

Here is a snippet of code (from jess/Main.java) which will load all the standard optional functions, without causing an error if any of them are missing:

        
  // Load in optional packages, but don't fail if any are missing.
  Rete rete = new Rete(nd);

  String [] packages = { "jess.StringFunctions",
                         "jess.PredFunctions",
                         "jess.MultiFunctions", 
                         "jess.MiscFunctions",
                         "jess.MathFunctions",
                         "jess.BagFunctions",
                         "jess.reflect.ReflectFunctions",
                         "jess.view.ViewFunctions" };

  for(int i=0; i< packages.length; i++)
    {
      try
        {
          rete.addUserpackage((Userpackage)
                              Class.forName(packages[i]).newInstance());
        }
      catch (Throwable t) { /* Optional package not present */ }
    }
To find out which functions are built into Jess and which are optional, see the Jess Function Guide, which lists the package in which each function appears.
5.1.3 Executing Individual Commands
For somewhat more control over Jess from your Java program, you can use the Rete class's executeCommand(String cmd) method. For example, after the above code, you could include the following:
  try
    {
      rete.executeCommand("(reset)");
      rete.executeCommand("(assert (foo bar foo))");
      rete.executeCommand("(run)");

      // Prints '42'
      System.out.println(rete.executeCommand("(+ 37 5)"));
    }
  catch (ReteException ex)
    {
      System.err.println("Foo bar error.");
    }
Commands executed via executeCommand() may refer to Jess variables; they will be interpreted in the global context. In general, only defglobals can be used in this way.
5.1.4 Other Methods in the Rete Class
Rete has a number of other public methods which I have not documented here; see the source for details. There are functions to assert and retract facts (which you are invited to use) and functions to find and remove various constructs (which you may also use.) There are also functions which allow you to add constructs (defrules, deftemplates, etc.) In general, it is best that you not use these in your programs, because they are highly subject to change in future Jess versions, as are the details of the classes like jess.Defrule which represent constructs. Two other functions you will certainly use are addUserfunction() and addUserpackage(). These are explained in Extending Jess With Commands Written in Java. In addition, the methods run(), reset(), and halt() are useful.

There is a set of diagnostic methods in Rete which return Enumerations of various data structures in the engine:

Feel free to use these for debugging purposes, but don't get too chummy with them: they are subject to change without notice, especially the types of the objects they return. Note that listUserfunctions() returns an Enumeration of all the Jess functions in the engine, including deffunctions and intrinsics.

5.2 The ReteDisplay Interface.

There is a lot you can do with just what we've discussed so far. One thing that you might not like, though, is that by default, programs we write using the above techniques will send their output to your Java program's System.out and take input from System.in. If you're writing a graphical program, this is clearly not what you want. Jess provides an interface jess.ReteDisplay that lets you deal with this in a simple way. ReteDisplay also provides some hooks into the engine's internal workings. The ReteDisplay interface provides two types of functions:
  1. Functions that return the intial input, output, and error streams that the engine should use.
  2. Functions that are called by the engine whenever an event occurs (events here meaning that a construct is parsed, fact is asserted, rule is activated, and so forth).
5.2.1 Using ReteDisplay
Every Rete object must be constructed with an instance of ReteDisplay. Here is the definition of the ReteDisplay interface:
  public interface ReteDisplay
    {
      // Rete sets its initial input/output using these        
      // These must be implemented
      public java.io.PrintStream stdout();
      public java.io.InputStream stdin();
      public java.io.PrintStream stderr();

      // These notify the ReteDisplay object when things happen
      // Can do nothing if you want!
      public void assertFact(ValueVector fact);
      public void retractFact(ValueVector fact);
      public void addDeffacts(Deffacts df);
      public void addDeftemplate(Deftemplate dt);
      public void addDefrule(Defrule rule);
      public void activateRule(Defrule rule);
      public void deactivateRule(Defrule rule);
      public void fireRule(Defrule rule);

      // This gives the Rete object access to Applet resources
      // Should return null if not in an Applet
      public java.applet.Applet applet();
    }
Jess ships with two different classes that implement this interface. You can write your own or modify these for use in your own applications.
5.2.2 The jess.TextAreaOutputStream and jess.TextInputStream Classes
Jess ships with two utility classes that are very useful when building GUIs for Jess: the jess.TextAreaOutputStream and jess.TextInputStream classes. Both can serve as adapters between Jess and graphical input/output widgets. The TextAreaOutputStream class is, as the name implies, a Java OutputStream that sends any data written to it to a java.awt.TextArea. This lets you place Jess's output in a scrolling window on your GUI. The jess.Console and jess.ConsoleApplet jess GUIs use these classes. To use TextAreaOutputStream, simply write a class that implements ReteDisplay, returning a suitably wrapped TextAreaOutputStream from the stdout() and stderr() methods:
import jess.*;
  public class MyDisplay implements ReteDisplay
    {        
       public TextArea ta = new TextArea(20, 80);
       TextAreaOutputTream taos = new TextAreaOutputStream(ta);
       PrintStream ps = new PrintStream(taos, true);
           
       public MyDisplay()
       {
         Frame f = new Frame("Jess Demo");
         f.add(ta);
         f.pack();
         f.show();
       }

       PrintStream stdout() { return ps; }
// ... (Plus all the other ReteDisplay methods) Now if you construct a jess.Rete object with an instance of this display, the Jess output will go into a scrolling window. If you have a source distribution, study jess/ConsoleDisplay.java and jess/Console.java to see a complete example of this.

jess.TextInputStream is similar, but it is an InputStream instead. It is actually quite similar to java.io.StringBufferInputStream, except that you can continually add new text to the end of the stream (using the appendText() method). It is intended that you create a jess.TextInputStream, return it from your jess.ReteDisplay.stdin() method, and then (in an AWT event handler, somewhere) append new input to the stream whenever it becomes available. See the same jess/Console* files for a complete usage example for this class as well.

5.2.3 Switching Streams in Mid-Stream
The Rete engine will call the stdout() and stdin() methods of your ReteDisplay class at least once when it is created. It is from these return values that the initial definition of the t, WSTDOUT, and WSTDERR I/O routers are made (see Manipulating Jess I/O Routers in Java). It will never call these methods again. This means that changing the return values of these functions over time may have no effect. To re-route input and output you must use the explicit router functions.

5.3 Manipulating Jess I/O Routers in Java

ReteDisplay lets you set up the minumal initial state for a Rete object, but Jess can read from more that just standard input and standard output. Jess I/O routers can be easily manipulated from Java. These six functions in the Rete class manipulate the router list: When Jess starts up, there are one input router and three output routers defined: the t router, which reads and writes from the standard input and output; the WSTDOUT router, which Jess uses for all prompts, diagnostic outputs, and other displays; and the WSTDERR router, which Jess uses to print stack traces and error messages. You can reroute these inputs and outputs simply by changing the Input and Output streams they are attached to using the above functions. You can use any kind of streams you can dream up: network streams, file streams, etc.

The boolean argument console to the addInputRouter method specifies whether the stream should be treated like the standard input or like a file. The difference is that on console-like streams, a read call consumes an entire line of input, but only the first token is returned; while on file-like streams, only the characters that make up each token are consumed on any one call. That means, for instance, that a read followed by a readline will consume two lines of text from a console-like stream, but only one from a file-like stream, given that the first line is of non-zero length. This odd behaviour is actually just following the behaviour of CLIPS.

The Rete class has two more handy router-related methods: outStream() and errStream(), both of which return a PrintStream object. outStream() returns a stream that goes to the same place as the current setting of WSTDOUT; errStream() does the same for WSTDERR.

You can add your own routers which do I/O through any Java stream