Class Diagrams
Below are a series of class diagrams describing the architecture of the Projog project. The diagrams start with implementations of Term, the low-level building blocks used to construct Prolog clauses, and finishes with ProjogConsole, the console based application.
Terms
Terms are the building blocks used to construct Prolog programs and queries.

Implementations of the Term interface.
Atom- Atoms are constant; their values cannot be changed after they are created. Atoms have no arguments.Structure- Compound terms are represented in Projog by theStructureimplementation of theTerminterface.Structureobjects consist of otherTermobjects representing the compound term's arguments. As an argument of aStructurecan be anotherStructureit is possible to use it to represent complex tree data structures. (Example of the "composite" design pattern.)List- Represents Prolog lists - a specific type of compound term that has two arguments (a head and a tail).EmptyList- Represents a list that contains no elements.Variable- Has aTermmember variable which provides a reference to the value theVariableis currently instantiated to. When aVariableis instantiated to anotherTermit delegates any method calls to it. To client code, aVariablebehaves just like theTermit is currently instantiated to. Over its lifetime aVariablecan be instantiated to a number of otherTerminstances. (Example of the "state" design pattern.)Numeric- Projog provides two number types -IntegerNumberandDecimalFractionboth of which implement theNumericinterface. TheIntegerNumberclass represents numbers using alongprimitive and theDecimalFractionclass represents numbers using adoubleprimitive.
Prolog Syntax Parser
ProjogSourceReader populates a KnowledgeBase with clauses constructed by a SentenceParser from Prolog syntax contained in a text file.
SentenceParser transforms Prolog syntax into Term objects. SentenceParser can parse pre-, post- and in-fix operands e.g. "p([X|Y], Z) :- Z < X+1, p(Y, X).". SentenceParser uses TokenParser to retrieve Token objects representing individual numbers, predicate names and seperators, etc. TokenParser constructs the Token objects from characters read from CharacterParser.
CharacterParser uses a java.io.BufferedReader to read characters from a stream. CharacterParser keeps track of the current line and column number being parsed - this is useful for producing descriptive messages when an error occurs during parsing. Errors are propagated up using a ParserException - which takes a CharacterParser as a constructor argument.

Structure of the classes used to parse Prolog code.
Built-in Predicates
Projog provides a number of built-in predicates. Built-in predicates are functionality that is implemented in Java rather than constructed from Prolog code. Built-in predicates make it possible to provide a convenient and efficient way of doing standard tasks - including functionality that is not possible using only pure Prolog syntax. New built-in predicates can be easily developed by Java developers and "plugged-in" to Projog - obeying the open/closed principle. See Adding Extra Functionality to Prolog Using Java.
A projog-bootstrap.pl file, containing Prolog syntax, is used to initialise new Projog instances. This mechanism promotes flexibility as the configuration of built-in predicates can be controlled without altering any Java code.
User Defined Predicates
User defined predicates are generated at runtime as a result of parsing Prolog code. User defined predicates can be static or dynamic. Unlike static predicates, dynamic predicates can have clauses added or removed after they are first defined.
DynamicUserDefinedPredicateFactory is used to represent dynamic perdicates. StaticUserDefinedPredicateFactory is used to represent static perdicates. For performance reasons StaticUserDefinedPredicateFactory delegates to specialised implementations of PredicateFactory. If a user-defined predicate is suitable for term indexing (a similar concept to indexing of relational detabases) then IndexablePredicateFactory is used. If a user-defined predicate is tail-recursive then InterpretedTailRecursivePredicate is used.

Implementations of the UserDefinedPredicateFactory interface.
Arithmetic Operators
Projog supports the common arithmetic operations. As with built-in predicates, new arithmetic operations can be easily developed by Java developers and "plugged-in" to Projog. See Adding New Arithmetic Operators to Prolog.

Implementations of the ArithmeticOperator interface.
Knowledge Base
KnowledgeBase is the central object that connects the various components of an instance of the "core" inference engine.

The KnowledgeBase class and the components it is associated with.
Predicates- A repository of user defined predicates (specified using Prolog syntax) and built-in predicates (implemented in Java).ArithmeticOperators- A repository of arithmetic operators.FileHandles- A repository of file handles used by predicates for reading and writing to files.ProjogListeners- A repository ofProjogListenerobjects that clients can register to recieve notifications of events.SpyPoints- A repository ofSpyPointobjects. Supports the debugging of Prolog queries.TermFormatter- Used to produceStringrepresentations ofTerminstances.Operands- A repository of operators used in the parsing and formatting of Prolog syntax. Prolog allows functors (names of predicates) to be defined as "operators". The use of operators allows syntax to be easier to read.ProjogProperties- Used for configuration. Currently only used to provide the location of the bootstrap file.
Java API to Prolog inference engine
The Projog class provides a single high-level entry point for Java applications to interface with an instance of a Prolog inference engine. By shielding client code from the low-level implementation of the "core" inference engine Projog reduces coupling and makes the subsystem easier to use. (Example of the "facade" design pattern.)
The mechanism for evaluating Prolog queries is similar to Java's JDBC API used to query relational databases. QueryStatement is similar to java.sql.PreparedStatement. QueryResult is similar to java.sql.ResultSet. See Using Prolog in Java Applications.

The Projog API for calling Prolog from Java.
Console Application
The ProjogConsole application allows Prolog developers to interact with the inference engine via a read-evaluate-print loop (REPL). ProjogConsole uses a Projog instance as a facade to the "core" inference engine. ProjogConsole registers a LoggingProjogListener so it can receive SpyPointEvent objects in order to provide feedback to the user.

Structure of the console based application.