The index for the Allegro CL Documentation is in index.htm. The documentation is described in introduction.htm.
This document contains the following sections:
1.0 IntroductionThis document has been updated since its original release with Allegro CL 6.0. New material, also provided in FAQ entry 1.4. (The link assumes the updated faq is in the faq/ subdirectory with respect to this file. If the link does not work, you can find this FAQ on the Franz Inc. home page: http://www.franz.com/.)
The purpose of this tool is to automate the interfacing of Lisp programs to Java class libraries. We have accomplished this goal with the use of remote interfaces supported by a proprietary socket connection.
jLinker allows dynamic, un-pre-mediated access to Java objects and methods from the Lisp runtime environment.
The end result is that the Lisp application may call Java methods as if they were Lisp functions. The documentation of the Java class is all that the Lisp programmer needs to know to use the Java library effectively. For example, the Java statements
java.awt.Canvas canvas = new java.awt.Canvas(); canvas.java.awt.setSize( new java.awt.Dimension(12, 17) );
have the Lisp equivalent
(setf canvas (jnew "java.awt.Canvas")) (jcall "setSize" canvas (jnew "java.awt.Dimension" 12 17))
Remote objects are retained as long as a reference exists in the calling environment. When a Lisp reference to a remote Java object is discarded and garbage collected, a reference to the Java object is eventually eliminated. The retention of the Java object is then controlled by Java rules.
To improve the efficiency of the interface, we allow values returned by methods to be ignored or copied. This prevents the construction of a remote object on the Java side. Ignored values are applicable to values that are already known or irrelevant to the Lisp application. Copied objects are applicable when the Java object is used only for the values of its fields and not for any method invocations.
General callbacks from Java to Lisp are accomplished through
the invokeInLispmethod
in class jLinkerDist.
To facilitate some commonly used callbacks from Java to Lisp
we provide a framework that
includes an object index, lightweight scalar messages, and a dispatcher
on the Lisp side. This framework has been suitable for all the callbacks
used in the java.awt library.
We have tested the concept with several Lisp applications that use the java.awt library for the gui component of the application. The performance of the gui is comparable to a native Java application in most cases. We have demonstrated portability by running the same application on Microsoft Windows NT and Sun Solaris.
Symbols naming Lisp operators and variables associated with jLinker
are in the javatools.jlinker package, which has th
nickname jl
Once the client-server interfaces have been established, Java constructors and methods are called by name.
All the following examples are shown in a :case-sensitive-lower
ACL lisp notation. In a standard (:case-insensitive-upper ACL)
all Java names would need to be enclosed in string quotes.
The form
(jcons java.util.StringTokenizer
java.lang.String java.lang.String)
returns a reference to a constructor, and the form
(jcall (jcons java.util.StringTokenizer
java.lang.String java.lang.String)
"ABC DEF GHI " " ")
returns a reference to an instance created by the constructor. These references are ordinary Lisp objects that may be bound to variables and stored in data structures.
(jcall (jmeth java.util.StringTokenizer countTokens)
x)
The operator lookup functions maintain a cache so that only the first mention of a class, constructor, method or field requires a remote call.
We provide a set of heuristic functions that allow Java constructors and methods to be specified with partial signatures.
We use the following meta notations:
When the operator is a macro:
class-ref -> string or quoted symbol that names a Java class
-> a form (cons) that evaluates to a class reference
method-ref -> a string or quoted symbol that names a Java method member
-> a form (cons) that evaluates to a method reference
When the operator is a function:
class-ref -> an expression that evaluates to a string, a
symbol or a class reference
method-ref -> an expression that evaluates to a string, a
symbol or a method reference
When a definition shows a macro and a function form, the macro form allows compile-time collection of java class names and method signatures. This information is used to generate a file of class and method definitions that may be loaded to initialize an application, and avoid the class and method lookup overhead in the body of the application.
The macro def-java-class can be used to define a Lisp class which corresponds to a Java class.
The macro def-java-constructor allows defining constructor functions to create instances of the classes defined with def-java-class. The macro def-java-method can be used to define methods. def-java-static defines static methods.
This section has been updated since its original release with Allegro CL 6.0. Item 4-11 of the Allegro CL FAQ also has this correction.
All the following classes and methods are defined in Java package
com.franz.jlinker and supplied in the
file jlinker.jar.
public class TranStruct
This class represents remote references passed between Java and Lisp.
All the methods below are defined in class JavaLinkDist.
public static TranStruct newDistOb (boolean x)
...
public static TranStruct newDistOb ( Object x )
These methods are used to create a remote reference to a Java value or object so that it may be passed to Lisp.
There is one method for each primitive
Java type, for int[], for String[],
and for Object.
public static TranStruct nullDistOb ()
This method is needed to create a remote reference to Java null
or to Lisp
nil.
static public boolean nullP (TranStruct str)static public boolean integerP (TranStruct str)static public boolean realP (TranStruct str)static public boolean stringP (TranStruct str)static public boolean errorP (TranStruct str)static public boolean pointerP (TranStruct str)static public int intValue (TranStruct str)static public double doubleValue (TranStruct str)static public char charValue (TranStruct str)static public char charValue (TranStruct str, int j)static public char charValue (TranStruct str, int j, int i)static public String stringValue (TranStruct str)static public String stringValue (TranStruct str, int i)
These predicates and accessors are used to test and extract primitive Java values from remote references. The TranStruct class acts as a tagged wrapper for values passed between Lisp and Java. The predicates determine the type of the primitive data in the wrapper and the other functions are accessors for the value.
Thus, if integerP(x) is true, intValue(x) returns the integer value inside the wrapper. Similarly for realP and stringP.
If pointerP(x) or errorP(x) is true, then stringValue(x) is the symbol-name of the Lisp type of the object.
stringValue(x, 0) is equivalent to stringValue(x) stringValue(x, 1) is defined only when errorP(x) is true in that case, it returns the "~A" representation of the Lisp error. pointerP is true for remote ref objects.
public static TranStruct[] invokeInLisp
( int style, TranStruct op, TranStruct args[] )
public static TranStruct[] invokeInLisp( int style, String op )
public static TranStruct[] invokeInLisp( int style, String op, int arg )
public static TranStruct[] invokeInLisp
( int style, String op, String arg )
This method is used to invoke a lisp function.
The second argument may be a remote reference to a string containing a fully qualified name of a symbol that represents a Lisp function. It may also be a remote reference to a symbol or a function obtained in a previous call to Lisp. The third argument is an array of argument references.
The first argument indicates the style of call:
The array of values represents the list of values returned by the Lisp function.
If the array size is 1, and the array element is an immediate string reference, the Lisp function signalled an error and the string contains a description of the error.
If array element 0 is not an immediate string reference, it is an immediate integer reference, and represents the number of values returned by the Lisp function.
public static void discardInLisp (TranStruct str)
The purpose of this method is to indicate to Java and to Lisp that a remote reference is no longer in use. Any further use of the argument will result in an error signal.
public static boolean query() public static boolean query(boolean verify) public static void disconnect()
The query fuction returns true if the interface is available. The verify argument, if true, requests a round-trip message to Lisp to verify that Lisp is actually there.
public static boolean connect(String j2l, String javaHost, int javaPort,
int pollInterval, int pollCount)
public static boolean connect(String lispHost, int lispPort,
String javaHost, int javaPort,
int pollInterval, int pollCount)
The connect method attempts to connect to a Lisp server. The first form looks for Lisp advertising in the file specified in the j2l argument. The second form attempts to connect to a Lisp server listening at the specified host and port.
If pollInterval is -1, only one attempt is made. Otherwise pollCount attempts are made pollInterval milliseconds apart.
j2l "" -> "JavaToLisp.trp" javaHost "" -> "localhost" javaPort 0 -> system assigned lispHost "" -> "localhost" lispPort 0 -> error, must be >0
public static boolean advertise(String l2j, String host, int port,
int timeoutSeconds)
public static boolean advertise(int port, int timeoutSeconds)
The first form of the advertise method advertises Java in the file JavaToLisp.trp or the one specified in the l2j argument, and waits until Lisp makes a connection. The second form does not write a file, but simply listens at the specified port which must be greater than zero. If timeoutSeconds is -1, wait forever.
public static boolean booleanP(TranStruct); public static boolean boolValue(TranStruct); public static Object objectValue(TranStruct);
If booleanP(x) is true, then boolValue(x) will return the boolean value referenced by x. If pointerP(x) is true and x is reference to a Java object then objectValue(x) is that Java object; if x is a reference to an immediate value, then objectValue(x) is the Java object form of that value; otherwise, x must be a remote reference to an object in Lisp, and x itself is returned.
public class com.franz.jlinker.LispConnector {
public static boolean lispAdvertises = true; // false -> Java advertises
public static boolean advertInFile = false; // true -> advertise in file
public static String lispFile = ""; // use default "JavaToLisp.trp"
public static String lispHost = ""; // use default "localhost"
public static int lispPort = 4321;
public static int pollInterval = 1000;
public static int pollCount = 300;
public static int javaTimeout = -1; // wait for ever
public static String javaFile = ""; // use default "LispToJava.trp"
public static String javaHost = ""; // use default "localhost"
public static int javaPort = 0;
public static boolean debug = true;
}This class implements a generic connection to Lisp. The typical way to use this is to create a subclass that overrides the go method with one that sets the connection variable to appropriate values and then calls the superclass go method.
public static boolean go(boolean verify, String[] throwErr)
This method tests the connection to Lisp.
If the connection succeeds, return true. If the connection fails, the result depends on the value of the throwErr argument.
The functions described in this section are used to setup and query the interface between Lisp and Java.
If the file jlinker.jar is not visible in the current directory, a continuable error is signalled.
The functions and variables are:
*jlinker-connection*:
This anchor variable defines all the parameters for one complete connection
between Lisp and Java.
*jlinker-verbose*:
The value of this variable is the default value for the :verbose keyword argument to
jlinker-init.
When true Lisp emits many status messages while connecting.
*jlinker-debug*: The value of
this variable is the default value for the :debug keyword argument to
jlinker-init.
The following functions and variables are typically defined in the file
jl-config.cl.
They are used when Java is started from Lisp.
The definitions may need to be modified to fit the configuration
of a particular site and Java version.
If Java is not started from Lisp, then these variables and functions
are ignored.
*jlinker-run-java*:
*jlinker-java-home*:
This variable must be set to the home directory of the Java library.
*file-type-comparator*:
The value of this variable should be a function name or function object
of the function used to compare file types.
Many Java classes customize their behavior by allowing the programmer to extend them with custom implementations of selected methods. The java.awt package make extensive use of this facility to handle the events associated with the use of a GUI.
In a distributed computing environment, the question arises of where the custom implementations of the methods should be executed. There is a range of answers to this question and some of the possibilities are discussed in the following sections.
If the custom behavior of an extended method does not require any data from the Lisp side of the application, the method can be implemented in a pure Jave extension of the class in question. The extended method may be linked to the application from Lisp.
----- Java ----------
public class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
};
----- Lisp ----------
(jcall "addWindowListener" frame (jnew "MyWindowAdapter"))
The Java method may also call back to Lisp with
invokeInLisp.
When callback methods follow a common pattern, it may be possible to implement a general function that passes enough information from Java to Lisp through a common interface.
In the case of java.awt events, this is a very reasonable approach, and we have subclassed many of the event handlers to transmit event information to Lisp in a common form where it is dispatched by Lisp functions.
(jcall (jmeth "com.franz.jlinker.JLWindowAdapter" "addTo") frame)
(jregister-handler frame :windowClosing #'(lambda (data frame &rest x)
(jcall "dispose" frame)))
This approach can be extended or modified to handle a wide range of callback situations.
jregister-handler
handler
query-handler
class com.franz.jlinker.JLActionListener implements ActionListener
Methods:
addTo(java.awt.Button)
addTo(java.awt.List)
addTo(java.awt.MenuItem)
addTo(java.awt.TextField)
Handler arguments:
object is argument to addTo
event= :actionPerformed
longs= { event.getModifiers() }
strings= { event.paramString(), event.getActionCommand() }
class com.franz.jlinker.JLComponentAdapter extends ComponentAdapter
Methods:
addTo(java.awt.Component)
Handler arguments:
object is argument to addTo
event= :componentResized :componentMoved
:componentShown :componentHidden
longs= { }
strings= { event.paramString() }
class com.franz.jlinker.JLItemListener implements ItemListener
Methods:
addTo(java.awt.Checkbox)
addTo(java.awt.CheckboxMenuItem)
addTo(java.awt.Choice)
addTo(java.awt.ItemSelectable)
addTo(java.awt.List)
Handler arguments:
object is argument to addTo
event= :itemStateChanged
longs= { (event.getStateChange()==event.SELECTED)?1:0 }
strings= { event.paramString(), (event.getItem()).toString() }
class com.franz.jlinker.JLKeyAdapter extends KeyAdapter
Methods:
addTo(java.awt.Component)
Handler arguments:
object is argument to addTo
event= :keyTyped :keyPressed :keyReleased
longs= { event.getModifiers(), (event.isActionKey()?1:0),
event.getKeyCode() }
strings= { event.paramString() }
class com.franz.jlinker.JLMouseAdapter extends MouseAdapter
Methods:
addTo(java.awt.Component)
Handler arguments:
object is argument to addTo
event= :mouseClicked :mousePressed :mouseReleased
:mouseEntered :mouseExited
longs= { event.getModifiers(), (event.isPopupTrigger()?1:0),
event.getClickCount(), event.getX(), event.getY() }
strings= { event.paramString() }
class com.franz.jlinker.JLMouseMotionAdapter extends MouseMotionAdapter
Methods:
addTo(java.awt.Component)
Handler arguments:
object is argument to addTo
event= :mouseDragged :mouseMoved
longs= { event.getModifiers(), (event.isPopupTrigger()?1:0),
event.getClickCount(), event.getX(), event.getY() }
strings= { event.paramString() }
class com.franz.jlinker.JLWindowAdapter extends WindowAdapter
Methods:
addTo(java.awt.Window)
Handler arguments:
object is argument to addTo
event= :windowOpened :windowClosing :windowClosed
:windowIconified :windowDeiconified
:windowActivated :windowDeactivated
longs= { }
strings= { }
The following code examples show parts of some of the above adapter implementations. The examples illustrate how to add a new event handler that propagates the Java event to the Lisp jregister-handler interface.
When the Java object supplied with the event is also the object registered in Lisp:
package com.franz.jlinker;
import java.awt.*;
import java.awt.event.*;
public class JLKeyAdapter extends KeyAdapter {
// One addTo method is needed for ech argument type.
public static synchronized void addTo( Component comp ) {
comp.addKeyListener( (KeyListener)(new JLKeyAdapter()) );
}
// One event method is needed for each event defined in the
// listener or adapter interface.
public void keyTyped(KeyEvent e) {
int[] l = { e.getModifiers(), (e.isActionKey()?1:0), e.getKeyCode() };
JavaLinkCommon.ltoj_anchor.callLisp
("keyTyped", (Object)(e.getComponent()), e.paramString(), l);
}
}
When the Java object associated with the event is not the object registered in Lisp:
package com.franz.jlinker;
import java.awt.*;
import java.awt.event.*;
public class JLActionListener implements ActionListener {
private Object handle;
// One addTo method is needed for ech argument type.
public static synchronized void addTo( Button comp ) {
JLActionListener l = new JLActionListener();
l.handle = (Object)comp;
comp.addActionListener( (ActionListener)l );
}
// One event method is needed for each event defined in the
// listener or adapter interface.
public void actionPerformed(ActionEvent e) {
String[] s = { e.paramString(), e.getActionCommand() };
int[] l = { e.getModifiers() };
JavaLinkCommon.ltoj_anchor.callLisp
("actionPerformed", handle, s, l);
}
}
Characters are converted to 16-bit positive integers for transmission and then converted back to characters using the following primitive sequences. This should yield consistent results when client and host are on the same machine.
Lisp Java
Start String s s
Extraction c<-(char s i) c<-s.charAt(i)
Conversion n<-(char-code c) n<-(int)c
Transmit 16-bit n 16-bit n
Conversion c<-(code-char n) c<-(char)n
Construction s<-(make-string len) sb<-new StringBuffer(len)
(setf (char s i) c) sb.append(c)
s <-sb.toString()
Result String s s
When calling Lisp from a Java Applet, the normal mode is to advertise in Lisp and use connect() in Java.
NOTE: The behavior of the plain APPLET tag in Netscape is not reliable. The plug-in style of applet activation seems to work without problems. In Netscape this is invoked with the EMBED html tag; in Internet Explorer, the OBJECThtml tag.
When a jLinker application is running as an applet in a browser, the security measures in the browser prevent the use of run-time method lookup in the Lisp application. All methods and constructors must be named with a complete signature in the Lisp code.
The Enterprise Edition of jLinker will include support for Java Servlets. The Java support consists of Java classes that implement communication between a Java HttpServlet and a Lisp image. The Lisp support consists of classes and functions that implement the Lisp side of the interface. We also include examples of simple servlets where the work of the servlet is performed in Lisp.
We will also include Java classes and Lisp code that allow Lisp components to be treated as Java Beans or Enterprise Java Beans.
The code and documentation for these feature will be released later.
One Java VM can support exactly one connection to Lisp (because static variables are used extensively).
If Lisp calls Java then Java may call back to Lisp before returning from the initial call, but a call to Java from the callback will block until the initial call returns. This will typically lead to to a deadlock.
If Java calls Lisp then Lisp may call back to Java, but a call to Lisp from the callback will block until the initial call to Lisp returns. This will typically lead to to a deadlock also.
On the Lisp side, the variable javatools.jlinker::*transport-timeout* may be set to an positive number. This will trigger an error when a call to Java blocks for more than the specified number of seconds. If the number is larger than most reasonable delays in Java, this should detect most deadlock situations in the Lisp code. There is no corresponding timeout feature in Java.
jLinker requires two open socket connections between Lisp and Java:
By default, Lisp listens for a connection from Java and that becomes the connection for calls from Java to Lisp; Java listens for a connection from Lisp and that becomes the connection for calls from Lisp to Java.
It is also possible for Lisp to listen and accept both connections.
Intranet:
Lisp and dedicated Java VM (Lisp starts the JVM)
Lisp and separate Java application
Lisp and applet must use EMBED or OBJECT tag to run Java plugin (APPLET tag signals random errors)
Internet:
The only secure connection is to connect to Lisp from a servlet. Servlet connection to Lisp is an intranet situation.
The other forms of connection will run into firewall problems.
// sample variable settings: String lispFile = ""; String lispHost = ""; int lispPort = 4321; int pollInterval = 1000; int pollCount = 300; int javaTimeout = -1; String javaFile = ""; String javaHost = ""; int javaPort = 0; // use this to emit progress messages in Java com.franz.jlinker.JavaLinkCommon.sdebug = true; Mode-> Lisp Lisp Java Java advertises advertises advertises advertises in file at port in file at port lispFile A1 -- -- -- lispHost -- B2 -- -- lispPort -- C2 -- -- pollInterval D1 D1 -- -- pollCount E1 E1 -- -- javaFile -- -- F3 -- javaHost G1 G1 G3 -- javaPort H1 H1 H3 H4 javaTimeout -- -- I3 I3 Java call: connect(lispFile, javaHost, javaPort, pollInterval, pollCount); -- ignored A1 The pathanme for the file where Lisp advertises host:port "" denotes default value "JavaToLisp.trp" D1 If Lisp advertises, then java will poll every pollInterval milliseconds. If pollInterval<0, look for Lisp exactly once E1 If pollInterval>=0 count down this value and stop polling when negative G1 This is the host name transmitted to Lisp when a connection is made to the advertising Lisp "" denotes the default host "localhost" H1 If this is 0, Java allocates a port and transmits the port number to Lisp If this is >0, Java listens at that port and transmits the port number to Lisp If this is <0, Java assumes the absval is the port number where lisp is listening to connect to the Java server Meanwhile back in Lisp: (jlinker-init :lisp-advertises :lisp-file non-nil [:lisp-host hh :lisp-port pp] [:java-port neg]) Lisp writes the effective host:port into the file Java call: connect(lispHost, lispPort, javaHost, javaPort, pollInterval, pollCount) B2 The hostname where Lisp is advertising C2 The port number where Lisp is advertising Meanwhile back in Lisp: (jlinker-init :lisp-advertises :lisp-file nil :lisp-port non-zero-non-neg [:lisp-host hh]) Java call: advertise(javaFile, javaHost, javaPort, javaTimeout) F3 The pathname for the file where Java advertises host:port "" denotes default value "LispToJava.trp" G3 This is the host name transmitted to Lisp in the advert file "" denotes the default host "localhost" H3 This is the port number transmitted to Lisp in the advert file If this is 0, Java allocates a port and transmits the port number to Lisp If this is >0, Java listens at that port and transmits the port number to Lisp I3 the number of milliseconds that Java will advertise -1 denotes forever Meanwhile back in Lisp: (jlinker-init :java-advertises ...) Java call: advertise(javaPort, javaTimeout) H4 This is the port number where Java will advertise, it must be >0 (since otherwise, Lisp would not know where to listen) I3 the number of milliseconds that Java will advertise -1 denotes forever Meanwhile back in Lisp: (jlinker-init :java-advertises :lisp-file nil [:lisp-host hh :lisp-port pp] :java-file nil :java-host "hh" :java-port pp)
When the interface is to a dedicated Java server, the interface is setup and controlled entirely from the Lisp application.
"jl-config.cl" is visible
and appropriately customized in the application startup directory.
(jlookup :gen-preload).If the jLinker interface is to an independently running Java application, the steps needed to establish the interface need to be modified.
Advertise in (default) file:
Lisp: (jlinker-init :lisp-advertises [:lisp-file path] [:timeout n] ...)
Java: com.franz.jlinker.JavaLinkDist.connect(j2l, "", 0, -1, -1);
Lisp must advertise before Java issues the connect() call; otherwise the connect() call will fail (return false). Lisp advertises the port in the specified file.
To advertise for a limited time, call jlinker-init
with :timeout n where n is the number of seconds to
advertise.
Java: com.franz.jlinker.JavaLinkDist.connect(j2l, "", 0,
pollInterval, pollCount);
Lisp: (jlinker-init :lisp-advertises [:lisp-file path] [:timeout n] ...)
If java makes the call first, then the Java program will keep checking every pollInterval (milliseconds) until Lisp starts or the count runs out.
If Lisp has made the call first, Java will connect immediately.
Java: com.franz.jlinker.JavaLinkDist.advertise(l2j, "", 0, -1)
Lisp: (jlinker-init :java-advertises [:java-file l2j] ...)
Java must make the call first, otherwise, the call to
jlinker-init will fail (return a list).
Java advertises a port number in the given file that defaults
to "LispToJava.trp", or Java may simply advertise at a pre-determined
port known to the Lisp application.
The function jlinker-listen sets up a process that creates a new listener every time Java makes a new connection, so that it is always possible for Java to connect to Lisp, except for a narrow time slots when Lisp is processing a new connection. In this case, the style is always for Lisp to advertise and Java to connect.
When multiple connections are active, the code for each must run in a
separate Lisp process, and in the scope of a separate binding of
*jlinker-connection*.
This section has been updated since its original release with Allegro CL 6.0. Item 4-11 of the Allegro CL FAQ also has this correction.
All the following classes and methods are defined in Java package
com.franz.jlinker and supplied in the
file jlinker.jar.
We include here a complete example of a simple program.
(in-package :user)
;;(set-case-mode :case-sensitive-lower)
(require :jlinker)
(use-package :javatools.jlinker)
(defpackage :javatools.jlinker (:nicknames :jl))
;; Make sure the required files are locally visible
;; customized copy of [Allegro directory]/jlinker/jl-config.cl
;; [Allegro directory]/jlinker/jlinker.jar
(load "jl-config")
(defun new-tokenizer (&optional (string "A B C D ")
(delimiters " "))
(jnew (jcons "java.util.StringTokenizer"
"java.lang.String" "java.lang.String")
string delimiters))
(defun next-token (inst)
(jcall (jmeth "java.util.StringTokenizer" "nextToken")
inst))
(defun run-tokenizer (&optional (string "A B C D ")
(delimiters " "))
(or (jlinker-query) (jlinker-init))
(let ((inst (new-tokenizer string delimiters))
res)
(dotimes (i (jcall (jmeth "java.util.StringTokenizer" "countTokens")
inst))
(push (next-token inst)
res))
(values inst (reverse res))))
------------------- console log: ---------------------
cl-user(4): :ld example
; Loading C:\mmWork\java\fi\java-cur\example.cl
; Loading C:\mmWork\java\fi\java-cur\jl-config.cl
cl-user(5): (run-tokenizer)
; Fast loading from bundle code\acldns.fasl.
#<tran-struct Java IP 1004,118185548 java.util.StringTokenizer>
("A" "B" "C" "D")
;; the following example shows how a Java error
;; is mapped to a Lisp error
cl-user(6): (next-token *)
Error: Java error: java.util.NoSuchElementException
result= "java.util.NoSuchElementException"
Restart actions (select using :continue):
0: Supply another value.
1: Return to Top Level (an "abort" restart)
2: Abort #<process Initial Lisp Listener(6d8)>
[1c] cl-user(7): :pop
cl-user(8):
There are additional code examples in <Allegro directory>/examples/jlinker/*, including:
applet/ examples of Java applets connected to Lisp. javabean/ examples of Java Beans connected to Lisp. servlet/ examples of Java servlets connected to Lisp. timecard/ a complete Lisp application using the Java AWT classes for the user interface.
This section (and its two subsections) has added since its original release with Allegro CL 6.0. Item 4-11 of the Allegro CL FAQ also has this addition.
The jLinker Java Bean API facilitates the creation of Java Bean classes that call Allegro CL functions to do the work of the Java Bean. The jLinker Servlet API facilitates the creation of Java Servlets that call Allegro CL functions to do the work of the Servlet. These features are available only in the Allegro Enterprise edition.
The jLinker Java Bean API facilitates the creation of Java Bean classes that call Allegro CL functions to do the work of the Java Bean. This feature is available only in the Allegro Enterprise edition.
All Lisp symbols are in package :javatools.jlinker.
The example code in examples/jlinker/javabean is described in the file readme.txt.
def-java-to-lisp-wrapper Macro class-name (&key lisp-supers static-slots java-slots lisp-slots java-file if-exists verbose connector) &rest java-methods
This macro generates an output file with Java code that defines a Java class. This macro also generates Lisp code corresponding to the Java class. See examples/jlinker/javabean/bean1gen.cl.
class-name -> name => (name name () :public)
-> (lisp-name java-name (java-super
java-interface ... )
java-flag ... )
lisp-supers -> (lisp-superclass ... )
static-slots -> name => ((name name :type :int :flags
(:public :static)))
-> (slot-name accessor ... )
java-slots -> name => ((name name :type :int :flags
(:public)))
-> (slot-name accessor ... )
slot-name -> (lisp-name java-name JiL-slot-def... )
lisp-slots -> (clos-slot-def ... )
java-file -> path-string OR T OR :none
if-exists -> :supersede OR :append OR nil
connector -> a JiL expression to test connection to Lisp
Default:
("LispConnector.go" |false| |null|)When a def-java-to-lisp-wrapper form is compiled (or evaluated) we write Java code definitions in the specified files. These definitions create Java classes where each method calls the corresponding Lisp function or method.
In the Lisp environment, we create a Lisp class with javatools.jlinker:def-java-class to represent the Java class.
The Lisp functions or methods must be separately defined by the programmer. See the file examples/jlinker/javabean/bean1.cl.
gen-output-lang&optional new Function
Helper function used in connection with def-java-to-lisp-wrapper to determine the language in the generated output file.
new -> :java ;; emit Java code in output file -> :jil ;; emit JiL code in output file -> :none ;; suppress output file -> other ;; ignored
This function always returns two values: the old value and the new setting.
gen-java-stream&optional new if-exists verbose Function
Helper function used in connection with def-java-to-lisp-wrapper to set the output stream used by the macro.
new -> t ;; send output to *standard-output* -> stream ;; send output to the stream -> :none ;; suppress output -> path ;; send output to the file
The if-exists argument is used only when new is a path.
if-exists -> :supersede ;; delete an existing file ;; and create a new file -> :append ;; add to an existing file ;; or create a new file -> otherwise ;; signal an error if the file exists
If the verbose argument is non-nil, emit a message when the output stream changes.
The jLinker Servlet API facilitates the creation of Java Servlets that call Allegro CL functions to do the work of the Servlet. This feature is available only in the Allegro Enterprise edition.
All Lisp symbols are in package :javatools.jlinker.
Java signatures are taken from "Java Servlet API Specification - Version 2.1a - November 1998" from Sun Microsystems at http://java.sun.com/products/servlet/.
The example code in examples/jlinker/servlet is described in the file readme.txt.
servlet Class
This is the superclass of all the Lisp implementation classes that support the servlet interface.
Slots: instances This is a class slot that keeps track of the number of instances of the class. instance An instance slot that identifies each instance uniquely. java-classes A list of strings naming Java classes that may invoke this Lisp class. Access from other Java classes causes an error signal.
new-servlet lisp-class-name servlet-ref config-ref Function
This function is called from the Java servlet init() method. The lisp-class-name argument must be a string containing a fully qualified class name and the class must be a sub-class of http-servlet.
destroy (self servlet) Method
This method is called from the Java servlet destroy() method. The pre-defined primary method discards any locally cached information and any remote references.
get-servlet-config (self servlet) Method
Returns the ServletConfig reference saved from the call to init()
get-servlet-info (self servlet) Method
Retrieve from Java a reference to the ServletInfo object.
http-servlet Class
A subclass of servlet. This is the Lisp counterpart to the Java class LispHttpServlet.
This class implements dummy methods for all the Java methods in the Java class HttpServlet. User code should subclass this class and override any method definitions that are actually used by the application. The subclass must also define a value for java-classes slot.
do-delete (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-get (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-head (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-options (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-post (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-put (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
do-trace (self http-servlet) request response Method
The default implementation simply prints a message and returns to Java. The user is free to implement any desired behavior in a method defined on a subclass.
async-http-servlet Class multi-async-http-servlet Class
These are classes that should be subclassed by the application. The subclass defines working methods for the above generic functions. The subclass also defines a value for the java-classes slot.
start-work (self async-http-servlet) work request response gate Method
This method is called from all the methods of the Java class LispAsyncHttpServlet. The work argument is the name of one of the work methods defined above.
The request and response arguments are remote references to the request and response arguments of the Java method. The gate argument is a remote reference to an array Object[2] used by the Java method as a gate to determine when the work for a particular request is completed.
This method queues the work into a common queue where all requests from servlets are saved. The queue is emptied by a single Lisp process.
start-work (self multi-async-http-servlet) work request response gate Method
This method starts a new Lisp process for each request that arrives. The process is discarded when the request is completed.
public void init(ServletConfig config) Java Method
The Java method invokes the Lisp function new-servlet to propagate this method call.
public void service(...) Java Method
Handled by the Java super-class implementation.
public void destroy() Java Method
The Java method calls the Lisp destroy method.
protected void doDelete(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-delete method.
protected void doGet(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-get method.
protected void doHead(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-head method.
protected void doOptions(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-options method.
protected void doPost(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-post method.
protected void doPut(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-put method.
protected void doTrace(HttpServletRequest request, Java Method
HttpServletResponse response)
throws ServletException;
The Java method calls the Lisp do-trace method.
public static Object[] newGate() Java Method
Return a new closed gate.
public static void testGate(Object[] gate) Java Method
Wait for gate to open and return a String x.
x.length()=0 if operation completed x.length()>0 if error or failure, string contains message
public static Object[] lispValues Java Method
(res, called, min, max, firstRefP)
Utility function called by the sample implementations of LispHttpServlet and LispAsyncHttpServlet to decode the result array returned from a call to Lisp.
res - result array returned from Lisp called - the name of the Lisp function called min - the minimum number of expected values max - the maximum number of expected values firstRefP - first returned value should be a remote reference to a Lisp object
returned value is an array Object[2] where the first element is an Integer return code and the second element a String error message.
Copyright (c) 1998-2000, Franz Inc. Berkeley, CA., USA. All rights reserved. Created 2000.10.5.