1. Introduction

1.1. Abstract

This report describes Jess, an expert system shell and scripting language written entirely in Sun Microsystem's Java language. 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. Guides to calling Java functions from Jess, to extending Jess by writing Java code, and to embedding Jess in Java applications are also included.

1.2. Compatibility

Jess 6.1 is compatible with all versions of Java starting with Java 1.2. In particular, this includes JDK 1.4 (or "Java 2" as it is now known.) Versions numbered 4.x are compatible with JDK 1.0, and the 5.x versions work with JDK 1.1.
When compiling Jess with JDK 1.4, you will see warnings concerning the use of the new keyword assert as a method name. This is normal -- note that these are warnings, not errors. The assert method is deprecated in Jess 6.1 and will be removed in Jess 7.0. Until then, these warnings are harmless.

1.3. Mailing List

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
  info jess-users
as the body of the message. There is an archive of the list at http://www.mail-archive.com/jess-users@sandia.gov .

1.4. Bugs

Although we've done everything we can to test Jess, no software is perfect. There may still be bugs. Please read the release notes for specific information. Comments and bug reports are welcome. Contact me at ejfried@ca.sandia.gov so I can fix them for a later release.

1.5. Assumptions

Jess is a programmer's library. The library itself is written in Java. The library serves as an interpreter for another language, which I will refer to in this document as the Jess language. The Jess language is very similar to the language defined by the CLIPS expert system shell, which in turn is a highly specialized form of LISP.

Therefore, I am going to assume that you, the reader, are a programmer who will be using either one or both of these languages. I will assume that all readers have at least a minimal facility with Java. You must have a Java compiler and runtime system, and you must know how to use it at least in a simple way. You should know how to use it to If you do not have at least this passing familiarity with a Java environment, then may I suggest you purchase an introductory book on the topic.

For those readers who are going to program in the Jess language, I assume general familiarity with the principles of programming. I will describe the entire Jess language, so no familiarity with LISP is required. Furthermore, I will attempt to describe, to the extent possible, the important concepts of rule-based systems as they apply to Jess. Again, though, I will assume that the reader has some familiarity with these concepts and more. If you are unfamiliar with rule-based systems, you may want to purchase a text on this topic as well.

Many readers will want to extend Jess' capabilities by either adding commands (written in Java) to the Jess language, or embedding the Jess library in a Java application. Others will want to use the Jess language's Java integration capabilities to call Java functions from Jess language programs. In sections of this document targeted towards these readers, I will assume moderate knowledge of Java programming. I will not teach any aspects of the Java language. The interested reader is once again referred to your local bookstore.

This document contains a bibliography wherein a number of books on all these topics are listed.

1.6. Getting ready

1.6.1. Unpacking the Distribution

If you download Jess for UNIX, you can extract the files using tar and gunzip:
        gunzip Jess61p8.tgz
        tar xf Jess61p8.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 Jess61p8/. There are two kinds of Jess distributions: binary-only and source. Inside this directory should be the following files and subdirectories, depending on which type of distribution you have:

docs/ This documentation
jess/ 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-only distribution of Jess, this directory will contain only the examples subdirectory.
examples/ A directory of tiny example Jess files.
jess/examples A directory of more complicated examples, containing example Java source files.
jess.jar (optional) A Java archive file containing the Jess classes themselves. Binary distribution only.
Makefile (optional) A simple makefile for Jess. Source distribution only.

1.6.2. Compiling Jess

If you have a source distribution of Jess, you have a set of Java source files, and you'll need to compile them first before you can run Jess. If you have a binary distribution, you can skip this section. If you have a make utility (any UNIX-like make; you could use the CygWin environment on Windows), you can just run make and the enclosed Makefile will build everything. You will have to edit it a bit first to specify the path to your Java compiler. Otherwise, you can compile Jess by typing a few commands yourself. Using Sun's JDK on some version of Windows, the commands
  javac -d . jess\*.java
  javac -d . jess\awt\*.java
  javac -d . jess\factory\*.java
