Advanced J/Link Programming

Todd Gayley
Wolfram Research

Periodical Tasks

The introduction of the ShareKernel function in J/Link allowed another type of operation that doesn't really have anything directly to do with Java--the ability to have the kernel execute tasks periodically while it is idle.

Making Mathematica into a Background Web Server

Here's a little fun with a periodical task.

$ServerSocket = JavaNew["java.net.ServerSocket", 7000];

HTTPServer[] :=
	JavaBlock[
		Module[{sock, is, os, buf, numRead, input},
			$ServerSocket@setSoTimeout[200];
			Off[Java::excptn];
			sock = $ServerSocket@accept[];
			On[Java::excptn];
			If[JavaObjectQ[sock],
				is = sock@getInputStream[];
				buf = JavaNew["[B", 2000];
				(* Read the incoming HTTP GET request: *)
				numRead = is@read[buf];
				input = FromCharacterCode[Take[Val[buf], numRead]];
				(* Extract the part of the URL that specifies the computation to be performed: *)
				input = StringTake[input,
							{First[Flatten[StringPosition[input, "?"]]] + 1,
							 First[Flatten[StringPosition[input, "HTTP"]]] - 1}
						];
				os = sock@getOutputStream[];
				(* Write the output header: *)
				os@write[ToCharacterCode["HTTP/1.0 200 OK\n\n"]];
				(* Write the result: *)
				os@write[ToCharacterCode["<pre>"]];
				os@write[ToCharacterCode[ToString[ToExpression[input]]]];
				sock@close[]
			];
		]
	]

Now we set up the kernel to check for incoming HTTP requests once every second:

AddPeriodical[HTTPServer[], 1]

To use the web server we just set up, point your browser at a URL such as http://localhost:7000?Expand[x-y)^12]

Everything after the ? is treated as Mathematica input to evaluate.

To prove that the web server is running in the same kernel session as the notebook, point your browser at http://localhost:7000?x=123, then evaluate x in the notebook.

Note that this is truly a toy program. It does not handle URLs that have been encoded to allow special characters such as spaces in the expression, it would probably need to be tweaked if you were behind a firewall, and it has many other shortcomings (notably security!). It is presented only to give you an idea of some of the things that can be done in just a few lines of Mathematica code.

Sending Java Object References to Mathematica

The ability to program with Java objects in Mathematica code is useful even when you are writing Java programs that call Mathematica.

To enable this capability, you must first call this KernelLink method:

ml.enableObjectReferences();

Calling putReference(), or put() on an object that will be sent as a reference, will not work correctly until after enableObjectReferences() is called.

This capability is used by webMathematica, which sends several Java objects to the Mathematica kernel during each MSP page evaluation (e.g., the ServletRequest and ServletResponse objects).

When you approach a programming problem, ask yourself if it would be simplified by sending Java objects to, and receiving Java objects from, Mathematica.

The Expr Class

J/Link includes a class called Expr, which represents an arbitrary Mathematica expression.

It is often more convenient to read an expression off a link as an Expr and inspect it using the Expr methods than to inspect it as it arrives by calling getType(), etc.

Some representative Expr methods:

public Expr head();
	public synchronized Expr[] args();
	public int length();
	public int[] dimensions();
	
	public Expr part(int i);
	
	public boolean stringQ();
	public boolean symbolQ();
	public boolean listQ();
	public boolean vectorQ(int type);

	public Expr take(int n);
	public Expr delete(int n);
	public Expr insert(Expr e, int n);
	
	public String toString();

One very common use of Expr is to print out the expression that is waiting on the link without consuming it from the link:

System.out.println(ml.peekExpr().toString());

PacketPrinter for Debugging

J/Link lets you "hook into" the packet loop to observe the flow of packets that arrive. It does this via the PacketListener interface.

J/Link comes with one implementation of PacketListener called PacketPrinter. It simply prints the contents of each packet to a stream of your choice (defaults to System.out).

Using a PacketPrinter is a trivial yet powerful and often overlooked aid in debugging. It is a sure-fire cure to the dreaded "MLGet out of sequence" exception.

Just add the following line to your program:

ml.addPacketListener(new PacketPrinter());

You can also write your own implementation of PacketListener. The nice thing about a PacketListener is that you don't have to worry about the state of the link. You can read all, some, or none of any packet without affecting J/Link (or any other installed PacketListener) in any way.

Some Tips on Being a Polite J/Link Developer

Call InstallJava[] at the start of significant functions that require Java to be running.

Don't call UninstallJava[] in code you release to others. It is only for use in development (for example, if you want to reload a modified class you must shut down and restart Java).

