Using copyright-year entity
[yazpp-moved-to-github.git] / doc / zoom.xml
index 0d3fcab..238c7d9 100644 (file)
@@ -1,37 +1,34 @@
 <chapter id="zoom">
- <!-- $Id: zoom.xml,v 1.5 2002-10-09 23:11:31 mike Exp $ -->
  <title>ZOOM-C++</title>
 
 
  <sect1 id="zoom-introduction">
   <title>Introduction</title>
   <para>
-   <ulink url="http://staging.zoom.z3950.org/">ZOOM</ulink>
+   <ulink url="&url.zoom;">ZOOM</ulink>
    is the emerging standard API for information retrieval programming
    using the Z39.50 protocol.  ZOOM's
-   <ulink url="http://staging.zoom.z3950.org/api/">Abstract API</ulink>
+   <ulink url="&url.zoom.api;">Abstract API</ulink>
    specifies semantics for classes representing key IR concepts such as
    connections, queries, result sets and records; and there are various
-   <ulink url="http://staging.zoom.z3950.org/bind/">bindings</ulink>
+   <ulink url="&url.zoom.bind;">bindings</ulink>
    specifying how those concepts should be represented in various
    programming languages.
   </para>
   <para>
-   The Yaz++ library includes an implementation of the <ulink
-   url="http://staging.zoom.z3950.org/bind/cplusplus/"
-       >C++ binding</ulink>
+   The YAZ++ library includes an implementation of the <ulink
+   url="&url.zoom.bind.cplusplus;">C++ binding</ulink>
    for ZOOM, enabling quick, easy development of client applications.
   </para>
   <para>
    For example, here is a tiny Z39.50 client that fetches and displays
-   the MARC record for Farlow & Brett Surman's
-   <!-- ### there must be a better way to mark up a book title? -->
-   <emphasis>The Complete Dinosaur</emphasis>
+   the MARC record for Farlow &amp; Brett Surman's
+   <citetitle>The Complete Dinosaur</citetitle>
    from the Library of Congress's Z39.50 server:
   </para>
-  <synopsis>
+  <programlisting>
     #include &lt;iostream&gt;
-    #include &lt;yaz++/zoom.h&gt;
+    #include &lt;yazpp/zoom.h&gt;
 
     using namespace ZOOM;
 
     {
         connection conn("z3950.loc.gov", 7090);
         conn.option("databaseName", "Voyager");
-        resultSet rs(conn, prefixQuery("@attr attr 1=7 0253333490"));
+        conn.option("preferredRecordSyntax", "USMARC");
+        resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
         const record *rec = rs.getRecord(0);
         cout &lt;&lt; rec-&gt;render() &lt;&lt; endl;
     }
-  </synopsis>
+  </programlisting>
+   <note>
+    <para>
+     For the sake of simplicity, this program does not check
+     for errors: we show a more robust version of the same program
+     <link linkend="revised-sample">later</link>.)
+    </para>
+   </note>
   <para>
-   (Note that, for the sake of simplicity, this does not check for
-   errors: we show a more realistic version of this program later.)
-  </para>
-  <para>
-   Yaz++'s implementation of the C++ binding is a thin layer over Yaz's
+   YAZ++'s implementation of the C++ binding is a thin layer over YAZ's
    implementation of the C binding.  For information on the supported
    options and other such details, see the ZOOM-C documentation, which
    can be found on-line at
-   <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php"/>
+   <ulink url="&url.yaz.zoom;"/>
   </para>
   <para>
    All of the classes defined by ZOOM-C++ are in the
    (links below).
   </para>
 
-  <sect2>
+  <sect2 id="connection.references">
    <title>References</title>
    <itemizedlist>
     <listitem>
      <para>
