63bff819120ef385cd0c559e98c556abf536a9f3
[yaz-moved-to-github.git] / doc / zoom.xml
1 <!-- $Id: zoom.xml,v 1.14 2001-11-30 08:24:06 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    ZOOM_connection ZOOM_connection_new (const char *host, int portnum);
56     
57    ZOOM_connection ZOOM_connection_create (ZOOM_options options);
58
59    void ZOOM_connection_connect(ZOOM_connection c, const char *host,
60                                  int portnum);
61    void ZOOM_connection_destroy (ZOOM_connection c);
62    </synopsis>
63    <para>
64     Connection objects are created with either function
65     <function>ZOOM_connection_new</function> or 
66     <function>ZOOM_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>ZOOM_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>ZOOM_connection_destroy</function>.
81    </para>
82    <synopsis>
83     void ZOOM_connection_option_set (ZOOM_connection c,
84                                      const char *key,
85                                      const char *val);
86
87     const char *ZOOM_connection_option_get (ZOOM_connection c,
88                                             const char *key);
89    </synopsis>
90    <para>
91     The <function>ZOOM_connection_option_set</function> allows you to
92     set an option given by <parameter>key</parameter> to the value
93     <parameter>value</parameter> for the connection.
94      Function <function>ZOOM_connection_option_get</function> returns
95     the value for an option given by <parameter>key</parameter>.
96    </para>
97    <table frame="sides" colsep="1"><title>ZOOM Connection Options</title>
98     <tgroup cols="3">
99      <colspec colwidth="4*" colname="name"></colspec>
100      <colspec colwidth="7*" colname="description"></colspec>
101      <colspec colwidth="3*" colname="default"></colspec>
102      <thead>
103       <row>
104        <entry>Option</entry>
105        <entry>Description</entry>
106        <entry>Default</entry>
107       </row>
108      </thead>
109      <tbody>
110       <row><entry>
111         implementationName</entry><entry>Name of Your client
112        </entry><entry>none</entry></row>
113       <row><entry>
114         user</entry><entry>Authentication user name
115        </entry><entry>none</entry></row>
116       <row><entry>
117         group</entry><entry>Authentication group name
118        </entry><entry>none</entry></row>
119       <row><entry>
120         pass</entry><entry>Authentication password
121       </entry><entry>none</entry></row>
122       <row><entry>
123         host</entry><entry>Target host. This setting is "read-only".
124         It's automatically set internally when connecting to a target.
125        </entry><entry>none</entry></row>
126       <row><entry>
127         proxy</entry><entry>Proxy host
128        </entry><entry>none</entry></row>
129       <row><entry>
130         async</entry><entry>If true (1) the connection operates in 
131         asynchronous operation which means that all calls are non-blocking
132         except
133         <link linkend="zoom.events"><function>ZOOM_event</function></link>.
134        </entry><entry>0</entry></row>
135       <row><entry>
136         maximumRecordSize</entry><entry> Maximum size of single record.
137        </entry><entry>1 MB</entry></row>
138       <row><entry>
139         preferredMessageSize</entry><entry> Maximum size of multiple records.
140        </entry><entry>1 MB</entry></row>
141      </tbody>
142     </tgroup>
143    </table>
144    <synopsis>
145      int ZOOM_connection_error (ZOOM_connection c, const char **cp,
146                                  const char **addinfo);
147    </synopsis>
148    <para>
149     Use <function>ZOOM_connection_error</function> to check for
150     errors for the last operation(s) performed. The function returns
151     zero if no errors occurred; non-zero otherwise indicating the error.
152     Pointers <parameter>cp</parameter> and <parameter>addinfo</parameter>
153     holds messages for the error and additional-info if passed as
154     non-<literal>NULL</literal>.
155    </para>
156    <sect2><title>Protocol behavior</title>
157     <para>
158      The calls <function>ZOOM_connection_new</function> and
159      <function>ZOOM_connection_connect</function> establises a TCP/IP
160       connection and sends an Initialize Request to the target if
161       possible. In addition, the calls waits for an Initialize Response
162       from the target and the result is inspected (OK or rejected).
163     </para>
164     <para>
165      If <literal>proxy</literal> is set then the client will establish
166      a TCP/IP connection with the peer as specified by the
167      <literal>proxy</literal> host and the hostname as part of the
168      connect calls will be set as part of the Initialize Request.
169      The proxy server will then "forward" the PDU's transparently
170      to the target behind the proxy.
171     </para>
172     <para>
173      For the authentication parameters, if option <literal>user</literal>
174      is set and both options <literal>group</literal> and
175      <literal>pass</literal> are unset, then Open style
176      authentication is used (Version 2/3) in which case the username
177      is usually followed by a slash, then by a password.
178      If either <literal>group</literal>
179      or <literal>pass</literal> is set then idPass authentication
180      (Version 3 only) is used. If none of the options are set, no
181      authentication parameters are set as part of the Initialize Request
182      (obviously).
183     </para>
184     <para>
185      When option <literal>async</literal> is 1, it really means that
186      all network operations are postponed (and queued) until the
187      function <literal>ZOOM_event</literal> is invoked. When doing so
188      it doesn't make sense to check for errors after
189      <literal>ZOOM_connection_new</literal> is called since that
190      operation "connecting - and init" is still incomplete and the
191      API cannot tell the outcome (yet).
192     </para>
193     </sect2>
194   </sect1>
195   <sect1 id="zoom.query"><title>Queries</title>
196    <para>
197     Query objects represents queries.
198    </para>
199    <synopsis>
200      ZOOM_query ZOOM_query_create(void);
201
202      void ZOOM_query_destroy(ZOOM_query q);
203
204      int ZOOM_query_prefix(ZOOM_query q, const char *str);
205
206      int ZOOM_query_sortby(ZOOM_query q, const char *criteria);
207    </synopsis>
208    <para>
209     Create query objects using <function>ZOOM_query_create</function>
210     and destroy them by calling <function>ZOOM_query_destroy</function>.
211     RPN-queries can be specified in <link linkend="PQF">PQF</link>
212     notation by using the
213     function <function>ZOOM_query_prefix</function>. More
214     query types will be added later, such as
215     <link linkend="CCL">CCL</link> to RPN-mapping, native CCL query,
216     etc. In addition to a search, a sort criteria may be set. Function
217     <function>ZOOM_query_sortby</function> specifies a 
218     sort criteria using the same string notation for sort as offered by
219     the <link linkend="sortspec">YAZ client</link>.
220    </para>
221    <sect2><title>Protocol behavior</title>
222     <para>
223      The query object is just an interface for the member Query
224      in the SearchRequest. The sortby-function is an interface to the
225      sortSequence member of the SortRequest.
226     </para>
227    </sect2>
228   </sect1>
229   <sect1 id="zoom.resultsets"><title>Result sets</title>
230    <para>
231     The result set object is a container for records returned from
232     a target.
233    </para>
234    <synopsis>
235      ZOOM_resultset ZOOM_connection_search(ZOOM_connection,
236                                            ZOOM_query q);
237
238      ZOOM_resultset ZOOM_connection_search_pqf(ZOOM_connection c,
239                                                const char *q);
240
241      void ZOOM_resultset_destroy(ZOOM_resultset r);
242    </synopsis>
243    <para>
244     Function <function>ZOOM_connection_search</function> creates
245      a result set given a connection and query.
246     Destroy a result set by calling
247     <function>ZOOM_resultset_destroy</function>.
248     Simple clients may using PQF only may use function
249     <function>ZOOM_connection_search_pqf</function> in which case
250     creating query objects is not necessary.
251    </para>
252    <synopsis>
253      void ZOOM_resultset_option_set (ZOOM_resultset r,
254                                       const char *key,
255                                       const char *val);
256
257      const char *ZOOM_resultset_option_get (ZOOM_resultset r,
258                                              const char *key);
259
260      size_t ZOOM_resultset_size (ZOOM_resultset r);
261    </synopsis>
262    <para>
263     Functions <function>ZOOM_resultset_options_set</function> and
264     <function>ZOOM_resultset_get</function> sets and gets an option
265     for a result set similar to <function>ZOOM_connection_option_get</function>
266     and <function>ZOOM_connection_option_set</function>.
267    </para>
268    <para>
269     The number of hits also called result-count is returned by
270     function <function>ZOOM_resultset_size</function>.
271    </para>
272    <table frame="top"><title>ZOOM Result set Options</title>
273     <tgroup cols="3">
274      <colspec colwidth="4*" colname="name"></colspec>
275      <colspec colwidth="7*" colname="description"></colspec>
276      <colspec colwidth="2*" colname="default"></colspec>
277      <thead>
278       <row>
279        <entry>Option</entry>
280        <entry>Description</entry>
281        <entry>Default</entry>
282       </row>
283      </thead>
284      <tbody>
285       <row><entry>
286         piggyback</entry><entry>True (1) if piggyback should be
287         used in searches; false (0) if not.
288        </entry><entry>1</entry></row>
289       <row><entry>
290         start</entry><entry>Offset of first record to be 
291         retrieved from target. First record has offset 0 unlike the
292         protocol specifications where first record has position 1.
293        </entry><entry>0</entry></row>
294       <row><entry>
295         count</entry><entry>Number of records to be retrieved.
296        </entry><entry>0</entry></row>
297       <row><entry>
298         elementSetName</entry><entry>Element-Set name of records. 
299         Most targets should honor element set name <literal>B</literal>
300         and <literal>F</literal> for brief and full respectively.
301        </entry><entry>none</entry></row>
302       <row><entry>
303         preferredRecordSyntax</entry><entry>Preferred Syntax, such as
304         <literal>USMARC</literal>, <literal>SUTRS</literal>, etc.
305        </entry><entry>none</entry></row>
306       <row><entry>
307         schema</entry><entry>Schema for retrieval, such as
308         <literal>Gils-schema</literal>, <literal>Geo-schema</literal>, etc.
309        </entry><entry>none</entry></row>
310       <row><entry>
311         smallSetUpperBound</entry><entry>If hits is less than or equal to this
312         value, then target will return all records using small element set name
313        </entry><entry>0</entry></row>
314       <row><entry>
315         largeSetLowerBound</entry><entry>If hits is greator than this
316         value, the target will return no records.
317        </entry><entry>1</entry></row>
318       <row><entry>
319         mediumSetPresentNumber</entry><entry>This value represents
320         the number of records to be returned as part of a search when when
321         hits is less than or equal to large set lower bound and if hits
322         is greator than small set upper bound.
323        </entry><entry>0</entry></row>
324       <row><entry>
325         smallSetElementSetName</entry><entry>
326         The element set name to be used for small result sets.
327        </entry><entry>none</entry></row>
328       <row><entry>
329         mediumSetElementSetName</entry><entry>
330         The element set name to be for medium-sized result sets.
331        </entry><entry>none</entry></row>
332       <row><entry>
333         databaseName</entry><entry>One or more database names
334         separated by character plus (<literal>+</literal>).
335        </entry><entry>Default</entry></row>
336       <row><entry>
337         setname</entry><entry>Name of Result Set (Result Set ID).
338         If this option isn't set, the ZOOM module will automatically
339         allocate a result set name.
340        </entry><entry>default</entry></row>
341      </tbody>
342     </tgroup>
343    </table>
344    <sect2>
345     <title>Protocol behavior</title>
346     <para>
347      The creation of a result set involves at least a SearchRequest
348      - SearchResponse protocol handshake. Following that, if a sort
349      critieria was specified as part of the query, a sortRequest -
350      SortResponse handshake takes place. Note that it is necessary to
351      perform sorting before any retrieval takes place, so no records will
352      be returned from the target as part of the SearchResponse because these
353      would be unsorted. Hence, piggyback is disabled when sort critieria
354      is set. Following Search - and a Possible sort, Retrieval takes
355      place - as one or more Present Requests - Present Response being
356      transferred.
357      </para>
358     <para>
359      The API allows for two different modes for retrieval. A high level
360      mode which is somewhat more powerful and a low level one.
361      The low level is "enabled" when the settings
362      <literal>smallSetUpperBound</literal>,
363      <literal>mediumSetPresentNumber</literal> and
364      <literal>largeSetLowerBound</literal> are set. The low level mode
365      thus allows you to precisely set how records are returned as part
366      of a search response as offered by the Z39.50 protocol.
367      Since the client may be retrieving records as part of the
368      search response, this mode doesn't work well if sorting is used.
369      </para>
370     <para>
371      The high-level mode allows you to fetch a range of records from
372      the result set with a given start offset. When you use this mode
373      the client will automatically use piggyback if that is possible
374      with the target and perform one or more present requests as needed.
375      Even if the target returns fewer records as part of a present response
376      because of a record size limit, etc. the client will repeat sending
377      present requests. As an example, if option <literal>start</literal>
378      is 0 (default) and <literal>count</literal> is 4, and
379      <literal>piggyback</literal> is 1 (default) and no sorting critieria
380      is specified, then the client will attempt to retrieve the 4
381      records as part the search response (using piggyback). On the other
382      hand, if either <literal>start</literal> is positive or if
383      a sorting criteria is set, or if <literal>piggyback</literal>
384      is 0, then the client will not perform piggyback but send Present
385      Requests instead.
386     </para>
387     <para>
388      If either of the options <literal>mediumSetElementSetName</literal> and
389      <literal>smallSetElementSetName</literal> are unset, the value
390      of option <literal>elementSetName</literal> is used for piggyback
391      searches. This means that for the high-level mode you only have
392      to specify one elementSetName option rather than three.
393      </para>
394    </sect2>
395   </sect1>
396   <sect1 id="zoom.records"><title>Records</title>
397    <para>
398     A record object is a retrival record on the client side -
399     created from result sets.
400    </para>
401    <synopsis>
402      void ZOOM_resultset_records (ZOOM_resultset r,
403                                   ZOOM_record *recs,
404                                   size_t start, size_t count);
405      ZOOM_record ZOOM_resultset_record (ZOOM_resultset s, size_t pos);
406
407      void *ZOOM_record_get (ZOOM_record rec, const char *type,
408                             size_t *len);
409
410      ZOOM_record ZOOM_record_clone (ZOOM_record rec);
411
412      void ZOOM_record_destroy (ZOOM_record rec);
413    </synopsis>
414    <para>
415     References to temporary records are returned by functions 
416     <function>ZOOM_resultset_records</function> or
417     <function>ZOOM_resultset_record</function>.
418     </para>
419    <para>
420     If a persistent reference to a record is desired
421     <function>ZOOM_record_clone</function> should be used.
422     It returns a record reference that should be destroyed
423     by a call to <function>ZOOM_record_destroy</function>.
424    </para>
425    <para>
426     A single record is returned by function
427     <function>ZOOM_resultset_record</function> that takes a 
428     position as argument. First record has position zero.
429     If no record could be obtained <literal>NULL</literal> is returned.
430    </para>
431    <para>
432     Function <function>ZOOM_resultset_records</function> retrieves
433     a number of records from a result set. Parameter <literal>start</literal>
434     and <literal>count</literal> specifies the range of records to
435     be returned. Upon completion array
436     <literal>recs[0], ..recs[count-1]</literal>
437     holds record objects for the records. The array of records
438      <literal>recs</literal> should be allocated prior the call
439     <function>ZOOM_resultset_records</function>. Note that for those
440     records that couldn't be retrieved from the target
441     <literal>recs[ ..]</literal> is set to <literal>NULL</literal>.
442    </para>
443    <para id="zoom.record.get">
444     In order to extract information about a single record,
445     <function>ZOOM_record_get</function> is provided. The
446     function returns a pointer to certain record information. The
447     nature (type) of the pointer depends on the parameter,
448     <function>type</function>.
449     In addition, for certain types, the length
450     <literal>len</literal> passed will be set to the size in bytes of
451     the returned information.
452     <variablelist>
453      <varlistentry><term><literal>database</literal></term>
454       <listitem><para>Database of record is returned
455         as a C null-terminated string. Return type <literal>char *</literal>. 
456        </para></listitem>
457       </varlistentry>
458      <varlistentry><term><literal>syntax</literal></term>
459       <listitem><para>The transfer syntax (OID) of the record is returned
460         as a C null-terminated string. Return type <literal>char *</literal>. 
461        </para></listitem>
462       </varlistentry>
463      <varlistentry><term><literal>render</literal></term>
464       <listitem><para>The record is returned in a display friendly
465         format. Upon completion buffer is returned
466         (type <literal>char *</literal>) and length is stored in
467         <literal>*len</literal>.
468        </para></listitem>
469       </varlistentry>
470      <varlistentry><term><literal>raw</literal></term>
471       <listitem><para>The record is returned in the internal
472         YAZ specific format. The raw data is returned as type 
473         <literal>Z_External *</literal> which is just the type for
474         the member <literal>retrievalRecord</literal> in
475         type <literal>NamePlusRecord</literal>.
476        </para></listitem>
477       </varlistentry>
478     </variablelist>
479    </para>
480    <sect2><title>Protocol behavior</title>
481     <para>
482      The functions <function>ZOOM_resultset_record</function> and
483      <function>ZOOM_resultset_records</function> inspects the client-side
484      record cache. Records not found in cache are fetched using
485      Present.
486      The functions may block (and perform network I/O)  - even though option
487      <literal>async</literal> is 1, because they return records objects.
488      (and there's no way to return records objects without retrieving them!).
489      </para>
490     <para>
491      There is a trick, however, in the usage of function
492      <function>ZOOM_resultset_records</function> that allows for
493      delayed retrieval (and makes it non-blocking). By passing
494      a null pointer for <parameter>recs</parameter> you're indicating
495      you're not interested in getting records objects
496      <emphasis>now</emphasis>.
497     </para>
498    </sect2>
499   </sect1>
500   <sect1 id="zoom.options"><title>Options</title>
501    <para>
502     Most &zoom; objects provide a way to specify options to change behavior.
503     From an implementation point of view a set of options is just like
504     an associative array / hash array, etc.
505    </para>
506    <synopsis>
507      ZOOM_options ZOOM_options_create (void);
508
509      ZOOM_options ZOOM_options_create_with_parent (ZOOM_options parent);
510
511      void ZOOM_options_destroy (ZOOM_options opt);
512    </synopsis>
513    <synopsis>
514      const char *ZOOM_options_get (ZOOM_options opt, const char *name);
515
516      void ZOOM_options_set (ZOOM_options opt, const char *name,
517                             const char *v);
518    </synopsis>
519    <synopsis>
520      typedef const char *(*ZOOM_options_callback)
521                                      (void *handle, const char *name);
522
523      ZOOM_options_callback
524              ZOOM_options_set_callback (ZOOM_options opt,
525                                         ZOOM_options_callback c,
526                                         void *handle);
527    </synopsis>
528   </sect1>
529   <sect1 id="zoom.events"><title>Events</title>
530    <para>
531     If you're developing non-blocking applications, you have to deal 
532     with events.
533    </para>
534    <synopsis>
535     int ZOOM_event (int no, ZOOM_connection *cs);
536    </synopsis>
537    <para>
538     The <function>ZOOM_event</function> executes pending events for
539     a number of connections. Supply the number of connections in
540     <literal>no</literal> and an array of connections in
541     <literal>cs</literal> (<literal>cs[0] ... cs[no-1]</literal>).
542     A pending event could be a sending a search, receiving a response,
543     etc.
544     When an event has occured for one of the connections, this function
545     returns a positive integer <literal>n</literal> denoting that an event
546     occurred for connection <literal>cs[n-1]</literal>.
547     When no events are pending for the connections, a value of zero is
548     returned.
549     To ensure that all outstanding requests are performed call this function
550     repeatedly until zero is returned.
551    </para>
552   </sect1>
553  </chapter>
554  
555  <!-- Keep this comment at the end of the file
556  Local variables:
557  mode: sgml
558  sgml-omittag:t
559  sgml-shorttag:t
560  sgml-minimize-attributes:nil
561  sgml-always-quote-attributes:t
562  sgml-indent-step:1
563  sgml-indent-data:t
564  sgml-parent-document: "yaz.xml"
565  sgml-local-catalogs: nil
566  sgml-namecase-general:t
567  End:
568  -->
569