fix documentation about SRU client support MP-572
[metaproxy-moved-to-github.git] / doc / book.xml
index d0e4cb2..8c308b1 100644 (file)
-<!-- $Id: book.xml,v 1.3 2006-03-27 14:18:23 adam Exp $ -->
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+    "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
+[
+     <!ENTITY copyright SYSTEM "copyright.xml">
+     <!ENTITY % local SYSTEM "local.ent">
+     %local;
+     <!ENTITY manref SYSTEM "manref.xml">
+     <!ENTITY gpl2 SYSTEM "gpl-2.0.xml">
+     <!ENTITY % idcommon SYSTEM "common/common.ent">
+     %idcommon;
+]>
+<book>
  <bookinfo>
   <title>Metaproxy - User's Guide and Reference</title>
-  <author>
-   <firstname>Mike</firstname><surname>Taylor</surname>
-  </author>
- <author>
-  <firstname>Adam</firstname><surname>Dickmeiss</surname>
- </author>
- <copyright>
-  <year>2006</year>
-  <holder>Index Data</holder>
- </copyright>
+  <authorgroup>
+   <author>
+    <firstname>Adam</firstname><surname>Dickmeiss</surname>
+   </author>
+   <author>
+    <firstname>Marc</firstname><surname>Cromme</surname>
+   </author>
+   <author>
+    <firstname>Mike</firstname><surname>Taylor</surname>
+   </author>
+  </authorgroup>
+  <releaseinfo>&version;</releaseinfo>
+  <copyright>
+   <year>2005-2014</year>
+   <holder>Index Data</holder>
+  </copyright>
   <abstract>
    <simpara>
-    Metaproxy - mangler of Z39.50/SRU operations.
+    This manual is part of Metaproxy version &version;.
+    </simpara>
+   <simpara>
+    Metaproxy is a universal router, proxy and encapsulated
+    metasearcher for information retrieval protocols.  It accepts,
+    processes, interprets and redirects requests from IR clients using
+    standard protocols such as the binary
+    <ulink url="&url.z39.50;">ANSI/NISO Z39.50</ulink>
+    and  the information search and retrieval
+    web service <ulink url="&url.sru;">SRU</ulink>
+    as well as functioning as a limited
+    <ulink url="&url.http;">HTTP</ulink> server.
+   </simpara>
+   <simpara>
+    Metaproxy is configured by an XML file which
+    specifies how the software should function in terms of routes that
+    the request packets can take through the proxy, each step on a
+    route being an instantiation of a filter.  Filters come in many
+    types, one for each operation: accepting Z39.50 packets, logging,
+    query transformation, multiplexing, etc.  Further filter-types can
+    be added as loadable modules to extend Metaproxy functionality,
+    using the filter API.
+   </simpara>
+   <simpara>
+    Metaproxy is covered by the GNU General Public License version 2.
+   </simpara>
+   <simpara>
+    <inlinemediaobject>
+     <imageobject>
+      <imagedata fileref="common/id.png" format="PNG"/>
+     </imageobject>
+     <imageobject>
+      <imagedata fileref="common/id.eps" format="EPS"/>
+     </imageobject>
+    </inlinemediaobject>
    </simpara>
   </abstract>
  </bookinfo>
+
  <chapter id="introduction">
   <title>Introduction</title>
-  
-  
-  <section>
-   <title>Overview</title>
+
+  <para>
+   <ulink url="&url.metaproxy;">Metaproxy</ulink>
+   is a stand alone program that acts as a universal router, proxy and
+   encapsulated metasearcher for information retrieval protocols such
+   as <ulink url="&url.z39.50;">Z39.50</ulink> and
+   <ulink url="&url.sru;">SRU</ulink>.
+   To clients, it acts as a server of these protocols: it can be searched,
+   records can be retrieved from it, etc.
+   To servers, it acts as a client: it searches in them,
+   retrieves records from them, etc.  it satisfies its clients'
+   requests by transforming them, multiplexing them, forwarding them
+   on to zero or more servers, merging the results, transforming
+   them, and delivering them back to the client.  In addition, it
+   acts as a simple <ulink url="&url.http;">HTTP</ulink> server; support
+   for further protocols can be added in a modular fashion, through the
+   creation of new filters.
+  </para>
+  <screen>
+   Anything goes in!
+   Anything goes out!
+   Fish, bananas, cold pyjamas,
+   Mutton, beef and trout!
+       - attributed to Cole Porter.
+  </screen>
+  <para>
+   Metaproxy is a more capable alternative to
+   <ulink url="&url.yazproxy;">YAZ Proxy</ulink>,
+   being more powerful, flexible, configurable and extensible.  Among
+   its many advantages over the older, more pedestrian work are
+   support for multiplexing (encapsulated metasearching), routing by
+   database name, authentication and authorization and serving local
+   files via HTTP.  Equally significant, its modular architecture
+   facilitites the creation of pluggable modules implementing further
+   functionality.
+  </para>
+  <para>
+   This manual will describe how to install Metaproxy
+   before giving an overview of its architecture, then discussing the
+   key concept of a filter in some depth and giving an overview of
+   the various filter types, then discussing the configuration file
+   format.  After this come several optional chapters which may be
+   freely skipped: a detailed discussion of virtual databases and
+   multi-database searching, some notes on writing extensions
+   (additional filter types) and a high-level description of the
+   source code.  Finally comes the reference guide, which contains
+   instructions for invoking the <command>metaproxy</command>
+   program, and detailed information on each type of filter,
+   including examples.
+  </para>
+ </chapter>
+
+ <chapter id="installation">
+  <title>Installation</title>
+  <para>
+   Metaproxy depends on the following tools/libraries:
+   <variablelist>
+    <varlistentry><term><ulink url="&url.yazplusplus;">YAZ++</ulink></term>
+     <listitem>
+      <para>
+       This is a C++ library based on <ulink url="&url.yaz;">YAZ</ulink>.
+      </para>
+     </listitem>
+    </varlistentry>
+    <varlistentry><term><ulink url="&url.libxslt;">Libxslt</ulink></term>
+     <listitem>
+      <para>This is an XSLT processor - based on
+       <ulink url="&url.libxml2;">Libxml2</ulink>. Both Libxml2 and
+       Libxslt must be installed with the development components
+       (header files, etc.) as well as the run-time libraries.
+      </para>
+     </listitem>
+    </varlistentry>
+    <varlistentry><term><ulink url="&url.boost;">Boost</ulink></term>
+     <listitem>
+      <para>
+       The popular C++ library. Initial versions of Metaproxy
+       was built with 1.32 but this is no longer supported.
+       Metaproxy is known to work with Boost version 1.33 through 1.55.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+  <para>
+   In order to compile Metaproxy a modern C++ compiler is
+   required. Boost, in particular, requires the C++ compiler
+   to facilitate the newest features. Refer to Boost
+   <ulink url="&url.boost.compilers.status;">Compiler Status</ulink>
+   for more information.
+  </para>
+  <para>
+   We have successfully built Metaproxy using the compilers
+   <ulink url="&url.gcc;">GCC</ulink> version 4.0 and
+   <ulink url="&url.vstudio;">Microsoft Visual Studio</ulink> 2003/2005/2008.
+  </para>
+
+  <para>
+   As an option, Metaproxy may also be compiled with
+   <ulink url="&url.usemarcon;">USEMARCON</ulink> support which allows for
+   MARC conversions for the <xref linkend="ref-record_transform"/> filter.
+  </para>
+  <section id="installation.unix">
+   <title>Installation on Unix (from Source)</title>
+   <para>
+    Here is a quick step-by-step guide on how to compile all the
+    tools that Metaproxy uses. Only few systems have none of the required
+    tools binary packages. If, for example, Libxml2/libxslt are already
+    installed as development packages use those (and omit compilation).
+   </para>
+
+   <note>
+    <para>
+     <ulink url="&url.usemarcon;">USEMARCON</ulink> is not available
+     as a package at the moment, so Metaproxy must be built from source
+     if that is to be used.
+    </para>
+   </note>
+
+   <section id="libxml2.fromsource">
+    <title>Libxml2/libxslt</title>
+    <para>
+     Libxml2/libxslt:
+    </para>
+    <screen>
+     gunzip -c libxml2-version.tar.gz|tar xf -
+     cd libxml2-version
+     ./configure
+     make
+     su
+     make install
+    </screen>
+    <screen>
+     gunzip -c libxslt-version.tar.gz|tar xf -
+     cd libxslt-version
+     ./configure
+     make
+     su
+     make install
+    </screen>
+   </section>
+   <section id="usemarcon">
+    <title>USEMARCON (optional)</title>
+    <screen>
+     gunzip -c usemarcon317.tar.gz|tar xf -
+     cd usemarcon317
+     ./configure
+     make
+     su
+     make install
+    </screen>
+   </section>
+
+   <section id="yaz.fromsource">
+    <title>YAZ/YAZ++</title>
+    <screen>
+     gunzip -c yaz-version.tar.gz|tar xf -
+     cd yaz-version
+     ./configure
+     make
+     su
+     make install
+    </screen>
+    <screen>
+     gunzip -c yazpp-version.tar.gz|tar xf -
+     cd yazpp-version
+     ./configure
+     make
+     su
+     make install
+    </screen>
+   </section>
+   <section>
+    <title id="boost.fromsource">Boost</title>
+    <para>
+     Metaproxy needs components thread and test from
+     Boost.
+    </para>
+    <screen>
+     gunzip -c boost-version.tar.gz|tar xf -
+     cd boost-version
+     ./configure --with-libraries=thread,test,regex --with-toolset=gcc
+     make
+     su
+     make install
+    </screen>
+    <para>
+     However, under the hood bjam is used. You can invoke that with
+    </para>
+    <screen>
+     ./bjam --toolset=gcc --with-thread --with-test --with-regex stage
+    </screen>
+    <para>
+     Replace <literal>stage</literal> with <literal>clean</literal> /
+     <literal>install</literal> to perform clean and install respectively.
+    </para>
+    <para>
+     Add <literal>--prefix=DIR</literal> to install Boost in other
+     prefix than <literal>/usr/local</literal>.
+    </para>
+   </section>
+   <section id="metaproxy.fromsource">
+    <title>Metaproxy</title>
+    <screen>
+     gunzip -c metaproxy-version.tar.gz|tar xf -
+     cd metaproxy-version
+     ./configure
+     make
+     su
+     make install
+    </screen>
+    <para>
+     You may have to tell configure where Boost is installed by supplying
+     options <literal>--with-boost</literal> and <literal>--with-boost-toolset</literal>.
+     The former sets the PREFIX for Boost (same as --prefix for Boost above).
+     The latter the compiler toolset (eg. gcc34).
+    </para>
+    <para>
+     Pass <literal>--help</literal> to configure to get a list of
+     available options.
+    </para>
+   </section>
+  </section>
+
+  <section id="installation.debian">
+   <title>Installation on Debian GNU/Linux</title>
+   <para>
+    All dependencies for Metaproxy are available as
+    <ulink url="&url.debian;">Debian</ulink> packages.
+   </para>
+   <para>
+    The procedures for Debian based systems, such as
+    <ulink url="&url.ubuntu;">Ubuntu</ulink> is probably similar
+   </para>
+   <para>
+    There is currently no official Debian package for YAZ++.
+    And the official Debian package for YAZ is probably too old.
+    But Index Data builds "new" versions of those for Debian (i386, amd64 only).
+   </para>
+   <para>
+    Update the <filename>/etc/apt/sources.list</filename>
+    to include the Index Data repository.
+    See YAZ' <ulink url="&url.yaz.download.debian;">Download Debian</ulink>
+    for more information.
+   </para>
+   <screen>
+    apt-get install libxslt1-dev
+    apt-get install libyazpp6-dev
+    apt-get install libboost-dev
+    apt-get install libboost-system-dev
+    apt-get install libboost-thread-dev
+    apt-get install libboost-test-dev
+    apt-get install libboost-regex-dev
+   </screen>
+   <para>
+    With these packages installed, the usual configure + make
+    procedure can be used for Metaproxy as outlined in
+    <xref linkend="installation.unix"/>.
+   </para>
+  </section>
+
+  <section id="installation.rpm">
+   <title>Installation on RPM based Linux Systems</title>
+   <para>
+    All external dependencies for Metaproxy are available as
+    RPM packages, either from your distribution site, or from the
+    <ulink url="http://fr.rpmfind.net/">RPMfind</ulink> site.
+   </para>
+   <para>
+    For example, an installation of the requires Boost C++ development
+    libraries on RedHat Fedora C4 and C5 can be done like this:
+    <screen>
+    wget ftp://fr.rpmfind.net/wlinux/fedora/core/updates/testing/4/SRPMS/boost-1.33.0-3.fc4.src.rpm
+    sudo rpmbuild --buildroot src/ --rebuild -p fc4/boost-1.33.0-3.fc4.src.rpm
+    sudo rpm -U /usr/src/redhat/RPMS/i386/boost-*rpm
+    </screen>
+   </para>
+   <para>
+    The  <ulink url="&url.yaz;">YAZ</ulink> library is needed to
+    compile &metaproxy;, see there
+    for more information on available RPM packages.
+   </para>
    <para>