-      <ulink url="http://staging.zoom.z3950.org/api/zoom-1.3.html#3.2"
+      <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.2"
        >Section 3.2 (Connection) of the ZOOM Abstract API</ulink>
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      <ulink url="file:///usr/local/src/z39.50/yaz/doc/zoom.html#zoom.connections"
-       >The Connections section of the ZOOM-C documentation</ulink>
-     </para>
-    </listitem>
-   </itemizedlist>
-  </sect2>
- </sect1>
+      </para>
+     </listitem>
+     <listitem>
+      <para>
+       <ulink url="&url.yaz.zoom.connections;"
+       >The Connections section f the ZOOM-C documentation</ulink>
+      </para>
+     </listitem>
+    </itemizedlist>
+   </sect2>
+  </sect1>
 
 
  <sect1 id="zoom-query">
    a specific query notation.
   </para>
 
-  <sect2>
+  <sect2 id="ZOOM::prefixQuery">
    <title><literal>ZOOM::prefixQuery</literal></title>
-   <para>
-    The class has this declaration:
-   </para>
    <synopsis>
     class prefixQuery : public query {
     public:
       ~prefixQuery ();
     };
    </synopsis>
-   <para>
-    It enables a query to be created from Yaz's cryptic but
-    powerful
-    <ulink url="file:///usr/local/src/z39.50/yaz/doc/tools.html#PQF"
-       >Prefix Query Notation (PQN)</ulink>.
-   </para>
-  </sect2>
-
-  <sect2>
+    <para>
+     This class enables a query to be created by compiling YAZ's
+     cryptic but powerful
+     <ulink url="&url.yaz.pqf;">Prefix Query Notation (PQN)</ulink>.
+    </para>
+   </sect2>
+   
+  <sect2 id="ZOOM::CCLQuery">
    <title><literal>ZOOM::CCLQuery</literal></title>
-   <para>
-    The class has this declaration:
-   </para>
    <synopsis>
     class CCLQuery : public query {
     public:
     };
    </synopsis>
    <para>
-    It enables a query to be created using the simpler but less
-    expressive
-    <ulink url="file:///usr/local/src/z39.50/yaz/doc/tools.html#CCL"
-       >Common Command Language (CCL)</ulink>.
+    This class enables a query to be created using the simpler but
+    less expressive
+    <ulink url="&url.yaz.ccl;">Common Command Language (CCL)</ulink>.
     The qualifiers recognised by the CCL parser are specified in an
-    external configuration file in the format described by the Yaz
+    external configuration file in the format described by the YAZ
     documentation.
    </para>
+   <para>
+    If query construction fails for either type of
+    <literal>query</literal> object - typically because the query
+    string itself is not valid PQN or CCL - then an
+    <link linkend="zoom-exception"><literal>exception</literal></link>
+    is thrown.
+   </para>
   </sect2>
 
-  <sect2>
+  <sect2 id="queries.discussion">
    <title>Discussion</title>
    <para>
     It will be readily recognised that these objects have no methods
    </screen>
   </sect2>
 
-  <sect2>
+  <sect2 id="query.references">
    <title>References</title>
    <itemizedlist>
     <listitem>
      <para>
-      <ulink url="http://staging.zoom.z3950.org/api/zoom-1.3.html#3.3"
+      <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
        >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
      </para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="file:///usr/local/src/z39.50/yaz/doc/zoom.query.html"
+       <ulink url="&url.yaz.zoom.query;"
        >The Queries section of the ZOOM-C documentation</ulink>
      </para>
     </listitem>
    which is passed a <literal>connection</literal>, indicating the
    server on which the search is to be performed, and a
    <literal>query</literal>, indicating what search to perform.  If
-   the search fails - for example, because the query is malformed -
-   then an
+   the search fails - for example, because the query uses attributes
+   that the server doesn't implement - then an
    <link linkend="zoom-exception"><literal>exception</literal></link>
    is thrown.
   </para>
    Finally, the <literal>getRecord</literal> method returns the
    <parameter>i</parameter>th record from the result set, where
    <parameter>i</parameter> is zero-based: that is, legitmate values
-   range from zero up to one less than the result-set size.
+   range from zero up to one less than the result-set size.  If the
+   method fails, for example because the requested record is out of
+   range, it <literal>throw</literal>s an
+   <link linkend="zoom-exception"><literal>exception</literal></link>.
   </para>
 
-  <sect2>
+  <sect2 id="resultset.references">
    <title>References</title>
    <itemizedlist>
     <listitem>
      <para>
