Using Qexo, you can run an XQuery program as a Servlet. This makes it easy to have them be executed by a web server.
See this article for a simpler how-to for deploying a servlet.
Suppose the file hello.xql
contains an XQuery "program".
(Below we show an example of what you can do with Kawa-XQuery servlets.)
You compile hello.xql
to servlet using the following command.
$KAWA --xquery --servlet -C hello.xqlHere
$KAWA
is how you invoke the Kawa application.
For example if you use kawa-1.7.jar
, you can do:
java -jar kawa-1.7.jar --xquery --servlet -C hello.xql
The -C
flag tells Kawa to compile the following source
files. The --xquery
flags tells Kawa that the source files are
in the XQuery language. (The default language is Scheme.) The
--servlet
tells Kawa to generate a servlet.
The result of the compilation is usually a single class file
hello.class
that implements
javax.servlet.http.HttpServlet
.
Sometimes Kawa will need to generate some extra helper classes;
these will all have the form hello$XXX.class
.
To copy or install all the generated classes you should
type hello*.class
.
There are a number of Web servers that can run servlets,
and most of them have various fancy ways of creating "web applications".
Here are some simple instructions for running your servlet
under Tomcat.
Tomcat is a web server
written in Java and released by the Apache Foundation's Jakarta project.
The instructions here assume version 4.0 of Tomcat,
and that $CATALINA_HOME
is where Tomcat is installed.
You first need to install the Kawa jar file
kawa-1.7.jar
somewhere where Tomcat can find it.
For example install it in $CATALINA_HOME/lib/kawa-1.7.jar
.
You next need to install your servlet.
In Tomcat (and the Servlet specification) a servlet is part of a
"web application". If you call your application myutils
,
you need to create directories $CATALINA_HOME/webapps/myutils
,
$CATALINA_HOME/webapps/myutils/WEB-INF
, and
$CATALINA_HOME/webapps/myutils/WEB-INF/classes
.
You then copy your servlet class files hello*.class
into the latter directory.
After you have started up Tomcat, it by default listens to port 8080.
To try out your servlet, point a browser to the URL
http://localhost:8080/myutils/servlet/hello
.
See the Tomcat documentation for how you can customize how Tomcat maps URLs to servlets and how they are executed.
cgi-wrapper
program that lets you
run servlets
as if they were CGI scripts.
There are also useful functions for getting
HTTP request
information,
setting HTTP
response headers,
and the unescaped-data
function for raw HTMP/XML output..
This example generates a response listing some of the properties of the request. An explanation follows.
define function invoke-row ($field,$style) { <tr><td>{$field}</td><td><{$style}>{invoke($request,$field)}</></td></tr>} define function do-invoke ($field,$style) { invoke-row($field,$style)," " } <p>Hello, the request was {$request}. The response was {$response}.</p>, <pre>The request URI was (using path) {$request/requestURI}. The request method (using path) was {$request/method}. The path-info (using path) was {$request/pathInfo}</pre>, <table> <tr><th>Field name (using invoke)</th><th>field value</th></tr> {do-invoke("getRequestURI","strong"), do-invoke("getContentType","code"), do-invoke("getProtocol","u"), do-invoke("getRemoteAddr","code"), do-invoke("getRemoteHost","code"), do-invoke("getScheme","code"), do-invoke("getServerName","code"), do-invoke("getServerPort","code"), do-invoke("getAuthType","code"), do-invoke("getMethod","code"), do-invoke("getPathInfo","code"), do-invoke("getPathTranslated","code"), do-invoke("getQueryString","code"), do-invoke("getRemoteUser","code"), do-invoke("getRequestURI","code"), do-invoke("getServletPath","code") }</table>
This program illustrates how you can use the prefined variables
$request
and $response
. The former is
the most useful, as it contains the information that the browser
sent to the servlet. The $response
variable has more
exotic uses for controlling the response.
Both variables are passed to the servlet by the servlet engine,
and have the types javax.servlet.http.HttpRequest
and javax.servlet.http.HttpResponse
respectively.
The program first defines the function invoke-row
, which takes
two parameters, in addition to the implicit $request
parameter.
The body of the function is an "element constructor expression"
which contructs a table row (<tr>
) element.
This looks like plain HTML (actually XML), but you can nest arbitrary
expressions in them using curly braces to "escape" nested expressions.
The $field
parameter is a string that names a 0-argument
Java method of the $request
object.
The built-in Kawa method invoke
takes an object, a
Java method name, and optionally some methods args. It calls the named
method with the given arguments.
The result from invoke
is wrapped in an HTML style
tag that is specified by the $style
parameter.
The result is made into a table row.
The do-invoke
function is just a simple wrapper that calls
invoke-row
. It then appends a newline using the
comma operator, which concatenates the operands to create a sequence.
In this case the result is a sequence with two values:
a <tr>
element node, and a newline string.
This effecticely adds a newline in the HTML after the
<tr>
element, which makes the HTML more readable.
The other reason for adding the do-invoke
function
is to illustrate how you can pass complex values around, with the
result of one function being "pasted" into the result of another.
Note that the Kawa implementation does not actually do any
copying in this case; the elements are written directly into the
servlet result buffer.
The main body of the function is two "element constructor expressions",
the pre
and the table
constuctors,
which again are concatenated using the comma operator, resuling in
a sequence consisting of two elements.
The pre
element contaisn the nested
expression $request/requestURI
. This is a convenience
feature of Kawa-XQuery. It means to extract the requestURI
"property" of the $request
object.
A property name like "requestURI"
is mapped into a
method name "getRequestURI"
, and basically the
expression $request/requestURI
is equivalent to
invoke(request, "getRequestURI")
.
The final part of the program just makes a lot of calls to
do-invoke
to build a big <table>
.
The Kawa servlet wrapper automatically wraps the entire result
in a <html>...</html>
wrapper.
You can see a sample of the generated output,
using the URL http://localhost:8080/myutils/servlet/hello/mypath
.
The Qexo debugging page has some general
notes on Qexo error behaviour and debugging.
Here are some notes specific to using servlets and
KawaPageServlet
.
If you request an .xql
after editing it,
KawaPageServlet
will automatically re-compile it.
This makes it easy to test out changes.
If you make a syntax error, the result sent to the browser
will contain the error messages from the compiler.
If a run-time errors causes an uncaught run-time exception, Tomcat will
return to your browser a stack trace showing which methods were active when
the exception was created.
The methods that
Tomcat re-directs the standard error output
to the file KawaPageServlet
compiles
from your XQuery program will be in that stack trace with
(if you're lucky) line numbers
referring to the lines in your XQuery program.
You may have to dig through the stack trace, and ignore methods belonging
to the Kawa or Tomcat run-time environment. You may also have to
look for the root cause.
$CATALINA_HOME/logs/catalina.out
.
This includes data written using the standard trace
function.
Per Bothner
Last modified: Wed Dec 1 16:40:47 PST 2004