-    <ulink url="http://indexdata.dk/metaproxy/">Metaproxy</ulink>
-    is ..
+    There is currently no official RPM package for YAZ++.
+    See the <ulink url="&url.yazplusplus;">YAZ++</ulink> pages
+    for more information on a Unix tarball install.
    </para>
    <para>
-    ### We should probably consider saying a little more by way of
-    introduction.
+    With these packages installed, the usual configure + make
+    procedure can be used for Metaproxy as outlined in
+    <xref linkend="installation.unix"/>.
    </para>
   </section>
+
+  <section id="installation.windows">
+   <title>Installation on Windows</title>
+   <para>
+    Metaproxy can be compiled with Microsoft
+    <ulink url="&url.vstudio;">Visual Studio</ulink>.
+    Versions 2003 (C 7.1), 2005 (C 8.0) and 2008 (C 9.0) are known to work.
+   </para>
+   <section id="installation.windows.boost">
+    <title>Boost</title>
+    <para>
+     For Windows, it's easiest to get the precompiled Boost
+     package from <ulink url="&url.boost.windows.download;">here</ulink>.
+     Several versions of the Boost libraries may be selected when
+     installing Boost for windows. Please choose at least the
+     <emphasis>multithreaded</emphasis> (non-DLL) version because
+     the Metaproxy makefile uses that.
+    </para>
+    <para>
+     For more information about installing Boost refer to the
+     <ulink url="&url.boost.getting.started;">getting started</ulink>
+     pages.
+    </para>
+   </section>
+
+   <section id="installation.windows.libxslt">
+    <title>Libxslt</title>
+    <para>
+     <ulink url="&url.libxslt;">Libxslt</ulink> can be downloaded
+     for Windows from
+     <ulink url="&url.libxml2.download.win32;">here</ulink>.
+    </para>
+    <para>
+     Libxslt has other dependencies, but these can all be downloaded
+     from the same site. Get the following package:
+     iconv, zlib, libxml2, libxslt.
+    </para>
+   </section>
+
+   <section id="installation.windows.yaz">
+    <title>YAZ</title>
+    <para>
+     <ulink url="&url.yaz;">YAZ</ulink> can be downloaded
+     for Windows from
+     <ulink url="&url.yaz.download.win32;">here</ulink>.
+    </para>
+   </section>
+
+   <section id="installation.windows.yazplusplus">
+    <title>YAZ++</title>
+    <para>
+     Get <ulink url="&url.yazplusplus;">YAZ++</ulink> as well.
+     Version 1.5.2 or later is required.
+    </para>
+    <para>
+     YAZ++ includes NMAKE makefiles, similar to those found in the
+     YAZ package.
+    </para>
+   </section>
+
+   <section id="installation.windows.metaproxy">
+    <title>Metaproxy</title>
+    <para>
+     Metaproxy is shipped with NMAKE makefiles as well - similar
+     to those found in the YAZ++/YAZ packages. Adjust this Makefile
+     to point to the proper locations of Boost, Libxslt, Libxml2,
+     zlib, iconv, yaz and yazpp.
+    </para>
+
+    <variablelist>
+     <varlistentry><term><literal>DEBUG</literal></term>
+      <listitem><para>
+       If set to 1, the software is
+       compiled with debugging libraries (code generation is
+       multi-threaded debug DLL).
+       If set to 0, the software is compiled with release libraries
+       (code generation is multi-threaded DLL).
+       </para></listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>BOOST</literal></term>
+      <listitem>
+       <para>
+       Boost install location
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>BOOST_VERSION</literal></term>
+      <listitem>
+       <para>
+       Boost version (replace . with _).
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>BOOST_TOOLSET</literal></term>
+      <listitem>
+       <para>
+       Boost toolset.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>LIBXSLT_DIR</literal>,
+       <literal>LIBXML2_DIR</literal> ..</term>
+      <listitem>
+       <para>
+       Specify the locations of Libxslt, libiconv, libxml2 and
+       libxslt.
+       </para>
+      </listitem>
+     </varlistentry>
+
+    </variablelist>
+
+    <para>
+     After successful compilation you'll find
+     <literal>metaproxy.exe</literal> in the
+     <literal>bin</literal> directory.
+    </para>
+   </section>
+
+
+  </section>
  </chapter>