-      <ulink url="http://staging.zoom.z3950.org/api/zoom-1.3.html#3.4"
+      <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
        >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
      </para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="file:///usr/local/src/z39.50/yaz/doc/zoom.resultsets.html"
+      <ulink url="&url.yaz.zoom.resultsets;"
        >The Result Sets section of the ZOOM-C documentation</ulink>
      </para>
     </listitem>
     };
   </synopsis>
   <para>
-   ### discusson
+   Records returned from Z39.50 servers are encoded using a record
+   syntax: the various national MARC formats are commonly used for
+   bibliographic data, GRS-1 or XML for complex structured data, SUTRS
+   for simple human-readable text, etc.  The
+   <literal>record::syntax</literal> enumeration specifies constants
+   representing common record syntaxes, and the
+   <literal>recsyn()</literal> method returns the value corresponding
+   to the record-syntax of the record on which it is invoked.
+   <note>
+    <para>
+     Because this interface uses an enumeration, it is difficult to
+     extend to other record syntaxes - for example, DANMARC, the MARC
+     variant widely used in Denmark.  We might either grow the
+     enumeration substantially, or change the interface to return
+     either an integer or a string.
+    </para>
+   </note>
+  </para>
+  <para>
+   The simplest thing to do with a retrieved record is simply to
+   <literal>render()</literal> it.  This returns a human-readable, but
+   not necessarily very pretty, representation of the contents of the
+   record.  This is useful primarily for testing and debugging, since
+   the application has no control over how the record appears.
+   (The application must <emphasis>not</emphasis>
+   <literal>delete</literal> the returned string - it is ``owned'' by
+   the record object.)
+  </para>
+  <para>
+   More sophisticated applications will want to deal with the raw data
+   themselves: the <literal>rawdata()</literal> method returns it.
+   Its format will vary depending on the record syntax: SUTRS, MARC
+   and XML records are returned ``as is'', and GRS-1 records as a
+   pointer to their top-level node, which is a
+   <literal>Z_GenericRecord</literal> structure as defined in the
+   <literal>&lt;yaz/z-grs.h&gt;</literal> header file.
+   (The application must <emphasis>not</emphasis>
+   <literal>delete</literal> the returned data - it is ``owned'' by
+   the record object.)
+  </para>
+  <para>
+   Perceptive readers will notice that there are no methods for access
+   to individual fields within a record.  That's because the different
+   record syntaxes are so different that there is no even a uniform
+   notion of what a field is across them all, let alone a sensible way
+   to implement such a function.  Fetch the raw data instead, and pick
+   it apart ``by hand''.
   </para>
 
-  <sect2>
+  <sect2 id="zoom.memory.management">
+   <title>Memory Management</title>
+   <para>
+    The <literal>record</literal> objects returned from
+    <literal>resultSet::getRecord()</literal> are ``owned'' by the
+    result set object: that means that the application is not
+    responsible for <literal>delete</literal>ing them - each
+    <literal>record</literal> is automatically deallocated when the
+    <literal>resultSet</literal> that owns it is
+    <literal>delete</literal>d.
+   </para>
+   <para>
+    Usually that's what you want: it means that you can easily fetch a
+    record, use it and forget all about it, like this:
+   </para>
+   <programlisting>
+    resultSet rs(conn, query);
+    cout &lt;&lt; rs.getRecord(0)-&gt;render();
+   </programlisting>
+   <para>
+    But sometimes you want a <literal>record</literal> to live on past
+    the lifetime of the <literal>resultSet</literal> from which it was
+    fetched.  In this case, the <literal>clone(f)</literal> method can
+    be used to make an autonomous copy.  The application must
+    <literal>delete</literal> it when it doesn't need it any longer:
+   </para>
+   <programlisting>
+    record *rec;
+    {
+        resultSet rs(conn, query);
+        rec = rs.getRecord(0)-&gt;clone();
+        // `rs' goes out of scope here, and is deleted
+    }
+    cout &lt;&lt; rec-&gt;render();
+    delete rec;
+   </programlisting>
+  </sect2>
+
+  <sect2 id="record.references">
    <title>References</title>
    <itemizedlist>
     <listitem>
      <para>