would work just fine, given that Jess61p8/ is your current directory.
NOTE: Jess works fine with JDK 1.4, but you will get warnings during the compilation about a conflict between the new Java keyword "assert" amd the Jess function jess.Rete.assert(). These are just warnings, and they don't stop the compilation. This function is now deprecated in Jess and will be phased out over the next few versions.

If you have problems, be sure that if you have the CLASSPATH environment variable set, it includes '.', the current directory. Don't try to compile from inside the Jess61p8/jess/ directory; it won't work.

If you're on a UNIX system instead of a Windows system, you can use the commands given above, but you'll need to change the backslashes (\) into forward slashes (/).

You must use a Java 2 compiler to compile Jess. The resulting code will run on any Java 2 or later VM. Jess works great with JDK 1.3.

There are a number of optional example source files in the subdirectories Jess61p8/jess/examples/ that aren't compiled if you follow the instructions above. You can compile the examples one at a time. For example, to compile the example named pumps using the JDK on a Windows system, you can use the command
  javac -d . jess\examples\pumps\*.java

Again, don't set your current directory to, for example, Jess61p8/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 Jess61p8 directory. I can't stress this enough: this is by far the most common problem people have in getting started with Jess!

I personally use the Jikes Java compiler from IBM. The compiler itself is very fast -- it compiles all of Jess in just a few seconds on my machine. I highly recommend it, and it's free!

1.6.3. Jess Example Programs