Use JavaBlock and/or ReleaseObject to prevent unneeded Java object references from being kept around. But, don't bother with this during development--only as you prepare your code for use by others.

Always save tokens returned from ShareKernel and ShareFrontEnd and pass them to the respective UnshareXXX functions. Just because your app is done with sharing doesn't mean your user is.

Use the correct directory structure for your application so that users don't need to fiddle with their CLASSPATH to run your program.

New Features in J/Link 1.2

Speed Improvements

In previous versions, a significant cost in non-static method calls was resolving the method name in its appropriate Mathematica context before dispatching to Java for execution. This overhead has been eliminated through caching. The optimizations MethodFunction and FieldFunction, which were meant to address this problem, are now mostly obsolete.

The rate at which method calls can be made into Java went up by almost a factor of two with this change.

ImplementInterface

There is now a means to implement a Java interface entirely in Mathematica code. This is made possible by the new Dynamic Proxy feature in Java 1.3 and later.

Among other uses, this means that you can create any "listener"-type object in Mathematica without requiring a Java MathXXXHandler class to already exist for that interface.

For example, J/Link does not provide a MathListener class for the Swing MenuListener. Here is how you could create such a class at dynamically at runtime. No Java code needed:

myMenuListener =
	ImplementInterface["javax.swing.event.MenuListener",
						{"menuCanceled" -> "menuCanceledHandler",
						 "menuSelected -> "menuSelectedHandler",
						 "menuDeselected" -> "menuDeselectedHandler"}
	];
myMenu@addMenuListener[myMenuListener];
(* Now, define the handler functions.... *)

ShowJavaConsole

On Windows, InstallJava used to make a DOS window appear and then minimize. This was distracting but sometimes useful because it was the Java console window (where output sent to System.out and System.err would appear).

This behavior was eliminated, making InstallJava invisible to the user. A new function, ShowJavaConsole, was added to display console output in a portable way.

ShowJavaConsole[]

JavaBlock

If a JavaBlock returns a Java object, it will not be released. This allows a useful programming idiom wherein a function does some work to create and return a Java object but wants all the objects created during the process to be treated as temporary and released.

It also supports a new option, KeepObjects.

At the end of the following JavaBlock, obj1 and obj2 will not be released:

JavaBlock[
	...
	obj1 = JavaNew["some.class"];
	...
	obj2 = obj1@someMethodThatReturnsAnObject[];
	...
	obj3 = obj1@someOtherMethodThatReturnsAnObject[];
	...
	obj1, KeepObjects->{obj2}
]

Good J/Link programs clean up all object references they create. You will see careful use of JavaBlock in all the J/Link example programs in the JLink\Examples\Part1 directory.

SetInternetProxy

The SetInternetProxy function is provided for users who need to access the internet via a proxy server. Most Windows and Macintosh users do not need it, as Java uses the browser settings on these platforms.

SetInternetProxy["machinename", portNumber]

MathSessionPane

J/Link 1.2 includes a new component called MathSessionPane that implements a complete In/Out window. It is a bit like the kernel's terminal interface, except that it has many more features. It is intended for developers who want a quick way to embed a direct interface to the Mathematica kernel into their programs. It could also be used as the foundation for a reasonably sophisticated front end to Mathematica.

import com.wolfram.jlink.MathLinkException;
import com.wolfram.jlink.ui.*;
import java.awt.*;
import java.awt.event.*;

public class MathSessionPaneExample {    

    public static void main(String[] argv) {
 		
 		final MathSessionPane msp = new MathSessionPane();
 
 		// Create the frame window to hold the pane.
 		Frame frm = new Frame();
 		frm.setSize(500, 500);
 		frm.setLayout(new BorderLayout());
 		frm.add(msp, "CENTER");
		frm.add(msp);
 		frm.doLayout();
 		frm.setVisible(true);
 		
 		// This causes the link to be closed when the Frame is closed.
 		frm.addWindowListener(new WindowAdapter() {
 			public void windowClosing(WindowEvent e) {
 				msp.closeLink();
 				System.exit(0);
 			}
 		});
 		
 		// Modify this for your setup.
 		msp.setLinkArguments("-linkmode launch -linkname d:/math412/mathkernel");
 		try {
 			msp.connect();
 		} catch (MathLinkException e) {
 			e.printStackTrace();
 		}
 	}
}

MathSessionPane is very customizable and extensible via properties. Some examples:

Syntax coloring on/off
ShowTiming panel on/off
Font faces, sizes, colors for In/Out/Prompts/Messages

J/Link in the Future

.NET/Link   !!??