-      <ulink url="http://staging.zoom.z3950.org/api/zoom-1.3.html#3.5"
+      <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
        >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
      </para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="file:///usr/local/src/z39.50/yaz/doc/zoom.records.html"
+      <ulink url="&url.yaz.zoom.records;"
        >The Records section of the ZOOM-C documentation</ulink>
      </para>
     </listitem>
   <para>
    The <literal>ZOOM::exception</literal> class is a virtual base
    class, representing a diagnostic generated by the ZOOM-C++ library
-   or returned from a server.  ###
+   or returned from a server.  Its subclasses represent particular
+   kinds of error.
+  </para>
+  <para>
+   When any of the ZOOM methods fail, they respond by
+   <literal>throw</literal>ing an object of type
+   <literal>exception</literal> or one of its subclasses.  This most
+   usually happens with the <literal>connection</literal> constructor,
+   the various query constructors, the <literal>resultSet</literal>
+   constructor (which is actually the searching method) and
+   <literal>resultSet::getRecord()</literal>.
+  </para>
+  <para>
+    The base class has this declaration:
   </para>
   <synopsis>
     class exception {
     };
   </synopsis>
   <para>
-   This class has three (so far) concrete subclasses:
+   It has three concrete subclasses:
   </para>
 
-  <sect2>
+  <sect2 id="ZOOM::systemException">
    <title><literal>ZOOM::systemException</literal></title>
-   <para>
-    The class has this declaration:
-   </para>
    <synopsis>
     class systemException: public exception {
     public:
       const char *errmsg () const;
     };
    </synopsis>
+   <para>
+    Represents a ``system error'', typically indicating that a system
+    call failed - often in the low-level networking code that
+    underlies Z39.50.  <literal>errcode()</literal> returns the value
+    that the system variable <literal>errno</literal> had at the time
+    the exception was constructed; and <literal>errmsg()</literal>
+    returns a human-readable error-message corresponidng to that error
+    code.
+   </para>
   </sect2>
 
-  <sect2>
+  <sect2 id="ZOOM::bib1Exception">
    <title><literal>ZOOM::bib1Exception</literal></title>
-   <para>
-    The class has this declaration:
-   </para>
    <synopsis>
     class bib1Exception: public exception {
     public:
       const char *addinfo () const;
     };
    </synopsis>
+   <para>
+    Represents an error condition communicated by a Z39.50 server.
+    <literal>errcode()</literal> returns the BIB-1 diagnostic code of
+    the error, and <literal>errmsg()</literal> a human-readable error
+    message corresponding to that code.  <literal>addinfo()</literal>
+    returns any additional information associated with the error.
+   </para>
+   <para>
+    For example, if a ZOOM application tries to search in the
+    ``Voyager'' database of a server that does not have a database of
+    that name, a <literal>bib1Exception</literal> will be thrown in
+    which <literal>errcode()</literal> returns 109,
+    <literal>errmsg()</literal> returns the corresponding error
+    message ``Database unavailable'' and <literal>addinfo()</literal>
+    returns the name of the requested, but unavailable, database.
+   </para>
   </sect2>
 
-  <sect2>
+  <sect2 id="ZOOM::queryException">
    <title><literal>ZOOM::queryException</literal></title>
-   <para>
-    The class has this declaration:
-   </para>
    <synopsis>
     class queryException: public exception {
     public:
       const char *addinfo () const;
     };
    </synopsis>
+   <para>
+    This class represents an error in parsing a query into a form that
+    a Z39.50 can understand.  It must be created with the
+    <literal>qtype</literal> parameter equal to one of the query-type
+    constants, which can be retrieved via the
+    <literal>errcode()</literal> method; <literal>errmsg()</literal>
+    returns an error-message specifying which kind of query was
+    malformed; and <literal>addinfo()</literal> returns a copy of the
+    query itself (that is, the value of <literal>source</literal> with
+    which the exception object was created.)
+   </para>
   </sect2>
 