There are a few trivial example programs (in the examples/ directory) that you can use to confirm that you have properly compiled Jess. These include 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
(if you've got a source distribution) or
  java -classpath jess.jar jess.Main examples/fullmab.clp
(if you've got a binary-only distribution) 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 generally need to make sure that the file ends with:
or no rules will fire. 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 large numbers of partial pattern matches, so they are slow and use up a lot of memory. Other examples include sticks.clp (an interactive game), frame.clp (a demo of building a graphical interface using Jess's Java integration capabilities), and animal.clp. Note that animal.clp is hardwired to expect a data file to exist in a subdirectory examples/ of the current directory.

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.6.4. Command-line Interface

Jess has an interactive command-line interface. Just type java jess.Main (or java -classpath jess.jar jess.Main) to get a Jess> prompt. To execute a file of CLIPS code from the command prompt, use the batch command:
  Jess> (batch examples/sticks.clp)
  Who moves first (Computer: c Human: h)?
Note that in the preceding example, you type what follows the Jess> prompt, and Jess responds with the text on the next line. I will follow this convention throughout this manual.

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 application named xlogo on your system, try:
Jess> (system xlogo &)

The & character makes the program run in the background. Omitting it will keep the system command from returning until the called program exits. The system command returns the Java Process object representing the launched application.

The class jess.Console is a graphical version of the Jess command-line interface. You type into a text field at the bottom of the window, and output appears in a scrolling window above. Type java jess.Console to try it.

1.6.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).

Since Jess 6 uses the Java 2 API, it won't work in the native JVM of most deployed web browsers. Netscape 4.x and all versions of Microsoft Internet Explorer use some version of a JDK 1.1 Java Virtual Machine. You can use Jess 4 or 5 in these browsers, or you can require the user to download the Java Plug-In. A full discussion of this topic is beyond the scope of this document -- you're encouraged to get a book that covers deploying applets on the Web if you're interested.

Note that even in Jess 4 and 5, the ConsoleApplet and ConsoleDisplay classes use the Java 1.1 event model, which is still not supported by some of the installed base of Web browsers; the Plug-in might still be necessary. Don't use ConsoleApplet if you want to deploy highly portable applets! Actually, the idea of deploying Jess as an applet makes less and less sense these days; a much better alternative is to run Jess on the server side (as a servlet, for example) and run only the GUI on the client. Good applets are generally very small (a few tens of kilobytes), while Jess's class files now occupy hundreds of kilobytes.

1.7. What makes a good Jess application?

Jess can be used in two overlapping ways. First, it can be a rule engine - a special kind of program that very efficiently applies rules to data. A rule-based program can have hundreds or even thousands of rules, and Jess will continually apply them to data in the form of a knowledge base. Often the rules will represent the heuristic knowledge of a human expert in some domain, and the knowledge base will represent the state of an evolving situation (an interview, an emergency). In this case, they are said to constitute an expert system. Expert systems are widely used in many domains. Among the newest applications of expert systems are as the reasoning part of intelligent agents, in enterprise resource planning (ERP) systems, and in order validation for electronic commerce.

But the Jess language is also a general-purpose programing language, and furthermore, it can directly access all Java classes and libraries. For this reason, Jess is also frequently used as a dynamic scripting or rapid application development environment. While Java code generally must be compiled before it can be run, a line of Jess code is executed immediately upon being typed. This allows you to experiment with Java APIs interactively, and build up large programs incrementally. It is also very easy to extend the Jess language with new commands written in Java or in Jess itself, and so the Jess language can be customized for specific applications.

Jess is therefore useful in a wide range of situations. One application for which Jess is not so well suited is as an applet intended for Internet use. Jess's size (a few hundred kilobytes of compiled code) makes it too large for applet use except on high-speed LANs. Furthermore, some of Jess's capabilities are lost when it is used in a browser: for example, access to Java APIs from the Jess language may not work at all due to security restrictions in some browsers. When building Web-based applications using Jess, you should strongly consider using Jess on the server side (in a servlet, for example.)

1.7.1. Jess vs. Prolog

As in all pursuits, in programming you should choose the right tool for the right job. Prolog and a Rete-based system like Jess are very different. The central concept in Prolog is backwards chaining: given the rules
  mortal(X) :- human(X).
you might be interested in knowing if mortal(Socrates) was true. Prolog uses the rules to find it by looking for human(Socrates). Note that if you forget the result and ask for it again, Prolog has to compute it again.

The central concept in Jess, though, is forwards chaining. Here, you have
Jess> (assert (human Socrates))
  Jess> (defrule mortal (human ?X) => (assert (mortal ?X)))
  Jess> (watch facts)
  Jess> (run)
   ==> f-1 (MAIN::mortal Socrates)

You don't specifically want to know (mortal Socrates) but rather you want to know what happens given that (human Socrates) is known. (mortal Socrates) is a result. After the rule has fired, (mortal Socrates) is known, and the rule mortal never has to assert this fact again.

One more difference is that Prolog is really meant to be used from the console; i.e., you're actually supposed to sit down and type mortal(Socrates). In Jess, only developers do this; the command line is not intended for end-users. Prolog is really about answering queries, while Jess is about acting in response to inputs.

Jess is different than some Rete-based systems in that it includes both a kind of backwards chaining and a construct called defquery which lets you make direct queries of the knowledge base. Both of these help Jess a better fit for some Prolog applications, but they don't make Jess into a Prolog-like system. Prolog is optimized, in a sense, for space, at the cost of speed. Jess (and its Rete algorithm) is optimized for speed at the cost of space. The Rete algorithm is all about computing things -once- so they never need to be recomputed, and then reusing them. Prolog's approach is targeted at exploring large numbers of possibilities once, while Rete is aimed at exploring medium-sized numbers of possibilities repeatedly.

Regarding different ways to express the kinds of relationships Prolog can express: Jess offers a rich set of possiblities. Here's one in which the mortality is encoded directly into the facts, so it never needs to be computed at all:
Jess> (deftemplate being (slot name))
  Jess> (deftemplate mortal extends being)
  Jess> (deftemplate immortal extends being)
  Jess> (deftemplate monster extends mortal)
  Jess> (deftemplate human extends mortal)
  Jess> (deftemplate god extends immortal)

  Jess> (defrule list-all-humanoids
    ;; fire for all beings, gods, monsters, and humans
    (being (name ?n))
    (printout t ?n " is a being " crlf))

  Jess> (defrule list-all-mortals
    ;; fires only for mortal things
    (mortal (name ?n))
    (printout t ?n " is mortal " crlf))

  Jess> (deffacts beings (human (name Bob)) (monster (name Gollum))
                          (god (name Zeus)))

  Jess> (reset)
  Jess> (run)
    Zeus is a being
  Gollum is a being
  Gollum is mortal
  Bob is mortal
  Bob is a being

Here's another that's closer in spirit to the Prolog example.
Jess> (deftemplate thing (slot type) (slot name))

  Jess> (deffacts things
    (thing (type human) (name Socrates))
    (thing (type mineral) (name Slate))
    (thing (type vegetable) (name Carrot))
    (thing (type dog) (name Rover))
    (thing (type human) (name Bob)))

  Jess> (deffacts mortality
    (mortal human)
    (mortal dog))

  Jess> (defrule list-all-mortals
    ;; fires for dogs and humans
    (mortal ?type)
    (thing (type ?type) (name ?n))
    (printout t ?n " is mortal." crlf))
  Jess> (reset)
  Jess> (run)
    Rover is mortal.
  Bob is mortal.
  Socrates is mortal.

There's a fact that expresses that humans are mortal, and one for each human known. In this example, no extra facts are generated. Nevertheless, the mortality of Socrates is remembered (in the Rete network) and may be used to optimize some later computation.

1.8. About Jess and performance

Jess's rule engine uses an improved form of a well-known algorithm called Rete (latin for "net") to match rules against the knowledge base. Jess is actually faster than some popular expert system shells written in C, especially on large problems, where performance is dominated by algorithm quality.

Note that Rete is an algorithm that explicitly trades space for speed, so Jess' memory usage is not inconsiderable. Jess does contain some commands which will allow you to sacrifice some performance to decrease memory usage. Nevertheless, Jess' memory usage is not ridiculous, and moderate-sized programs will fit easily into Java's default 16M heap.

1.8.1. Sun's HotSpot Virtual Machine

Because Jess is a memory-intensive application, its performance is sensitive to the behavior of the Java garbage collector. Recent JVMs from Sun feature an advanced Java runtime called HotSpot which includes a flexible, configurable garbage collection subsystem. Excellent articles on GC performance tuning are available at Sun's web site. Although every Jess rule base is different, in general, Jess will benefit if the heap size and the object nursery size are each set larger than the default. For example, on my machine, Jess' performance on the Miranker manners benchmark with 90 guests is improved by 25% by increasing the initial heap size and nursery size to 32 and 16 megabytes, respectively, from their defaults of 16 meg and 640K. You can do this using
     java -XX:NewSize=16m -Xms32m -Xmx32m jess.Main <scriptfile>

Note that the object nursery is a subset of the Java heap set aside for recently-allocated objects; the total heap size in this example is 32M, not 48M.

1.9. Command-line, GUI, or embedded?

As we've discussed, Jess can be used in many ways. Besides the different categories of problems Jess can be applied to, being a library, it is amenable to being used in many different kinds of Java programs. Jess can be used in command-line applications, GUI applications, servlets, and applets. Furthermore, Jess can either provide the Java main() for your program, or you can write it yourself. You can develop Jess applications (with or without GUIs) without compiling a single line of Java code. You can also write Jess applications which are controlled entirely by Java code you write, with a minumum of Jess language code.

The most important step in developing a Jess application is to choose an architecture from among the almost limitless range of possibilities. One way to organize the possibilities is to list them in increasing order of the amount of Java programming involved.
  1. Pure Jess language scripts. No Java code at all.
  2. Pure Jess language scripts, but the scripts access Java APIs.
  3. Mostly Jess language scripts, but some custom Java code in the form of new Jess commands written in Java.
  4. Half Jess language scripts, with a substantial amount of Java code providing custom commands and APIs; main() provided by Jess.
  5. Half Jess language scripts, with a substantial amount of Java code providing custom commands and APIs; main() written by you.
  6. Mostly Java code, which loads Jess language scripts at runtime.
  7. All Java code, which maniulates Jess entirely through its Java API. This option is not fully supported at this time, but will in a future release.
Examples of some of these types of applications are package with Jess. The basic examples like wordgame.clp, zebra.clp, and fullmab.clp are all type 1) programs. draw.clp and frame.clp are type 2) programs. The pumps example is packaged two ways. If you run it using the script file pumps.clp, it is a type 4) program; if you run it using MainInJava.java, it is a type 6) application.

Your choice can be guided by many factors, but ultimately it will depend on what you feel most comfortable with. Types 4) and 5) are most prevalent in real-world applications.

Back to index