+
+<chapter id="yazproxy-comparison">
+ <title>YAZ Proxy Comparison</title>
+ <para>
+  The table below lists facilities either supported by either
+   <ulink url="&url.yazproxy;">YAZ Proxy</ulink> or Metaproxy.
+ </para>
+<table id="yazproxy-comparison-table">
+ <title>Metaproxy / YAZ Proxy comparison</title>
+ <tgroup cols="3">
+  <thead>
+   <row>
+    <entry>Facility</entry>
+    <entry>Metaproxy</entry>
+    <entry>YAZ Proxy</entry>
+   </row>
+  </thead>
+  <tbody>
+   <row>
+    <entry>Z39.50 server</entry>
+    <entry>Using filter <xref linkend="ref-frontend_net"/></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>SRU server</entry>
+    <entry>Supported with filter <xref linkend="ref-sru_z3950"/></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Z39.50 client</entry>
+    <entry>Supported with filter <xref linkend="ref-z3950_client"/></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>SRU client</entry>
+    <entry>Supported with filter <xref linkend="ref-zoom"/></entry>
+    <entry>Unsupported</entry>
+   </row>
+   <row>
+    <entry>Connection reuse</entry>
+    <entry>Supported with filter <literal>session_shared</literal></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Connection share</entry>
+    <entry>Supported with filter <literal>session_shared</literal></entry>
+    <entry>Unsupported</entry>
+   </row>
+   <row>
+    <entry>Result set reuse</entry>
+    <entry>Supported with filter <literal>session_shared</literal></entry>
+    <entry>Within one Z39.50 session / HTTP keep-alive</entry>
+   </row>
+   <row>
+    <entry>Record cache</entry>
+    <entry>Supported by filter <literal>session_shared</literal></entry>
+    <entry>Supported for last result set within one Z39.50/HTTP-keep alive session</entry>
+   </row>
+   <row>
+    <entry>Z39.50 Virtual database, i.e. select any Z39.50 target for database</entry>
+    <entry>Supported with filter <literal>virt_db</literal></entry>
+    <entry>Unsupported</entry>
+   </row>
+   <row>
+    <entry>SRU Virtual database, i.e. select any Z39.50 target for path</entry>
+    <entry>Supported with filter <literal>virt_db</literal>,
+     <literal>sru_z3950</literal></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Multi target search</entry>
+    <entry>Supported with filter <literal>multi</literal> (round-robin)</entry>
+    <entry>Unsupported</entry>
+   </row>
+   <row>
+    <entry>Retrieval and search limits</entry>
+    <entry>Supported using filter <literal>limit</literal></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Bandwidth limits</entry>
+    <entry>Supported using filter <literal>limit</literal></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Connect limits</entry>
+    <entry>Supported by filter <literal>frontend_net</literal> (connect-max)</entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Retrieval sanity check and conversions</entry>
+    <entry>Supported using filter <literal>record_transform</literal></entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Query check</entry>
+    <entry>
+      Supported by <literal>query_rewrite</literal> which may be check
+      a query and throw diagnostics (errors)
+    </entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Query rewrite</entry>
+    <entry>Supported with <literal>query_rewrite</literal></entry>
+    <entry>Unsupported</entry>
+   </row>
+   <row>
+    <entry>Session invalidate for -1 hits</entry>
+    <entry>Unsupported</entry>
+    <entry>Supported</entry>
+   </row>
+   <row>
+    <entry>Architecture</entry>
+    <entry>Multi-threaded + select for networked modules such as
+      <literal>frontend_net</literal>)</entry>
+    <entry>Single-threaded using select</entry>
+   </row>
+
+   <row>
+    <entry>Extensability</entry>
+    <entry>Most functionality implemented as loadable modules</entry>
+    <entry>Unsupported and experimental</entry>
+   </row>
+
+   <row>
+    <entry><ulink url="&url.usemarcon;">USEMARCON</ulink></entry>
+    <entry>Supported with <literal>record_transform</literal></entry>
+    <entry>Supported</entry>
+   </row>
+
+   <row>
+    <entry>Portability</entry>
+    <entry>
+     Requires YAZ, YAZ++ and modern C++ compiler supporting
+     <ulink url="&url.boost;">Boost</ulink>.
+    </entry>
+    <entry>
+     Requires YAZ and YAZ++.
+     STL is not required so pretty much any C++ compiler out there should work.
+    </entry>
+   </row>
+
+  </tbody>
+ </tgroup>
+</table>
+</chapter>
+
+ <chapter id="architecture">
+  <title>The Metaproxy Architecture</title>
+  <para>
+   The Metaproxy architecture is based on three concepts:
+   the <emphasis>package</emphasis>,
+   the <emphasis>route</emphasis>
+   and the <emphasis>filter</emphasis>.
+  </para>
+  <variablelist>
+   <varlistentry>
+    <term>Packages</term>
+    <listitem>
+     <para>
+      A package is request or response, encoded in some protocol,
+      issued by a client, making its way through Metaproxy, send to or
+      received from a server, or sent back to the client.
+     </para>
+     <para>
+      The core of a package is the protocol unit - for example, a
+      Z39.50 Init Request or Search Response, or an SRU searchRetrieve
+      URL or Explain Response.  In addition to this core, a package
+      also carries some extra information added and used by Metaproxy
+      itself.
+     </para>
+     <para>
+      In general, packages are doctored as they pass through
+      Metaproxy.  For example, when the proxy performs authentication
+      and authorization on a Z39.50 Init request, it removes the
+      authentication credentials from the package so that they are not
+      passed onto the back-end server; and when search-response
+      packages are obtained from multiple servers, they are merged
+      into a single unified package that makes its way back to the
+      client.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>Routes</term>
+    <listitem>
+     <para>
+      Packages make their way through routes, which can be thought of
+      as programs that operate on the package data-type.  Each
+      incoming package initially makes its way through a default
+      route, but may be switched to a different route based on various
+      considerations.  Routes are made up of sequences of filters (see
+      below).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>Filters</term>
+    <listitem>
+     <para>
+      Filters provide the individual instructions within a route, and
+      effect the necessary transformations on packages.  A particular
+      configuration of Metaproxy is essentially a set of filters,
+      described by configuration details and arranged in order in one
+      or more routes.  There are many kinds of filter - about a dozen
+      at the time of writing with more appearing all the time - each
+      performing a specific function and configured by different
+      information.
+     </para>
+     <para>
+      The word ``filter'' is sometimes used rather loosely, in two
+      different ways: it may be used to mean a particular
+      <emphasis>type</emphasis> of filter, as when we speak of ``the
+      auth_simple filter'' or ``the multi filter''; or it may be used
+      to be a specific <emphasis>instance</emphasis> of a filter
+      within a Metaproxy configuration.  For example, a single
+      configuration will often contain multiple instances of the
+      <literal>z3950_client</literal> filter.  In
+      operational terms, of these is a separate filter.  In practice,
+      context always make it clear which sense of the word ``filter''
+      is being used.
+     </para>
+     <para>
+      Extensibility of Metaproxy is primarily through the creation of
+      plugins that provide new filters.  The filter API is small and
+      conceptually simple, but there are many details to master.  See
+      the section below on
+      <link linkend="filters">Filters</link>.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+  <para>
+   Since packages are created and handled by the system itself, and
+   routes are conceptually simple, most of the remainder of this
+   document concentrates on filters.  After a brief overview of the
+   filter types follows, along with some thoughts on possible future
+   directions.
+  </para>
+ </chapter>
+
 
 
  <chapter id="filters">
   <title>Filters</title>
-  
-  
-  <section>
+
+
+  <section id="filters-introductory-notes">
    <title>Introductory notes</title>
    <para>
     It's useful to think of Metaproxy as an interpreter providing a small
     complex data type, namely the ``package''.
    </para>
    <para>