-  <sect2>
-   <title>Discussion</title>
+  <sect2 id="revised-sample">
+   <title>Revised Sample Program</title>
+   <para>
+    Now we can revise the sample program from the
+    <link linkend="zoom-introduction">introduction</link>
+    to catch exceptions and report any errors:
+   </para>
+   <programlisting>
+    /* g++ -o zoom-c++-hw zoom-c++-hw.cpp -lzoompp -lyaz */
+
+    #include &lt;iostream&gt;
+    #include &lt;yazpp/zoom.h&gt;
+
+    using namespace ZOOM;
+
+    int main(int argc, char **argv)
+    {
+        try {
+            connection conn("z3950.loc.gov", 7090);
+            conn.option("databaseName", "Voyager");
+            conn.option("preferredRecordSyntax", "USMARC");
+            resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
+            const record *rec = rs.getRecord(0);
+            cout &lt;&lt; rec-&gt;render() &lt;&lt; endl;
+        } catch (systemException &amp;e) {
+            cerr &lt;&lt; "System error " &lt;&lt;
+                e.errcode() &lt;&lt; " (" &lt;&lt; e.errmsg() &lt;&lt; ")" &lt;&lt; endl;
+        } catch (bib1Exception &amp;e) {
+            cerr &lt;&lt; "BIB-1 error " &lt;&lt; 
+                e.errcode() &lt;&lt; " (" &lt;&lt; e.errmsg() &lt;&lt; "): " &lt;&lt; e.addinfo() &lt;&lt; endl;
+        } catch (queryException &amp;e) {
+            cerr &lt;&lt; "Query error " &lt;&lt;
+                e.errcode() &lt;&lt; " (" &lt;&lt; e.errmsg() &lt;&lt; "): " &lt;&lt; e.addinfo() &lt;&lt; endl;
+        } catch (exception &amp;e) {
+            cerr &lt;&lt; "Error " &lt;&lt;
+                e.errcode() &lt;&lt; " (" &lt;&lt; e.errmsg() &lt;&lt; ")" &lt;&lt; endl;
+        }
+    }
+   </programlisting>
+   <para>
+    The heart of this program is the same as in the original version,
+    but it's now wrapped in a <literal>try</literal> block followed by
+    several <literal>catch</literal> blocks which try to give helpful
+    diagnostics if something goes wrong.
+   </para>
    <para>
-    ### discusson
+    The first such block diagnoses system-level errors such as memory
+    exhaustion or a network connection being broken by a server's
+    untimely death; the second catches errors at the Z39.50 level,
+    such as a server's report that it can't provide records in USMARC
+    syntax; the third is there in case there's something wrong with
+    the syntax of the query (although in this case it's correct); and
+    finally, the last <literal>catch</literal> block is a
+    belt-and-braces measure to be sure that nothing escapes us.
    </para>
   </sect2>
 
-  <sect2>
+  <sect2 id="exception.references">
    <title>References</title>
    <itemizedlist>
     <listitem>
      <para>
-      <ulink url="http://staging.zoom.z3950.org/api/zoom-1.3.html#3.7"
+      <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
        >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
      </para>
     </listitem>
+    <listitem>
+     <para>
+      <ulink url="&url.z39.50.diagnostics;">Bib-1 Diagnostics</ulink> on the
+      <ulink url="&url.z39.50;">Z39.50 Maintenance Agency</ulink> site.
+     </para>
+    </listitem>
    </itemizedlist>
    <para>
     Because C does not support exceptions, ZOOM-C has no API element
     <literal>exception</literal> class and its subclasses.  The
     closest thing is the <literal>ZOOM_connection_error</literal>
     function described in
-    <ulink url="file:///usr/local/src/z39.50/yaz/doc/zoom.html#zoom.connections"
+     <ulink url="&url.yaz.zoom.connections;"
        >The Connections section</ulink> of the documentation.
    </para>
   </sect2>
  sgml-always-quote-attributes:t
  sgml-indent-step:1
  sgml-indent-data:t
- sgml-parent-document: "zebra.xml"
+ sgml-parent-document: "yazpp.xml"
  sgml-local-catalogs: nil
  sgml-namecase-general:t
  End: