First finished version!
[yazpp-moved-to-github.git] / doc / zoom.xml
1 <chapter id="zoom">
2  <!-- $Id: zoom.xml,v 1.6 2002-10-10 22:48:10 mike Exp $ -->
3  <title>ZOOM-C++</title>
4
5
6  <sect1 id="zoom-introduction">
7   <title>Introduction</title>
8   <para>
9    <ulink url="http://zoom.z3950.org/">ZOOM</ulink>
10    is the emerging standard API for information retrieval programming
11    using the Z39.50 protocol.  ZOOM's
12    <ulink url="http://zoom.z3950.org/api/">Abstract API</ulink>
13    specifies semantics for classes representing key IR concepts such as
14    connections, queries, result sets and records; and there are various
15    <ulink url="http://zoom.z3950.org/bind/">bindings</ulink>
16    specifying how those concepts should be represented in various
17    programming languages.
18   </para>
19   <para>
20    The Yaz++ library includes an implementation of the <ulink
21    url="http://zoom.z3950.org/bind/cplusplus/"
22         >C++ binding</ulink>
23    for ZOOM, enabling quick, easy development of client applications.
24   </para>
25   <para>
26    For example, here is a tiny Z39.50 client that fetches and displays
27    the MARC record for Farlow & Brett Surman's
28    <!-- ### there must be a better way to mark up a book title? -->
29    <emphasis>The Complete Dinosaur</emphasis>
30    from the Library of Congress's Z39.50 server:
31   </para>
32   <synopsis>
33     #include &lt;iostream&gt;
34     #include &lt;yaz++/zoom.h&gt;
35
36     using namespace ZOOM;
37
38     int main(int argc, char **argv)
39     {
40         connection conn("z3950.loc.gov", 7090);
41         conn.option("databaseName", "Voyager");
42         resultSet rs(conn, prefixQuery("@attr attr 1=7 0253333490"));
43         const record *rec = rs.getRecord(0);
44         cout &lt;&lt; rec-&gt;render() &lt;&lt; endl;
45     }
46   </synopsis>
47   <para>
48    (Note that, for the sake of simplicity, this does not check for
49    errors: we show a more realistic version of this program later.)
50   </para>
51   <para>
52    Yaz++'s implementation of the C++ binding is a thin layer over Yaz's
53    implementation of the C binding.  For information on the supported
54    options and other such details, see the ZOOM-C documentation, which
55    can be found on-line at
56    <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php"/>
57   </para>
58   <para>
59    All of the classes defined by ZOOM-C++ are in the
60    <literal>ZOOM</literal> namespace.  We will now consider
61    the five main classes in turn:
62
63    <itemizedlist>
64     <listitem>
65      <para>
66       <literal>connection</literal>
67      </para>
68     </listitem>
69
70     <listitem>
71      <para>
72       <literal>query</literal> and its subclasses
73       <literal>prefixQuery</literal> and
74       <literal>CCLQuery</literal>
75      </para>
76     </listitem>
77
78     <listitem>
79      <para>
80       <literal>resultSet</literal>
81      </para>
82     </listitem>
83
84     <listitem>
85      <para>
86       <literal>record</literal>
87      </para>
88     </listitem>
89
90     <listitem>
91      <para>
92       <literal>exception</literal> and its subclasses
93       <literal>systemException</literal>,
94       <literal>bib1Exception</literal> and
95       <literal>queryException</literal>
96      </para>
97     </listitem>
98    </itemizedlist>
99   </para>
100  </sect1>
101
102
103  <sect1 id="zoom-connection">
104   <title><literal>ZOOM::connection</literal></title>
105   <para>
106    A <literal>ZOOM::connection</literal> object represents an open
107    connection to a Z39.50 server.  Such a connection is forged by
108    constructing a <literal>connection</literal> object.
109   </para>
110   <para>
111    The class has this declaration:
112   </para>
113   <synopsis>
114     class connection {
115     public:
116       connection (const char *hostname, int portnum);
117       ~connection ();
118       const char *option (const char *key) const;
119       const char *option (const char *key, const char *val);
120     };
121   </synopsis>
122   <para>
123    When a new <literal>connection</literal> is created, the hostname
124    and port number of a Z39.50 server must be supplied, and the
125    network connection is forged and wrapped in the new object.  If the
126    connection can't be established - perhaps because the hostname
127    couldn't be resolved, or there is no server listening on the
128    specified port - then an
129    <link linkend="zoom-exception"><literal>exception</literal></link>
130    is thrown.
131   </para>
132   <para>
133    The only other methods on a <literal>connection</literal> object
134    are for getting and setting options.  Any name-value pair of
135    strings may be set as options, and subsequently retrieved, but
136    certain options have special meanings which are understood by the
137    ZOOM code and affect the behaviour of the object that carries
138    them.  For example, the value of the
139    <literal>databaseName</literal> option is used as the name of the
140    database to query when a search is executed against the
141    <literal>connection</literal>.  For a full list of such special
142    options, see the ZOOM abstract API and the ZOOM-C documentation
143    (links below).
144   </para>
145
146   <sect2>
147    <title>References</title>
148    <itemizedlist>
149     <listitem>
150      <para>
151       <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.2"
152         >Section 3.2 (Connection) of the ZOOM Abstract API</ulink>
153      </para>
154     </listitem>
155     <listitem>
156      <para>
157       <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php#zoom.connections"
158         >The Connections section of the ZOOM-C documentation</ulink>
159      </para>
160     </listitem>
161    </itemizedlist>
162   </sect2>
163  </sect1>
164
165
166  <sect1 id="zoom-query">
167   <title><literal>ZOOM::query</literal> and subclasses</title>
168   <para>
169    The <literal>ZOOM::query</literal> class is a virtual base class,
170    representing a query to be submitted to a server.  This class has
171    no methods, but two (so far) concrete subclasses, each implementing
172    a specific query notation.
173   </para>
174
175   <sect2>
176    <title><literal>ZOOM::prefixQuery</literal></title>
177    <synopsis>
178     class prefixQuery : public query {
179     public:
180       prefixQuery (const char *pqn);
181       ~prefixQuery ();
182     };
183    </synopsis>
184    <para>
185     This class enables a query to be created by compiling Yaz's
186     cryptic but powerful
187     <ulink url="http://www.indexdata.dk/yaz/doc/tools.php#PQF"
188         >Prefix Query Notation (PQN)</ulink>.
189    </para>
190   </sect2>
191
192   <sect2>
193    <title><literal>ZOOM::CCLQuery</literal></title>
194    <synopsis>
195     class CCLQuery : public query {
196     public:
197       CCLQuery (const char *ccl, void *qualset);
198       ~CCLQuery ();
199     };
200    </synopsis>
201    <para>
202     This class enables a query to be created using the simpler but
203     less expressive
204     <ulink url="http://www.indexdata.dk/yaz/doc/tools.php#CCL"
205         >Common Command Language (CCL)</ulink>.
206     The qualifiers recognised by the CCL parser are specified in an
207     external configuration file in the format described by the Yaz
208     documentation.
209    </para>
210    <para>
211     If query construction fails for either type of
212     <literal>query</literal> object - typically because the query
213     string itself is not valid PQN or CCL - then an
214     <link linkend="zoom-exception"><literal>exception</literal></link>
215     is thrown.
216    </para>
217   </sect2>
218
219   <sect2>
220    <title>Discussion</title>
221    <para>
222     It will be readily recognised that these objects have no methods
223     other than their constructors: their only role in life is to be
224     used in searching, by being passed to the
225     <literal>resultSet</literal> class's constructor.
226    </para>
227    <para>
228     Given a suitable set of CCL qualifiers, the following pairs of
229     queries are equivalent:
230    </para>
231    <screen>
232     prefixQuery("dinosaur");
233     CCLQuery("dinosaur");
234
235     prefixQuery("@and complete dinosaur");
236     CCLQuery("complete and dinosaur");
237
238     prefixQuery("@and complete @or dinosaur pterosaur");
239     CCLQuery("complete and (dinosaur or pterosaur)");
240
241     prefixQuery("@attr 1=7 0253333490");
242     CCLQuery("isbn=0253333490");
243    </screen>
244   </sect2>
245
246   <sect2>
247    <title>References</title>
248    <itemizedlist>
249     <listitem>
250      <para>
251       <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
252         >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
253      </para>
254     </listitem>
255     <listitem>
256      <para>
257       <ulink url="http://www.indexdata.dk/yaz/doc/zoom.query.php"
258         >The Queries section of the ZOOM-C documentation</ulink>
259      </para>
260     </listitem>
261    </itemizedlist>
262   </sect2>
263  </sect1>
264
265
266  <sect1 id="zoom-resultset">
267   <title><literal>ZOOM::resultSet</literal></title>
268   <para>
269    A <literal>ZOOM::resultSet</literal> object represents a set of
270    records identified by a query that has been executed against a
271    particular connection.  The sole purpose of both
272    <literal>connection</literal> and <literal>query</literal> objects
273    is that they can be used to create new
274    <literal>resultSet</literal>s - that is, to perform a search on the
275    server on the remote end of the connection.
276   </para>
277   <para>
278    The class has this declaration:
279   </para>
280   <synopsis>
281     class resultSet {
282     public:
283       resultSet (connection &amp;c, const query &amp;q);
284       ~resultSet ();
285       const char *option (const char *key) const;
286       const char *option (const char *key, const char *val);
287       size_t size () const;
288       const record *getRecord (size_t i) const;
289     };
290   </synopsis>
291   <para>
292    New <literal>resultSet</literal>s are created by the constructor,
293    which is passed a <literal>connection</literal>, indicating the
294    server on which the search is to be performed, and a
295    <literal>query</literal>, indicating what search to perform.  If
296    the search fails - for example, because the query uses attributes
297    that the server doesn't implement - then an
298    <link linkend="zoom-exception"><literal>exception</literal></link>
299    is thrown.
300   </para>
301   <para>
302    Like <literal>connection</literal>s, <literal>resultSet</literal>
303    objects can carry name-value options.  The special options which
304    affect ZOOM-C++'s behaviour are the same as those for ZOOM-C and
305    are described in its documentation (link below).  In particular,
306    the <literal>preferredRecordSyntax</literal> option may be set to
307    a string such as ``USMARC'', ``SUTRS'' etc. to indicate what the
308    format in which records should be retrieved; and the
309    <literal>elementSetName</literal> option indicates whether brief
310    records (``B''), full records (``F'') or some other composition
311    should be used.
312   </para>
313   <para>
314    The <literal>size()</literal> method returns the number of records
315    in the result set.  Zero is a legitimate value: a search that finds
316    no records is not the same as a search that fails.
317   </para>
318   <para>
319    Finally, the <literal>getRecord</literal> method returns the
320    <parameter>i</parameter>th record from the result set, where
321    <parameter>i</parameter> is zero-based: that is, legitmate values
322    range from zero up to one less than the result-set size.  If the
323    method fails, for example because the requested record is out of
324    range, it <literal>throw</literal>s an
325    <link linkend="zoom-exception"><literal>exception</literal></link>.
326   </para>
327
328   <sect2>
329    <title>References</title>
330    <itemizedlist>
331     <listitem>
332      <para>
333       <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
334         >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
335      </para>
336     </listitem>
337     <listitem>
338      <para>
339       <ulink url="http://www.indexdata.dk/yaz/doc/zoom.resultsets.php"
340         >The Result Sets section of the ZOOM-C documentation</ulink>
341      </para>
342     </listitem>
343    </itemizedlist>
344   </sect2>
345  </sect1>
346
347
348  <sect1 id="zoom-record">
349   <title><literal>ZOOM::record</literal></title>
350   <para>
351    A <literal>ZOOM::record</literal> object represents a chunk of data
352    from a <literal>resultSet</literal> returned from a server.
353   </para>
354   <para>
355    The class has this declaration:
356   </para>
357   <synopsis>
358     class record {
359     public:
360       ~record ();
361       enum syntax {
362         UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
363       };
364       record *clone () const;
365       syntax recsyn () const;
366       const char *render () const;
367       const char *rawdata () const;
368     };
369   </synopsis>
370   <para>
371    Records returned from Z39.50 servers are encoded using a record
372    syntax: the various national MARC formats are commonly used for
373    bibliographic data, GRS-1 or XML for complex structured data, SUTRS
374    for simple human-readable text, etc.  The
375    <literal>record::syntax</literal> enumeration specifies constants
376    representing common record syntaxes, and the
377    <literal>recsyn()</literal> method returns the value corresponding
378    to the record-syntax of the record on which it is invoked.
379    <note>
380     <para>
381      Because this interface uses an enumeration, it is difficult to
382      extend to other record syntaxes - for example, DANMARC, the MARC
383      variant widely used in Denmark.  We might either grow the
384      enumeration substantially, or change the interface to return
385      either an integer or a string.
386     </para>
387    </note>
388   </para>
389   <para>
390    The simplest thing to do with a retrieved record is simply to
391    <literal>render()</literal> it.  This returns a human-readable, but
392    not necessarily very pretty, representation of the contents of the
393    record.  This is useful primarily for testing and debugging, since
394    the application has no control over how the record appears.
395    (The application must <emphasis>not</emphasis>
396    <literal>delete</literal> the returned string - it is ``owned'' by
397    the record object.)
398   </para>
399   <para>
400    More sophisticated applications will want to deal with the raw data
401    themselves: the <literal>rawdata()</literal> method returns it.
402    Its format will vary depending on the record syntax: SUTRS, MARC
403    and XML records are returned ``as is'', and GRS-1 records as a
404    pointer to their top-level node, which is a
405    <literal>Z_GenericRecord</literal> structure as defined in the
406    <literal>&lt;yaz/z-grs.h&gt;</literal> header file.
407    (The application must <emphasis>not</emphasis>
408    <literal>delete</literal> the returned data - it is ``owned'' by
409    the record object.)
410   </para>
411   <para>
412    Perceptive readers will notice that there are no methods for access
413    to individual fields within a record.  That's because the different
414    record syntaxes are so different that there is no even a uniform
415    notion of what a field is across them all, let alone a sensible way
416    to implement such a function.  Fetch the raw data instead, and pick
417    it apart ``by hand''.
418   </para>
419
420   <sect2>
421    <title>Memory Management</title>
422    <para>
423     The <literal>record</literal> obejcts returned from
424     <literal>resultSet::getRecord()</literal> are ``owned'' by the
425     result set object: that means that the application is not
426     responsible for <literal>delete</literal>ing them - each
427     <literal>record</literal> is automatically deallocated when the
428     <literal>resultSet</literal> that owns it is
429     <literal>delete</literal>d.
430    </para>
431    <para>
432     Usually that's what you want: it means that you can easily fetch a
433     record, use it and forget all about it, like this:
434    </para>
435    <screen>
436     resultSet rs(conn, query);
437     cout &lt;&lt; rs.getRecord(0)-&gt;render();
438    </screen>
439    <para>
440     But sometimes you want a <literal>record</literal> to live on past
441     the lifetime of the <literal>resultSet</literal> from which it was
442     fetched.  In this case, the <literal>clone(f)</literal> method can
443     be used to make an autonomous copy.  The application must
444     <literal>delete</literal> it when it doesn't need it any longer:
445    </para>
446    <screen>
447     record *rec;
448     {
449         resultSet rs(conn, query);
450         rec = rs.getRecord(0)-&gt;clone();
451         // `rs' goes out of scope here, and is deleted
452     }
453     cout &lt;&lt; rec-&gt;render();
454     delete rec;
455    </screen>
456   </sect2>
457
458   <sect2>
459    <title>References</title>
460    <itemizedlist>
461     <listitem>
462      <para>
463       <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
464         >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
465      </para>
466     </listitem>
467     <listitem>
468      <para>
469       <ulink url="http://www.indexdata.dk/yaz/doc/zoom.records.php"
470         >The Records section of the ZOOM-C documentation</ulink>
471      </para>
472     </listitem>
473    </itemizedlist>
474   </sect2>
475  </sect1>
476
477
478  <sect1 id="zoom-exception">
479   <title><literal>ZOOM::exception</literal> and subclasses</title>
480   <para>
481    The <literal>ZOOM::exception</literal> class is a virtual base
482    class, representing a diagnostic generated by the ZOOM-C++ library
483    or returned from a server.  Its subclasses represent particular
484    kinds of error.
485   </para>
486   <para>
487    When any of the ZOOM methods fail, they respond by
488    <literal>throw</literal>ing an object of type
489    <literal>exception</literal> or one of its subclasses.  This most
490    usually happens with the <literal>connection</literal> constructor,
491    the various query constructors, the <literal>resultSet</literal>
492    constructor (which is actually the searching method) and
493    <literal>resultSet::getRecord()</literal>.
494   </para>
495   <para>
496     The base class has this declaration:
497   </para>
498   <synopsis>
499     class exception {
500     public:
501       exception (int code);
502       int errcode () const;
503       const char *errmsg () const;
504     };
505   </synopsis>
506   <para>
507    It has three concrete subclasses:
508   </para>
509
510   <sect2>
511    <title><literal>ZOOM::systemException</literal></title>
512    <synopsis>
513     class systemException: public exception {
514     public:
515       systemException ();
516       int errcode () const;
517       const char *errmsg () const;
518     };
519    </synopsis>
520    <para>
521     Represents a ``system error'', typically indicating that a system
522     call failed - often in the low-level networking code that
523     underlies Z39.50.  <literal>errcode()</literal> returns the value
524     that the system variable <literal>errno</literal> had at the time
525     the exception was constructed; and <literal>errmsg()</literal>
526     returns a human-readable error-message corresponidng to that error
527     code.
528    </para>
529   </sect2>
530
531   <sect2>
532    <title><literal>ZOOM::bib1Exception</literal></title>
533    <synopsis>
534     class bib1Exception: public exception {
535     public:
536       bib1Exception (int errcode, const char *addinfo);
537       int errcode () const;
538       const char *errmsg () const;
539       const char *addinfo () const;
540     };
541    </synopsis>
542    <para>
543     Represents an error condition communicated by a Z39.50 server.
544     <literal>errcode()</literal> returns the BIB-1 diagnostic code of
545     the error, and <literal>errmsg()</literal> a human-readable error
546     message corresponding to that code.  <literal>addinfo()</literal>
547     returns any additional information associated with the error.
548    </para>
549    <para>
550     For example, if a ZOOM application tries to search in the
551     ``Voyager'' database of a server that does not have a database of
552     that name, a <literal>bib1Exception</literal> will be thrown in
553     which <literal>errcode()</literal> returns 109,
554     <literal>errmsg()</literal> returns the corresponding error
555     message ``Database unavailable'' and <literal>addinfo()</literal>
556     returns the name of the requested, but unavailable, database.
557    </para>
558   </sect2>
559
560   <sect2>
561    <title><literal>ZOOM::queryException</literal></title>
562    <synopsis>
563     class queryException: public exception {
564     public:
565       static const int PREFIX = 1;
566       static const int CCL = 2;
567       queryException (int qtype, const char *source);
568       int errcode () const;
569       const char *errmsg () const;
570       const char *addinfo () const;
571     };
572    </synopsis>
573    <para>
574     This class represents an error in parsing a query into a form that
575     a Z39.50 can understand.  It must be created with the
576     <literal>qtype</literal> parameter equal to one of the query-type
577     constants, which can be retrieved via the
578     <literal>errcode()</literal> method; <literal>errmsg()</literal>
579     returns an error-message specifying which kind of query was
580     malformed; and <literal>addinfo()</literal> returns a copy of the
581     query itself (that is, the value of <literal>source</literal> with
582     which the exception object was created.)
583    </para>
584   </sect2>
585
586   <sect2>
587    <title>References</title>
588    <itemizedlist>
589     <listitem>
590      <para>
591       <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
592         >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
593      </para>
594     </listitem>
595     <listitem>
596      <para>
597       <ulink url="http://lcweb.loc.gov/z3950/agency/defns/bib1diag.html"
598         >Bib-1 Diagnostics</ulink> on the
599       <ulink url="http://lcweb.loc.gov/z3950/agency/"
600         >Z39.50 Maintenance Agency</ulink> site.
601      </para>
602     </listitem>
603    </itemizedlist>
604    <para>
605     Because C does not support exceptions, ZOOM-C has no API element
606     that corresponds directly with ZOOM-C++'s
607     <literal>exception</literal> class and its subclasses.  The
608     closest thing is the <literal>ZOOM_connection_error</literal>
609     function described in
610     <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php#zoom.connections"
611         >The Connections section</ulink> of the documentation.
612    </para>
613   </sect2>
614  </sect1>
615
616 </chapter>
617
618  <!-- Keep this comment at the end of the file
619  Local variables:
620  mode: sgml
621  sgml-omittag:t
622  sgml-shorttag:t
623  sgml-minimize-attributes:nil
624  sgml-always-quote-attributes:t
625  sgml-indent-step:1
626  sgml-indent-data:t
627  sgml-parent-document: "zebra.xml"
628  sgml-local-catalogs: nil
629  sgml-namecase-general:t
630  End:
631  -->