-    A package represents a Z39.50 or SRW/U request (whether for Init,
+    A package represents a Z39.50 or SRU/W request (whether for Init,
     Search, Scan, etc.)  together with information about where it came
     from.  Packages are created by front-end filters such as
     <literal>frontend_net</literal> (see below), which reads them from
    </para>
    <para>
     There are many kinds of filter: some that are defined statically
-    as part of Metaproxy, and other that may be provided by third parties
+    as part of Metaproxy, and others may be provided by third parties
     and dynamically loaded.  They all conform to the same simple API
     of essentially two methods: <function>configure()</function> is
-    called at startup time, and is passed a DOM tree representing that
+    called at startup time, and is passed an XML DOM tree representing that
     part of the configuration file that pertains to this filter
     instance: it is expected to walk that tree extracting relevant
     information; and <function>process()</function> is called every
     packages
     (<literal>frontend_net</literal>);
     others are sinks: they consume packages and return a result
-    (<literal>z3950_client</literal>,
-    <literal>backend_test</literal>,
-    <literal>http_file</literal>);
+    (<literal>backend_test</literal>,
+    <literal>bounce</literal>,
+    <literal>http_file</literal>,
+    <literal>z3950_client</literal>);
     the others are true filters, that read, process and pass on the
     packages they are fed
     (<literal>auth_simple</literal>,
     <literal>log</literal>,
     <literal>multi</literal>,
+    <literal>query_rewrite</literal>,
+    <literal>record_transform</literal>,
     <literal>session_shared</literal>,
+    <literal>sru_z3950</literal>,
     <literal>template</literal>,
     <literal>virt_db</literal>).
    </para>
  </section>
-  
-  
-  <section>
-   <title>Individual filters</title>
+
+
+  <section id="overview.filter.types">
+   <title>Overview of filter types</title>
+   <para>
+    We now briefly consider each of the types of filter supported by
+    the core Metaproxy binary.  This overview is intended to give a
+    flavor of the available functionality; more detailed information
+    about each type of filter is included below in
+    <xref linkend="reference"/>.
+   </para>
    <para>
     The filters are here named by the string that is used as the
     <literal>type</literal> attribute of a
     <literal>&lt;filter&gt;</literal> element in the configuration
     file to request them, with the name of the class that implements
-    them in parentheses.
+    them in parentheses.  (The classname is not needed for normal
+    configuration and use of Metaproxy; it is useful only to
+    developers.)
    </para>
-   
-   <section>
+   <para>
+    The filters are here listed in alphabetical order:
+   </para>
+
+<!--
+
+### New filters:
+
+New virt_db-alike that does inteligent peer choice, explain merging,
+adds FD&N to explain.  Keeps init responses (like "virt_db Classic"),
+makes routing choices based on local explain knowledge.  Ref IDDI
+paper.
+
+Filter to convert Explain Classic to ZeeRex.
+
+CQL2PQF (which needs augmented ZeeRex) - MARC for Talis.
+
+SRU2Z39.50 (ditto).
+
+Figure out what additional information we need in:
+       ZeeRex (check against D3.1)
+       Init request (e.g. loop detection)
+       Query package (e.g. number of hops)
+       Query response (e.g. record source)
+
+-->
+
+   <section id="auth_simple">
     <title><literal>auth_simple</literal>
      (mp::filter::AuthSimple)</title>
     <para>
-     Simple authentication and authorisation.  The configuration
+     Simple authentication and authorization.  The configuration
      specifies the name of a file that is the user register, which
      lists <varname>username</varname>:<varname>password</varname>
      pairs, one per line, colon separated. When a session begins, it
      is rejected unless username and passsword are supplied, and match
-     a pair in the register.
-    </para>
-    <para>
-     ### discuss authorisation phase
+     a pair in the register.  The configuration file may also specific
+     the name of another file that is the target register: this lists
+     lists <varname>username</varname>:<varname>dbname</varname>,<varname>dbname</varname>...
+     sets, one per line, with multiple database names separated by
+     commas.  When a search is processed, it is rejected unless the
+     database to be searched is one of those listed as available to
+     the user.
     </para>
    </section>
-   
-   <section>
+
+   <section id="backend_test">
     <title><literal>backend_test</literal>
     (mp::filter::Backend_test)</title>
     <para>
-     A sink that provides dummy responses in the manner of the
+     A partial sink that provides dummy responses in the manner of the
      <literal>yaz-ztest</literal> Z39.50 server.  This is useful only
-     for testing.
+     for testing.  Seriously, you don't need this.  Pretend you didn't
+     even read this section.
     </para>
    </section>
-   
-   <section>
+
+   <section id="bounce">
+    <title><literal>bounce</literal>
+    (mp::filter::Bounce)</title>
+    <para>
+     A sink that swallows <emphasis>all packages</emphasis>,
+     and returns them almost unprocessed.
+     It never sends any package of any type further down the row, but
+     sets Z39.50 packages to Z_Close, and HTTP_Request packages to
+     HTTP_Response err code 400 packages, and adds a suitable bounce
+     message.
+     The bounce filter is usually added at end of each filter chain route
+     to prevent infinite hanging of for example HTTP
+     requests packages when only the Z39.50 client partial sink
+     filter is found in the
+     route.
+    </para>
+   </section>
+
+   <section id="cql_rpn">
+    <title><literal>cql_rpn</literal>
+    (mp::filter::CQLtoRPN)</title>
+    <para>
+     A query language transforming filter which catches Z39.50
+     <literal>searchRequest</literal>
+     packages containing <literal>CQL</literal> queries, transforms
+     those to <literal>RPN</literal> queries,
+     and sends the <literal>searchRequests</literal> on to the next
+     filters. It is among other things useful in a SRU context.
+    </para>
+   </section>
+
+   <section id="frontend_net">
     <title><literal>frontend_net</literal>
      (mp::filter::FrontendNet)</title>
     <para>
-     A source that accepts Z39.50 and SRW connections from a port
+     A source that accepts Z39.50 connections from a port
      specified in the configuration, reads protocol units, and
-     feeds them into the next filter, eventually returning the
-     result to the origin.
+     feeds them into the next filter in the route.  When the result is
+     received, it is returned to the original origin.
     </para>
    </section>
 
-   <section>
+   <section id="http_file">
     <title><literal>http_file</literal>
      (mp::filter::HttpFile)</title>
     <para>
-     A sink that returns the contents of files from the local
-     filesystem in response to HTTP requests.  (Yes, Virginia, this
+     A partial sink which swallows only
+     <literal>HTTP_Request</literal> packages, and
+     returns the contents of files from the local
+     filesystem in response to HTTP requests.
+     It lets Z39.50 packages and all other forthcoming package types
+     pass untouched.
+     (Yes, Virginia, this
      does mean that Metaproxy is also a Web-server in its spare time.  So
      far it does not contain either an email-reader or a Lisp
      interpreter, but that day is surely coming.)
     </para>
    </section>
-   
-   <section>
+
+   <section id="load_balance">
+    <title><literal>load_balance</literal>
+     (mp::filter::LoadBalance)</title>
+    <para>
+     Performs load balancing for incoming Z39.50 init requests.
+     It is used together with the <literal>virt_db</literal> filter,
+     but unlike the <literal>multi</literal> filter it does send an
+     entire session to only one of the virtual backends. The
+     <literal>load_balance</literal> filter is assuming that
+     all backend targets have equal content, and chooses the backend
+     with least load cost for a new session.
+    <warning>
+     <para>
+      This filter is experimental and yet not mature for heavy load
+      production sites.
+     </para>
+    </warning>
+   </para>
+   </section>
+
+   <section id="log">
     <title><literal>log</literal>
      (mp::filter::Log)</title>
     <para>
      Writes logging information to standard output, and passes on
-     the package unchanged.
+     the package unchanged. A log file name can be specified, as well
+     as multiple different logging formats.
    </para>
    </section>
-   
-   <section>
+
+   <section id="multi">
    <title><literal>multi</literal>
      (mp::filter::Multi)</title>
     <para>
-     Performs multicast searching.  See the extended discussion of
-     multi-database searching below.
+     Performs multi-database searching.
+     See
+     <link linkend="multidb">the extended discussion</link>
+     of virtual databases and multi-database searching below.
     </para>
    </section>
-   
-   <section>
+
+   <section id="query_rewrite">
+   <title><literal>query_rewrite</literal>
+     (mp::filter::QueryRewrite)</title>
+    <para>
+     Rewrites Z39.50 <literal>Type-1</literal>
+     and <literal>Type-101</literal> (``<literal>RPN</literal>'')
+     queries by a
+     three-step process: the query is transliterated from Z39.50
+     packet structures into an XML representation; that XML
+     representation is transformed by an XSLT stylesheet; and the
+     resulting XML is transliterated back into the Z39.50 packet
+     structure.
+    </para>
+   </section>
+
+
+   <section id="record_transform">
+    <title><literal>record_transform</literal>
+    (mp::filter::RecordTransform)</title>
+    <para>
+     This filter acts only on Z3950 present requests, and let all
+     other types of packages and requests pass untouched. It's use is
+     twofold: blocking Z3950  present requests, which the backend
+     server does not understand and can not honor, and transforming
+     the present syntax and elementset name according to the rules
+     specified, to fetch only existing record formats, and transform
+     them on the fly to requested record syntaxes.
+    </para>
+   </section>
+
+   <section id="session_shared">
     <title><literal>session_shared</literal>
      (mp::filter::SessionShared)</title>
     <para>
-     When this is finished, it will implement global sharing of
+     This filter implements global sharing of
      result sets (i.e. between threads and therefore between
-     clients), but it's not yet done.
+     clients), yielding performance improvements by clever resource
+     pooling.
     </para>
    </section>
-   
-   <section>
+
+   <section id="sru_z3950">
+    <title><literal>sru_z3950</literal>
+    (mp::filter::SRUtoZ3950)</title>
+    <para>
+     This filter transforms valid
+     SRU GET/POST/SOAP searchRetrieve requests to Z3950 init, search,
+     and present requests, and wraps the
+     received hit counts and XML records into suitable SRU response
+     messages.
+     The <literal>sru_z3950</literal> filter  processes also  SRU
+     GET/POST/SOAP explain requests, returning
+     either the absolute minimum required by the standard, or a  full
+     pre-defined ZeeReX explain record.
+     See the
+     <ulink url="&url.zeerex.explain;">ZeeReX Explain</ulink>
+     standard pages and the
+     <ulink url="&url.sru.explain;">SRU Explain</ulink> pages
+     for more information on the correct explain syntax.
+     SRU scan requests are not supported yet.
+    </para>
+   </section>
+
+   <section id="template">
     <title><literal>template</literal>
      (mp::filter::Template)</title>
     <para>
      should be called <literal>nop</literal> or
      <literal>passthrough</literal>?)  This exists not to be used, but
      to be copied - to become the skeleton of new filters as they are
-     written.
+     written.  As with <literal>backend_test</literal>, this is not
+     intended for civilians.
     </para>
    </section>
-   
-   <section>
+
+   <section id="virt_db">
     <title><literal>virt_db</literal>
-     (mp::filter::Virt_db)</title>
+     (mp::filter::VirtualDB)</title>
     <para>
-     Performs virtual database selection.  See the extended discussion
-     of virtual databases below.
+     Performs virtual database selection: based on the name of the
+     database in the search request, a server is selected, and its
+     address added to the request in a <literal>VAL_PROXY</literal>
+     otherInfo packet.  It will subsequently be used by a
+     <literal>z3950_client</literal> filter.
+     See
+     <link linkend="multidb">the extended discussion</link>
+     of virtual databases and multi-database searching below.
     </para>
    </section>
-   
-   <section>
+
+   <section id="z3950_client">
     <title><literal>z3950_client</literal>
      (mp::filter::Z3950Client)</title>
     <para>
-     Performs Z39.50 searching and retrieval by proxying the
+     A partial sink which swallows only Z39.50 packages.
+     It performs Z39.50 searching and retrieval by proxying the
      packages that are passed to it.  Init requests are sent to the
      address specified in the <literal>VAL_PROXY</literal> otherInfo
      attached to the request: this may have been specified by client,
      or generated by a <literal>virt_db</literal> filter earlier in
      the route.  Subsequent requests are sent to the same address,
      which is remembered at Init time in a Session object.
+     HTTP_Request packages and all other forthcoming package types
+     are passed untouched.
     </para>
   </section>
+
+
+   <section id="zeerex_explain">
+    <title><literal>zeerex_explain</literal>
+     (mp::filter::ZeerexExplain)</title>
+    <para>
+     This filter acts as a sink for
+     Z39.50 explain requests, returning a static ZeeReX
+     Explain XML record from the config section. All other packages
+     are passed through.
+     See the
+     <ulink url="&url.zeerex.explain;">ZeeReX Explain</ulink>
+     standard pages
+     for more information on the correct explain syntax.
+    </para>
+    <warning>
+     <para>
+      This filter is not yet completed.
+     </para>
+    </warning>
+   </section>
+
+
   </section>
-  
-  
-  <section>
+
+
+  <section id="future.directions">
    <title>Future directions</title>
   <para>
     Some other filters that do not yet exist, but which would be
     useful, are briefly described.  These may be added in future
-    releases.
+    releases (or may be created by third parties, as loadable
+    modules).
    </para>
 
    <variablelist>
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><literal>srw2z3950</literal> (filter)</term>
-     <listitem>
-      <para>
-       Translate SRW requests into Z39.50 requests.
-     </para>
-     </listitem>
-    </varlistentry>
-    <varlistentry>
-     <term><literal>srw_client</literal> (sink)</term>
-     <listitem>
-      <para>
-       SRW searching and retrieval.
-      </para>
-     </listitem>
-    </varlistentry>
-    <varlistentry>
      <term><literal>sru_client</literal> (sink)</term>
      <listitem>
       <para>
