Writing Java Programs That Use Mathematica
Introduction
The first part of this
User Guide describes using
J/Link to allow you to call from
Mathematica into Java, thereby extending the
Mathematica 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
Mathematica kernel as a computational engine.
J/Link uses
MathLink, 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
MathLink 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
MathLink. Programmers may have to rely a little on the general documentation of
MathLink 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 Mathematica", you should at least skim it at some point. Your Java "front end" can use the same techniques for calling Java methods from
Mathematica 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
Mathematica. When you are writing
MathLink 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
Mathematica.
J/Link truly obliterates the boundary between Java and
Mathematica.
Although Java is quite useful as a web-related development language, such as for writing applets or servlets, it is by no means restricted to this domain, and this User Guide does not address the specifics of these types of programs. Addressed are generic issues in
J/Link programming, leaving the application of these concepts in specific types of programs up to the reader. In other words, if you are looking for a worked-out example program showing how a suite of servlets running on a web or application server can allow remote Java clients to share a cluster of
Mathematica kernels, you will not find it here. But
J/Link is just the sort of tool you will need if you embark on such a project.
This half of the User Guide is organized as follows. "
What Is MathLink?" is a very brief introduction to
MathLink. 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
Mathematica 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
Mathematica, 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 MathLink?
MathLink is a platform-independent protocol for communicating between programs. In more concrete terms, it is a means to send and receive
Mathematica expressions.
MathLink 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
Mathematica and other programs or languages.
MathLink 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.
Throughout this part of the User Guide, the term
MathLink will be used in two ways—as a generic term for the capability
Mathematica has to communicate with other programs, and as the name for one specific
J/Link interface. It will always be written in the special font used for Java names when the interface name is being used.
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
MathLink C API into Java. Most of the method names will be familiar to experienced
MathLink 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
Mathematica 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
Mathematica 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
MathLink 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
MLOpen 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
MathLink C API. In C, you write code that checks the return values like this:
// C code
if (!MLPutInteger(link, 42)) {
// was error; print message and clean up.
}
In
J/Link, you wrap
MathLink calls in a
try block and catch
MathLinkException.
Expr
The
Expr class provides a direct representation of
Mathematica 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
Mathematica 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
MathLink program is a packet-reading loop, which typically consists of calling the
MathLink API functions
MLNextPacket and
MLNewPacket 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
Mathematica graphics and typeset expressions. These classes are often used from
Mathematica 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 Mathematica Code: The 'MathListener' Classes") can be be used from Java code to trigger evaluations in
Mathematica 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
Mathematica 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 from the menu. The
MathSessionPane class provides an
In/
Out Mathematica 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
Mathematica 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
MathLink 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
Mathematica 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\6.0\mathkernel.exe"
(Unix)
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
Mathematica 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
MLOpen 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
Mathematica 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, for example:
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\6.0\\mathkernel'");
Note that the linkname argument is wrapped in single quotation marks (
'). This is because
MathLink 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 filename. 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
Mathematica, 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\\mathkernel.exe'");
// Typical launch on Unix
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 1234 -linkprotocol tcp");
// Windows can use the default protocol for listen/connect links:
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\\6.0\\mathkernel"};
// Typical launch on UNIX:
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", "1234", "-linkprotocol", "tcp"};
// Windows can use the default protocol for listen/connect links:
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
MLOpen in the
MathLink C API. Consult the
MathLink 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\\6.0\\mathkernel'");
} catch (MathLinkException e) {
// This is equivalent to MLOpen 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
MathLink,
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,
MathLink 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
MathLink, 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
MathLink-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\\6.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
MathLink programs. See the
MathLink Tutorial (
http://library.wolfram.com/infocenter/TechNotes/174/) or "
MathLink and External Program Communication" for more information.
Using a Remote Kernel
To attach a remote
Mathematica kernel to a
J/Link program, open the link using the listen/connect style. On the remote Unix machine, launch
Mathematica and have it listen on a link by executing the following on a command line.
math -mathlink -linkmode listen -linkname 1234 -linkprotocol tcpip
Note the use of the TCPIP
MathLink protocol. The TCPIP protocol is an improved version of the TCP protocol that is only supported in
Mathematica 5.0 and later. If you are launching
Mathematica 4.x, use
tcp as the protocol name instead of
tcpip (also in the following line).
Then in your Java program:
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
Mathematica. You can have the Java program automatically launch
Mathematica on the remote machine by using an
rsh or
ssh client program. Unix machines have
rsh and
ssh built in, and
Mathematica ships with the
winrsh client program for Windows. Here is an example of using
winrsh to launch and connect to
Mathematica on a remote Unix machine.
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode listen -linkprotocol tcpip -linkname 1234");
Runtime.exec("c:\\program files\\wolfram research\\mathematica\\6.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
MathLink 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
Mathematica 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 printed 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
int error();
boolean clearError();
String errorMessage();
void setError(int err);
Link State
boolean ready() throws MathLinkException;
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
MLPutInteger and
MLPutDouble; 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
MLPutUCS2String),
putSymbol() (equivalent to
MLPutUCS2Symbol), and
putByteString() (equivalent to
MLPutByteString).
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;
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
Mathematica symbol
True, and
False for Java
false:
void put(boolean b) throws MathLinkException;
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
Mathematica. 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
Mathematica strings, and the wrapper classes are sent as their numeric value. (The last case is for complex numbers, which will be discussed later.)
void put(Object obj) throws MathLinkException;
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 (
MLPutInteger32Array,
MLPutReal64Array, and so on), you do not have to specify the depth or dimensions because they can be inferred from the array itself:
void put(Object array, String[] heads) throws MathLinkException;
For putting
Mathematica functions:
void putFunction(String f, int argCount) throws MathLinkException;
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;
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;
// New in J/Link 2.0:
Object getArray(int type, int depth, String[] heads) throws MathLinkException;
New in
J/Link 2.0 is
getArray(int type, int depth, String[] heads). It reads an array and also tells you the heads at each level. See the JavaDocs for more information.
Unlike the C
MathLink API, there are no methods for "disowning" 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;
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
Mathematica warning messages, but a low-level type of
MathLink communication used mainly to send interrupt and abort requests. The
getMessage() and
messageReady() methods no longer function in
J/Link 2.0 and later. You must use
setMessageHandler() if you want to receive messages from
Mathematica.
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
Mathematica. "Mapped" means that the
put(Object) method will send a
Mathematica 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
MathLink.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 printed 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
Mathematica 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 MathLink 'Packet Loop'".
void evaluate(String s) throws MathLinkException;
void evaluate(Expr e) throws MathLinkException;
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 MathLink 'Packet Loop'".
void waitForAnswer() throws MathLinkException;
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().
void discardAnswer() throws MathLinkException;
The "evaluateTo" Methods
The next set of 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
Mathematica 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
Mathematica.
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
Mathematica so that
Mathematica code can call back into your Java runtime via the "installable Java" facility described in "
Calling Java from Mathematica", you must first call the
enableObjectReferences() method. This is described in "
Sending Object References to Mathematica".
void enableObjectReferences() throws MathLinkException;
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 Mathematica".
void put(Object obj) throws MathLinkException;
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".
void abortEvaluation();
void interruptEvaluation()
void abandonEvaluation();
void terminateKernel();
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.
void handlePacket(int pkt) throws MathLinkException;
Methods Valid Only for "StdLinks"
Finally, there are some methods that are meaningful only in methods that are themselves called from
Mathematica via the "installable Java" functionality described in "
Calling Java from Mathematica". These methods are documented in
"Writing Your Own Installable Java Classes". You will not use them if you are writing a program that uses
Mathematica 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
MathLink Packets
Communication with the
Mathematica kernel generally takes place in the form of "packets". A
MathLink packet is just a
Mathematica function, albeit one from a set that is recognized and treated specially by
MathLink. When you send something to
Mathematica to be evaluated, you wrap it in a packet that tells
Mathematica 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
Mathematica, 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
MathLink program typically sends a computation to
Mathematica 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
Mathematica warning messages,
DisplayPacket expressions containing PostScript, and several other types.
You can look at existing
MathLink documentation for information on the various packet types for sending things to
Mathematica and for what
Mathematica sends back. In particular, you should look at
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 MathLink "Packet Loop"
In a C
MathLink program, a typical code fragment for sending a computation to
Mathematica and throwing away the result might look like this:
// C code
MLPutFunction(ml, "EvaluatePacket", 1);
MLPutFunction(ml, "ToExpression", 1);
MLPutString(ml, "Needs[\"MyPackage`\"]");
MLEndPacket(ml);
while (MLNextPacket(ml)
RETURNPKT)
MLNewPacket(ml);
MLNewPacket();
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
MLNewPacket once again to discard the
ReturnPacket.
A
MathLink 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:
ml.evaluate("Needs[\"MyPackage`\"]");
ml.discardAnswer();
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
later.
Sending an Evaluation
J/Link provides three main ways to send an expression to
Mathematica 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
MathLink 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
MathLink 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
MathLink C API, so to some extent you can learn how to use them by reading standard
MathLink 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
Mathematica 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. For example:
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
Mathematica 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
Mathematica or if you need to save it to 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
Mathematica 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
MathLink program is a packet-reading loop, which typically consists of calling the
MathLink API functions
MLNextPacket and
MLNewPacket 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():
public boolean packetArrived(PacketArrivedEvent evt) throws MathLinkException;
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:
public PacketPrinter(PrintStream strm);
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
Mathematica messages that were generated during the computation. Using a
PacketPrinter to see exactly what
Mathematica 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
Mathematica to be evaluated, you wrap it in a packet.
Mathematica 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
Mathematica 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
Mathematica 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
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) {
// Mathematica 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
Mathematica, 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
MathLink error occurs. This is in contrast to the
MathLink 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
MathLink 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
MathLink 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
MathLink 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
MathLink error code, which can be looked up in the
MathLink 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"
MathLink 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
MathLink 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
Mathematica will want to produce
Mathematica 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
Mathematica 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 were discussed in
"The MathCanvas and MathGraphicsJPanel Classes" because they are often used from
Mathematica programs. They are just as useful in Java programs. Each is a simple graphical component (a JavaBean, in fact), that can display
Mathematica graphics and typeset expressions.
MathCanvas is a subclass of the AWT
Canvas class, and
MathGraphicsJPanel is a sublcass of the Swing
JPanel class. They are conceptually identical and have the same set of extra methods for dealing with
Mathematica 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
Mathematica code that will be evaluated and have its result displayed. If you are using your
MathCanvas to display
Mathematica 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
Mathematica 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
Mathematica you have. In
Mathematica 6.0 and later, all graphics output requires the front end, so the
setUsesFE() mehod 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 get display
Mathematica 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 is if your image is a bitmap created with some
Mathematica data, or if you have drawn into an offscreen image using the Java graphics API. The
setImage() method was created mainly for use from
Mathematica 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
Mathematica.
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
Mathematica 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\6.0\mathkernel"
(Unix)
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
Mathematica 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
Mathematica to use its default value. The image will be sized to fit within a box of width x 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 later—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 is 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 wellsuited to most
Mathematica 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
Mathematica 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\6.0\mathkernel" "Sqrt[z]" test.gif
(Unix)
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
Mathematica kernel, the second argument is the expression to typeset, and the third argument is the filename 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
MathLink 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:
void abortEvaluation();
void interruptEvaluation()
void abandonEvaluation();
void terminateKernel();
The
abortEvaluation() method will send an abort request to
Mathematica, identical to what happens in the notebook front end when you select .
Mathematica 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
Mathematica, identical to what happens in the notebook front end when you select .
Mathematica 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 is 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
Mathematica, 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
Mathematica. It does this by sending the low-level
MathLink message
MLTERMINATEMESSAGE. 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
Mathematica 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
Mathematica), 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
Mathematica error and warning messages. Instead, they are a special type of communication between two
MathLink 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 they are not discussed in detail. Please note that
messageReady() and
getMessage() no longer function in J/Link 2.0 and later. If you want to be able to receive messages from
Mathematica, you must use
addMessageHandler() and
removeMessageHandler(). There is more information in the JavaDocs for these methods.
Using Marks
MathLink 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
MathLink 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
MathLink that allow a program to conveniently store
Mathematica 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
MathLink, because it has different behavior than a normal one-sided
MathLink. 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.
Already mentioned is a common case where loopback links are convenient—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
Mathematica, 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
MathLink.
// 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
Mathematica expressions in Java. You can guess that this will be useful, since everything in
Mathematica is an expression and
MathLink is all about communicating
Mathematica expressions between programs.
You have several ways of handling
Mathematica expressions in a
MathLink 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
Mathematica 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
Mathematica 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
Mathematica 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
Mathematica 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 API for examining an expression. Consider the task of receiving an arbitrary expression from
Mathematica and determining if its element at position [[2, 3]] (in
Mathematica 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 API. The
Expr class provides a minimal
Mathematica-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
Mathematica 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 to easily 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
Mathematica 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
Mathematica 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
Mathematica,
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
Mathematica-like API for examination and manipulation. The functions are generally named after their
Mathematica 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:
public Expr head();
public Expr[] args();
public int length();
public int[] dimensions();
There are a number of methods whose names end in "Q", following the same naming pattern as in
Mathematica 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
Mathematica, 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
Mathematica error messages you would get if you made the same error in
Mathematica 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
MathLink 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 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 this:
System.out.println("the result was " + ml.getExpr().toString());
instead of the more verbose:
Expr e = ml.getExpr();
System.out.println("the result was " + e.toString());
e.dispose();
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 one:
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:
synchronized (ml) {
ml.evaluate("2+2");
ml.waitForAnswer();
int result = ml.getInteger();
}
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
Mathematica 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.
MathLink has the notion of a "yield function," which is a function you can designate to be called from the internals of
MathLink while
MathLink 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
MathLink 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, for example:
public boolean myYielder();
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 Mathematica
The first part of this User Guide describes how to use
J/Link to allow
Mathematica 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 is probably writing his or her own program to launch and communicate with the
Mathematica kernel, is that you can have a very high-level interaction with
Mathematica. You can send your own objects to
Mathematica and use them in
Mathematica 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
Mathematica kernel and a user of your program calls a
Mathematica function that uses the "installable Java" features of
J/Link and thus calls
InstallJava in
Mathematica.
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
Mathematica 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
Mathematica code to interact with Java objects? You might want to send Java object references to
Mathematica and operate on them with
Mathematica code.
Mathematica "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
Mathematica, 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
Mathematica, and they will arrive as
JavaObject expressions that can be used in
Mathematica code as described throughout "
Calling Java from Mathematica". Recall that the difference between the
put() and
putReference() methods is that
put() sends objects that have meaningful "value" representations in
Mathematica (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
Mathematica, you can also read Java object references that
Mathematica 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.
public Object getObject() throws MathLinkException;
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,
MathLink programmers have worked with the C API, which limits the types of data that can be passed back and forth between C and
Mathematica to
Mathematica expressions. Since
Mathematica 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
Mathematica. As a result, programmers tend to use a simplistic one-way communication with
Mathematica, 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
Mathematica used solely for mathematical computations.
In contrast,
J/Link allows Java and
Mathematica code to collaborate in a high-level way. You can easily code algorithms and other program behavior in
Mathematica if it is easier for you. As an example, say you are writing a Java servlet that needs to use the
Mathematica 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
Mathematica, and send the desired computation for evaluation. But another approach would be simply to
send the HttpServletRequest and HttpServletResponse objects themselves to
Mathematica. You can then use the features and syntax described in "
Calling Java from Mathematica" to code the behavior of the servlet in
Mathematica, 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
Mathematica 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
Mathematica. The behavior of the servlet is written completely in
Mathematica. You can use this approach even if you do not need
Mathematica as a mathematics engine—you might just find it easier to develop and debug your servlet logic in the
Mathematica language. You can draw the line between Java and
Mathematica 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
Mathematica function
DoGet that takes the two Java object arguments and implements the servlet behavior. The syntax is explained in "
Calling Java from Mathematica":
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
Mathematica 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 Mathematica 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
Mathematica 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
Mathematica. 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 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, Unix, 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
Mathematica 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
Mathematica 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
Mathematica 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
Mathematica code. It ignores brackets within strings and within
Mathematica 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
Mathematica code into 4 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
Mathematica 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 from the 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
Mathematica statement:
Then select 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
Mathematica, 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
MathLink 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
Mathematica 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
MathLink 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
Mathematica 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.