--- /dev/null
+BUILDING A SIMPLE HTTP-TO-Z3950 GATEWAY USING YAZ4J AND TOMCAT
+==============================================================
+
+[Yaz4J](http://www.indexdata.com/yaz4j) is a wrapper library over the
+client-specific parts of YAZ, a C-based Z39.50 toolkit, and allows you to use
+the ZOOM API directly from Java.
+[ZOOM](http://zoom.z3950.org/api/zoom-1.4.html) is a relatively straightforward
+API and with a few lines of code you can write a basic application that can
+establish connection to a Z39.50 server.
+Here we will try to build a very simple HTTP-to-Z3950 gateway using yaz4j and
+the Java Servlet technology.
+
+## COMPILING AND INSTALLING YAZ4J
+
+Yaz4j is still an experimental piece of software and as such is not distributed
+via Index Data's public Debian apt repository and there is no Windows installer
+either. While it is possible to use the pre-built Linux binaries, users of
+other OSes will have compile yaz4j from source. No need to worry (yet) - the
+process of compiling yaz4j is quite simple and we will be up and running in no
+time :). The source code can be checked-out out from our
+[Git repository](http://git.indexdata.com/?p=yaz4j.git;a=summary), and assuming
+you have Git installed on your machine you can do that with:
+
+ git clone git://git.indexdata.com/yaz4j
+
+The compilation of both native and Java source code is controlled by Maven2,
+to build the library, invoke the following commands:
+
+ cd yaz4j
+ mvn install
+
+That's it. If the build has completed successfully you end up with two files:
+os-independent jar archive with Java ZOOM API classes
+(yaz4j/any/target/yaz4j-any-VERSION.jar) and os-dependent shared library
+(yaz4j/linux/target/libyaz4j.so or yaz4j/win32/target/yaz4j.dll) that contains
+all necessary JNI "glue" to make the native calls possible from Java. If we were
+writing a command line Java application, like any other external Java library,
+yaz4j-any-VERSION.jar would have to be placed on your application classpath
+and the native, shared library would have to be added to your system shared
+library path (LD_LIBRARY_PATH on linux, PATH on Windows) or specified as a
+Java system property (namely the java.library.path) just before your
+application is executed:
+
+ java -cp /path/to/yaz4j-*.jar -Djava.library.path=/path/to/libyaz4j.so MyApp
+
+## SETTING UP THE DEVELOPMENT ENVIRONMENT
+
+Setting up a development/runtime environment for a web (servlet) application is
+a bit more complicated. First, you are not invoking the JVM directly, but the
+servlet container (e.g Tomcat) run-script is doing that for you. At this
+point the shared library (so or dll) has to be placed on the servlet container's
+shared libraries load path. Unless your library is deployed to the standard
+system location for shared libs (/usr/lib on Linux) or it's location is already
+added to the path, the easiest way to do this in Tomcat is by editing
+(create it if it does not exist) the CATALINA_HOME/bin/setenv.sh (setenv.bat on
+Windows) script and putting the following lines in there:
+
+ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libyaz4j.so
+ export LD_LIBRARY_PATH
+
+on Windows
+
+ set PATH=%PATH;X:\path\to\yaz4j.dll
+
+That's one way of doing it, another would be to alter the standard set of
+arguments passed to the JVM before the Tomcat starts and add
+-Djava.library.path=/path/to/lib there. Depending on a situation this might be
+preferable/easier (on Debian/Ubuntu you can specify JVM arguments using
+/etc/default/tomcat6).
+
+With the shared library installed we need to install the pure-Java yaz4j-any*jar
+with ZOOM API classes by placing it in Tomcat's `lib` directory
+(CATALINA_HOME/lib). As this library makes the Java System call to load the
+native library into the JVM you cannot simply package it along with your web
+application (inside the .war file) - it would try to load the library each time
+you deploy the webapp and all consecutive deployments would fail.
+
+## WRITING A SERVLET-BASED GATEWAY
+
+With your servlet environment set up all that is left is to write the actual
+application (peanuts :)). At IndexData we use Maven for managing builds of our
+Java software components but Maven is also a great tool for quickly starting up
+a project. To generate a skeleton for our webapp use the Maven archetype plugin:
+
+ mvn -DarchetypeVersion=1.0.1 -Darchetype.interactive=false -DarchetypeArtifactId=webapp-jee5 -DarchetypeGroupId=org.codehaus.mojo.archetypes -Dpackage=com.indexdata.zgate -DgroupId=com.indexdata -DartifactId=zgate archetype:generate --batch-mode
+
+This will generate a basic webapp project structure:
+
+|-- pom.xml
+`-- src
+|-- main
+| |-- java
+| | `-- com
+| | `-- indexdata
+| | `-- zgate
+| `-- webapp
+| |-- WEB-INF
+| | `-- web.xml
+| `-- index.jsp
+`-- test
+ `-- java
+ `-- com
+ `-- indexdata
+ `-- zgate
+
+Maven has already added basic JEE APIs for web development as the project
+dependencies, we need to do the same for yaz4j, so edit the `pom.xml` and
+add the following lines in the `dependencies` section:
+
+<dependency>
+ <groupId>org.yaz4j</groupId>
+ <artifactId>yaz4j-any</artifactId>
+ <version>VERSION</version>
+ <scope>provided</scope>
+</dependency>
+
+It's crucial that the scope of this dependency is set to `provided` otherwise
+the library would end up packaged in the .war archive and we don't want that.
+
+The implementation of our simple gateway will be contained in a single servlet -
+`ZGateServlet` - which we need to place under `src/main/webapp/com/indexdata/zgate.`
+The gateway will work by answering HTTP GET requests and will be controlled
+solely by HTTP parameters, the servlet doGet method is shown below:
+
+protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String zurl = request.getParameter("zurl");
+ if (zurl == null || zurl.isEmpty()) { response.sendError(400, "Missing parameter 'zurl'"); return; }
+
+ String query = request.getParameter("query");
+ if (query == null || query.isEmpty()) { response.sendError(400, "Missing parameter 'query'"); return; }
+
+ String syntax = request.getParameter("syntax");
+ if (syntax == null || syntax.isEmpty()) { response.sendError(400, "Missing parameter 'syntax'"); return; }
+
+ int maxrecs=10;
+ if (request.getParameter("maxrecs") != null && !request.getParameter("maxrecs").isEmpty()) {
+ try {
+ maxrecs = Integer.parseInt(request.getParameter("maxrecs"));
+ } catch (NumberFormatException nfe) {
+ response.sendError(400, "Malformed parameter 'maxrecs'");
+ return;
+ }
+ }
+
+ response.getWriter().println("SEARCH PARAMETERS");
+ response.getWriter().println("zurl: " + zurl);
+ response.getWriter().println("query: " + query);
+ response.getWriter().println("syntax: " + syntax);
+ response.getWriter().println("maxrecs: " + maxrecs);
+ response.getWriter().println();
+
+ Connection con = new Connection(zurl, 0);
+ con.setSyntax(syntax);
+ try {
+ con.connect();
+ ResultSet set = con.search(query, Connection.QueryType.PrefixQuery);
+ response.getWriter().println("Showing " + maxrecs + " of " +set.getSize());
+ response.getWriter().println();
+ for(int i=0; i<set.getSize() && i<maxrecs; i++) {
+ Record rec = set.getRecord(i);
+ response.getWriter().print(rec.render());
+ }
+ } catch (ZoomException ze) {
+ throw new ServletException(ze);
+ } finally {
+ con.close();
+ }
+ }
+
+
+With the code in-place we can try to compile the project:
+
+ mvn compile
+
+If all is OK, the next step is to register our servlet and map it to an URL in
+src/main/webapp/WEB-INF/web.xml:
+
+<servlet>
+ <servlet-name>ZgateServlet</servlet-name>
+ <servlet-class>com.indexdata.zgate.ZgateServlet</servlet-class>
+</servlet>
+<servlet-mapping>
+ <servlet-name>ZgateServlet</servlet-name>
+ <url-pattern>/zgate</url-pattern>
+</servlet-mapping>
+
+On top of that, we will also make sure that our servlet is automatically
+triggered when accessing the root path of our application:
+
+<welcome-file-list>
+ <welcome-file>zgate</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+</welcome-file-list>
+
+Now we are ready to build our webapp:
+
+ mvn package
+
+The resulting .war archive is located under `target/zgate.war`, we can deploy
+it on tomcat (e.g by using the /admin Tomcat admin console) and test by issuing
+the follwoing request with your browser or curl
+(assuming Tomcat is running on localhost:8080):
+
+ http://localhost:8080/zgate/?zurl=z3950.loc.gov:7090/voyager&query=@attr%201=7%200253333490&syntax=usmarc
+
+
+That's it! You just build yourself a HTTP-to-Z3950 gateway! Just be careful
+with exposing it to the outside world - it's not very secure and could be easily
+exploited. The source code for the gateway's Maven project is attached. Also,
+IndexData is working on a Debian/Ubuntu package (and maybe even a Windows
+installer :)) and the installation of yaz4j and Tomcat configuration will be
+greatly simplified - so stay tuned!