-       SRU searching and retrieval.
+       SRU/GET and SRU/SOAP searching and retrieval.
       </para>
      </listitem>
     </varlistentry>
    </variablelist>
   </section>
  </chapter>
+
+
+
  <chapter id="configuration">
   <title>Configuration: the Metaproxy configuration file format</title>
-  
-  
-  <section>
+
+
+  <section id="configuration-introductory-notes">
    <title>Introductory notes</title>
    <para>
     If Metaproxy is an interpreter providing operations on packages, then
     its configuration file can be thought of as a program for that
-    interpreter.  Configuration is by means of a single file, the name
+    interpreter.  Configuration is by means of a single XML file, the name
     of which is supplied as the sole command-line argument to the
-    <command>yp2</command> program.
-   </para>
-   <para>
-    The configuration files are written in XML.  (But that's just an
-    implementation detail - they could just as well have been written
-    in YAML or Lisp-like S-expressions, or in a custom syntax.)
-   </para>
-   <para>
-    Since XML has been chosen, an XML schema,
-    <filename>config.xsd</filename>, is provided for validating
-    configuration files.  This file is supplied in the
-    <filename>etc</filename> directory of the Metaproxy distribution.  It
-    can be used by (among other tools) the <command>xmllint</command>
-    program supplied as part of the <literal>libxml2</literal>
-    distribution:
-   </para>
-   <screen>
-    xmllint --noout --schema etc/config.xsd my-config-file.xml
-   </screen>
-   <para>
-    (A recent version of <literal>libxml2</literal> is required, as
-    support for XML Schemas is a relatively recent addition.)
+    <command>metaproxy</command> program.  (See
+    <xref linkend="reference"/> below for more information on invoking
+    Metaproxy.)
    </para>
   </section>
-  
-  <section>
-   <title>Overview of XML structure</title>
+
+  <section id="overview.xml.structure">
+   <title>Overview of the config file XML structure</title>
    <para>
     All elements and attributes are in the namespace
-    <ulink url="http://indexdata.dk/yp2/config/1"/>.
+    <ulink url="http://indexdata.com/metaproxy"/>.
      This is most easily achieved by setting the default namespace on
      the top-level element, as here:
    </para>
    <screen>
-    &lt;yp2 xmlns="http://indexdata.dk/yp2/config/1"&gt;
+    &lt;metaproxy xmlns="http://indexdata.com/metaproxy" version="1.0"&gt;
    </screen>
    <para>
-    The top-level element is &lt;yp2&gt;.  This contains a
-    &lt;start&gt; element, a &lt;filters&gt; element and a
-    &lt;routes&gt; element, in that order.  &lt;filters&gt; is
-    optional; the other two are mandatory.  All three are
-    non-repeatable.
+    The top-level element is &lt;metaproxy&gt;.  This contains
+    a &lt;dlpath&gt; element,
+    a &lt;start&gt; element,
+    a &lt;filters&gt; element and
+    a &lt;routes&gt; element, in that order.  &lt;dlpath&gt; and
+    &lt;filters&gt; are optional; the other two are mandatory.
+    All four are non-repeatable.
+   </para>
+   <para>
+     The &lt;dlpath;&gt; element contains a text element which
+     specifies the location of filter modules. This is only needed
+     if Metaproxy must load 3rd party filters (most filters with Metaproxy
+     are built into the Metaproxy application).
    </para>
   <para>
     The &lt;start&gt; element is empty, but carries a
     <literal>route</literal> attribute, whose value is the name of
-    route at which to start running - analogouse to the name of the
+    route at which to start running - analogous to the name of the
     start production in a formal grammar.
    </para>
   <para>
     If present, &lt;filters&gt; contains zero or more &lt;filter&gt;
-    elements; filters carry a <literal>type</literal> attribute and
-    contain various elements that provide suitable configuration for
-    filters of that type.  The filter-specific elements are described
-    below.  Filters defined in this part of the file must carry an
+    elements.  Each filter carries a <literal>type</literal> attribute
+    which specifies what kind of filter is being defined
+    (<literal>frontend_net</literal>, <literal>log</literal>, etc.)
+    and contain various elements that provide suitable configuration
+    for a filter of its type.  The filter-specific elements are
+    described in
+    <xref linkend="reference"/>.
+    Filters defined in this part of the file must carry an
     <literal>id</literal> attribute so that they can be referenced
     from elsewhere.
    </para>
     &lt;filters&gt; section.  Alternatively, a route within a filter
     may omit the <literal>refid</literal> attribute, but contain
     configuration elements similar to those used for filters defined
-    in the &lt;filters&gt; section.
+    in the &lt;filters&gt; section.  (In other words, each filter in a
+    route may be included either by reference or by physical
+    inclusion.)
    </para>
   </section>
 
 
-  <section>
-   <title>Filter configuration</title>
+  <section id="example.configuration">
+   <title>An example configuration</title>
    <para>
-    All &lt;filter&gt; elements have in common that they must carry a
-    <literal>type</literal> attribute whose value is one of the
-    supported ones, listed in the schema file and discussed below.  In
-    additional, &lt;filters&gt;s occurring the &lt;filters&gt; section
-    must have an <literal>id</literal> attribute, and those occurring
-    within a route must have either a <literal>refid</literal>
-    attribute referencing a previously defined filter or contain its
-    own configuration information.
+    The following is a small, but complete, Metaproxy configuration
+    file (included in the distribution as
+    <literal>metaproxy/etc/config1.xml</literal>).
+    This file defines a very simple configuration that simply proxies
+    to whatever back-end server the client requests, but logs each
+    request and response.  This can be useful for debugging complex
+    client-server dialogues.
    </para>
+   <screen><![CDATA[<?xml version="1.0"?>
+<metaproxy xmlns="http://indexdata.com/metaproxy" version="1.0">
+  <dlpath>/usr/lib/metaproxy/modules</dlpath>
+  <start route="start"/>
+  <filters>
+    <filter id="frontend" type="frontend_net">
+      <port>@:9000</port>
+    </filter>
+    <filter id="backend" type="z3950_client">
+    </filter>
+  </filters>
+  <routes>
+    <route id="start">
+      <filter refid="frontend"/>
+      <filter type="log"/>
+      <filter refid="backend"/>
+      <filter type="bounce"/>
+    </route>
+  </routes>
+</metaproxy>
+]]></screen>
    <para>
-    In general, each filter recognises different configuration
-    elements within its element, as each filter has different
-    functionality.  These are as follows:
+    It works by defining a single route, called
+    <literal>start</literal>, which consists of a sequence of four
+    filters.  The first and last of these are included by reference:
+    their <literal>&lt;filter&gt;</literal> elements have
+    <literal>refid</literal> attributes that refer to filters defined
+    within the prior <literal>&lt;filters&gt;</literal> section.  The
+    middle filter is included inline in the route.
    </para>
+   <para>
+    The four filters in the route are as follows: first, a
+    <literal>frontend_net</literal> filter accepts Z39.50 requests
+    from any host on port 9000; then these requests are passed through
+    a <literal>log</literal> filter that emits a message for each
+    request; they are then fed into a <literal>z3950_client</literal>
+    filter, which forwards all Z39.50 requests to the client-specified
+    back-end Z39.509 server. Those Z39.50 packages are returned by the
+    <literal>z3950_client</literal> filter, with the response data
+    filled by the external Z39.50 server targeted.
+    All non-Z39.50 packages are passed through to the
+    <literal>bounce</literal> filter, which definitely bounces
+    everything, including fish, bananas, cold pyjamas,
+    mutton, beef and trout packages.
+    When the response arrives, it is handed
+    back to the <literal>log</literal> filter, which emits another
+    message; and then to the <literal>frontend_net</literal> filter,
+    which returns the response to the client.
+   </para>
+  </section>
 
-   <section>
-    <title><literal>auth_simple</literal></title>
-    <screen>
-     &lt;filter type="auth_simple"&gt;
-     &lt;userRegister&gt;../etc/example.simple-auth&lt;/userRegister&gt;
-     &lt;/filter&gt;
-    </screen>
-   </section>
-
-   <section>
-    <title><literal>backend_test</literal></title>
-    <screen>
-     &lt;filter type="backend_test"/&gt;
-    </screen>
-   </section>
+  <section id="config-file-modularity">
+   <title>Config file modularity</title>
+   <para>
+    Metaproxy XML configuration snippets can be reused by other
+    filters using the <literal>XInclude</literal> standard, as seen in
+    the <literal>/etc/config-sru-to-z3950.xml</literal> example SRU
+    configuration.
+   <screen><![CDATA[
+    <filter id="sru" type="sru_z3950">
+      <database name="Default">
+       <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+                    href="explain.xml"/>
+      </database>
+    </filter>
+]]></screen>
+    </para>
+  </section>
 
-   <section>
-    <title><literal>frontend_net</literal></title>
-    <screen>
-     &lt;filter type="frontend_net"&gt;
-     &lt;threads&gt;10&lt;/threads&gt;
-     &lt;port&gt;@:9000&lt;/port&gt;
-     &lt;/filter&gt;
-    </screen>
+  <section id="config-file-syntax-check">
+   <title>Config file syntax checking</title>
+   <para>
+    The distribution contains RelaxNG Compact and XML syntax checking
+    files, as well as XML Schema files. These are found in the
+    distribution paths
+   <screen>
+    xml/schema/metaproxy.rnc
+    xml/schema/metaproxy.rng
+    xml/schema/metaproxy.xsd
+   </screen>
+    and can be used to verify or debug the XML structure of
+    configuration files. For example, using the utility
+    <filename>xmllint</filename>, syntax checking is done like this:
+   <screen>
+    xmllint --noout --schema xml/schema/metaproxy.xsd etc/config-local.xml
+    xmllint --noout --relaxng xml/schema/metaproxy.rng etc/config-local.xml
+   </screen>
+    (A recent version of <literal>libxml2</literal> is required, as
+    support for XML Schemas is a relatively recent addition.)
+   </para>
+   <para>
+    You can of course use any other RelaxNG or XML Schema compliant tool
+    you wish.
+   </para>
    </section>
