315e78e1a1e56914d6750bdbfd90477f541c882b
[yaz-moved-to-github.git] / doc / zoom.xml
1 <!-- $Id: zoom.xml,v 1.10 2001-11-15 21:58:50 adam Exp $ -->
2  <chapter id="zoom"><title>Building clients with ZOOM</title>
3   
4   <para>
5     &zoom; is an acronym for 'Z39.50 Object-Orientation Model' and is
6    an initiative started by Mike Taylor (Mike is from the UK, which
7    explains the peculiar name of the model). The goal of &zoom; is to
8    provide a common Z39.50 client API not bound to a particular
9    programming language or toolkit.
10   </para>
11   <para>
12    The lack of a simple Z39.50 client API for &yaz; has become more
13    and more apparent over time. So when the first &zoom; specification
14    became available,
15    an implementation for &yaz; was quickly developed. For the first time, it is
16    now as easy (or easier!) to develop clients than servers with &yaz;. This
17    chapter describes the &zoom; C binding. Before going futher, please
18    reconsider whether C is the right programming language for the job.
19    There are other language bindings available for &yaz;, and still
20    more
21    are in active development. See the
22    <ulink url="http://zoom.z3950.org/">ZOOM website</ulink> for
23    more information.
24   </para>
25
26   <para>
27    In order to fully understand this chapter you should read and
28    try the example programs <literal>zoomtst1.c</literal>,
29    <literal>zoomtst2.c</literal>, .. in the <literal>zoom</literal>
30    directory.
31   </para>
32
33   <para>
34    The C language misses many features found in object oriented languages
35    such as C++, Java, etc. For example, you'll have to manually,
36    destroy all objects you create, even though you may think of them as
37    temporary. Most objects has a <literal>_create</literal> - and a
38    <literal>_destroy</literal> variant.
39    All objects are in fact pointers to internal stuff, but you don't see
40    that because of typedefs. All destroy methods should gracefully ignore a
41    <literal>NULL</literal> pointer.
42   </para>
43   <para>
44    In each of the sections below you'll find a sub section called
45    protocol behavior, that descries how the API maps to the Z39.50
46    protocol.
47   </para>
48   <sect1 id="zoom.connections"><title>Connections</title>
49    
50    <para>The Connection object is a session with a target.
51    </para>
52    <synopsis>
53    #include &lt;yaz/zoom.h>
54     
55    Z3950_connection Z3950_connection_new (const char *host, int portnum);
56     
57    Z3950_connection Z3950_connection_create (Z3950_options options);
58
59    void Z3950_connection_connect(Z3950_connection c, const char *host,
60                                  int portnum);
61    void Z3950_connection_destroy (Z3950_connection c);
62    </synopsis>
63    <para>
64     Connection objects are created with either function
65     <function>Z3950_connection_new</function> or 
66     <function>Z3950_connection_create</function>.
67     The former creates and automatically attempts to establish a network
68     connection with the target. The latter doesn't establish
69     a connection immediately, thus allowing you to specify options
70     before establishing network connection using the function
71     <function>Z3950_connection_connect</function>. 
72     If the portnumber, <literal>portnum</literal>, is zero, the
73     <literal>host</literal> is consulted for a port specification.
74     If no port is given, 210 is used. A colon denotes the beginning of
75     a port number in the host string. If the host string includes a
76     slash, the following part specifies a database for the connection.
77    </para>
78    <para>
79     Connection objects should be destroyed using the function
80     <function>Z3950_connection_destroy</function>.
81    </para>
82    <synopsis>
83     void Z3950_connection_option_set (Z3950_connection c,
84                                       const char *key,
85                                       const char *val);
86
87     const char *Z3950_connection_option_get (Z3950_connection c,
88                                              const char *key);
89
90     const char *Z3950_connection_host (Z3950_connection c);
91    </synopsis>
92    <para>
93     The <function>Z3950_connection_option_set</function> allows you to
94     set an option given by <parameter>key</parameter> to the value
95     <parameter>value</parameter> for the connection.
96      Function <function>Z3950_connection_option_get</function> returns
97     the value for an option given by <parameter>key</parameter>.
98    </para>
99    <table frame="top"><title>ZOOM Connection Options</title>
100     <tgroup cols="3">
101      <colspec colwidth="4*" colname="name"></colspec>
102      <colspec colwidth="7*" colname="description"></colspec>
103      <colspec colwidth="3*" colname="default"></colspec>
104      <thead>
105       <row>
106        <entry>Option</entry>
107        <entry>Description</entry>
108        <entry>Default</entry>
109       </row>
110      </thead>
111      <tbody>
112       <row><entry>
113         implementationName</entry><entry>Name of Your client
114        </entry><entry>none</entry></row>
115       <row><entry>
116         user</entry><entry>Authentication user name
117        </entry><entry>none</entry></row>
118       <row><entry>
119         group</entry><entry>Authentication group name
120        </entry><entry>none</entry></row>
121       <row><entry>
122         pass</entry><entry>Authentication password
123       </entry><entry>none</entry></row>
124       <row><entry>
125         proxy</entry><entry>Proxy host
126        </entry><entry>none</entry></row>
127       <row><entry>
128         async</entry><entry>If true (1) the connection operates in 
129         asynchronous operation which means that all calls are non-blocking
130         except
131         <link linkend="zoom.events"><function>Z3950_event</function></link>.
132        </entry><entry>0</entry></row>
133       <row><entry>
134         maximumRecordSize</entry><entry> Maximum size of single record.
135        </entry><entry>1 MB</entry></row>
136       <row><entry>
137         preferredMessageSize</entry><entry> Maximum size of multiple records.
138        </entry><entry>1 MB</entry></row>
139      </tbody>
140     </tgroup>
141    </table>
142    <para>
143     Function <function>Z3950_connection_host</function> returns
144      the host for the connection as specified in a call to
145     <function>Z3950_connection_new</function> or 
146     <function>Z3950_connection_connect</function>.
147     This function returns <literal>NULL</literal> if host isn't
148     set for the connection.
149    </para>
150    <synopsis>
151      int Z3950_connection_error (Z3950_connection c, const char **cp,
152                                  const char **addinfo);
153    </synopsis>
154    <para>
155     Use <function>Z3950_connection_error</function> to check for
156     errors for the last operation(s) performed. The function returns
157     zero if no errors occurred; non-zero otherwise indicating the error.
158     Pointers <parameter>cp</parameter> and <parameter>addinfo</parameter>
159     holds messages for the error and additional-info if passed as
160     non-<literal>NULL</literal>.
161    </para>
162    <sect2><title>Protocol behavior</title>
163     <para>
164      The calls <function>Z3950_connection_new</function> and
165      <function>Z3950_connection_connect</function> establises a TCP/IP
166       connection and sends an Initialize Request to the target if
167       possible. In addition, the calls waits for an Initialize Response
168       from the target and the result is inspected (OK or rejected).
169     </para>
170     <para>
171      If <literal>proxy</literal> is set then the client will establish
172      a TCP/IP connection with the peer as specified by the
173      <literal>proxy</literal> host and the hostname as part of the
174      connect calls will be set as part of the Initialize Request.
175      The proxy server will then "forward" the PDU's transparently
176      to the target behind the proxy.
177     </para>
178     <para>
179      For the authentication parameters, if option <literal>user</literal>
180      is set and both options <literal>group</literal> and
181      <literal>pass</literal> are unset, then Open style
182      authentication is used (Version 2/3) in which case the username
183      is usually followed by a slash, then by a password.
184      If either <literal>group</literal>
185      or <literal>pass</literal> is set then idPass authentication
186      (Version 3 only) is used. If none of the options are set, no
187      authentication parameters are set as part of the Initialize Request
188      (obviously).
189     </para>
190     <para>
191      When option <literal>async</literal> is 1, it really means that
192      all network operations are postponed (and queued) until the
193      function <literal>Z3950_event</literal> is invoked. When doing so
194      it doesn't make sense to check for errors after
195      <literal>Z3950_connection_new</literal> is called since that
196      operation "connecting - and init" is still incomplete and the
197      API cannot tell the outcome (yet).
198     </para>
199     </sect2>
200   </sect1>
201   <sect1 id="zoom.query"><title>Queries</title>
202    <para>
203     Query objects represents queries.
204    </para>
205    <synopsis>
206      Z3950_query Z3950_query_create(void);
207
208      void Z3950_query_destroy(Z3950_query q);
209
210      int Z3950_query_prefix(Z3950_query q, const char *str);
211
212      int Z3950_query_sortby(Z3950_query q, const char *criteria);
213    </synopsis>
214    <para>
215     Create query objects using <function>Z3950_query_create</function>
216     and destroy them by calling <function>Z3950_query_destroy</function>.
217     RPN-queries can be specified in <link linkend="PQF">PQF</link>
218     notation by using the
219     function <function>Z3950_query_prefix</function>. More
220     query types will be added later, such as
221     <link linkend="CCL">CCL</link> to RPN-mapping, native CCL query,
222     etc. In addition to a search, a sort criteria may be set. Function
223     <function>Z3950_query_sortby</function> specifies a 
224     sort criteria using the same string notation for sort as offered by
225     the <link linkend="sortspec">YAZ client</link>.
226    </para>
227    <sect2><title>Protocol behavior</title>
228     <para>
229      The query object is just an interface for the member Query
230      in the SearchRequest. The sortby-function is an interface to the
231      sortSequence member of the SortRequest.
232     </para>
233    </sect2>
234   </sect1>
235   <sect1 id="zoom.resultsets"><title>Result sets</title>
236    <para>
237     The result set object is a container for records returned from
238     a target.
239    </para>
240    <synopsis>
241      Z3950_resultset Z3950_connection_search(Z3950_connection,
242                                              Z3950_query q);
243
244      Z3950_resultset Z3950_connection_search_pqf(Z3950_connection c,
245                                                  const char *q);
246
247      void Z3950_resultset_destroy(Z3950_resultset r);
248    </synopsis>
249    <para>
250     Function <function>Z3950_connection_search</function> creates
251      a result set given a connection and query.
252     Destroy a result set by calling
253     <function>Z3950_resultset_destroy</function>.
254     Simple clients may using PQF only may use function
255     <function>Z3950_connection_search_pqf</function> in which case
256     creating query objects is not necessary.
257    </para>
258    <synopsis>
259      void Z3950_resultset_option_set (Z3950_resultset r,
260                                       const char *key,
261                                       const char *val);
262
263      const char *Z3950_resultset_option_get (Z3950_resultset r,
264                                              const char *key);
265
266      size_t Z3950_resultset_size (Z3950_resultset r);
267    </synopsis>
268    <para>
269     Functions <function>Z3950_resultset_options_set</function> and
270     <function>Z3950_resultset_get</function> sets and gets an option
271     for a result set similar to <function>Z3950_connection_option_get</function>
272     and <function>Z3950_connection_option_set</function>.
273    </para>
274    <para>
275     The number of hits also called result-count is returned by
276     function <function>Z3950_resultset_size</function>.
277    </para>
278    <table frame="top"><title>ZOOM Result set Options</title>
279     <tgroup cols="3">
280      <colspec colwidth="4*" colname="name"></colspec>
281      <colspec colwidth="7*" colname="description"></colspec>
282      <colspec colwidth="2*" colname="default"></colspec>
283      <thead>
284       <row>
285        <entry>Option</entry>
286        <entry>Description</entry>
287        <entry>Default</entry>
288       </row>
289      </thead>
290      <tbody>
291       <row><entry>
292         piggyback</entry><entry>True (1) if piggyback should be
293         used in searches; false (0) if not.
294        </entry><entry>1</entry></row>
295       <row><entry>
296         start</entry><entry>Offset of first record to be 
297         retrieved from target. First record has offset 0 unlike the
298         protocol specifications where first record has position 1.
299        </entry><entry>0</entry></row>
300       <row><entry>
301         count</entry><entry>Number of records to be retrieved.
302        </entry><entry>0</entry></row>
303       <row><entry>
304         elementSetName</entry><entry>Element-Set name of records. 
305         Most targets should honor element set name <literal>B</literal>
306         and <literal>F</literal> for brief and full respectively.
307        </entry><entry>none</entry></row>
308       <row><entry>
309         preferredRecordSyntax</entry><entry>Preferred Syntax, such as
310         <literal>USMARC</literal>, <literal>SUTRS</literal>, etc.
311        </entry><entry>none</entry></row>
312       <row><entry>
313         smallSetUpperBound</entry><entry>If hits is less than or equal to this
314         value, then target will return all records using small element set name
315        </entry><entry>0</entry></row>
316       <row><entry>
317         largeSetLowerBound</entry><entry>If hits is greator than this
318         value, the target will return no records.
319        </entry><entry>1</entry></row>
320       <row><entry>
321         mediumSetPresentNumber</entry><entry>This value represents
322         the number of records to be returned as part of a search when when
323         hits is less than or equal to large set lower bound and if hits
324         is greator than small set upper bound.
325        </entry><entry>0</entry></row>
326       <row><entry>
327         smallSetElementSetName</entry><entry>
328         The element set name to be used for small result sets.
329        </entry><entry>none</entry></row>
330       <row><entry>
331         mediumSetElementSetName</entry><entry>
332         The element set name to be for medium-sized result sets.
333        </entry><entry>none</entry></row>
334       <row><entry>
335         databaseName</entry><entry>One or more database names
336         separated by character plus (<literal>+</literal>).
337        </entry><entry>Default</entry></row>
338      </tbody>
339     </tgroup>
340    </table>
341    <sect2>
342     <title>Protocol behavior</title>
343     <para>
344      The creation of a result set involves at least a SearchRequest
345      - SearchResponse protocol handshake. Following that, if a sort
346      critieria was specified as part of the query, a sortRequest -
347      SortResponse handshake takes place. Note that it is necessary to
348      perform sorting before any retrieval takes place, so no records will
349      be returned from the target as part of the SearchResponse because these
350      would be unsorted. Hence, piggyback is disabled when sort critieria
351      is set. Following Search - and a Possible sort, Retrieval takes
352      place - as one or more Present Requests - Present Response being
353      transferred.
354      </para>
355     <para>
356      The API allows for two different modes for retrieval. A high level
357      mode which is somewhat more powerful and a low level one.
358      The low level is "enabled" when the settings
359      <literal>smallSetUpperBound</literal>,
360      <literal>mediumSetPresentNumber</literal> and
361      <literal>largeSetLowerBound</literal> are set. The low level mode
362      thus allows you to precisely set how records are returned as part
363      of a search response as offered by the Z39.50 protocol.
364      Since the client may be retrieving records as part of the
365      search response, this mode doesn't work well if sorting is used.
366      </para>
367     <para>
368      The high-level mode allows you to fetch a range of records from
369      the result set with a given start offset. When you use this mode
370      the client will automatically use piggyback if that is possible
371      with the target and perform one or more present requests as needed.
372      Even if the target returns fewer records as part of a present response
373      because of a record size limit, etc. the client will repeat sending
374      present requests. As an example, if option <literal>start</literal>
375      is 0 (default) and <literal>count</literal> is 4, and
376      <literal>piggyback</literal> is 1 (default) and no sorting critieria
377      is specified, then the client will attempt to retrieve the 4
378      records as part the search response (using piggyback). On the other
379      hand, if either <literal>start</literal> is positive or if
380      a sorting criteria is set, or if <literal>piggyback</literal>
381      is 0, then the client will not perform piggyback but send Present
382      Requests instead.
383     </para>
384     <para>
385      If either of the options <literal>mediumSetElementSetName</literal> and
386      <literal>smallSetElementSetName</literal> are unset, the value
387      of option <literal>elementSetName</literal> is used for piggyback
388      searches. This means that for the high-level mode you only have
389      to specify one elementSetName option rather than three.
390      </para>
391    </sect2>
392   </sect1>
393   <sect1 id="zoom.records"><title>Records</title>
394    <para>
395     A record object is a retrival record on the client side -
396     created from result sets.
397    </para>
398    <synopsis>
399      void Z3950_resultset_records (Z3950_resultset r,
400                                    Z3950_record *recs,
401                                    size_t start, size_t count);
402      Z3950_record Z3950_resultset_record (Z3950_resultset s, size_t pos);
403
404      void *Z3950_record_get (Z3950_record rec, const char *type,
405                              size_t *len);
406
407      Z3950_record Z3950_record_dup (Z3950_record rec);
408
409      void Z3950_record_destroy (Z3950_record rec);
410    </synopsis>
411    <para>
412     References to temporary records are returned by functions 
413     <function>Z3950_resultset_records</function> or
414     <function>Z3950_resultset_record</function>.
415     </para>
416    <para>
417     If a persistent pointer to a record is desired
418     <function>Z3950_record_dup</function> should be used.
419     It returns a record reference that at any
420     later stage should be destroyed by
421     <function>Z3950_record_destroy</function>.
422    </para>
423    <para>
424     A single record is returned by function
425     <function>Z3950_resultset_record</function> that takes a 
426     position as argument. First record has position zero.
427     If no record could be obtained <literal>NULL</literal> is returned.
428    </para>
429    <para>
430     Function <function>Z3950_resultset_records</function> retrieves
431     a number of records from a result set. Parameter <literal>start</literal>
432     and <literal>count</literal> specifies the range of records to
433     be returned. Upon completion array
434     <literal>recs[0], ..recs[count-1]</literal>
435     holds record objects for the records. The array of records
436      <literal>recs</literal> should be allocate prior to calling 
437     <function>Z3950_resultset_records</function>. Note that for those
438     records that couldn't be retrieved from the target
439     <literal>recs[ ..]</literal> is set to <literal>NULL</literal>.
440    </para>
441    <para id="zoom.record.get">
442     In order to extract information about a single record,
443     <function>Z3950_record_get</function> is provided. The
444     function returns a pointer to certain record information. The
445     nature (type) of the pointer depends on the <function>type</function>
446     given. In addition for certain types, the length
447     <literal>len</literal> passed will be set to the size in bytes of
448     the returned information.
449     <variablelist>
450      <varlistentry><term><literal>database</literal></term>
451       <listitem><para>Database of record is returned
452         as a C null-terminated string. Return type <literal>char *</literal>. 
453        </para></listitem>
454       </varlistentry>
455      <varlistentry><term><literal>syntax</literal></term>
456       <listitem><para>The transfer syntax (OID) of the record is returned
457         as a C null-terminated string. Return type <literal>char *</literal>. 
458        </para></listitem>
459       </varlistentry>
460      <varlistentry><term><literal>render</literal></term>
461       <listitem><para>The record is returned in a display friendly
462         format. Upon completion buffer is returned
463         (type <literal>char *</literal>) and length is stored in
464         <literal>*len</literal>.
465        </para></listitem>
466       </varlistentry>
467      <varlistentry><term><literal>raw</literal></term>
468       <listitem><para>The record is returned in the internal
469         YAZ specific format. The raw data is returned as type 
470         <literal>Z_External *</literal> which is just the type for
471         the member <literal>retrievalRecord</literal> in
472         type <literal>NamePlusRecord</literal>.
473        </para></listitem>
474       </varlistentry>
475     </variablelist>
476    </para>
477    <sect2><title>Protocol behavior</title>
478     <para>
479      The functions <function>Z3950_resultset_record</function> and
480      <function>Z3950_resultset_records</function> inspects the client-side
481      record cache. If the records(s) were not found, i.e. not yet retrieved
482      from, they are fetched using Present Requests.
483     </para>
484    </sect2>
485   </sect1>
486   <sect1 id="zoom.options"><title>Options</title>
487    <para>
488     Most &zoom; objects provide a way to specify options to default behavior.
489     From an implementation point of view a set of options is just like
490     an associate array / hash array, etc.
491    </para>
492    <synopsis>
493      Z3950_options Z3950_options_create (void);
494
495      Z3950_options Z3950_options_create_with_parent (Z3950_options parent);
496
497      void Z3950_options_destroy (Z3950_options opt);
498    </synopsis>
499    <synopsis>
500      const char *Z3950_options_get (Z3950_options opt, const char *name);
501
502      void Z3950_options_set (Z3950_options opt, const char *name,
503                              const char *v);
504    </synopsis>
505    <synopsis>
506      typedef const char *(*Z3950_options_callback)
507                                      (void *handle, const char *name);
508
509      Z3950_options_callback
510              Z3950_options_set_callback (Z3950_options opt,
511                                          Z3950_options_callback c,
512                                          void *handle);
513    </synopsis>
514   </sect1>
515   <sect1 id="zoom.events"><title>Events</title>
516    <para>
517     If you're developing non-blocking applications, you have to deal 
518     with events.
519    </para>
520    <synopsis>
521     int Z3950_event (int no, Z3950_connection *cs);
522    </synopsis>
523    <para>
524     The <function>Z3950_event</function> executes pending events for
525     a number of connections. Supply the number of connections in
526     <literal>no</literal> and an array of connections in
527     <literal>cs</literal> (<literal>cs[0] ... cs[no-1]</literal>).
528     A pending event could be a sending a search, receiving a response,
529     etc.
530     When an event has a occured for one of the connections, this function
531     returns a positive integer <literal>n</literal> denoting that an event
532     occurred for connection <literal>cs[n-1]</literal>.
533     When no events are pending for the connections, a value of zero is
534     returned.
535     To ensure that all outstanding requests are performed call this function
536     repeatedly until zero is returned.
537    </para>
538   </sect1>
539  </chapter>
540  
541  <!-- Keep this comment at the end of the file
542  Local variables:
543  mode: sgml
544  sgml-omittag:t
545  sgml-shorttag:t
546  sgml-minimize-attributes:nil
547  sgml-always-quote-attributes:t
548  sgml-indent-step:1
549  sgml-indent-data:t
550  sgml-parent-document: "yaz.xml"
551  sgml-local-catalogs: nil
552  sgml-namecase-general:t
553  End:
554  -->
555