Writing Java Programs That Use the Wolfram Language
Introduction
The first part of this User Guide describes using J/Link to allow you to call from the Wolfram Language into Java, thereby extending the Wolfram Language environment to include the functionality in all existing and future Java classes. This part shows you how to use J/Link in the opposite direction, as a means to write Java programs that use the Wolfram Language kernel as a computational engine.
J/Link uses the Wolfram Symbolic Transfer Protocol (WSTP), Wolfram Research's protocol for sending data and commands between programs. Many of the concepts and techniques in J/Link programming are the same as those for programming with the WSTP C-language API. The J/Link documentation is not intended to be an encyclopedic compendium of everything you need to know to write Java programs that use WSTP. Programmers may have to rely a little on the general documentation of WSTP programming. Many of the functions J/Link provides have C-language counterparts that are identical or nearly so.
If you have not read "Calling Java from the Wolfram Language", you should at least skim it at some point. Your Java "front end" can use the same techniques for calling Java methods from Wolfram Language code and passing Java objects as arguments that programmers use when running the kernel from the notebook front end. This allows you to have a very high-level interface between Java and the Wolfram Language. When you are writing WSTP programs in C, you have to think about passing and returning simple things like strings and integers. With J/Link you can pass Java objects back and forth between Java and the Wolfram Language. J/Link truly obliterates the boundary between Java and the Wolfram Language.
This half of the User Guide is organized as follows. "What Is WSTP?" is a very brief introduction to WSTP. The section "Preamble" introduces the most important J/Link interfaces and classes. "Sample Program" presents a simple example program. "Creating Links with MathLinkFactory" shows how to launch the Wolfram Language and create links. "The MathLink Interface" and "The KernelLink Interface" give a listing of methods in the large and all-important MathLink and KernelLink interfaces. The methods are grouped by function, and there is some commentary mixed in. This treatment does not replace the actual JavaDoc help files for J/Link, found in the JLink/Documentation/JavaDoc directory. The JavaDoc files are the main method-by-method reference for J/Link, and they include all the classes and interfaces that programmers will use. The remaining sections of this User Guide present discussions of a number of important topics in J/Link programming, including how to handle exceptions and get graphics and typeset output.
When you are reading this text or programming in Java or the Wolfram Language, remember that the entire source code for J/Link is provided. If you want to see how anything works (or why it does not), you can always consult the source code directly.
What Is WSTP?
The Wolfram Symbolic Transfer Protocol (WSTP) is a platform-independent protocol for communicating between programs. In more concrete terms, it is a means to send and receive Wolfram Language expressions. WSTP is the means by which the notebook front end and kernel communicate with each other. It is also used by a large number of commercial and freeware applications and utilities that link the Wolfram Language and other programs or languages.
WSTP is implemented as a library of C-language functions. Using it from another language (such as Java) typically requires writing some type of "glue" code that translates between the data types and calling conventions of that language and C. At the core of J/Link is just such a translation layer—a library built using Java's JNI (Java Native Interface) specification.
An old name for WSTP was MathLink, and this explains the appearance of that legacy name in several J/Link classes and interfaces.
Overview of the Main J/Link Interfaces and Classes
Preamble
The J/Link classes are written in an object-oriented style intended to maximize their extensibility in the future without requiring users' code to change. This requires a clean separation between interface and implementation. This is accomplished by exposing the main link functionality through interfaces, not classes. The names of the concrete classes that implement these interfaces will hardly be mentioned because programmers do not need to know or care what they are. Rather, you will use objects that belong to one of the interface types. You do not need to know what the actual classes are because you will never create an instance directly; instead, you use a "factory method" to create an instance of a link class. This will become clear further on.
MathLink and KernelLink
The two most important link interfaces you need to know about are MathLink and KernelLink. The MathLink interface is essentially a port of the WSTP C API into Java. Most of the method names will be familiar to experienced WSTP programmers. KernelLink extends MathLink and adds some important high-level convenience methods that are only meaningful if the other side of the link is a Wolfram Language kernel (for example, the method waitForAnswer(), which assumes the other side of the link will respond with a defined series of packets).
The basic idea is that the MathLink interface encompasses all the operations that can be performed on a link without making any assumptions about what program is on the other side of the link. KernelLink adds the assumption that the other side is a Wolfram Language kernel. In the future, other interfaces could be added that also extend MathLink and encapsulate other conventions for communicating over a link.
KernelLink is the most important interface, as most programmers will work exclusively with KernelLink. Of course, since KernelLink extends MathLink, many of the methods you will use on your KernelLink objects are declared and documented in the MathLink interface.
The most important class that implements MathLink is NativeLink, so named because it uses native methods to call into Wolfram Research's WSTP library. In the future, other classes could be added that do not rely on native methods—for example, one that uses RMI to communicate across a network. As discussed above, most programmers do not need to be concerned about what these classes are, because they will never type a link class name in their code.
MathLinkFactory
MathLinkFactory is the class that you use to create link objects. It contains the static methods createMathLink(), createKernelLink(), and createLoopbackLink(), which take various argument sequences. These are the equivalents of calling WSOpen in a C program. The MathLinkFactory methods are discussed in detail in "Creating Links with MathLinkFactory".
MathLinkException
MathLinkException is the exception class that is thrown by many of the methods in MathLink and KernelLink. The J/Link API uses exceptions to indicate errors, rather than function return values like the WSTP C API. In C, you write code that checks the return values as follows.
In J/Link, you wrap calls in a try block and catch MathLinkException.
Expr
The Expr class provides a direct representation of Wolfram Language expressions in Java. Expr has a number of methods that provide information about the structure of the expression and that let you extract components. These methods have names and behaviors that will be familiar to Wolfram Language programmers—for example, length(), part(), numberQ(), vectorQ(), take(), delete(), and so on. When reading from a link, instead of using the low-level MathLink interface methods for discovering the structure and properties of the incoming expression, you can just read an entire expression from the link using getExpr(), and then use Expr methods to inspect it or decompose it. For writing to a link, Expr objects can be used as arguments to some of the most important KernelLink methods. The Expr class is discussed in detail in "Motivation for the Expr Class".
PacketListener
A central component of a standard C WSTP program is a packet-reading loop, which typically consists of calling the WSTP API functions WSNextPacket and WSNewPacket until a desired packet is encountered. J/Link programs will typically not include such a loop—instead, you call the KernelLink methods waitForAnswer() or discardAnswer(), which hide the packet loop within them. Not only is this a convenience to avoid having to put the same boilerplate code into every program, it is necessary since in some circumstances programmers cannot write a correct packet because special packets may arrive that J/Link needs to handle internally. It is therefore necessary to hide the details of the packet loop from programmers. In some cases, though, programmers will want to observe and/or operate on the incoming flow of packets. A typical example would be to display Print output or messages generated by a computation. These outputs are side effects of a computation and not the "answer", and they are normally discarded by waitForAnswer().
To accommodate this need, KernelLink objects fire a PacketArrivedEvent for each packet that is encountered while running an internal packet loop. You can register your interest in receiving notifications of these packets by creating a class that implements the PacketListener interface and registering an object of this class with the KernelLink object. The PacketListener interface has only one method, packetArrived(), which will be called for each packet. Your packetArrived() method can consume or ignore the packet without affecting the internal packet loop in any way. Very advanced programmers can optionally indicate that the internal packet loop should not see the packet.
The PacketListener interface is discussed in greater detail in "Using the PacketListener Interface".
High-Level User Interface Classes
J/Link includes several classes that are useful for creating programs that have user interfaces. The MathCanvas and MathGraphicsJPanel classes provide an easy way to display Wolfram Language graphics and typeset expressions. These classes are often used from Wolfram Language code, as described in "The MathCanvas and MathGraphicsJPanel Classes", but they are just as useful in Java programs. They are discussed in "MathCanvas and MathGraphicsJPanel". The various "MathListener" classes ("Handling Events with Wolfram Language Code: The 'MathListener' Classes") can be used from Java code to trigger evaluations in the Wolfram Language when user interface actions occur.
New in J/Link 2.0 are the classes in the com.wolfram.jlink.ui package. These classes provide some very high-level user interface elements. There is the ConsoleWindow class, which gives you a console output window (this is the class used to implement the Wolfram Language function ShowJavaConsole, discussed in "The Java Console Window"). The InterruptDialog class gives you an Interrupt Evaluation dialog similar to the one you see in the notebook front end when you choose Interrupt Evaluation from the Evaluation menu. The MathSessionPane class provides an In/Out Wolfram System session window complete with a full set of editing functions including cut/copy/paste/undo/redo, support for graphics, syntax coloring, and customizable font styles. The auxiliary classes SyntaxTokenizer and BracketMatcher are used by MathSessionPane, but can also be used separately to provide these services in your own programs. All these classes are discussed in the section "Some Special User Interface Classes: Introduction".
Sample Program
Here is a basic Java program that launches the Wolfram Language kernel, uses it for some computations, and then shuts it down. This program is provided in source code and compiled form in the JLink/Examples/Part2 directory. The usual WSTP arguments including the path to the kernel are given on the command line you use to launch the program, and some typical examples are given below. You will have to adjust the Wolfram Language kernel path for your system. If you have your CLASSPATH environment variable set to include JLink.jar, then you can leave off the -classpath specification in these command lines. It is assumed that these commands are executed from the JLink/Examples/Part2 directory.
(Windows)
java -classpath .;..\..\JLink.jar SampleProgram -linkmode launch -linkname "c:\program files\wolfram research\mathematica\10.0\mathkernel.exe"
(Linux)
java -classpath .:../../JLink.jar SampleProgram -linkmode launch -linkname 'math -mathlink'
(Mac OS X from a terminal window)
java -classpath .:../../JLink.jar SampleProgram -linkmode launch -linkname '"/Applications/Mathematica.app/Contents/MacOS/MathKernel" -mathlink'
Here is the code from SampleProgram.java. This program demonstrates launching the kernel with MathLinkFactory.createKernelLink(), and several different ways to send computations to the Wolfram Language and read the result.
import com.wolfram.jlink.*;
public class SampleProgram {
public static void main(String[] argv) {
KernelLink ml = null;
try {
ml = MathLinkFactory.createKernelLink(argv);
} catch (MathLinkException e) {
System.out.println("Fatal error opening link: " + e.getMessage());
return;
}
try {
// Get rid of the initial InputNamePacket the kernel will send
// when it is launched.
ml.discardAnswer();
ml.evaluate("<<MyPackage.m");
ml.discardAnswer();
ml.evaluate("2+2");
ml.waitForAnswer();
int result = ml.getInteger();
System.out.println("2 + 2 = " + result);
// Here's how to send the same input, but not as a string:
ml.putFunction("EvaluatePacket", 1);
ml.putFunction("Plus", 2);
ml.put(3);
ml.put(3);
ml.endPacket();
ml.waitForAnswer();
result = ml.getInteger();
System.out.println("3 + 3 = " + result);
// If you want the result back as a string, use evaluateToInputForm
// or evaluateToOutputForm. The second arg for either is the
// requested page width for formatting the string. Pass 0 for
// PageWidth->Infinity. These methods get the result in one
// step--no need to call waitForAnswer.
String strResult = ml.evaluateToOutputForm("4+4", 0);
System.out.println("4 + 4 = " + strResult);
} catch (MathLinkException e) {
System.out.println("MathLinkException occurred: " + e.getMessage());
} finally {
ml.close();
}
}
}
Creating Links with MathLinkFactory
To isolate clients of the J/Link classes from implementation details it is required that clients never explicitly name a link class in their code. This means that programs will never call new to create an instance of a link class. Instead, a so-called "factory method" is supplied that creates an appropriate instance for you, based on the arguments you pass in. This factory method takes the place of calling WSOpen in a C program.
The method that creates a KernelLink is a static method called createKernelLink() in the MathLinkFactory class.
public static KernelLink createKernelLink(String cmdLine) throws MathLinkException
public static KernelLink createKernelLink(String[] argv) throws MathLinkException
. . . plus a few more of limited usefulness
There are also two functions called createMathLink() that take the same arguments but create a MathLink instead of a KernelLink. Very few programmers will need to use createMathLink() because the only reason to do so is if you are connecting to a program other than the Wolfram Language kernel. See the JavaDoc files for a complete listing of the methods.
The second signature of createKernelLink() is convenient if you are using the command-line parameters that your program was launched with, which are, of course, provided to your main() function as an array of strings. An example of this use can be found in the sample program in the section "Sample Program". Other times it will be convenient to specify the parameters as a single string.
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\10.0\\mathkernel'");
Note that the linkname argument is wrapped in single quotation marks ('). This is because WSTP parses this string as a complete command line, and wrapping it in single quotation marks is an easy way to force it to be seen as just a file name. Also note that it is required to type two backslashes to indicate a Windows directory separator character when you are typing a literal string in your Java code because Java, like C and the Wolfram Language, treats the \ as a meta-character that quotes the character following.
Here are some typical arguments for createKernelLink() on various platforms when given as a single string. Note the use of quote characters (' and ").
// Typical launch on Windows
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\10.0\\mathkernel.exe'");
// Typical launch on Linux
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'math -mathlink'");
// Typical launch on Mac OS X
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname '\"/Applications/Mathematica.app/Contents/MacOS/MathKernel\" -mathlink'");
// Typical "listen" link on any platform:
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode listen -linkname foo");
Here are typical arguments for createKernelLink() when given as an array of strings.
// Typical launch on Windows:
String[] argv = {"-linkmode", "launch", "-linkname", "c:\\program files\\wolfram research\\mathematica\\10.0\\mathkernel"};
// Typical launch on Linux:
String[] argv = {"-linkmode", "launch", "-linkname", "math -mathlink"};
// Typical launch on Mac OS X:
String[] argv = {"-linkmode", "launch", "-linkname", "\"/Applications/Mathematica.app/Contents/MacOS/MathKernel\" -mathlink"};
// Typical "listen" link on any platform:
String[] argv = {"-linkmode", "listen", "-linkname", "foo"};
The arguments for createKernelLink() and createMathLink() (e.g. -linkmode, -linkprotocol, and so on) are identical to those used for WSOpen in the WSTP C API. Consult the WSTP documentation for more information.
The createKernelLink() and createMathLink() methods will always return a link object that is not null or throw a MathLinkException. You do not need to test whether the returned link is null. Because these methods throw a MathLinkException on failure, you need to wrap the call in a try block.
KernelLink ml = null;
try {
ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\10.0\\mathkernel'");
} catch (MathLinkException e) {
// This is equivalent to WSOpen returning NULL in a C program.
System.out.println(e.getMessage());
System.exit(1);
}
The fact that createKernelLink() succeeds does not mean that the link is connected and functioning properly. There are a lot of things that could be wrong. For example, if you launch a program that knows nothing about WSTP, createKernelLink() will still succeed. There is a difference between creating a link (which involves setting up your side) and connecting one (which verifies that the other side is alive and well).
If a link has not been connected yet, WSTP will automatically try to connect it the first time you try to read or write something. Alternatively, you can call the connect() method to explicitly connect the link after creating it. If the link cannot be connected, then the attempt to connect, whether made explicitly by you or internally by WSTP, will fail or even hang indefinitely. It can hang because the attempt to connect will block until the connection succeeds or until it detects a fatal problem with the link. In some cases, neither will happen—for example, if you mistakenly launch a program that is not WSTP-aware. Dealing with blocking in J/Link methods is discussed more thoroughly later, but in the case of connecting the link you have an easy solution. The connect() method has a second signature that takes a long argument specifying the number of milliseconds to wait before abandoning the attempt to connect: connect(long timeoutMillis). You do not need to explicitly call connect() on a link—it will be connected for you the first time you try to read something. You can use a call to connect() to catch failures at a well-defined place, or if you want to use the automatic time-out feature. Here is a code fragment that demonstrates how to implement a time out in connect().
KernelLink ml = null;
try {
ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\10.0\\mathkernel'");
} catch (MathLinkException e) {
System.out.println("Link could not be created: " + e.getMessage());
return; // Or whatever is appropriate.
}
try {
connect(10000); // Wait at most 10 seconds
} catch (MathLinkException e) {
// If the timeout expires, a MathLinkException will be thrown.
System.out.println("Failure to connect link: " + e.getMessage());
ml.close();
return; // Or whatever is appropriate.
}
When you are finished with a link, call its close() method. Although the finalizer for a link object will close the link, you cannot guarantee that the finalizer will be called in a timely fashion, or even at all, so you should always manually close a link when you are done.
Using Listen and Connect Modes
You can use the listen and connect linkmodes, instead of launch, if you want to connect to an already-running program. Using listen and connect linkmodes in J/Link works in the same way as with C WSTP programs. See the MathLink Tutorial (http://library.wolfram.com/infocenter/TechNotes/174/) or "WSTP and External Program Communication" for more information.
Using a Remote Kernel
To attach a remote Wolfram Language kernel to a J/Link program, open the link using the listen/connect style. On the remote machine, launch the Wolfram Language and have it listen on a link by executing the following on a command line.
Then in your Java program, use the following.
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode connect -linkprotocol tcpip -linkname 1234@remotemachinename");
The drawback to the listen/connect technique is that you must manually log into the remote machine and launch the Wolfram Language. You can have the Java program automatically launch the Wolfram Language on the remote machine by using an rsh or ssh client program. Linux and OSX machines have rsh and ssh built in, and the Wolfram Language ships with the winrsh client program for Windows. Here is an example of using winrsh to launch and connect to the Wolfram Language on a remote Linux machine.
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode listen -linkprotocol tcpip -linkname 1234");
Runtime.exec("c:\\program files\\wolfram research\\mathematica\\10.0\\systemfiles\\frontend\\binaries\\windows\\winrsh -m -q -h -l YourUsername -'math -mathlink -linkmode connect -linkprotocol tcpip -linkname 1234@localmachinename'");
The MathLink Interface
MathLink is the low-level interface that is the root of all link objects in J/Link. The methods in MathLink correspond roughly to a subset of those in the C-language WSTP API. Most programmers will deal instead with objects of type KernelLink, a higher-level interface that extends MathLink and incorporates the assumption that the program on the other side of the link is a Wolfram Language kernel.
There will not be much said here about most of these methods, as they behave like their C API counterparts in most respects. The JavaDoc help files are the main method-by-method documentation for all the J/Link classes and interfaces. They can be found in the JLink/Documentation/JavaDoc directory. This section is provided mainly for those who want to skim a traditional listing.
These are all public methods (the public has been left off to keep lines short).
Managing Links
void close();
void connect() throws MathLinkException;
// Wait at most timeoutMillis for the connect to occur, then throw a MathLinkException
void connect(long timeoutMillis) throws MathLinkException;
//A synonym for connect. This is the newer name.
void activate() throws MathLinkException;
Packet Functions
//Does not throw exception because it will often be needed in a catch block.
void newPacket();
int nextPacket() throws MathLinkException;
void endPacket() throws MathLinkException;
Error Handling
Link State
Putting
Putting expressions on the link is a bit different in Java than C because Java lets you overload functions. Thus, there is no need to have methods with names like the C functions WSPutInteger and WSPutDouble; it suffices to have a single function named put() that has different definitions for each argument type. The only exceptions to this are the few cases where the argument needs to be interpreted in a special way. For example, there are three "put" methods that take a single string argument: put() (equivalent to the C-language function WSPutUCS2String), putSymbol() (equivalent to WSPutUCS2Symbol), and putByteString() (equivalent to WSPutByteString).
For numeric types, there are the following methods (there is no need to provide a put() method for byte, char, and short types, as these can be automatically promoted to int):
void put(int i) throws MathLinkException;
void put(long i) throws MathLinkException;
void put(double d) throws MathLinkException;
For strings and symbols, use the following.
void put(String s) throws MathLinkException;
void putByteString(byte[] b) throws MathLinkException;
void putSymbol(String s) throws MathLinkException;
All the J/Link methods that put or get strings use Unicode, which is the native format for Java strings.
For Booleans, a Java true is sent as the Wolfram Language symbol True, and False for Java false.
There is also a put() method for arbitrary Java objects. In the default implementation, this does not do anything very useful for most objects (what it does is send obj.toString()). A handful of objects, however, have a meaningful representation to the Wolfram Language. These are arrays, strings, Expr objects (discussed elsewhere), and instances of the so-called "wrapper" classes (Integer, Double, Character, and so on), which hold single numeric values. Arrays are sent as lists, strings are sent as Wolfram Language strings, and the wrapper classes are sent as their numeric value. (The last case is for complex numbers, which will be discussed later.)
There is a special method for arrays that lets you specify the heads of the array in each dimension. The heads are passed as an array of strings. Note that unlike the C counterparts (WSPutInteger32Array, WSPutReal64Array, and so on), you do not have to specify the depth or dimensions because they can be inferred from the array itself.
Use the following for putting Wolfram Language functions.
Use the following for transferring expressions from one link to another (the "this" link is the destination)
void transferExpression(MathLink source) throws MathLinkException;
void transferToEndOfLoopbackLink(LoopbackLink source) throws MathLinkException;
Use this for a low-level "textual interface".
void putNext(int type) throws MathLinkException;
void putArgCount(int argCount) throws MathLinkException;
void putSize(int size) throws MathLinkException;
int bytesToPut() throws MathLinkException;
void putData(byte[] data) throws MathLinkException;
void putData(byte[] data, int len) throws MathLinkException;
Getting
Because you cannot overload methods on the basis of return type, there is no catchall get() method for reading from the link, as is the case with the put() method. Instead, there are separate methods for each data type. Notice that unlike their counterparts in the C API, these methods return the actual data that was read, not an error code (exceptions are used for errors, as with all the methods).
int getInteger() throws MathLinkException;
long getLongInteger() throws MathLinkException;
double getDouble() throws MathLinkException;
String getString() throws MathLinkException;
byte[] getByteString(int missing) throws MathLinkException;
String getSymbol() throws MathLinkException;
boolean getBoolean() throws MathLinkException;
Arrays of the nine basic types (boolean, byte, char, short, int, long, float, double, String), as well as complex numbers, can be read with a set of methods of the form getXXXArrayN(), where XXX is the data type and N specifies the depth of the array. For each type there are two methods like the following examples for int. There is no way to get the heads of the array using these functions (it will typically be "List" at every level). If you need to get the heads as well, you should use getExpr() to read the expression as an Expr and then examine it using the Expr methods.
int[] getIntArray1() throws MathLinkException;
int[][] getIntArray2() throws MathLinkException;
... and others for all the eight primitive types and String and the complex class
Note that you do not have to know exactly how deep the array is to use these functions. If you call, say, getFloatArray1(), and what is actually on the link is a matrix of reals, then the data will be flattened into the requested depth (a one-dimensional array in this case). Unfortunately, if you do this you cannot determine what the original depth of the data was. If you call a function that expects an array of depth greater than the actual depth of the array on the link, it will throw a MathLinkException.
If you need to read an array of depth greater than 2 (but a maximum of 5) , you can use the getArray() method. The getXXXArrayN() methods already discussed are just convenience methods that use getArray() internally. The type argument must be one of TYPE_BOOLEAN, TYPE_BYTE, TYPE_CHAR, TYPE_SHORT, TYPE_INT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, TYPE_EXPR, TYPE_BIGINTEGER, TYPE_BIGDECIMAL, or TYPE_COMPLEX.
Object getArray(int type, int depth) throws MathLinkException;
Object getArray(int type, int depth, String[] heads) throws MathLinkException;
Unlike the C WSTP API, there are no methods for "releasing" strings or arrays because this is not necessary. When you read a string or array off the link, your program gets its own copy of the data, so you can write into it if you desire (although Java strings are immutable).
The getFunction() method needs to return two things: the head and the argument count. Thus, there is a special class called MLFunction that encapsulates both these pieces of information, and this is what getFunction() returns. The MLFunction class is documented later.
MLFunction getFunction() throws MathLinkException;
// Returns the function's argument count. Throws MathLinkException if the function
// is not the specified one.
int checkFunction(String f) throws MathLinkException;
//Throws an exception if the incoming function does not have this head and arg count.
void checkFunctionWithArgCount(String f, int argCount) throws MathLinkException;
These methods support the low-level interface for reading from a link.
int getNext() throws MathLinkException;
int getType() throws MathLinkException;
int getArgCount() throws MathLinkException;
int bytesToGet() throws MathLinkException;
byte[] getData(int len) throws MathLinkException;
Use the following for reading Expr objects.
public Expr getExpr() throws MathLinkException;
// Gets an expression off the link, then resets the link to the state
// prior to reading the expr. You can "peek" ahead without consuming anything
// off the link.
public Expr peekExpr() throws MathLinkException;
Messages
The messages referred to by the following functions are not Wolfram System warning messages, but a low-level type of WSTP communication used mainly to send interrupt and abort requests. The getMessage() and messageReady() methods no longer function in J/Link 2.0 and higher. You must use setMessageHandler() if you want to receive messages from the Wolfram Language.
int getMessage() throws MathLinkException;
void putMessage(int msg) throws MathLinkException;
boolean messageReady() throws MathLinkException;
Marks
long createMark() throws MathLinkException;
//Next two don't throw, since they are often used in cleanup operations in catch handlers.
void seekMark(long mark);
void destroyMark(long mark);
Complex Class
The setComplexClass() method lets you assign the class that will be mapped to complex numbers in the Wolfram Language. "Mapped" means that the put(Object) method will send a Wolfram Language complex number when you call it with an object of your complex class, and getComplex() will return an instance of this class. For further discussion about this subject and the restrictions on the classes that can be used as the complex class, see "Complex Numbers".
public boolean setComplexClass(Class cls);
public Class getComplexClass();
public Object getComplex() throws MathLinkException;
Yield and Message Handlers
The setYieldFunction() and addMessageHandler() methods take a class, an object, and a method name as a string. The class is the class that contains the named method, and the object is the object of that class on which to call the method. Pass null for the object if it is a static method. The signature of the method you use in setYieldFunction() must be V(Z); for addMessageHandler() it must be II(V). See "Threads, Blocking, and Yielding" for more information and examples.
public boolean setYieldFunction(Class cls, Object obj, String methName);
public boolean addMessageHandler(Class cls, Object obj, String methName);
public boolean removeMessageHandler(String methName);
Constants
The MathLink class also includes the full set of user-level constants from WSTP.h. They have exactly the same names in Java as in C. In addition, there are some J/Link-specific constants.
static int ILLEGALPKT;
static int CALLPKT;
static int EVALUATEPKT;
static int RETURNPKT;
static int INPUTNAMEPKT;
static int ENTERTEXTPKT;
static int ENTEREXPRPKT;
static int OUTPUTNAMEPKT;
static int RETURNTEXTPKT;
static int RETURNEXPRPKT;
static int DISPLAYPKT;
static int DISPLAYENDPKT;
static int MESSAGEPKT;
static int TEXTPKT;
static int INPUTPKT;
static int INPUTSTRPKT;
static int MENUPKT;
static int SYNTAXPKT;
static int SUSPENDPKT;
static int RESUMEPKT;
static int BEGINDLGPKT;
static int ENDDLGPKT;
static int FIRSTUSERPKT;
static int LASTUSERPKT;
//These next two are unique to J/Link.
static int FEPKT;
static int EXPRESSIONPKT;
static int MLTERMINATEMESSAGE;
static int MLINTERRUPTMESSAGE;
static int MLABORTMESSAGE;
static int MLTKFUNC;
static int MLTKSTR;
static int MLTKSYM;
static int MLTKREAL;
static int MLTKINT;
static int MLTKERR;
//Constants for use in getArray()
static int TYPE_BOOLEAN;
static int TYPE_BYTE;
static int TYPE_CHAR;
static int TYPE_SHORT;
static int TYPE_INT;
static int TYPE_LONG;
static int TYPE_FLOAT;
static int TYPE_DOUBLE;
static int TYPE_STRING;
static int TYPE_BIGINTEGER;
static int TYPE_BIGDECIMAL;
static int TYPE_EXPR;
static int TYPE_COMPLEX;
The KernelLink Interface
KernelLink is the interface that you will probably use for the links in your programs. These are all public methods, as is always the case with a Java interface. This section provides only a brief summary of the KernelLink methods; it is intended mainly for those who want to skim a traditional listing. The JavaDoc help files are the main method-by-method documentation for all the J/Link classes and interfaces. They can be found in the JLink/Documentation/JavaDoc directory.
Evaluate
The evaluate() method encapsulates the steps needed to put an expression to the Wolfram Language as a string or Expr and get the answer back as an expression. Internally, it uses an EvaluatePacket for sending the expression. The answer comes back in a ReturnPacket, although the waitForAnswer() method opens up the ReturnPacket—all you have to do is read out its contents. You should always use waitForAnswer() or discardAnswer() instead of spinning your own packet loop waiting for a ReturnPacket. See "The WSTP 'Packet Loop'".
Waiting for the Result
Call waitForAnswer() right after evaluate() (or if you manually send calculations wrapped in EvaluatePacket). It will read packets off the link until it encounters a ReturnPacket, which will hold the result. See "The WSTP 'Packet Loop'".
The discardAnswer() method just throws away all the results from the calculation, so the link will be ready for the next calculation. As you may have guessed, it is nothing more than waitForAnswer() followed by newPacket().
The "evaluateTo" Methods
The next methods are extensions of evaluate() that perform the put and the reading of the result. You do not call waitForAnswer() and then read the result yourself. They also do not throw MathLinkException—if there is an error, they clean up for you and return null. The "evaluateTo" in their names indicates that the methods perform the entire process themselves. evaluateToInputForm() returns a string formatted in InputForm at the specified page width. Specify 0 for the page width to get Infinity. evaluateToOutputForm() is exactly like evaluateToInputForm() except that it returns a string formatted in OutputForm. OutputForm results are more attractive for display to the user, but InputForm is required if you want to pass the string back to the Wolfram Language to be used in further computations. The evaluateToImage() method will return a byte[] of GIF data if you give it an expression that returns a graphic, for example, a Plot command. Pass 0 for the dpi, int, and width arguments if you want their Automatic settings in the Wolfram Language. evaluateToTypeset() returns a byte[] of GIF data of the result of the computation, typeset in either StandardForm or TraditionalForm. These methods are discussed in detail in "EvaluateToImage() and EvaluateToTypeset()".
String evaluateToInputForm(String s, int pageWidth);
String evaluateToInputForm(Expr e, int pageWidth);
String evaluateToOutputForm(String s, int pageWidth);
String evaluateToOutputForm(Expr e, int pageWidth);
byte[] evaluateToImage(String s, int width, int height);
byte[] evaluateToImage(Expr e, int width, int height);
byte[] evaluateToImage(String s, int width, int height, int dpi, boolean useFrontEnd);
byte[] evaluateToImage(Expr e, int width, int height, int dpi, boolean useFrontEnd);
byte[] evaluateToTypeset(String s, int pageWidth, boolean useStdForm);
byte[] evaluateToTypeset(Expr e, int pageWidth, boolean useStdForm);
// Returns the exception that caused the most recent "evaluateTo" method to return null
Throwable getLastError();
Sending Java Object References
If you want to send Java objects "by reference" to the Wolfram Language so that Wolfram Language code can call back into your Java runtime via the "installable Java" facility described in "Calling Java from the Wolfram Language", you must first call the enableObjectReferences() method. This is described in "Sending Object References to the Wolfram Language".
Like the MathLink interface, KernelLink has a put() method that sends objects. The MathLink version of this method only sends objects "by value". The KernelLink version behaves just like the MathLink version for those objects that can be sent by value. In addition, though, it sends all other objects by reference. You must have called enableObjectReferences() before calling put() on an object that will be sent by reference. See "Sending Object References to the Wolfram Language".
The next methods are for putting and getting objects by reference (you must have called enableObjectReferences() to use these methods).
public void putReference(Object obj) throws MathLinkException;
Object getObject() throws MathLinkException;
// These two methods from the MathLink interface are enhanced to return MLTKOBJECT if a Java
// object reference is waiting to be read.
int getNext() throws MathLinkException;
int getType() throws MathLinkException;
Interrupting, Aborting, and Abandoning Evaluations
These methods are for aborting and interrupting evaluations. They are discussed in "Aborting and Interrupting Computations".
Support for PacketListeners
These methods support the registering and notification of PacketListener objects. They are discussed in "Using the PacketListener Interface".
void addPacketListener(PacketListener listener);
void removePacketListener(PacketListener listener);
boolean notifyPacketListeners(int pkt);
The handlePacket() Method (Advanced Users Only)
The handlePacket() method is for very advanced users who are writing their own packet loop instead of calling waitForAnswer(), discardAnswer(), or any of the "evaluateTo" methods. See the JavaDocs for more information.
Methods Valid Only for "StdLinks"
Finally, there are some methods that are meaningful only in methods that are themselves called from the Wolfram Language via the "installable Java" functionality described in "Calling Java from the Wolfram Language". These methods are documented in "Writing Your Own Installable Java Classes". You will not use them if you are writing a program that uses the Wolfram Language as a computational engine.
public void print(String s);
public void message(String symtag, String[] args);
public void message(String symtag, String arg);
public void beginManual();
public boolean wasInterrupted();
public void clearInterrupt();
Sending Computations and Reading Results
WSTP Packets
Communication with the Wolfram Language kernel generally takes place in the form of "packets". A WSTP packet is just a Wolfram Language function, albeit one from a set that is recognized and treated specially by WSTP. When you send something to the Wolfram Language to be evaluated, you wrap it in a packet that tells the Wolfram Language that this is a request for something to be computed, and also tells something about how it is to be computed. All output you receive from the Wolfram Language, including the result and any other side effect output like messages, Print output, and graphics, will also arrive wrapped in a packet. The type of packet tells you about the contents.
A WSTP program typically sends a computation to the Wolfram Language wrapped in a special packet, and then reads a succession of packets arriving from the kernel until the one containing the result of the computation arrives. Along the way, packets that do not contain the result can be either discarded without bothering to examine them or they can be "opened" and operated on. Such nonresult packets include TextPacket expressions containing Print output, MessagePacket expressions containing Wolfram System warning messages, DisplayPacket expressions containing PostScript, and several other types.
You can look at existing WSTP documentation for information on the various packet types for sending things to the Wolfram Language and for what the Wolfram Language sends back. In particular, you should look at the MathLink Tutorial (http://library.wolfram.com/infocenter/TechNotes/174/). For most uses, J/Link hides all the details of packet types and how to send and receive them. You only need to read about packet types if you want to do something beyond what the built-in behavior of J/Link provides. This can be useful for many programs.
The WSTP "Packet Loop"
In a C WSTP program, a typical code fragment for sending a computation to the Wolfram Language and throwing away the result might look like the following.
// C code
WSPutFunction(ml, "EvaluatePacket", 1);
WSPutFunction(ml, "ToExpression", 1);
WSPutString(ml, "Needs[\"MyPackage`\"]");
WSEndPacket(ml);
while (WSNextPacket(ml) != RETURNPKT)
WSNewPacket(ml);
WSNewPacket();
After sending the computation (wrapped in an EvaluatePacket), the code enters a while loop that reads and discards packets until it encounters the ReturnPacket, which will contain the result (which will be the symbol Null here). Then it calls WSNewPacket once again to discard the ReturnPacket.
A WSTP program will typically do this same basic operation many times, so J/Link hides it within some higher-level methods in the KernelLink interface. Here is the J/Link equivalent.
The discardAnswer() method discards all packets generated by the computation until it encounters the one containing the result, and then discards that one too. There is a related method, waitForAnswer(), that discards everything up until the result is encountered. When waitForAnswer() returns, the ReturnPacket has been opened and you are ready to read out its contents. You can probably guess that discardAnswer() is just waitForAnswer() followed by newPacket().
Not only is it a convenience to hide the packet loop within waitForAnswer() and discardAnswer(), it is necessary in some circumstances, since special packets may arrive that J/Link needs to handle internally. Although J/Link has nextPacket() and newPacket() methods, programmers should not write nextPacket()/newPacket() loops like the one in the last C code fragment. Stick to calling waitForAnswer(), discardAnswer(), or using the "evaluateTo" methods discussed in the next section. If you really need to know about all the packets that arrive in your program, use the PacketListener interface, discussed in "Using the PacketListener Interface".
Sending an Evaluation
J/Link provides three main ways to send an expression to the Wolfram Language for evaluation. All three techniques are demonstrated in the sample program in the section "Sample Program".
If you do not care about the result of the evaluation, or if you want the result to arrive in a form other than a string or image, you can use the evaluate() method.
You can send the expression "manually", like in a traditional C WSTP program, by putting the EvaluatePacket head followed by the parts of the expression using low-level methods from the MathLink interface.
If you want the result back as a string or image, you can use the "evaluateTo" methods, which provide a very high-level and convenient interface.
The "evaluateTo" methods are recommended for their convenience, if you want the result back in one of the formats that that they provide. These methods are discussed in "The 'evaluateTo' Methods". If the expression you want evaluated is in the form of a string or Expr (the Expr class is discussed in "Motivation for the Expr Class"), or can be easily converted into one, then you will want to use the evaluate() method. If none of these convenience methods are appropriate, you can put the expression piece by piece similar to a traditional C WSTP program. You do this by sending pieces in a structure that mirrors the FullForm of the expression. Here is a comparison of using these three techniques for sending the computation NIntegrate[x2+y2,{x,-1,1},{y,-1,1}].
String strResult = ml.evaluateToInputForm("NIntegrate[x^2 + y^2, {x,-1,1}, {y,-1,1}]");
ml.evaluate("NIntegrate[x^2 + y^2, {x,-1,1}, {y,-1,1}]");
ml.waitForAnswer();
double doubleResult1 = ml.getDouble();
// It is convenient to use indentation to indicate the structure
ml.putFunction("EvaluatePacket", 1);
ml.putFunction("NIntegrate", 3);
ml.putFunction("Plus", 2);
ml.putFunction("Power", 2);
ml.putSymbol("x");
ml.put(2);
ml.putFunction("Power", 2);
ml.putSymbol("y");
ml.put(2);
ml.putFunction("List", 3);
ml.putSymbol("x");
ml.put(-1);
ml.put(1);
ml.putFunction("List", 3);
ml.putSymbol("y");
ml.put(-1);
ml.put(1);
ml.endPacket();
ml.waitForAnswer();
double doubleResult2 = ml.getDouble();
Reading the Result
Before diving into reading expressions from a link, keep in mind that if you just want the result back as a string or an image, then you are better off using one of the "evaluateTo" methods described in the next section. These methods send a computation and return the answer as a string or image, so you do not have to read it off the link yourself. Also, if you are not interested in the result, you will use discardAnswer() and thus not have to bother reading it.
J/Link provides a number of methods for reading expressions from a link. Many of these methods are essentially identical to functions in the WSTP C API, so to some extent you can learn how to use them by reading standard WSTP documentation. You should also consult the J/Link JavaDoc files for more information. The reading methods generally begin with "get". Examples are getInteger(), getString(), getFunction(), and getDoubleArray2(). There are also two type-testing methods that will tell you the type of the next thing waiting to be read off the link. These methods are getType() and getNext().
As stated earlier, one method you will generally not call is nextPacket(). When waitForAnswer() returns, nextPacket() has already been called internally on the ReturnPacket that holds the answer, so this final packet has already been "opened" and you can start reading its contents right away.
The vast majority of MathLinkException occurrences in J/Link programs are caused by trying to read the incoming expression in a manner that is not appropriate for its type. A typical example is calling a Wolfram Language function that you expect to return an integer, but you call it with incorrect arguments and therefore it returns unevaluated. You call getInteger() to read an integer, but what is waiting on the link is a function like foo[badArgument]. There are several general ways for dealing with problems like this. The first technique is to avoid the exception by using getNext() to determine the type of the expression waiting.
ml.evaluate("SomeFunction[]");
ml.waitForAnswer();
int result;
int type = ml.getNext();
if (type == MathLink.MLTKINT) {
result = ml.getInteger();
} else {
// What you do here is up to you.
System.out.println("Unexpected result: " + ml.getExpr().toString());
// Throw away the packet contents.
ml.newPacket();
}
A related technique is to read the result as an Expr and examine it using the Expr methods. The Expr class is discussed in "Motivation for the Expr Class".
ml.evaluate("SomeFunction[]");
ml.waitForAnswer();
int result;
Expr e = ml.getExpr();
if (e.integerQ()) {
result = e.asInt();
} else {
// What you do here is up to you.
System.out.println("Unexpected result: " + e.toString());
}
A final technique is to just go ahead and read the expression in the form that you expect, but catch and handle any MathLinkException. (Remember that the entire code fragment that follows must be wrapped in a try/catch block for MathLinkException objects, but you are only seeing an inner try/catch block for MathLinkException objects known to be thrown during the read.)
ml.evaluate("SomeFunction[]");
ml.waitForAnswer();
int result;
try {
result = ml.getInteger();
} catch (MathLinkException e) {
ml.clearError();
System.out.println("Unexpected result: " + ml.getExpr().toString());
ml.newPacket(); // Not strictly necessary because of the getExpr() above
}
Another tip for avoiding bugs in code that reads from a link is to use the newPacket() method liberally. A second very common cause of MathLinkException occurrences is forgetting to read the entire contents of a packet before going on to the next computation. The newPacket() method causes the currently opened packet to be discarded. Another way of saying this is that it throws away all unread parts of the expression that is currently being read. It is a clean-up method that ensures that there are no remnants left over from the last packet when you go on to the next evaluation. Consider the following code.
ml.evaluate("SomeFunction[]");
ml.waitForAnswer();
int result;
try {
result = ml.getInteger();
} catch (MathLinkException e) {
ml.clearError();
System.out.println("Unexpected result");
// Oops. Forgot to call newPacket() to throw away the contents.
}
// Boom. The next line causes a MathLinkException if the previous getInteger()
// call failed, because nextPacket() will be called before the previous packet
// was emptied.
ml.evaluate("AnotherFunction[]");
ml.discardAnswer();
This code will cause a MathLinkException to be thrown at the indicated point if the previous call to getInteger() had failed because the programmer forgot to either finish reading the result or call newPacket(). Here is an even simpler example of this error.
ml.evaluate("SomeFunction[]");
ml.waitForAnswer();
// Oops. Forgot to read or throw away the result.
// Probably meant to call discardAnswer() instead of
// waitForAnswer().
ml.evaluate("AnotherFunction[]");
ml.discardAnswer(); // MathLinkException here!
The "evaluateTo" Methods
J/Link provides another set of convenience methods that hide the packet loop within them. These methods perform the entire procedure of sending something to the Wolfram Language and returning the result in one form or another. They have names that begin with "evaluateTo" to indicate that they actually return the result, rather than merely send it, as with the evaluate() method.
String evaluateToInputForm(String s,int pageWidth);
String evaluateToInputForm(Expr e,int pageWidth);
String evaluateToOutputForm(String s,int pageWidth);
String evaluateToOutputForm(Expr e,int pageWidth);
byte[] evaluateToImage(String s, int width, int height);
byte[] evaluateToImage(Expr e, int width, int height);
byte[] evaluateToImage(String s, int width, int height, int dpi, boolean useFE);
byte[] evaluateToImage(Expr e, int width, int height, int dpi, boolean useFE);
byte[] evaluateToTypeset(String s, int width, boolean useStdForm);
byte[] evaluateToTypeset(Expr e, int width, boolean useStdForm);
Only evaluateToInputForm() and evaluateToOutputForm() are discussed in this section, deferring consideration of evaluateToImage() and evaluateToTypeset() until the section "evaluateToImage() and evaluateToTypeset()", "Graphics and Typeset Output". The evaluateToInputForm() and evaluateToOutputForm() methods encapsulate the very common need of sending some code as a string and getting the result back as a formatted string. They differ only in whether the string is formatted in InputForm or OutputForm. OutputForm is good when you want to display the string to the user, and InputForm is good if you need to send the expression back to the Wolfram Language or if you need to save it to a file or splice it into another expression. These methods take a pageWidth argument to specify how many character widths you want the maximum line length to be. Pass in 0 for a page width of infinity.
The evaluateTo methods do not throw a MathLinkException. Instead, they return null to indicate that a problem occurred. This is not very likely unless there is a serious problem, such as if the kernel has unexpectedly quit. In the event that null is returned from one of these methods, you can call getLastError() to get the Throwable object that represents the exception thrown to cause the unexpected result. Generally, it will be a MathLinkException, but there are some other rare cases (like an OutOfMemoryError if an image was returned that would have been too big to handle).
// Give the (caught) exception that prevented a normal return from the last
// call to an "evaluateTo" method.
Throwable getLastError();
All the evaluateTo methods take the input to evaluate in the form of a string or an Expr. Although a full discussion of the Expr class is deferred until "Motivation for the Expr Class", a brief discussion is provided here on how and why you might want to send the input as an Expr. It is often convenient to specify Wolfram Language input as a string, particularly if it is taken directly from a user, such as the contents of a text field. There are times, though, when it is difficult or unwieldy to work with strings. This is particularly true if the expression to evaluate is built up programmatically, or if it is being read off one link to be written onto the link to the kernel. One way to deal with this circumstance is to forgo the convenience of using, say, evaluateToOutputForm() and instead hand-code the entire operation of sending the input so that the answer will come back formatted in OutputForm. You would have to send the EvaluatePacket head and use the ToString function to get the output as a string.
// This duplicates the following:
// String output = ml.evaluateToOutputForm("Integrate[5 x^n a^x, x]", 0);
// As an expression, we send ToString[Integrate[5 x^n a^x, x], PageWidth->Infinity]
ml.putFunction("EvaluatePacket", 1);
ml.putFunction("ToString", 2);
ml.putFunction("Integrate", 2);
ml.putFunction("Times", 3);
ml.put(5);
ml.putFunction("Power", 2);
ml.putSymbol("x");
ml.putSymbol("n");
ml.putFunction("Power", 2);
ml.putSymbol("a");
ml.putSymbol("x");
ml.putSymbol("x");
ml.putFunction("Rule", 2);
ml.putSymbol("PageWidth");
ml.putSymbol("x");
ml.endPacket();
ml.waitForAnswer();
String output = ml.getString();
This version is considerably more verbose, but most of the code comes from the deliberate decision to send the expression piece-by-piece, not as a single string. There are a few extra lines that ensure that the answer comes back as a properly formatted string and that read the result from the link. It is no great loss to have to do it all by hand. But what if you wanted to do the equivalent with evaluateToTypeset()? Most programmers would have no idea how to perform all the work to get the answer in the desired form. If all the evaluateTo methods took only strings, then J/Link programmers would have to either compose all their input as strings or figure out the difficult steps that are already handled for them by the internals of the various evaluateTo methods.
The solution to this is to allow Expr arguments as an alternative to strings. Although Expr has a set of constructors, the easiest way to create a complicated one is to build the expression on a loopback link and read it off the link as an Expr. You can then pass that Expr to the desired evaluateTo method.
LoopbackLink loop = MathLinkFactory.createLoopbackLink();
// Create the expression EvaluatePacket[Integrate[5 x^n a^x, x]] on the loopback link
loop.putFunction("Integrate", 2);
loop.putFunction("Times", 3);
loop.put(5);
loop.putFunction("Power", 2);
loop.putSymbol("x");
loop.putSymbol("n");
loop.putFunction("Power", 2);
loop.putSymbol("a");
loop.putSymbol("x");
loop.putSymbol("x");
loop.endPacket();
// Now read the Expr off the loopback link
Expr e = loop.getExpr();
// We are done with the loopback link now.
loop.close();
String result = ml.evaluateToOutputForm(e, 0);
e.dispose();
In this way, you can build expressions manually with a series of "put" calls and still have the convenience of using the high-level evaluateTo methods.
Using the PacketListener Interface
A central component of a standard C WSTP program is a packet-reading loop, which typically consists of calling the WSTP API functions WSNextPacket and WSNewPacket until a desired packet is encountered. J/Link programs will typically not include such a loop—instead, you call the KernelLink methods waitForAnswer(), discardAnswer(), or one of the "evaluateTo" methods, which hide the packet loop within them. In some cases, though, programmers will want to observe and/or operate on the incoming flow of packets. A typical example would be to display Print output or messages generated by a computation. These outputs are side effects of a computation and not part of the "answer", and they are normally discarded by J/Link's internal packet loop.
To accommodate this need, KernelLink objects fire a PacketArrivedEvent when the internal packet loop reads a packet (that is, right after nextPacket() has been called). You can register your interest in receiving notifications when packets arrive by creating a class that implements the PacketListener interface and registering it with the KernelLink object. This event notification is done according to the standard Java design pattern for events and event listeners. You create a class that implements PacketListener, and then call the KernelLink method addPacketListener() to register this object to receive notifications.
The PacketListener interface contains only one method, packetArrived().
Your PacketListener object will have its packetArrived() method called for every incoming packet. At the time packetArrived() is called, the packet has been opened with nextPacket(). Your code can begin reading the packet contents. The argument to packetArrived() is a PacketArrivedEvent, from which you can extract the link and the packet type (see the example that follows).
The really nice thing about your packetArrived() implementation is that you can consume or ignore the packet without affecting the internal packet loop in any way. You do not need to be concerned about interfering with any other PacketListener or J/Link's own internal handling of packets. You can read all, some, or none of the contents of any packet.
The packetArrived() method returns a Boolean to indicate whether you want to prevent J/Link's internal code from seeing the packet. This very advanced option lets you completely override J/Link's own handling of packets. At this time, the internals of J/Link's packet handling are undocumented, so programmers will have no use for the override ability. Your packetArrived() method should always return true.
Here is a sample packetArrived() implementation that looks only for TextPacket expressions, printing their contents to the System.out stream.
public boolean packetArrived(PacketArrivedEvent evt) throws MathLinkException {
if (evt.getPktType() == MathLink.TEXTPKT) {
KernelLink ml = (KernelLink) evt.getSource();
System.out.println(ml.getString());
}
return true;
}
This design pattern of using an event listener that gets a callback for every packet received allows your program to be very flexible in its handling of packets. You do not have to significantly change your program to implement different policies, such as ignoring nonresult packets, printing them to the System.out stream, writing them to a file, displaying them in a window, and so on. Just slot in different PacketListener objects with different behavior, and leave all the program logic unchanged. You can use as many PacketListener objects as you want.
The PacketPrinter Class for Debugging
J/Link provides one implementation of the PacketListener interface that is designed to simplify debugging J/Link programs. The PacketPrinter class prints out the contents of each packet on a stream you specify. Here is the constructor.
Here is a code fragment showing a typical use.
PacketListener stdoutPrinter = new PacketPrinter(System.out);
ml.addPacketListener(stdoutPrinter);
...
String result = ml.evaluateToOutputForm("Integrate[x^n a^x, x]", 72);
It is especially useful to see Wolfram System messages that were generated during the computation. Using a PacketPrinter to see exactly what the Wolfram Language is sending back is an extremely useful debugging technique. It is no exaggeration to say that the vast majority of problems with J/Link programs can be identified simply by adding one line of code that creates and installs a PacketPrinter. When you are satisfied that your program is behaving as expected, just take out the addPacketListener() line. No other code changes are required.
Using EnterTextPacket
As noted earlier, when you send something to the Wolfram Language to be evaluated, you wrap it in a packet. The Wolfram Language supports three different packets for sending computations, but the two that are most important are EvaluatePacket and EnterTextPacket. EvaluatePacket has been used manually in a few code fragments, and they are used internally by the evaluate() and evaluateTo methods. When the Wolfram Language receives something wrapped in EvaluatePacket, it evaluates it and sends the result back in a ReturnPacket. Side effects like Print output and PostScript for graphics are sent in their own packets prior to the ReturnPacket. In contrast, when the Wolfram Language receives something in an EnterTextPacket, it runs its full "main loop", which includes, among other things, generating In and Out prompts, applying the $Pre, $PrePrint, and $Post functions, and keeping an input and output history. This is how the notebook front end uses the kernel. You might want to look at the more detailed discussion of the properties of these packets in the MathLink Tutorial, available on MathSource.
If you are using the kernel as a computational engine, you probably want to use EvaluatePacket. Use EnterTextPacket instead when you want to present your users with an interactive "session" where previous outputs can be retrieved by number or %. An example is if you are providing functionality similar to the notebook front end, or the kernel's standalone "terminal" interface. The use of EnterTextPacket as the wrapper packet for computations is not as well supported in J/Link, since it will be used much more rarely. You cannot use the evaluateTo methods, since they use EvaluatePacket.
The packet sequence you get in return from an EnterTextPacket computation will not always have a ReturnTextPacket in it. If the computation returns Null, or if there is a syntax error, no ReturnTextPacket will be sent. The final packet that will always be sent is InputNamePacket, containing the input prompt to use for the next computation. This means that the waitForAnswer() method must accommodate two situations: for most computations, the answer will be in a ReturnTextPacket, but for some computations, there will be no answer at all. Therefore waitForAnswer() returns when either a ReturnTextPacket or an InputNamePacket is encountered. This is why waitForAnswer() returns an int—this is the packet type that caused waitForAnswer() to return. If your call to waitForAnswer() returns MathLink.RETURNTEXTPKT, then you can read the answer (it will be a string), and then you call waitForAnswer() again to receive the InputNamePacket that will come afterward. You can read the prompt string with getString() (it will be something like "In[1]:="). If the original waitForAnswer() returns MathLink.INPUTNAMEPKT, then there was no result to display, and you can just call getString() to read the input prompt string. In the first case, where a ReturnTextPacket does come, instead of calling waitForAnswer() a second time to read off the subsequent InputNamePacket, you could simply call nextPacket(), because the InputNamePacket will always immediately follow the ReturnTextPacket. Although it might look a little weird, calling waitForAnswer() has the advantage of triggering notification of all registered PacketListener objects, which would not happen if you manually read a packet with nextPacket(). In other words, it is better to let all packets be read by J/Link's internal loop.
String inputString = getStringFromUser();
ml.putFunction("EnterTextPacket", 1);
ml.put(inputString);
String result = null;
int pkt = ml.waitForAnswer();
if (pkt == MathLink.RETURNTEXTPKT) {
// Wolfram Language computation returned a non-Null result, so a RETURNTEXTPKT
// was generated. Read its contents (a string).
result = ml.getString();
// Now call waitForAnswer() again, which will return after opening the
// InputNamePacket that will always follow. It is essentially
// nothing more than a call to nextPacket() in this circumstance:
ml.waitForAnswer();
}
// At this point, a call to waitForAnswer() has returned MathLink.INPUTNAMEPKT,
// so we just read out the contents, which is the next input prompt.
String nextPrompt = ml.getString();
You will probably want to use a PacketListener when you are using EnterTextPacket, because you probably want to show your users the full stream of output arriving from the Wolfram Language, which might include messages and Print output. Your PacketListener implementation could write the incoming packets to your input/output session window. In fact, if you have such a PacketListener, you might want to let it handle all output, including the ReturnTextPacket containing the result and the InputNamePacket containing the next prompt. Then you would just call discardAnswer() in your main program and let your PacketListener handle everything.
Handling MathLinkExceptions
Most of the MathLink and KernelLink methods throw a MathLinkException if a WSTP error occurs. This is in contrast to the WSTP C API, where functions return an error code. The methods that do not throw a MathLinkException are generally ones that will often need to be used within a catch block handling a MathLinkException that had already been thrown. If these methods threw their own exceptions, then you would need to nest another try/catch block within the catch block.
A well-formed J/Link program will typically not throw a MathLinkException except in the case of fatal WSTP errors, such as the kernel unexpectedly quitting. What is meant by "well-formed" is that you do not make any overt mistakes when putting or getting expressions, such as specifying an argument count of three in a putFunction() call but only sending two, or calling nextPacket() before you have finished reading the contents of the current packet. The J/Link API helps you avoid such mistakes by providing high-level functions like waitForAnswer() and evaluateToOutputForm() that hide the low-level interaction with the link, but in all but the most trivial J/Link programs it is still possible to make such errors. Just remember that the vast majority of MathLinkException objects thrown represent logic errors in the code of the program, not user errors or runtime anomalies. They are just bugs to which the programmer needs to be alerted so that they can be fixed.
In a small, well-formed J/Link program, you may be able to put a lot of J/Link calls, perhaps even the entire program, within a single try/catch block because there is no need to know exactly what the program was doing when the error occurred—all you are going to do is print a message and exit. The example program in the section "Sample Program" has this structure. Many J/Link programs will need to be a little more refined in their treatment of MathLinkException objects than just quitting. No matter what type of program you are writing, it is strongly recommended that while you are developing the program, you use try/catch blocks in a fine-grained way (that is, only wrapping small, meaningful units of code in each try/catch block), and always put code in your catch block that prints a message or alerts you in some way. Many hours of debugging have been wasted because programmers did not realize a WSTP error had occurred, or they incorrectly identified the region of code where it happened.
Here is a sample of how to handle a MathLinkException in the case where you want to try to recover. The first thing is to call clearError(), as other WSTP calls will fail until the error state is cleared. If clearError() returns false then there is nothing to do but close the link. An example of the type of error that clearError() will fix is the very common mistake of calling nextPacket() before the current packet has been completely read. After clearError() is called, the link is reset to the state it was in before the offending nextPacket(). You can then read the rest of the current packet or call newPacket() to throw it away. Another example of a class of errors where clearError() will work is calling an incorrect "get" method for the type of data waiting on the link—for example, calling getFunction() when an integer is waiting. After calling clearError(), you can read the integer.
try {
...
} catch (MathLinkException e) {
System.err.println(e.toString());
if (ml.clearError() != true) {
System.err.println("MathLinkException was unrecoverable; closing link.");
ml.close();
return; // Or whatever cleanup is appropriate
}
// How you respond after clearError is up to you.
}
What you do in your catch block after calling clearError() will depend on what you were doing when the exception was thrown. About the only useful general guideline provided here is that if you are reading from the link when the exception is thrown, call newPacket() to abandon the rest of the packet. At least then you will know that you are ready to read a fresh packet, even if you have lost the contents of the previous packet.
MathLinkException has a few useful methods that will tell you about the cause of the exception. The getErrCode() method will give you the internal WSTP error code, which can be looked up in the WSTP documentation. It is probably more useful to get the internal message associated with the error, which is given by getMessage(). The toString() method gives you all this information, and will be the most useful output for debugging.
// Some useful MathLinkException methods.
public int getErrCode();
public String getMessage();
public String toString();
public Throwable getCause();
Some MathLinkException exceptions might not be "native" WSTP errors, but rather special exceptions thrown by implementations of the various link interfaces. J/Link follows the standard "exception chaining" idiom by allowing link implementations to catch these exceptions internally, wrap them in a MathLinkException, and re-throw them. As an example, consider a KernelLink implementation built on top of Java Remote Method Invocation (RMI). Methods called via RMI can throw a RemoteException, so such a link implementation might choose to catch internally every RemoteException and wrap it in a MathLinkException. If it did not do this, and instead all its methods could throw a RemoteException in addition to MathLinkException, all client code that used it would have to be modified. What all this means is that if you catch a MathLinkException, it might be "wrapping" another exception, instead of representing an internal WSTP problem. You can use the getCause() method on the MathLinkException instance to retrieve the wrapped exception that was the actual cause of the problem. The getCause() method will return null in the typical case where the MathLinkException is not wrapping another type of exception.
Graphics and Typeset Output
Preamble
Many developers who are writing Java programs that use the Wolfram Language will want to produce Wolfram Language graphics and typeset expressions. This is a relatively complex subject, although J/Link has some very high-level methods designed to make obtaining and displaying these images very simple. If you want to display Wolfram Language images in a Java window, you can use the MathCanvas or MathGraphicsJPanel components, discussed in the next section. If you want a little more control over the process, or if you want to do something with the image data other than display it (like write it to a file or stream), you should read the section on the "evaluateToImage() and evaluateToTypeset()" methods.
MathCanvas and MathGraphicsJPanel
The MathCanvas and MathGraphicsJPanel classes are discussed in "The MathCanvas and MathGraphicsJPanel Classes" because they are often used from Wolfram Language programs. They are just as useful in Java programs. Each is a simple graphical component (a JavaBean, in fact), that can display Wolfram Language graphics and typeset expressions. MathCanvas is a subclass of the AWT Canvas class, and MathGraphicsJPanel is a subclass of the Swing JPanel class. They are conceptually identical and have the same set of extra methods for dealing with Wolfram Language graphics. You use MathCanvas when you want an AWT component and MathGraphicsJPanel when you want a Swing component.
Programmers who want to see how they work are strongly encouraged to examine the source code. The most important methods from these classes are as follows.
public void setMathCommand(String cmd);
public void setImageType(int type);
public void setUsesFE(boolean useFE);
public void setUsesTraditionalForm(boolean useTradForm);
public void setImage(Image im);
public void recompute();
public void repaintNow();
For brevity, the discussion that follows will refer only to MathCanvas; everything said applies equally to MathGraphicsJPanel. Use setMathCommand() to specify arbitrary Wolfram Language code that will be evaluated and have its result displayed. If you are using your MathCanvas to display Wolfram Language graphics, the result of the computation must be a graphics object (that is, an expression with head Graphics, Graphics3D, and so on). It is not enough that the command produces a graphic—it must return a graphic. Thus, setMathCommand("Plot[x,{x,0,1}]") will work, but setMathCommand("Plot[x,{x,0,1}];") will not because the trailing semicolon causes the expression to evaluate to Null. If you are using the MathCanvas to display typeset output, then the result of executing the code supplied in setMathCommand() can be anything. Its typeset form will be displayed. Within the code that you specify via setMathCommand(), quotation marks and other characters that have special meanings inside Java strings must be escaped by preceding them with a backslash, as in setMathCommand("Plot[x,{x,0,1},PlotLabel->\"A Plot\"]").
The setImageType() method is what toggles between displaying a graphic and displaying a typeset expression. Call setImageType(MathCanvas.GRAPHICS) or setImageType(MathCanvas.TYPESET) to toggle between the two modes.
J/Link can create images of Wolfram Language graphics in two ways, either by using only the kernel or by using the kernel along with some extra services from the front end. The front end generally can do a better job, but there are some tradeoffs involved. If you want to use the front end, call setUsesFE(true). When you call setUsesFE(true), the front end may be launched, or an already running copy may be used. The exact behavior depends on what operating system and version of the Wolfram Language you have. In Mathematica 6.0 and higher, all graphics output requires the front end, so the setUsesFE() method has no effect—it is always true.
For typeset output, the default is StandardForm. To change to TraditionalForm call setUsesTraditionalForm(true). When generating typeset output (that is, if you have called setImageType(MathCanvas.TYPESET)), the front end is always involved in generating typeset output, so make sure you understand the issues discussed in "Using the Front End as a Service".
When you call setMathCommand(), the command is executed immediately and the resulting image is cached and used every time the window is repainted. Sometimes the code in your math command depends on variables that will change. To force the command to be recomputed and the new image displayed, call recompute().
The repaintNow() method is like a "smart" version of the JComponent method paintImmediately(), and you use it in the same circumstances as paintImmediately(). It knows about the image that needs to be drawn and it will block until all the pixels are ready. You can use this method to force an immediate redraw when you want the image to be updated instantly in response to some user action like dragging a slider that controls a variable upon which the plot depends. If you call the standard method repaint() instead, Java might not get around to repainting the image until many frames have gone by, and the plot will appear to jump from one value to another, rather than being redrawn for every change in the variable's value.
The preceding discussion described how you can easily display Wolfram Language output in a MathCanvas simply by supplying some code to setMathCommand(). Another way to get an image displayed in a MathCanvas is to create a Java Image object yourself and call the setImage() method. You might want to do this if your image is a bitmap created with some Wolfram Language data, or if you have drawn into an offscreen image using the Java graphics API. The setImage() method was created mainly for use from Wolfram Language code, and it is somewhat less important for Java programmers because you already have other ways to draw into your own components. It can still be useful in Java programs, though, since it can save you from having to write your own subclass of an AWT component just to override its paint() method, which is the usual technique for drawing your own content in components. When used with the setImage() method, a MathCanvas is really just a useful AWT component—it has nothing directly to do with the Wolfram Language.
The next section presents a sample program that uses a MathCanvas to display graphics and typeset output.
A Sample Program That Displays Graphics and Typeset Results
Here is the code for a simple program that presents a window that displays Wolfram Language graphics and typeset output. It is an example of how to use the MathCanvas class. The code and compiled class files for this program are available in the JLink/Examples/Part2/GraphicsApp directory. Launch the program with the pathname to the kernel executable as an argument (note the use of the quote marks " and '):
(Windows)
java -classpath GraphicsApp.jar;..\..\..\JLink.jar GraphicsApp "c:\program files\wolfram research\mathematica\10.0\mathkernel"
(Linux)
java -classpath GraphicsApp.jar:../../../JLink.jar GraphicsApp 'math -mathlink'
(Mac OSX command line)
java -classpath GraphicsApp.jar:../../../JLink.jar GraphicsApp '"/Applications/Mathematica.app/Contents/MacOS/MathKernel" -mathlink'
import com.wolfram.jlink.*;
import java.awt.*;
import java.awt.event.*;
public class GraphicsApp extends Frame {
static GraphicsApp app;
static KernelLink ml;
MathCanvas mathCanvas;
TextArea inputTextArea;
Button evalButton;
Checkbox useFEButton;
Checkbox graphicsButton;
Checkbox typesetButton;
public static void main(String[] argv) {
try {
String[] mlArgs = {"-linkmode", "launch", "-linkname", argv[0]};
ml = MathLinkFactory.createKernelLink(mlArgs);
ml.discardAnswer();
} catch (MathLinkException e) {
System.out.println("An error occurred connecting to the kernel.");
if (ml != null)
ml.close();
return;
}
app = new GraphicsApp();
}
public GraphicsApp() {
setLayout(null);
setTitle("Graphics App");
mathCanvas = new MathCanvas(ml);
add(mathCanvas);
mathCanvas.setBackground(Color.white);
inputTextArea = new TextArea("", 2, 40, TextArea.SCROLLBARS_VERTICAL_ONLY);
add(inputTextArea);
evalButton = new Button("Evaluate");
add(evalButton);
evalButton.addActionListener(new BnAdptr());
useFEButton = new Checkbox("Use front end", false);
CheckboxGroup cg = new CheckboxGroup();
graphicsButton = new Checkbox("Show graphics output", true, cg);
typesetButton = new Checkbox("Show typeset result", false, cg);
add(useFEButton);
add(graphicsButton);
add(typesetButton);
setSize(300, 400);
setLocation(100,100);
mathCanvas.setBounds(10, 25, 280, 240);
inputTextArea.setBounds(10, 270, 210, 60);
evalButton.setBounds(230, 290, 60, 30);
graphicsButton.setBounds(20, 340, 160, 20);
typesetButton.setBounds(20, 365, 160, 20);
useFEButton.setBounds(180, 340, 100, 20);
addWindowListener(new WnAdptr());
setBackground(Color.lightGray);
setResizable(false);
// Although this code would automatically be called in
// evaluateToImage or evaluateToTypeset, it can cause the
// front end window to come in front of this Java window.
// Thus, it is best to get it out of the way at the start
// and call toFront to put this window back in front.
// KernelLink.PACKAGE_CONTEXT is just "JLink`", but it is
// preferable to use this symbolic constant instead of
// hard-coding the package context.
ml.evaluateToInputForm("Needs[\"" + KernelLink.PACKAGE_CONTEXT + "\"]", 0);
ml.evaluateToInputForm("ConnectToFrontEnd[]", 0);
setVisible(true);
toFront();
}
class BnAdptr implements ActionListener {
public void actionPerformed(ActionEvent e) {
mathCanvas.setImageType(
graphicsButton.getState() ? MathCanvas.GRAPHICS : MathCanvas.TYPESET);
mathCanvas.setUsesFE(useFEButton.getState());
mathCanvas.setMathCommand(inputTextArea.getText());
}
}
class WnAdptr extends WindowAdapter {
public void windowClosing(WindowEvent event) {
if (ml != null) {
// Because we used the front end, it is important
// to call CloseFrontEnd[] before closing the link.
// Counterintuitively, this is not because we want
// to force the front end to quit, but because we
// _don't_ want to do this if the user has begun
// working in the front end session we started.
// CloseFrontEnd knows how to politely disengage
// from the front end if necessary. The need for
// this will go away in future releases of
// Mathematica.
ml.evaluateToInputForm("CloseFrontEnd[]", 0);
ml.close();
}
dispose();
System.exit(0);
}
}
}
evaluateToImage() and evaluateToTypeset()
If the MathCanvas or MathGraphicsJPanel classes described in the preceding two sections are not suitable for your needs, you can manually produce images of Wolfram Language graphics and typeset expressions using the evaluateToImage() and evaluateToTypeset() methods in the KernelLink interface.
There are multiple signatures for each. For evaluateToImage(), one set takes a simpler argument list and uses default values for the less commonly used arguments. Here are graphics and typesetting methods from the KernelLink interface
The evaluateToImage() method takes the input as a string or Expr, and a width and height of the resulting graphic in pixels. The extended versions let you specify a dots-per-inch value, and whether to use the notebook front end or not (as discussed later). The short versions use the values of 0 for the dpi and false for whether to use the front end. Specifying 0 for dpi causes the Wolfram Language to use its default value. The image will be sized to fit within a box of width height, without changing its aspect ratio. In other words, the image might not have exactly these dimensions, but it will never be larger in either dimension and it will never be stretched in one dimension to make it fit better. Pass 0 for the width and height to get their Automatic values. If the input does not evaluate to a graphics expression, then null is returned. It is not enough that the computation causes a plot to be generated—the return value of the computation must have head Graphics (or Graphics3D, etc.). If the useFrontEnd argument is true, evaluateToImage() will launch the notebook front end if it is not already running. Note that the useFrontEnd argument is irrelevant when using Mathematica 5.1 and higher—the front end is always used for graphics.
The evaluateToTypeset() method takes the input as a string or Expr, a page width to wrap the output to before it is typeset, and a flag specifying whether to use StandardForm or TraditionalForm. The units for the page width are pixels (use 0 for a page width of infinity). The evaluateToTypeset() method requires the services of the notebook front end, which will be launched if it is not already running.
The result of both of these methods is a byte array of GIF data. The GIF format is well suited to most Wolfram Language graphics, but for some 3D graphics the color usage is not ideal. If you want to change to using JPEG format, you can set $DefaultImageFormat to "JPEG" in the kernel.
// Specifies JPEG format for subsequent calls to evaluateToImage()
// and evaluateToTypeset().
ml.evaluateToOutputForm("$DefaultImageFormat = \"JPEG\"", 0);
These methods are like evaluateToInputForm() and evaluateToOutputForm() in that they perform the computation and return the result in a single step. Together, all these methods are referred to as the "evaluateTo" methods. They all return null in the unlikely event that a MathLinkException occurred.
The MathCanvas and MathGraphicsJPanel classes use these methods internally, so their source code is a good place to look for examples of calling the methods. The MathCanvas code demonstrates how to take the byte array of GIF or JPEG data and turn it into a Java Image for display.
The following Typesetter sample program is another example. It takes a Wolfram Language expression supplied on the command line, calls evaluateToTypeset(), and writes the image data out to a GIF file. You would invoke it from the command line like this.
(Windows)
java Typesetter "c:\program files\wolfram research\mathematica\10.0\mathkernel" "Sqrt[z]" test.gif
(Linux)
java Typesetter 'math -mathlink' "Sqrt[z]" test.gif
(Mac OSX command line)
java Typesetter '"/Applications/Mathematica.app/Contents/MacOS/MathKernel" -mathlink' "Sqrt[z]" test.gif
The first argument is the command line to launch the Wolfram Language kernel, the second argument is the expression to typeset, and the third argument is the file name to create. This program is not intended to be particularly useful—it is just a simple demonstration.
import com.wolfram.jlink.*;
import java.io.*;
public class Typesetter {
public static void main(String[] argv) throws MathLinkException {
KernelLink ml;
try {
String[] mlArgs = {"-linkmode", "launch", "-linkname", argv[0]};
ml = MathLinkFactory.createKernelLink(mlArgs);
ml.discardAnswer();
} catch (MathLinkException e) {
System.err.println("FATAL ERROR: link creation failed.");
return;
}
byte[] gifData = ml.evaluateToTypeset(argv[1], 0, false);
try {
FileOutputStream s = new FileOutputStream(new File(argv[2]));
s.write(gifData);
s.close();
} catch (IOException e) {}
// ALWAYS execute CloseFrontEnd[] before killing the kernel if you used
// evaluateToTypeset(), or evaluateToImage() with the useFE parameter
// set to true:
ml.evaluateToOutputForm("CloseFrontEnd[]", 0);
ml.close();
}
}
It is very important to note that you execute CloseFrontEnd[] before closing the link to the kernel. This is essential to prevent the front end from quitting in circumstances where it should not—specifically, if an already-running copy was used and the user has open documents.
Aborting and Interrupting Computations
J/Link provides two ways in which you can interrupt or abort computations. The first technique uses the low-level putMessage() function to send the desired WSTP message. The second and preferred technique is to use a new set of KernelLink methods introduced in J/Link 2.0. These are listed as follows.
The abortEvaluation() method will send an abort request to the Wolfram Language, identical to what happens in the notebook front end when you select Evaluation ▶ Abort Evaluation. The Wolfram Language responds to this command by terminating the current evaluation and returning the symbol $Aborted. Be aware that sometimes the kernel is in a state where it cannot respond immediately to interrupts or aborts.
The interruptEvaluation() method will send an interrupt request to the Wolfram Language, identical to what happens in the notebook front end when you select Evaluation ▶ Interrupt Evaluation. The Wolfram Language responds to this command by interrupting the current evaluation and sending back a special packet that contains choices for what to do next. The choices can depend on what the kernel is doing at the moment, but in most cases they include aborting, continuing, or entering a dialog. It is not likely that you will want to have to deal with this list of choices on your own, so you might choose instead to call abortEvaluation() and just stop the computation. If you are developing an interactive front end, however, you might decide that you want your users to see the same types of choices that the notebook front end provides. If this is the case, then you can use the new InterruptDialog class, which provides a dialog box very similar to the front end's Interrupt Evaluation dialog. The InterruptDialog class is discussed in a later section.
The abandonEvaluation() method does exactly what its name suggests—it causes any command that is currently waiting for something to arrive on the link to back out immediately and throw a MathLinkException. This MathLinkException is recoverable (meaning that clearError() will return true), so in theory you could call waitForAnswer() again later and get the result when it arrives. In practice, however, you should generally not use this method unless you plan to close the link. You should think of abandonEvaluation() method as an "emergency exit" function that lets your program back out of waiting for a result no matter what state the kernel is in. Remember that the abortEvaluation() method simply sends an abort request to the Wolfram Language, and thus it requires some cooperation from the kernel; there is no guarantee that the current evaluation will abort in a timely manner, if ever. If you call close() right after abandonEvaluation(), the kernel will typically not die, because it is still busy with a computation. You should call terminateKernel() before close() to ensure that the kernel shuts down. A code fragment that follows demonstrates this.
The terminateKernel() method will send a terminate request to the Wolfram Language. It does this by sending the low-level WSTP message WSTERMINATEMESSAGE. This is the strongest step you can take to tell the kernel to shut down, short of killing the kernel process with operating system commands. In "normal" operation of the kernel, when you call close() on the link, the kernel will quit. In some cases, however, generally only if the kernel is currently busy computing, it will not quit. In such cases you can generally force the kernel to quit immediately by calling terminateKernel(). You should always call close() immediately afterward. In a server environment, where a Java program that starts and stops Wolfram Language kernels needs to run unattended for a very long period of time with the highest reliability possible, you might consider always calling terminateKernel() before close(), if there is any chance that close() needs to be called while the kernel is still busy. In some rare circumstances (generally only if something has gone wrong with the Wolfram Language), even calling terminateKernel() will not force the kernel to quit, and you might need to use facilities of your operating system (perhaps invoked via Java's Runtime.exec() method) to kill the kernel process.
If you want to be able to abort, interrupt, or abandon computations, your program will need to have at least two threads. The thread on which the computation is called will probably look like all the sample programs you have seen. You would call one of the "evaluateTo" methods, or perhaps evaluate() followed by waitForAnswer(). This thread will block, waiting for the result. On a separate thread, such as the user interface thread, you could periodically check for some event, like a time-out period elapsing. Or, you could use an event listener to be notified when the Esc key was pressed. Whichever way you want to detect the abort request, all you need to do is call putMessage(MathLink.MLABORTMESSAGE). If the kernel receives the message before it finishes, and it is doing something that can be aborted, the computation will end and return the symbol $Aborted. You typically will not need to do anything special in the computation thread. You wait for the answer as usual; it might come back as $Aborted instead of the final result, that is all. Here are some typical code fragments that demonstrate aborting a computation.
// On thread 1
ml.evaluate("Do[2+2, {20000000}]");
ml.waitForAnswer();
// If user aborted, the result will be the symbol $Aborted.
// On thread 2
if (userPressedEscKey() || timeoutElapsed())
ml.abortEvaluation();
Here is some code that demonstrates how to abandon a computation and force an immediate shutdown of the kernel.
// On thread 1
try {
ml.evaluate("While[True]");
ml.discardAnswer();
} catch (MathLinkException e) {
// We will get here when abandonEvaluation() is called on the other thread.
System.err.println("MathLinkException occurred: " + e.toString());
if (!ml.clearError()) {
// clearError() will always fail when abandonEvaluation() was called.
ml.terminateKernel();
ml.close();
}
}
// On thread 2
if (timeoutElapsedAndReallyNeedToShutdownKernel())
ml.abandonEvaluation();
The discussion so far has focused on the high-level interface for interrupting and aborting computations. The alternative is to use the low-level method putMessage() and pass one of the constants MathLink.MLINTERRUPTMESSAGE, MathLink.MLABORTMESSAGE, or MathLink.MLTERMINATEMESSAGE. There is no reason to do this, however, as interruptEvaluation(), abortEvaluation(), and terminateKernel() are just one-line methods that put the appropriate message. The "messages" referred to in the MathLink method putMessage() are not related to the familiar Wolfram System error and warning messages. Instead, they are a special type of communication between two WSTP programs. This communication takes place on a different channel from the normal flow of expressions, which is why you can call putMessage() while the kernel is in the middle of a computation and not reading from the link.
There are several other MathLink methods with "message" in their names. These are messageReady(), getMessage(), addMessageHandler(), and removeMessageHandler(). These methods are only useful if you want to be able to detect messages the kernel sends to you. J/Link programmers will rarely want to do this, so these methods are not discussed in detail. Please note that messageReady() and getMessage() no longer function in J/Link 2.0 and higher. If you want to be able to receive messages from the Wolfram System, you must use addMessageHandler() and removeMessageHandler(). There is more information in the JavaDocs for these methods.
Using Marks
WSTP allows you to set a "mark" in a link, so that you can read more data and then seek back to the mark, restoring the link to the state it was in before you read the data. Thus, marks let you read data off a link and not have the data consumed, so you can read it again later. There are three mark-related methods in the MathLink interface.
// In the MathLink interface:
long createMark() throws MathLinkException;
void seekMark(long mark);
void destroyMark(long mark);
One common reason to use a mark is if you want to examine an incoming expression and branch to different code depending on some property of the expression. You want the code that actually handles the expression to see the entire expression, but you will need to read at least a little bit of the expression to decide how it must be handled (perhaps just calling getFunction() to see the head). Here is a code fragment demonstrating this technique.
String head = null;
long mark = ml.createMark();
try {
head = ml.getFunction().name;
ml.seekMark(mark);
} finally {
ml.destroyMark(mark);
}
if (head.equals("foo"))
handleFoo(ml);
else if (head.equals("bar"))
handleBar(ml);
Because you seek back to the mark after calling getFunction(), the link will be reset to the beginning of the expression when the handleFoo() and handleBar() methods are entered. Note the use of a try/finally block to ensure that the mark is always destroyed, whether or not an exception of any kind is thrown after it is created. You should always use marks in this way. Right after calling createMark(), start a try block whose finally clause calls destroyMark(). It is important that no other code intervenes between createMark() and the try block, especially WSTP calls (which can throw MathLinkException). If a mark is created and not destroyed, a memory leak will result because incoming data will pile up on the link, never to be freed.
Another common use for marks is to allow you to read an expression one way, and if a MathLinkException is thrown, go back and try reading it a different way. For example, you might be expecting a list of real numbers to be waiting on the link. You can set a mark and then call getDoubleArray1(). If the data on the link cannot be coerced to a list of reals, getDoubleArray1() will throw a MathLinkException. You can then seek back to the mark and try a different method of reading the data.
double[] data = null;
long mark = ml.createMark();
ty {
data = ml.getDoubleArray1();
} catch (MathLinkException e) {
ml.clearError();
ml.seekMark(mark);
// Here, try a different way of reading the data:
switch (ml.getNext()) {
...
}
} finally {
ml.destroyMark(mark);
}
Much of the functionality of marks is subsumed by the Expr class, described in "Motivation for the Expr Class". Expr objects allow you to easily examine an expression over and over in different ways, and with the peekExpr() method you can look at the upcoming expression without consuming it off the link.
Using Loopback Links
In addition to the MathLink and KernelLink interfaces, there is one other link interface: LoopbackLink. Loopback links are a feature of WSTP that allow a program to conveniently store Wolfram Language expressions. Say you want to read an expression off a link, keep it around for awhile, and then write it back onto the same or a different link. How would you do this? If you read it with the standard reading functions (getFunction(), getInteger(), and so on), you will have broken the expression down into its atomic components, of which there might be very many. Then you will have to reconstruct it later with the corresponding series of "put" methods. What you really need is a temporary place to transfer the expression in its entirety, where it can be read later or transferred again to a different link. A loopback link serves this purpose.
Before proceeding to examine loopback links, please note that J/Link's Expr class is used for the same sorts of things that a loopback link is used for. Expr objects use loopback links internally, and are a much richer extension of the functionality that loopback links provide. You should consider using Expr objects instead of loopback links in your programs.
If a MathLink is like a pipe, then a loopback link is a pipe that bends around to point back at you. You manage both ends of the link, writing into one "end" and reading out the other, in FIFO order. To create a loopback link in J/Link, use the MathLinkFactory method createLoopbackLink().
// In class MathLinkFactory:
public static LoopbackLink createLoopbackLink() throws MathLinkException;
The LoopbackLink interface extends the MathLink interface, so all the MathLink methods can be used on loopback links. LoopbackLink adds no methods beyond those in the MathLink interface. Why have a separate interface then? It can be useful to have a separate type for this kind of link, because it has different behavior than a normal one-sided WSTP link. Furthermore, there is one method in the MathLink interface (transferToEndOfLoopbackLink()) that requires, as an argument, a loopback link. Thus, it provides a small measure of type safety within J/Link and your own programs to have a separate LoopbackLink type.
You will probably use the MathLink method transferExpression(), or its variant transferToEndOfLoopbackLink(), in conjunction with loopback links. You will need transferExpression() either to move an expression from another link onto a loopback link or to move an expression you have manually placed on a loopback link onto another link. Here are the declarations of these two methods.
// In the MathLink interface
void transferExpression(MathLink source) throws MathLinkException;
void transferToEndOfLoopbackLink(LoopbackLink source) throws MathLinkException;
Note that the source link is the argument and the destination is the this link. The transferExpression() method reads one expression from the source link and puts it on the destination link, and the transferToEndOfLoopbackLink() method moves all the expressions on the source link (which must be a LoopbackLink) to the destination link.
As already mentioned, a common case where loopback links are convenient is in the temporary storage of an expression for later writing to a different link. This is done more simply using an Expr object, however ("Motivation for the Expr Class"). Another use for loopback links is to allow you to begin sending an expression before you know how long it will be. Recall that the putFunction() method requires you to specify the number of arguments (i.e., the length). There are times, though, when you do not know ahead of time how long the expression will be. Consider the following code fragment. You need to send a list of random numbers to the Wolfram Language, the length of which depends on a test whose outcome cannot be known at compile time. You can create a loopback link and push the numbers onto it as they are generated, counting them as you go. When the loop finishes, you know how many were generated, so you call putFunction() and then just "pour out" the contents of the loopback link onto the destination link. In this example, it would be easy to store the accumulating numbers in a Java array or Vector rather than a loopback link. But if you were sending complicated expressions it might not be so easy to store them in native Java structures. It is often easier just to write them on a link as you go, and leave the storage issues up to the internals of WSTP.
// Here we demonstrate sending an expression (a list of reals)
// whose length is unknown at the start.
try {
...
LoopbackLink loop = MathLinkFactory.createLoopbackLink();
int count = 0;
while (someTest) {
loop.put(Math.random());
count++;
}
ml.putFunction("List", count);
ml.transferToEndOfLoopbackLink(loop);
loop.close();
...
} catch (MathLinkException e) {}
Using Expr Objects
Motivation for the Expr Class
The Expr class provides a direct representation of Wolfram Language expressions in Java. You can guess that this will be useful, since everything in the Wolfram Language is an expression and WSTP is all about communicating Wolfram Language expressions between programs.
You have several ways of handling Wolfram Language expressions in a WSTP program. First, you can send and/or receive them as strings. This is often convenient, particularly if you are taking input typed by a user, or displaying results to the user. Many of the KernelLink methods can take input as a string and return the result as a string. A second way of handling Wolfram Language expressions is to put them on the link or read them off the link a piece at a time with a series of "put" or "get" calls. A third way is to store them on a loopback link and shuttle them around between links. Each of these methods has advantages and disadvantages.
Loopback links were described in the previous section, but it is worthwhile to summarize them here, as it provides some of the background to understanding the motivation for the Expr class. Basically, a loopback link provides a means to store a Wolfram Language expression without having tediously to read it off the link, disassembling it into its component atoms in the process. Loopback links, then, let you store expressions for later reading or just dumping onto another link. If you eventually want to read and examine the expression, however, you are still stuck with the difficult task of dissecting an arbitrary expression off a link with the correct sequence of "get" calls. This is where the Expr class comes in. Like a loopback link, an Expr object stores an arbitrary Wolfram Language expression. The Expr class goes further, though, and provides a set of methods for examining the structure of the expression, extracting parts of it, and building new ones. The names and operation of these methods will be familiar to Wolfram Language programmers: head(), length(), dimensions(), part(), stringQ(), vectorQ(), matrixQ(), insert(), delete(), and many others.
The advantage of an Expr over a loopback link, then, is that you are not restricted to using the low-level MathLink interface for examining an expression. Consider the task of receiving an arbitrary expression from the Wolfram Language and determining if its element at position [[2, 3]] (in Wolfram Language notation) is a vector (a list with no sublists). This can be done with an Expr object as follows.
ml.evaluate("some code");
ml.waitForAnswer();
Expr e = ml.getExpr();
Expr part23 = e.part(new int[] {2, 3});
boolean isVector = part23.vectorQ();
This task would be much more difficult with the MathLink interface. The Expr class provides a minimal Wolfram Language-like functional interface for examining and dissecting expressions.
Methods in the MathLink Interface for Reading and Writing Exprs
There are three methods in the MathLink interface for dealing with Expr objects. This is in addition to the numerous methods in the Expr class itself, which deal with composing and decomposing Expr objects. The getExpr() and peekExpr() methods read an expression off a link, but peekExpr() resets the link to the beginning of the expression—it "peeks" ahead at the upcoming expression without consuming it. This is quite useful for debugging. The put() method will send an Expr object as its corresponding Wolfram Language expression.
// In the MathLink interface:
Expr getExpr() throws MathLinkException;
Expr peekExpr() throws MathLinkException;
void put(Object obj) throws MathLinkException;
Exprs as Replacements for Loopback Links
One way to use Expr is as a simple replacement for a loopback link. You can use the MathLink method getExpr() to read any type of expression off a link and store it in the resulting Expr object. To write the expression onto a link, use the put() method. Compare the following two code fragments.
// Old way, using a loopback link
LoopbackLink loop = MathLinkFactory.createLoopbackLink();
// Read expr off of link and store it on loopback
loop.transferExpression(ml);
...
// Later, write the expr back on the link
ml.transferExpression(loop);
loop.close();
// New way, using an Expr
Expr e = ml.getExpr();
...
// Later, write the expression back on the link
ml.put(e);
e.dispose();
Note the call to dispose() at the end. The dispose() method tells an Expr object to release certain resources that it might be using internally. You should generally use dispose() on an Expr when you are finished with it. The dispose() method is discussed in more detail in "Disposing of Exprs".
Exprs as a Means to Get String Representations of Expressions
A particularly useful method in the Expr class is toString(), which produces a string representation of the expression similar to InputForm (without involving the kernel, of course). This is particularly handy for debugging purposes, when you want a quick way to see what is arriving on the link. In "The PacketPrinter Class for Debugging" it was mentioned that J/Link has a class PacketPrinter that implements the PacketListener interface and can be used easily to print out the contents of packets as they arrive in your program, without modifying your program. Following is the packetArrived() method of that class, which uses an Expr object and its toString() method to get the printable text representation of an arbitrary expression.
public boolean packetArrived(PacketArrivedEvent evt) throws MathLinkException {
KernelLink ml = (KernelLink) evt.getSource();
Expr e = ml.getExpr();
strm.println("Packet type was " + pktToName(evt.getPktType()) +
". Contents follows.");
strm.println(e.toString());
e.dispose();
return true;
}
Whether you use the PacketPrinter class or not, this technique is useful to see what expressions are being passed around. This is often used in conjunction with the MathLink peekExpr() method, which reads an expression off the link, but then resets the link so that the expression is not consumed. In this way, you can look at expressions arriving on links without interfering with the rest of the link-reading code in your program. The PacketPrinter code shown does not use peekExpr(), but it has the same effect since the resetting of the link is handled elsewhere.
Exprs as Arguments to KernelLink Methods
The KernelLink methods evaluate(), evaluateToInputForm(), evaluateToOutputForm(), evaluateToImage(), and evaluateToTypeset() take the Wolfram Language expression to evaluate as either a string or an Expr. "The 'evaluateTo' Methods" discusses why and how you would use an Expr object to provide the input instead of a string. This examines one trivial example comparing how you would send 2+2 to the Wolfram Language as both a string and as an Expr. In the Expr case you build the expression on a loopback link and then read the Expr off this link. For all but the simplest expressions, this is generally easier than trying to use the Expr constructors.
// Send input as a string:
String result = MathLink.evaluateToOutputForm("2+2", 0);
// Send input as an Expr:
LoopbackLink loop = MathLinkFactory.createLoopbackLink();
// Create the expression 2+2 on the loopback link
loop.putFunction("Plus", 2);
loop.put(2);
loop.put(2);
loop.endPacket();
// Now read the Expr off the loopback link
Expr e = loop.getExpr();
// We are done with the loopback link now.
loop.close();
String result = ml.evaluateToOutputForm(e, 0);
e.dispose();
Examining and Manipulating Exprs
Like expressions in the Wolfram Language, Expr objects are immutable, meaning that they cannot be modified once they have been created. Operations that might appear to modify an Expr, like the insert() method, actually copy the original, modify this copy, and then return a new immutable object. One consequence of being immutable is that the Expr class is thread-safe—multiple threads can operate on the same Expr without worrying about synchronization.
The Expr class provides a minimal Wolfram Language-like API for examination and manipulation. The functions are generally named after their Wolfram Language counterparts, and they operate in the same way. This section will only provide a brief review of the Expr API. Consult the JavaDocs (found in the JLink/Documentation/JavaDoc directory) for more information about these methods.
Here are some methods for learning about the structure of an Expr.
There are a number of methods whose names end in "Q", following the same naming pattern as in the Wolfram Language for functions that return true or false. This is not the complete list.
// A sampling of the "Q" methods
public boolean atomQ();
public boolean stringQ();
public boolean integerQ();
public boolean numberQ();
public boolean trueQ();
public boolean listQ();
public boolean vectorQ();
public boolean matrixQ();
There are several methods for taking apart and building up an Expr. Like in the Wolfram Language, part numbers and indices are 1-based. You can also supply negative numbers to count backward from the end. Many Expr methods throw an IllegalArgumentException if they are called with invalid input, such as a part index larger than the length of the Expr. These exceptions parallel the Wolfram System error messages you would get if you made the same error in Wolfram Language code.
public Expr part(int index);
public Expr part(int[] indices);
public Expr take(int n);
public Expr delete(int n);
public Expr insert(Expr e, int n);
Here is some very simple code that demonstrates a few Expr operations.
ml.evaluate("Expand[(x + y)^4]");
ml.waitForAnswer();
Expr e1 = ml.getExpr();
System.out.println("e1 is: " + e1.toString());
System.out.println("the length is: " + e1.length());
System.out.println("the head is: " + e1.head().toString());
System.out.println("part [[2]] is: " + e1.part(2));
System.out.println("part [[-1]] is: " + e1.part(-1));
System.out.println("part [[2, 2]] is: " + e1.part(new int[]{2, 2}));
System.out.println("drop the last element: " + e1.delete(-1).toString());
System.out.println("e1 is unmodified: " + e1.toString());
Expr e2 = e1.insert(new Expr(new double[] {1.0, 2.0, 3.0}), 1);
System.out.println("e2 is: " + e2.toString());
That code prints the following.
e1 is: Plus[Power[x,3],Times[3,Power[x,2],y],Times[3,x,Power[y,2]],Power[y,3]]
the length is: 4
the head is: Plus
part [[2]] is: Times[3,Power[x,2],y]
part [[-1]] is: Power[y,3]
part [[2, 2]] is: Power[x,2]
drop the last element: Plus[Power[x,3],Times[3,Power[x,2],y],Times[3,x,Power[y,2]]]
e1 is unmodified: Plus[Power[x,3],Times[3,Power[x,2],y],Times[3,x,Power[y,2]],Power[y,3]]
e2 is: Plus[{1.0,2.0,3.0},Power[x,3],Times[3,Power[x,2],y],Times[3,x,Power[y,2]],Power[y,3]]
Disposing of Exprs
You have seen the dispose() method used frequently in this discussion of the Expr class. An Expr object might make use of a loopback link internally, and any time a Java class holds such a non-Java resource it is important to provide programmers with a dispose() method that causes the resource to be released. Although the finalizer for the Expr class will call dispose(), you cannot rely on the finalizer ever being called. Although it is good style to always call dispose() on an Expr when you are finished using it, you should know that many of the operations you can perform on an Expr will cause it to be "unwound" off its internal loopback link and cause that link to be closed. After this happens, the dispose() method is unnecessary. Calling the toString() method is an example of an operation that makes dispose() unnecessary, and in fact virtually any operation that queries the structure of an Expr or extracts a part will have this effect. This is useful to know since it allows shorthand code like the following.
This replaces the more verbose code following.
You should get in the habit of calling dispose() explicitly on Expr objects. In cases where it is inconvenient to store an Expr in a named variable, and you know that the Expr does not need to be disposed, then you can skip calling it.
Because extracting any piece of an existing expression will make dispose() unnecessary, you do not have to worry about calling dispose() on Expr objects that are obtained as parts of another expression.
Expr e = ml.getExpr();
// The moment that head() or part() are called on e below, you know that neither
// e, e2, nor e3 need to be disposed.
Expr e2 = e.head();
Expr e3 = e.part(1);
You cannot reliably use an Expr object after dispose() has been called on it. You have already seen that dispose() is often unnecessary because many Expr objects have already had their internal loopback links closed. For such an Expr, dispose() will have no effect at all and there would be no problem continuing to use the Expr after dispose() had been called. That being said, it is horrible style to ever try to use an Expr after calling dispose(). A call to dispose() should always be an unambiguous indicator that you have no further use for the given Expr or any part of it.
Threads, Blocking, and Yielding
The classes that implement the MathLink and KernelLink interfaces are not thread-safe. This means that if you write a J/Link program in which one link object is used by more than one thread, you need to pay careful attention to concurrency issues. The relevant methods in the link implementation classes are synchronized, so at the individual method level there is no chance that two threads can try to use the link at the same time. However, this is not enough to guarantee thread safety, because interactions with the link typically involve an entire transaction, encompassing a multistep write and read of the result. This entire transaction must be guarded. This is done by using synchronized blocks to ensure that the threads do not interfere with each other's use of the link.
The "evaluateTo" methods are synchronized, and they encapsulate an entire transaction within one call, so if you use only these methods you will have no concerns. On the other hand, if you use evaluate() and waitForAnswer(), or any other technique that splits up a single transaction across multiple method calls, you should wrap the transaction in a synchronized block, as follows.
Synchronization is only an issue if you have multiple threads using the same link.
J/Link functions that read from a link will block until data arrives on that link. For example, when you call evaluateToOutputForm(), it will not return until the Wolfram Language has computed and returned the result. This might be a problem if the thread on which evaluateToOutputForm() was called needs to stay active—for example, if it is the AWT thread, which processes user interface events.
How to handle blocking is a general programming problem, and there are a number of solutions. The Java environment is multithreaded, and thus an obvious solution is simply to make J/Link calls on a thread that does not need to be continuously responsive to other events in the system.
WSTP has the notion of a "yield function", which is a function you can designate to be called from the internals of WSTP while WSTP is blocking, waiting for input to arrive from the other side. A primary use for yield functions was to solve the blocking problem on operating systems that did not have threads, or for programming languages that did not have portable threading libraries. The way this would typically work is that your single-threaded program would install a yield function that ran its main event loop, so that the program could process user interface events even while it was waiting for WSTP data.
With Java, this motivation goes away. Rather than using a yield function to allow your program's only thread to still handle events while blocking, you simply start a separate thread from the user interface thread and let it happily block inside J/Link calls. Despite the limited usefulness of yield functions in Java programs, J/Link provides the ability to use them anyway.
// From the MathLink interface
public boolean setYieldFunction(Class cls, Object obj, String methName);
The setYieldFunction() method in the MathLink interface takes three arguments that identify the function to be called. These arguments are designed to accommodate static and nonstatic methods, so only two of the three need to be specified. For a static method, supply the method's Class and its name, leaving the second argument null. For a nonstatic method, supply the object on which you want the method called and the method's name, leaving the Class argument null. The function must be public, take no arguments, and return a boolean.
The function you specify will be called periodically while J/Link is blocking in a call that tries to read from the link. The return value is used to indicate whether J/Link should back out of the read call and return right away. Backing out of a read call will cause a MathLinkException to be thrown by the method that is reading from the link. This MathLinkException is recoverable (meaning that clearError() will return true), so you could call waitForAnswer() again later and get the result when it arrives if you want. Return false from the yield function to indicate that no action should be taken (thus false is the normal return value for a yield function), and return true to indicate that J/Link should back out of the reading call. To turn off the yield function, call setYieldFunction(null, null, null).
Very few J/Link programmers will have any need for yield functions. They are a solution to a problem that is better handled in Java by using multiple threads. About the only reasonable motivation for using a yield function is to be able to back out of a computation that is taking too long and either resists attempts to abort it, or you know you want to close the link anyway. This can also be done by calling abandonEvaluation() on a separate thread. The abandonEvaluation() method is described in "Aborting and Interrupting Computations". Note that abandonEvaluation() uses a yield function internally, so calling it will wipe out any yield function you might have installed on your own.
Sending Object References to the Wolfram Language
The first part of this User Guide describes how to use J/Link to allow Wolfram Language code to launch a Java runtime, load Java classes and directly execute Java methods. What this means for you, the reader of this tutorial, who are probably writing your own program to launch and communicate with the Wolfram Language kernel, is that you can have a very high-level interaction with the Wolfram Language. You can send your own objects to the Wolfram Language and use them in Wolfram Language code, but you have to take a special step to enable this type of interaction.
Consider what happens if you have written a Java front end to the Wolfram Language kernel and a user of your program calls a Wolfram Language function that uses the "installable Java" features of J/Link and thus calls InstallJava in the Wolfram Language. InstallJava launches a separate Java runtime and proceeds to direct all J/Link traffic to that Java runtime. The kernel is blissfully unconcerned whether the front end that is driving it is the notebook front end or your Java program—it does the same thing in each case. This is fine and it is what many J/Link programmers will want. You do not have to worry about doing anything special if some Wolfram Language code happens to invoke the "installable Java" features of J/Link, because a separate Java runtime will be used.
But what if you want to make use of the ability that J/Link gives Wolfram Language code to interact with Java objects? You might want to send Java object references to the Wolfram Language and operate on them with Wolfram Language code. The Wolfram Language "operates" on Java objects by calling into Java, so any callbacks for such objects must be directed to your Java runtime. A further detail of J/Link is that it only supports one active Java runtime for all installable Java uses. What this all adds up to is that if you want to pass references to your own objects into the Wolfram Language, then you must call InstallJava and specify the link to your Java runtime, and you must do this before any function is executed that itself calls InstallJava. Actually, a number of steps need to be taken to enable J/Link callbacks into your Java environment, so J/Link includes a special method in the KernelLink interface, enableObjectReferences(), that takes care of everything for you.
public void enableObjectReferences() throws MathLinkException;
// For sending object references:
public void put(Object obj) throws MathLinkException;
public void putReference(Object obj) throws MathLinkException;
After calling enableObjectReferences(), you can use the KernelLink interface's put() or putReference() methods to send Java objects to the Wolfram Language, and they will arrive as JavaObject expressions that can be used in Wolfram Language code as described throughout "Calling Java from the Wolfram Language". Recall that the difference between the put() and putReference() methods is that put() sends objects that have meaningful "value" representations in the Wolfram Language (like arrays and strings) by value, and all others by reference. The putReference() method sends everything as a reference. If you want to use enableObjectReferences(), call it early on in your program, before you call putReference(). It requires that the JLink.m file be present in the expected location, which means that J/Link must be installed in the standard way on the machine that is running the kernel.
Once you have called enableObjectReferences(), not only can you send Java objects to the Wolfram Language, you can also read Java object references that the Wolfram Language sends back to Java. The getObject() method is used for this purpose. If a valid JavaObject expression is waiting on the link, getObject() will return the object that it refers to.
If you call enableObjectReferences() in your program, it is imperative that you do not try to write your own packet loop. Instead, you must use the KernelLink methods that encapsulate the reading and handling of packets until a result is received. These methods are waitForAnswer(), discardAnswer(), evaluateToInputForm(), evaluateToOutputForm(), evaluateToImage(), and evaluateToTypeset(). If you want to see all the incoming packets yourself, use a PacketListener object in conjunction with one of these methods. This is discussed in "Using the PacketListener Interface".
It is worthwhile to examine in more detail the question of why you would want to use enableObjectReferences(). Traditionally, WSTP programmers have worked with the C API, which limits the types of data that can be passed back and forth between C and the Wolfram Language to Wolfram Language expressions. Since Wolfram Language expressions are not generally meaningful in a C program, this translates basically to numbers, strings, and arrays of these things. The native structures that are meaningful in your C or C++ program (structs, objects, functions, and so on) are not meaningful in the Wolfram Language. As a result, programmers tend to use a simplistic one-way communication with the Wolfram Language, decomposing the native data structures and objects into simple components like numbers and strings. Program logic and behavior is coded entirely in C or C++, with the Wolfram Language used solely for mathematical computations.
In contrast, J/Link allows Java and Wolfram Language code to collaborate in a high-level way. You can easily code algorithms and other program behavior in the Wolfram Language if it is easier for you. As an example, say you are writing a Java servlet that needs to use the Wolfram Language kernel in some way. Your servlet's doGet() method will be called with HttpServletRequest and HttpServletResponse objects as arguments. One approach would be to extract the information you need out of these objects, package it up in some way for the Wolfram Language, and send the desired computation for evaluation. But another approach would be simply to send the HttpServletRequest and HttpServletResponse objects themselves to the Wolfram Language. You can then use the features and syntax described in "Calling Java from the Wolfram Language" to code the behavior of the servlet in the Wolfram Language, rather than in Java. Of course, these are just two extremes of a continuum. At one end you have the servlet behavior hard-coded into a compiled Java class file, and you make use of the Wolfram Language in a limited way, using a very narrow pipeline (narrow in the logical sense, passing only simple things like numbers, strings, or arrays). At the other end of the continuum you have a completely generic servlet that does nothing but forward all the work into the Wolfram Language. The behavior of the servlet is written completely in the Wolfram Language. You can use this approach even if you do not need the Wolfram Language as a mathematics engine—you might just find it easier to develop and debug your servlet logic in the Wolfram Language. You can draw the line between Java and the Wolfram Language anywhere you like along the continuum, doing whatever amount of work you prefer in each language.
In case you are wondering what such a generic servlet might look like, here is the doGet() method.
// ml.enableObjectReferences() must have been called prior, for example
// in the servlet's init method.
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
ml.putFunction("EvaluatePacket", 1);
ml.putFunction("DoGet", 2);
// We could also use plain 'put' here, as these objects would be put
// by reference anyway.
ml.putReference(req);
ml.putReference(res);
ml.endPacket();
ml.discardAnswer();
} catch (MathLinkException e) {}
}
This would be accompanied by a Wolfram Language function DoGet that takes the two Java object arguments and implements the servlet behavior. The syntax is explained in "Calling Java from the Wolfram Language".
doGet[req_, resp_] :=
JavaBlock[
Module[{outStream},
outStream = resp@getOutputStream[];
outStream@print["<HTML> <BODY>"];
outStream@print["Hello World"];
outStream@print["</BODY> </HTML>"];
]
]
]
Some Special User Interface Classes
Introduction
J/Link has several classes that provide some very high-level user interface components for your Java programs. They are discussed individually in the next subsections. These classes are in the new com.wolfram.jlink.ui package, so do not forget to import that package if you want to use the classes.
ConsoleWindow
The ConsoleWindow class gives you a top-level frame window that displays output printed to the System.out and/or System.err streams. It has no input facilities. This is the class used to implement the Wolfram Language function ShowJavaConsole, discussed in "The Java Console Window". This class is quite useful for debugging Java programs that do not have a convenient place for console output. An example is a servlet—rather than digging around in your servlet container's log files after every run, you can just display a ConsoleWindow and see debugging output as it happens.
This class is a singleton, meaning that there is only ever one instance in existence. It has no public constructors. You call the static getInstance() method to acquire the sole ConsoleWindow object. Here is a code fragment that demonstrates how to use ConsoleWindow. You can find more information on this class in its JavaDoc page.
// Don't forget to import it (a different package than the rest of J/Link):
// import com.wolfram.jlink.ui.ConsoleWindow;
ConsoleWindow cw = ConsoleWindow.getInstance();
cw.setLocation(100, 100);
cw.setSize(450, 400);
cw.show();
// Specify that we want to capture System.out and System.err.
cw.setCapture(ConsoleWindow.STDOUT | ConsoleWindow.STDERR);
System.out.println("hello world from stdout");
System.err.println("hello world from stderr");
MathSessionPane
The MathSessionPane class provides an In/Out Wolfram System session window complete with a full set of editing functions including cut/copy/paste/undo/redo, support for graphics, syntax coloring, and customizable font styles. It is a bit like the Wolfram Language kernel's "terminal" interface, but much more sophisticated. You can easily drop it into any Java program that needs a full command-line interface to the Wolfram Language. The class is a Java Bean and will work nicely in a GUI builder environment. It has a very large number of properties that allow its look and behavior to be customized.
The best way to familiarize yourself with the features of MathSessionPane is to run the SimpleFrontEnd example program, found in the JLink/Examples/Part2/SimpleFrontEnd directory. SimpleFrontEnd is little more than a frame and menu bar that host a MathSessionPane. Essentially all the features you see are built into MathSessionPane, including the keyboard commands and the properties settable via the Options menu. To run this example, go to the SimpleFrontEnd directory and execute the following command line.
(Windows)
java -classpath SimpleFrontEnd.jar;..\..\..\JLink.jar SimpleFrontEnd
(Linux, Mac OS X):
java -classpath SimpleFrontEnd.jar:../../../JLink.jar SimpleFrontEnd
The application window will appear and you will be prompted to enter a path to a kernel to launch. Once the Wolfram Language is running, try various computations, including plots. Experiment with the numerous settings and commands on the menus. One feature of MathSessionPane not exposed via the SimpleFrontEnd menu bar is a highly customizable syntax coloring capability. The default behavior is to color built-in Wolfram Language symbols, but you can get as fancy as you like, such as specifying that symbols from a certain list should always appear in red, and symbols from a certain package should always appear in blue.
The methods and properties of MathSessionPane are described in greater detail in the JavaDocs, which are found in the JLink/Documentation/JavaDoc directory.
BracketMatcher and SyntaxTokenizer
The auxiliary classes BracketMatcher and SyntaxTokenizer are used by MathSessionPane, but can also be used separately to provide these services in your own programs. An example of the sort of program that would find these classes useful is a text-editor component that needs to have special features for Wolfram Language programmers.
These classes are described in greater detail in their JavaDoc pages. The JavaDocs for J/Link are found in the JLink/Documentation/JavaDoc directory. You can also look to see how they are used in the source code for the MathSessionPane class (MathSessionPane.java).
The BracketMatcher class locates matching bracket pairs (any of (), {}, [], and (**)) in Wolfram Language code. It ignores brackets within strings and within Wolfram Language comments, and it can accommodate nested comments. It searches in the typical way—expanding the current selection left and right to find the first enclosing matching brackets. To see its behavior in action, simply run the SimpleFrontEnd sample program discussed in the previous section on MathSessionPane and experiment with its bracket-matching feature.
SyntaxTokenizer is a utility class that can break up Wolfram Language code into four syntax classes: strings, comments, symbols, and normal (meaning everything else). You can use it to implement syntax coloring or a code analysis tool that can extract all comments or symbols from a file of Wolfram Language code.
InterruptDialog
The InterruptDialog class gives you an Interrupt Evaluation dialog box similar to the one you see in the notebook front end when you choose Interrupt Evaluation from the Evaluation menu. The dialog box that appears has choices for aborting, quitting the kernel, and so on, depending on what the kernel is doing at the time.
The InterruptDialog constructor takes a Dialog or Frame instance that will be the parent window of the dialog box. What you supply for this argument will typically be the main top-level window in your application. InterruptDialog implements the PacketListener interface, and you use it like any other PacketListener.
// Don't forget to import it (a different package than the rest of J/Link):
// import com.wolfram.jlink.ui.InterruptDialog;
ml.addPacketListener(new InterruptDialog(myParentFrame));
After the line of code is executed, whenever you interrupt a computation (by sending an MLINTERRUPTMESSAGE or, more commonly, by calling the KernelLink interruptEvaluation() method), a modal dialog box will appear with choices for how to proceed.
The SimpleFrontEnd sample program discussed in the section "MathSessionPane" makes use of an InterruptDialog. To see it in action, launch that sample program and execute the following Wolfram Language statement.
Then select Interrupt Evaluation from the Evaluation menu. The Interrupt Evaluation dialog box will appear and you can click the Abort Command Being Evaluated button to stop the computation. To use an InterruptDialog in your own program, your user interface must provide a means for users to send an interrupt request, such as an Interrupt button or special key combination. In response to this action, your program would call the KernelLink interruptEvaluation() method.
That a behavior as complex as a complete Interrupt Evaluation dialog box can be plugged into a Java program with only a single line of code is a testament to the versatility of the PacketListener interface, described in "Using the PacketListener Interface". The InterruptDialog class works by monitoring the incoming flow of packets from the kernel and detecting the special type of MenuPacket that the kernel sends after an interrupt request. Anytime you have some application logic that needs to know about packets that arrive from the Wolfram Language, you should implement it as a PacketListener.
Writing Applets
This User Guide has presented a lot of information about how to use J/Link to enable WSTP functionality in Java programs, whether those Java programs are applications, JavaBeans, servlets, applets, or anything else. If you want to write an applet that makes use of a local Wolfram Language kernel, you have some special considerations because you will need to escape the Java security "sandbox" within which the browser runs applets.
The only thing that J/Link needs special browser security permission for is to load the J/Link native library. The only reason the native library is required, or even exists at all, is to perform the translation between Java calls in the NativeLink class and Wolfram Research's platform-dependent WSTP library. NativeLink is the class that implements the MathLink interface in terms of native methods. Currently, every time you call MathLinkFactory.createMathLink() or MathLinkFactory.createKernelLink(), an instance of the NativeLink class is created, so the J/Link native library must be loaded. In other words, the only thing in J/Link that needs the native library is the NativeLink class, but currently all MathLink or KernelLink objects use a NativeLink object. You cannot do anything with J/Link without requiring the native library to be loaded.
Different browsers have different requirements for allowing applets to load native libraries. In many cases, the applet must be "signed", and the browser must have certain settings enabled. Note that letting Java applets launch local kernels is an extreme breach of security, since the Wolfram Language can read sensitive files, delete files, and so on. It is probably not a very good idea in general for users to allow applets to blast such an enormous hole in their browser's security sandbox. A better choice is to have Java applets use a kernel residing on the server. In this scenario, the browser's Java runtime does not need to load any local native libraries, so there are no security issues to overcome. This requires significant support on both the client and server side. This support is not part of J/Link itself, but it is a good example of the sort of programs J/Link can be used to create.