+ </chapter>
 
-   <section>
-    <title><literal>http_file</literal></title>
-    <screen>
-     &lt;filter type="http_file"&gt;
-     &lt;mimetypes&gt;/etc/mime.types&lt;/mimetypes&gt;
-     &lt;area&gt;
-     &lt;documentroot&gt;.&lt;/documentroot&gt;
-     &lt;prefix&gt;/etc&lt;/prefix&gt;
-     &lt;/area&gt;
-     &lt;/filter&gt;
-    </screen>
-   </section>
 
-   <section>
-    <title><literal>log</literal></title>
-    <screen>
-     &lt;filter type="log"&gt;
-     &lt;message&gt;B&lt;/message&gt;
-     &lt;/filter&gt;
-    </screen>
-   </section>
 
-   <section>
-    <title><literal>multi</literal></title>
-    <screen>
-     &lt;filter type="multi"/&gt;
-    </screen>
-   </section>
+ <chapter id="multidb">
+  <title>Virtual databases and multi-database searching</title>
 
-   <section>
-    <title><literal>session_shared</literal></title>
-    <screen>
-     &lt;filter type="session_shared"&gt;
-     ### Not yet defined
-     &lt;/filter&gt;
-    </screen>
-   </section>
 
-   <section>
-    <title><literal>template</literal></title>
-    <screen>
-     &lt;filter type="template"/&gt;
-    </screen>
-   </section>
+  <section id="multidb-introductory-notes">
+   <title>Introductory notes</title>
+   <para>
+    Two of Metaproxy's filters are concerned with multiple-database
+    operations.  Of these, <literal>virt_db</literal> can work alone
+    to control the routing of searches to one of a number of servers,
+    while <literal>multi</literal> can work together with
+    <literal>virt_db</literal> to perform multi-database searching, merging
+    the results into a unified result-set - ``metasearch in a box''.
+   </para>
+   <para>
+    The interaction between
+    these two filters is necessarily complex: it reflects the real,
+    irreducible complexity of multi-database searching in a protocol such
+    as Z39.50 that separates initialization from searching, and in
+    which the database to be searched is not known at initialization
+    time.
+   </para>
+   <para>
+    It's possible to use these filters without understanding the
+    details of their functioning and the interaction between them; the
+    next two sections of this chapter are ``HOW-TO'' guides for doing
+    just that.  However, debugging complex configurations will require
+    a deeper understanding, which the last two sections of this
+    chapters attempt to provide.
+   </para>
+  </section>
 
-   <section>
-    <title><literal>virt_db</literal></title>
-    <screen>
-     &lt;filter type="virt_db"&gt;
-     &lt;virtual&gt;
-     &lt;database&gt;loc&lt;/database&gt;
-     &lt;target&gt;z3950.loc.gov:7090/voyager&lt;/target&gt;
-     &lt;/virtual&gt;
-     &lt;virtual&gt;
-     &lt;database&gt;idgils&lt;/database&gt;
-     &lt;target&gt;indexdata.dk/gils&lt;/target&gt;
-     &lt;/virtual&gt;
-     &lt;/filter&gt;
-    </screen>
-   </section>
 
-   <section>
-    <title><literal>z3950_client</literal></title>
-    <screen>
-     &lt;filter type="z3950_client"&gt;
-     &lt;timeout&gt;30&lt;/timeout&gt;
-     &lt;/filter&gt;
-    </screen>
-   </section>
+  <section id="multidb.virt_db">
+   <title>Virtual databases with the <literal>virt_db</literal> filter</title>
+   <para>
+    Working alone, the purpose of the
+    <literal>virt_db</literal>
+    filter is to route search requests to one of a selection of
+    back-end databases.  In this way, a single Z39.50 endpoint
+    (running Metaproxy) can provide access to several different
+    underlying services, including those that would otherwise be
+    inaccessible due to firewalls.  In many useful configurations, the
+    back-end databases are local to the Metaproxy installation, but
+    the software does not enforce this, and any valid Z39.50 servers
+    may be used as back-ends.
+   </para>
+   <para>
+    For example, a <literal>virt_db</literal>
+    filter could be set up so that searches in the virtual database
+    ``lc'' are forwarded to the Library of Congress bibliographic
+    catalogue server, and searches in the virtual database ``marc''
+    are forwarded to the toy database of MARC records that Index Data
+    hosts for testing purposes.  A <literal>virt_db</literal>
+    configuration to make this switch would look like this:
+   </para>
+   <screen><![CDATA[<filter type="virt_db">
+  <virtual>
+    <database>lc</database>
+    <target>z3950.loc.gov:7090/voyager</target>
+  </virtual>
+  <virtual>
+    <database>marc</database>
+    <target>indexdata.com/marc</target>
+  </virtual>
+</filter>]]></screen>
+   <para>
+    As well as being useful in it own right, this filter also provides
+    the foundation for multi-database searching.
+   </para>
   </section>
- </chapter>
 
 
-
- <chapter id="multidb">
-  <title>Virtual database as multi-database searching</title>
+  <section id="multidb.multi">
+   <title>Multi-database search with the <literal>multi</literal> filter</title>
+   <para>
+    To arrange for Metaproxy to broadcast searches to multiple back-end
+    servers, the configuration needs to include two components: a
+    <literal>virt_db</literal>
+    filter that specifies multiple
+    <literal>&lt;target&gt;</literal>
+    elements, and a subsequent
+    <literal>multi</literal>
+    filter.  Here, for example, is a complete configuration that
+    broadcasts searches to both the Library of Congress catalogue and
+    Index Data's tiny testing database of MARC records:
+   </para>
+   <screen><![CDATA[<?xml version="1.0"?>
+<metaproxy xmlns="http://indexdata.com/metaproxy" version="1.0">
+  <start route="start"/>
+  <routes>
+    <route id="start">
+      <filter type="frontend_net">
+        <threads>10</threads>
+        <port>@:9000</port>
+      </filter>
+      <filter type="virt_db">
+        <virtual>
+          <database>lc</database>
+          <target>z3950.loc.gov:7090/voyager</target>
+        </virtual>
+        <virtual>
+          <database>marc</database>
+          <target>indexdata.com/marc</target>
+        </virtual>
+        <virtual>
+          <database>all</database>
+          <target>z3950.loc.gov:7090/voyager</target>
+          <target>indexdata.com/marc</target>
+        </virtual>
+      </filter>
+      <filter type="multi"/>
+      <filter type="z3950_client">
+        <timeout>30</timeout>
+      </filter>
+      <filter type="bounce"/>
+    </route>
+  </routes>
+</metaproxy>]]></screen>
+   <para>
+    (Using a
+    <literal>virt_db</literal>
+    filter that specifies multiple
+    <literal>&lt;target&gt;</literal>
+    elements but without a subsequent
+    <literal>multi</literal>
+    filter yields surprising and undesirable results, as will be
+    described below.  Don't do that.)
+   </para>
+   <para>
+    Metaproxy can be invoked with this configuration as follows:
+   </para>
+   <screen>../src/metaproxy --config config-simple-multi.xml</screen>
+   <para>
+    And thereafter, Z39.50 clients can connect to the running server
+    (on port 9000, as specified in the configuration) and search in
+    any of the databases
+    <literal>lc</literal> (the Library of Congress catalogue),
+    <literal>marc</literal> (Index Data's test database of MARC records)
+    or
+    <literal>all</literal> (both of these).  As an example, a session
+    using the YAZ command-line client <literal>yaz-client</literal> is
+    here included (edited for brevity and clarity):
+   </para>
+   <screen><![CDATA[$ yaz-client @:9000
+Connecting...OK.
+Z> base lc
+Z> find computer
+Search was a success.
+Number of hits: 10000, setno 1
+Elapsed: 5.521070
+Z> base marc
+Z> find computer
+Search was a success.
+Number of hits: 10, setno 3
+Elapsed: 0.060187
+Z> base all
+Z> find computer
+Search was a success.
+Number of hits: 10010, setno 4
+Elapsed: 2.237648
+Z> show 1
+[marc]Record type: USmarc
+001    11224466
+003 DLC
+005 00000000000000.0
+008 910710c19910701nju           00010 eng
+010    $a 11224466
+040    $a DLC $c DLC
+050 00 $a 123-xyz
+100 10 $a Jack Collins
+245 10 $a How to program a computer
+260 1  $a Penguin
+263    $a 8710
+300    $a p. cm.
+Elapsed: 0.119612
+Z> show 2
+[VOYAGER]Record type: USmarc
+001 13339105
+005 20041229102447.0
+008 030910s2004    caua          000 0 eng
+035    $a (DLC)  2003112666
+906    $a 7 $b cbc $c orignew $d 4 $e epcn $f 20 $g y-gencatlg
+925 0  $a acquire $b 1 shelf copy $x policy default
+955    $a pc10 2003-09-10 $a pv12 2004-06-23 to SSCD; $h sj05 2004-11-30 $e sj05 2004-11-30 to Shelf.
+010    $a   2003112666
+020    $a 0761542892
+040    $a DLC $c DLC $d DLC
+050 00 $a MLCM 2004/03312 (G)
+245 10 $a 007, everything or nothing : $b Prima's official strategy guide / $c created by Kaizen Media Group.
+246 3  $a Double-O-seven, everything or nothing
+246 30 $a Prima's official strategy guide
+260    $a Roseville, CA : $b Prima Games, $c c2004.
+300    $a 161 p. : $b col. ill. ; $c 28 cm.
+500    $a "Platforms: Nintendo GameCube, Macintosh, PC, PlayStation 2 computer entertainment system, Xbox"--P. [4] of cover.
+650  0 $a Video games.
+710 2  $a Kaizen Media Group.
+856 42 $3 Publisher description $u http://www.loc.gov/catdir/description/random052/2003112666.html
+Elapsed: 0.150623
+Z>
+]]></screen>
+   <para>
+    As can be seen, the first record in the result set is from the
+    Index Data test database, and the second from the Library of
+    Congress database.  The result-set continues alternating records
+    round-robin style until the point where one of the databases'
+    records are exhausted.
+   </para>
+   <para>
+    This example uses only two back-end databases; more may be used.
+    There is no limitation imposed on the number of databases that may
+    be metasearched in this way: issues of resource usage and
+    administrative complexity dictate the practical limits.
+   </para>
+   <para>
+    What happens when one of the databases doesn't respond?  By default,
+    the entire multi-database search fails, and the appropriate
+    diagnostic is returned to the client.  This is usually appropriate
+    during development, when technicians need maximum information, but
+    can be inconvenient in deployment, when users typically don't want
+    to be bothered with problems of this kind and prefer just to get
+    the records from the databases that are available.  To obtain this
+    latter behavior add an empty
+    <literal>&lt;hideunavailable&gt;</literal>
+    element inside the
+    <literal>multi</literal> filter:
+   </para>
+   <screen><![CDATA[      <filter type="multi">
+        <hideunavailable/>
+      </filter>]]></screen>
+   <para>
+    Under this regime, an error is reported to the client only if
+    <emphasis>all</emphasis> the databases in a multi-database search
+    are unavailable.
+   </para>
+  </section>
 
 
-  <section>
-   <title>Introductory notes</title>
+  <section id="multidb.what">
+   <title>What's going on?</title>
+   <warning>
+    <title>Lark's vomit</title>
+    <para>
+     This section goes into a level of technical detail that is
+     probably not necessary in order to configure and use Metaproxy.
+     It is provided only for those who like to know how things work.
+     You should feel free to skip on to the next section if this one
+     doesn't seem like fun.
+    </para>
+   </warning>
    <para>
-    Two of Metaproxy's filters are concerned with multiple-database
-    operations.  Of these, <literal>virt_db</literal> can work alone
-    to control the routing of searches to one of a number of servers,
-    while <literal>multi</literal> can work with the output of
-    <literal>virt_db</literal> to perform multicast searching, merging
-    the results into a unified result-set.  The interaction between
-    these two filters is necessarily complex, reflecting the real
-    complexity of multicast searching in a protocol such as Z39.50
-    that separates initialisation from searching, with the database to
-    search known only during the latter operation.
+    Hold on tight - this may get a little hairy.
    </para>
    <para>
-    ### Much, much more to say!
+    In the general course of things, a Z39.50 Init request may carry
+    with it an otherInfo packet of type <literal>VAL_PROXY</literal>,
+    whose value indicates the address of a Z39.50 server to which the
+    ultimate connection is to be made.  (This otherInfo packet is
+    supported by YAZ-based Z39.50 clients and servers, but has not yet
+    been ratified by the Maintenance Agency and so is not widely used
+    in non-Index Data software.  We're working on it.)
+    The <literal>VAL_PROXY</literal> packet functions
+    analogously to the absoluteURI-style Request-URI used with the GET
+    method when a web browser asks a proxy to forward its request: see
+    the
+    <ulink url="http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2"
+          >Request-URI</ulink>
+    section of
+    <ulink url="http://www.w3.org/Protocols/rfc2616/rfc2616.html"
+          >the HTTP 1.1 specification</ulink>.
    </para>
+   <para>
+    Within Metaproxy, Search requests that are part of the same
+    session as an Init request that carries a
+    <literal>VAL_PROXY</literal> otherInfo are also annotated with the
+    same information.  The role of the <literal>virt_db</literal>
+    filter is to rewrite this otherInfo packet dependent on the
+    virtual database that the client wants to search.
+   </para>
+   <para>
+    When Metaproxy receives a Z39.50 Init request from a client, it
+    doesn't immediately forward that request to the back-end server.
+    Why not?  Because it doesn't know <emphasis>which</emphasis>
+    back-end server to forward it to until the client sends a Search
+    request that specifies the database that it wants to search in.
+    Instead, it just treasures the Init request up in its heart; and,
+    later, the first time the client does a search on one of the
+    specified virtual databases, a connection is forged to the
+    appropriate server and the Init request is forwarded to it.  If,
+    later in the session, the same client searches in a different
+    virtual database, then a connection is forged to the server that
+    hosts it, and the same cached Init request is forwarded there,
+    too.
+   </para>
+   <para>
+    All of this clever Init-delaying is done by the
+    <literal>frontend_net</literal> filter.  The
+    <literal>virt_db</literal> filter knows nothing about it; in
+    fact, because the Init request that is received from the client
+    doesn't get forwarded until a Search request is received, the
+    <literal>virt_db</literal> filter (and the
+    <literal>z3950_client</literal> filter behind it) doesn't even get
+    invoked at Init time.  The <emphasis>only</emphasis> thing that a
+    <literal>virt_db</literal> filter ever does is rewrite the
+    <literal>VAL_PROXY</literal> otherInfo in the requests that pass
+    through it.
+   </para>
+   <para>
+    It is possible for a <literal>virt_db</literal> filter to contain
+    multiple
+    <literal>&lt;target&gt;</literal>
+    elements.  What does this mean?  Only that the filter will add
+    multiple <literal>VAL_PROXY</literal> otherInfo packets to the
+    Search requests that pass through it.  That's because the virtual
+    DB filter is dumb, and does exactly what it's told - no more, no
+    less.
+    If a Search request with multiple <literal>VAL_PROXY</literal>
+    otherInfo packets reaches a <literal>z3950_client</literal>
+    filter, this is an error.  That filter doesn't know how to deal
+    with multiple targets, so it will either just pick one and search
+    in it, or (better) fail with an error message.
+   </para>
+   <para>
+    The <literal>multi</literal> filter comes to the rescue!  This is
+    the only filter that knows how to deal with multiple
+    <literal>VAL_PROXY</literal> otherInfo packets, and it does so by
+    making multiple copies of the entire Search request: one for each
+    <literal>VAL_PROXY</literal>.  Each of these new copies is then
+    passed down through the remaining filters in the route.  (The
+    copies are handled in parallel though the
+    spawning of new threads.)  Since the copies each have only one
+    <literal>VAL_PROXY</literal> otherInfo, they can be handled by the
+    <literal>z3950_client</literal> filter, which happily deals with
+    each one individually.  When the results of the individual
+    searches come back up to the <literal>multi</literal> filter, it
+    merges them into a single Search response, which is what
+    eventually makes it back to the client.
+   </para>
+
+    <mediaobject>
+     <imageobject>
+      <imagedata fileref="multi.pdf" format="PDF" scale="50"/>
+     </imageobject>
+     <imageobject>
+      <imagedata fileref="multi.png" format="PNG"/>
+     </imageobject>
+     <textobject>
+      <!-- Fall back if none of the images can be used -->
+      <phrase>
+       [Here there should be a diagram showing the progress of
+       packages through the filters during a simple virtual-database
+       search and a multi-database search, but is seems that your
+       tool chain has not been able to include the diagram in this
+       document.]
+      </phrase>
+     </textobject>
+     <caption>
+      <para>A picture is worth a thousand words (but only five hundred on 64-bit architectures)</para>
+     </caption>
+    </mediaobject>
   </section>
  </chapter>
 
- <chapter id="moduleref">
-  <title>Module Reference</title>
+
+ <chapter id="sru-server">
+  <title>Combined SRU webservice and Z39.50 server configuration</title>
+  <para>
+   Metaproxy can act as
+   <ulink url="&url.sru;">SRU</ulink> and
+   web service server, which translates web service requests to
+   <ulink url="&url.z39.50;">ANSI/NISO Z39.50</ulink> packages and
+   sends them off to common available targets.
+  </para>
+  <para>
+  A typical setup for this operation needs a filter route including the
+  following modules:
+  </para>
+
+  <table id="sru-server-table-config" frame="top">
+   <title>SRU/Z39.50 Server Filter Route Configuration</title>
+   <tgroup cols="3">
+    <thead>
+     <row>
+      <entry>Filter</entry>
+      <entry>Importance</entry>
+      <entry>Purpose</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><literal>frontend_net</literal></entry>
+      <entry>required</entry>
+      <entry>Accepting HTTP connections and passing them to following
+      filters. Since this filter also accepts Z39.50 connections, the
+      server works as SRU and Z39.50 server on the same port.</entry>
+     </row>
+     <row>
+      <entry><literal>sru_z3950</literal></entry>
+      <entry>required</entry>
+      <entry>Accepting SRU GET/POST/SOAP explain and
+       searchRetrieve requests for the the configured databases.
+       Explain requests are directly served from the static XML configuration.
+       SearchRetrieve requests are
+       transformed  to Z39.50 search and present packages.
+       All other HTTP and Z39.50 packages are passed unaltered.</entry>
+     </row>
+     <row>
+      <entry><literal>http_file</literal></entry>
+      <entry>optional</entry>
+      <entry>Serving HTTP requests from the filesystem. This is only
+      needed if the server should serve XSLT stylesheets, static HTML
+      files or Java Script for thin browser based clients.
+       Z39.50 packages are passed unaltered.</entry>
+     </row>
+     <row>
+      <entry><literal>cql_rpn</literal></entry>
+      <entry>required</entry>
+      <entry>Usually, Z39.50 servers do not talk CQL, hence the
+      translation of the CQL query language to RPN is mandatory in
+      most cases. Affects only  Z39.50 search packages.</entry>
+     </row>
+     <row>
+      <entry><literal>record_transform</literal></entry>
+      <entry>optional</entry>
+      <entry>Some Z39.50 backend targets can not present XML record
+      syntaxes in common wanted element sets. using this filter, one
+      can transform binary MARC records to MARCXML records, and
+      further transform those to any needed XML schema/format by XSLT
+      transformations. Changes only  Z39.50 present packages.</entry>
+     </row>
+     <row>
+      <entry><literal>session_shared</literal></entry>
+      <entry>optional</entry>
+      <entry>The stateless nature of web services requires frequent
+      re-searching of the same targets for display of paged result set
+      records. This might be an unacceptable burden for the accessed
+      backend Z39.50 targets, and this mosule can be added for
+      efficient backend target resource pooling.</entry>
+     </row>
+     <row>
+      <entry><literal>z3950_client</literal></entry>
+      <entry>required</entry>
+      <entry>Finally, a Z39.50 package sink is needed in the filter
+      chain to provide the response packages. The Z39.50 client module
+      is used to access external targets over the network, but any
+      coming local Z39.50 package sink could be used instead of.</entry>
+     </row>
+     <row>
+      <entry><literal>bounce</literal></entry>
+      <entry>required</entry>
+      <entry>Any Metaproxy package arriving here did not do so by
+      purpose, and is bounced back with connection closure. this
+      prevents inifinite package hanging inside the SRU server.</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
   <para>
-   The material in this chapter includes the man pages material
+   A typical minimal example <ulink url="&url.sru;">SRU</ulink>
+   server configuration file is found in the tarball distribution at
+   <literal>etc/config-sru-to-z3950.xml</literal>.
   </para>
-  &manref;
+  <para>
+   Off course, any other metaproxy modules can be integrated into a
+   SRU server solution, including, but not limited to, load balancing,
+   multiple target querying
+   (see  <xref linkend="multidb"/>), and complex RPN query rewrites.
+  </para>
+
+
+ </chapter>
+
+ <!--
+ <chapter id="extensions">
+  <title>Writing extensions for Metaproxy</title>
+  <para>### To be written</para>
  </chapter>
+ -->
+
+
 
  <chapter id="classes">
   <title>Classes in the Metaproxy source code</title>
 
 
-  <section>
+  <section id="classes-introductory-notes">
    <title>Introductory notes</title>
    <para>
     <emphasis>Stop!  Do not read this!</emphasis>
-    You won't enjoy it at all.
+    You won't enjoy it at all.  You should just skip ahead to
+    <xref linkend="reference"/>,
+    which tells
+    <!-- The remainder of this paragraph is lifted verbatim from
+    Douglas Adams' _Hitch Hiker's Guide to the Galaxy_, chapter 8 -->
+    you things you really need to know, like the fact that the
+    fabulously beautiful planet Bethselamin is now so worried about
+    the cumulative erosion by ten billion visiting tourists a year
+    that any net imbalance between the amount you eat and the amount
+    you excrete whilst on the planet is surgically removed from your
+    bodyweight when you leave: so every time you go to the lavatory it
+    is vitally important to get a receipt.
    </para>
    <para>
     This chapter contains documentation of the Metaproxy source code, and is
     of interest only to maintainers and developers.  If you need to
-    change Metaproxy's behaviour or write a new filter, then you will most
+    change Metaproxy's behavior or write a new filter, then you will most
     likely find this chapter helpful.  Otherwise it's a waste of your
     good time.  Seriously: go and watch a film or something.
     <citetitle>This is Spinal Tap</citetitle> is particularly good.
    </para>
   </section>
 
-  <section>
+  <section id="individual.classes">
    <title>Individual classes</title>
    <para>
     The classes making up the Metaproxy application are here listed by
     parentheses.
    </para>
 
-   <section>
+   <section id="class-FactoryFilter">
     <title><literal>mp::FactoryFilter</literal>
      (<filename>factory_filter.cpp</filename>)</title>
     <para>
     </para>
    </section>
 
-   <section>
+   <section id="class-FactoryStatic">
     <title><literal>mp::FactoryStatic</literal>
      (<filename>factory_static.cpp</filename>)</title>
     <para>
      structures, which are listed in its constructor.  Merely
      instantiating this class registers all the static classes.  It is
      for the benefit of this class that <literal>struct
-      yp2_filter_struct</literal> exists, and that all the filter
+      metaproxy_1_filter_struct</literal> exists, and that all the filter
      classes provide a static object of that type.
     </para>
    </section>
 
-   <section>
+   <section id="class-filter-Base">
     <title><literal>mp::filter::Base</literal>
      (<filename>filter.cpp</filename>)</title>
     <para>
      The virtual base class of all filters.  The filter API is, on the
      surface at least, extremely simple: two methods.
-     <literal>configure()</literal> is passed a DOM tree representing
+     <literal>configure()</literal> is passed an XML DOM tree representing
      that part of the configuration file that pertains to this filter
      instance, and is expected to walk that tree extracting relevant
      information.  And <literal>process()</literal> processes a
-     package (see below).  That surface simplicitly is a bit
+     package (see below).  That surface simplicity is a bit
      misleading, as <literal>process()</literal> needs to know a lot
      about the <literal>Package</literal> class in order to do
      anything useful.
     </para>
    </section>
 
-   <section>
+   <section id="class-AuthSimple">
     <title><literal>mp::filter::AuthSimple</literal>,
      <literal>Backend_test</literal>, etc.
      (<filename>filter_auth_simple.cpp</filename>,
      <filename>filter_*.cpp</filename> respectively.  All the header
      files should be pretty much identical, in that they declare the
      class, including a private <literal>Rep</literal> class and a
-     member pointer to it, and the two public methods.  The only extra
-     information in any filter header is additional private types and
-     members (which should really all be in the <literal>Rep</literal>
-     anyway) and private methods (which should also remain known only
-     to the source file, but C++'s brain-damaged design requires this
-     dirty laundry to be exhibited in public.  Thanks, Bjarne!)
+     member pointer to it, and the two public methods.
     </para>
     <para>
      The source file for each filter needs to supply:
     </itemizedlist>
    </section>
 
-   <section>
+   <section id="class-Package">
     <title><literal>mp::Package</literal>
      (<filename>package.cpp</filename>)</title>
     <para>
     </para>
    </section>
 
-   <section>
+   <section id="class-Pipe">
     <title><literal>mp::Pipe</literal>
      (<filename>pipe.cpp</filename>)</title>
     <para>
     </para>
    </section>
 
-   <section>
+   <section id="class-RouterChain">
     <title><literal>mp::RouterChain</literal>
      (<filename>router_chain.cpp</filename>)</title>
     <para>
-     ###
+     ### to be written
     </para>
    </section>
 
-   <section>
+   <section id="class-RouterFleXML">
     <title><literal>mp::RouterFleXML</literal>
      (<filename>router_flexml.cpp</filename>)</title>
     <para>
-     ###
+     ### to be written
     </para>
    </section>
 
-   <section>
+   <section id="class-Session">
     <title><literal>mp::Session</literal>
      (<filename>session.cpp</filename>)</title>
     <para>
-     ###
+     ### to be written
     </para>
    </section>
 
-   <section>
+   <section id="class-ThreadPoolSocketObserver">
     <title><literal>mp::ThreadPoolSocketObserver</literal>
      (<filename>thread_pool_observer.cpp</filename>)</title>
     <para>
-     ###
+     ### to be written
     </para>
    </section>
 
-   <section>
+   <section id="class-util">
     <title><literal>mp::util</literal>
      (<filename>util.cpp</filename>)</title>
     <para>
     </para>
    </section>
 
-   <section>
+   <section id="class-xml">
     <title><literal>mp::xml</literal>
      (<filename>xmlutil.cpp</filename>)</title>
     <para>
   </section>
 
 
-  <section>
+  <section id="other.source.files">
    <title>Other Source Files</title>
    <para>
     In addition to the Metaproxy source files that define the classes
      <term><literal>metaproxy_prog.cpp</literal></term>
      <listitem>
       <para>
-       The main function of the <command>yp2</command> program.
+       The main function of the <command>metaproxy</command> program.
       </para>
      </listitem>
     </varlistentry>
     <literal>plainfile.cpp</literal>,
     <literal>tstdl.cpp</literal>.
    </para>
-   
-   
-   <!-- Epilogue -->
-   <para>
-    --
-   </para>
-   <screen>
-    <!-- This is just a lame way to get some vertical whitespace at
-    the end of the document -->
-    
-    
-    
-    
-   </screen>
   </section>
  </chapter>
 
- <!-- Keep this comment at the end of the file
- Local variables:
- mode: sgml
- sgml-omittag:t
- sgml-shorttag:t
- sgml-minimize-attributes:nil
- sgml-always-quote-attributes:t
- sgml-indent-step:1
- sgml-indent-data:t
- sgml-parent-document: "main.xml"
- sgml-local-catalogs: nil
- sgml-namecase-general:t
- End:
- -->
+
+ <reference id="reference">
+  <title>Reference</title>
+   <partintro id="reference-introduction">
+    <para>
+     The material in this chapter is drawn directly from the individual
+     manual entries.  In particular, the Metaproxy invocation section is
+     available using <command>man metaproxy</command>, and the section
+     on each individual filter is available using the name of the filter
+     as the argument to the <command>man</command> command.
+    </para>
+   </partintro>
+   &manref;
+ </reference>
+
+<appendix id="license">
+ <title>License</title>
+
+  &copyright;
+
+  <para>
+   Metaproxy is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+   </para>
+
+  <para>
+   Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+  </para>
+
+  <para>
+   You should have received a copy of the GNU General Public License
+   along with Metaproxy; see the file LICENSE.  If not, write to the
+   Free Software Foundation,
+   51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+   </para>
+
+ </appendix>
+
+ &gpl2;
+</book>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: nxml
+nxml-child-indent: 1
+End:
+-->