Merge branch 'master' of git://git.indexdata.com/pazpar2
authorJason Skomorowski <jason@indexdata.com>
Fri, 18 Sep 2009 14:41:34 +0000 (10:41 -0400)
committerJason Skomorowski <jason@indexdata.com>
Fri, 18 Sep 2009 14:41:34 +0000 (10:41 -0400)
Conflicts:
src/logic.c

51 files changed:
Makefile.am
NEWS
configure.ac
debian/changelog
doc/Makefile.am
doc/book.xml
doc/pazpar2.xml
doc/pazpar2_conf.xml
doc/pazpar2_protocol.xml
etc/edu.xml
js/pz2.js
src/.gitignore
src/Makefile.am
src/charsets.c
src/charsets.h
src/client.c
src/connection.c
src/database.c
src/database.h
src/http.c
src/http.h
src/http_command.c
src/http_command.h [deleted file]
src/logic.c
src/parameters.h
src/pazpar2.c
src/pazpar2.h
src/pazpar2_config.c
src/pazpar2_config.h
src/reclists.c
src/reclists.h
src/record.c
src/settings.c
src/settings.h
src/test_config.c [deleted file]
src/test_record.c [deleted file]
src/zeerex.c
test/Makefile.am
test/gils_service.xml [new file with mode: 0644]
test/marc_service.xml [new file with mode: 0644]
test/run_pazpar2.sh
test/test_http.cfg
test/test_http.xml [deleted file]
test/test_http_26.res [new file with mode: 0644]
test/test_http_27.res [new file with mode: 0644]
test/test_http_28.res [new file with mode: 0644]
test/test_http_urls
test/test_icu.cfg
test/z3950_indexdata_com_gils.xml [new file with mode: 0644]
test/z3950_indexdata_com_marc.xml [new file with mode: 0644]
win/makefile

index dafe4e6..191b027 100644 (file)
@@ -16,3 +16,6 @@ dist-hook:
                done; \
        done; exit 0
 
+.PHONY:debian
+debian:
+       dpkg-buildpackage -rfakeroot
diff --git a/NEWS b/NEWS
index 106bb99..7e42df1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,32 @@
+Option -t tests the Pazpar2 configuration and returns exit code
+(0=success, non-zero=failure). In previous version of Pazpar2, -t
+specified local settings.
+
+In version 1.2.0 the configuration file - after include processing -
+was dumped to stdout. Now, the configuration is only dumped to the
+yaz log file if option -d is given.
+
+--- 1.2.0 2009/09/10
+
+Configuration may now have multiple server areas. This means that a
+Pazpar2 instance may listen on multiple ports. Virtual hosting is not
+yet supported - on a server basis. Configuration may also have multiple
+services .. That is repeating service elements inside a server. Each
+has an attribute 'id' which serves as service ID. This ID in turn may
+be used in a Pazpar2 session, by specifying parameter service=ID for
+command init. There can be at most one unnamed service inside a server
+which can be referred to by not specifying an service ID for command
+init (backwards compatible). In order to partition multiple servers and
+services a new include directive has been added. This takes an attribute
+'src' which specifies one or more sub-files. For example to include
+service files, one might use:
+  <server >.. <include src=/"etc/pazpar2/conf.d/*.xml"/> .. </server>.
+It is the intention that that completely makes the settings directive
+redundant.
+
+Fix problem where the record command would wait forever if there were
+no targets to wait for (activeclients == 0).
+
 --- 1.1.1 2009/08/28
 
 One result set is created per session (last search) rather than for
index 4841ba6..97a2099 100644 (file)
@@ -4,7 +4,7 @@
 
 # Autoconf and automake setup
 AC_PREREQ(2.60)
-AC_INIT([pazpar2],[1.1.1],[pazpar2-help@indexdata.dk])
+AC_INIT([pazpar2],[1.2.0],[pazpar2-help@indexdata.dk])
 
 AC_CONFIG_HEADERS(src/config.h)
 
@@ -19,13 +19,13 @@ AC_PROG_RANLIB
 
 AC_LANG(C)
 
-YAZ_INIT([static icu threads],[3.0.39])
+YAZ_INIT([static icu threads],[3.0.46])
 if test -z "$YAZLIB"; then
        AC_MSG_ERROR([YAZ development libraries missing])
 fi
 YAZ_DOC
 
-AC_CHECK_HEADERS([sys/time.h sys/socket.h unistd.h netinet/in.h netdb.h arpa/inet.h])
+AC_CHECK_HEADERS([sys/time.h sys/socket.h unistd.h netinet/in.h netdb.h arpa/inet.h glob.h])
 AC_CHECK_FUNCS([getaddrinfo])
 
 if test -d ${srcdir}/.git; then
index 626907b..380fd99 100644 (file)
@@ -1,3 +1,9 @@
+pazpar2 (1.2.0-1indexdata) unstable; urgency=low
+
+  * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Thu, 10 Sep 2009 09:48:25 +0200
+
 pazpar2 (1.1.1-1indexdata) unstable; urgency=low
 
   * Upstream.
index b3fd0b2..0188dbb 100644 (file)
@@ -67,7 +67,7 @@ doc-clean:
 install-data-hook:
        if test -f index.html; then d=.; else d="$(srcdir)"; fi; \
        for p in $$d/*.html; do \
-               $(docDATA_INSTALL) $$p $(DESTDIR)$(docdir); \
+               $(INSTALL_DATA) $$p $(DESTDIR)$(docdir); \
        done
 
 uninstall-hook:
index c77f60a..0bbd98e 100644 (file)
     <screen>
      cd etc
      cp pazpar2.cfg.dist pazpar2.cfg
-     ../src/pazpar2 -f pazpar2.cfg -t edu.xml
+     cp edu.xml settings
+     ../src/pazpar2 -f pazpar2.cfg
     </screen>
     And on Windows:
     <screen>
      cd etc
      copy pazpar2.cfg.dist pazpar2.cfg
-     ..\bin\pazpar2 -f pazpar2.cfg -t edu.xml
+     copy edu.xml settings
+     ..\bin\pazpar2 -f pazpar2.cfg
     </screen>
-    This will start a Pazpar2 listener on port 8004. It will proxy 
+    This will start a Pazpar2 listener on port 9004. It will proxy 
     HTTP requests to localhost - port 80, which we assume will be the regular
     HTTP server on the system. Inspect and modify pazpar2.cfg as needed
-    if this is to be changed. The -t option specifies the list of targets
+    if this is to be changed. The pazpar2.cfg includes settings from the
+    directory <filename>settings</filename>.
     to use for searches.
    </para>
    <para>
index 54f92b4..c9b2614 100644 (file)
@@ -32,7 +32,7 @@
    <arg choice="opt"><option>-h <replaceable>ip:port</replaceable></option></arg>
    <arg choice="opt"><option>-l <replaceable>logfile</replaceable></option></arg>
    <arg choice="opt"><option>-p <replaceable>pidfile</replaceable></option></arg>
-   <arg choice="opt"><option>-t <replaceable>path</replaceable></option></arg>
+   <arg choice="opt"><option>-t</option></arg>
    <arg choice="opt"><option>-T <replaceable>session_timeout</replaceable></option></arg>
    <arg choice="opt"><option>-u <replaceable>uid</replaceable></option></arg>
    <arg choice="opt"><option>-V</option></arg>
    </varlistentry>
 
    <varlistentry>
-    <term><option>-t <replaceable>path</replaceable></option></term>
+    <term><option>-t</option></term>
     <listitem>
      <para>
-      Specifies a file or directory with alternative settings. This
-      overrides the <literal>settings</literal> element in the main
-      configuration.
+      Checks parameters and configuration. No service or daemon is
+      started. Useful for checking a new configuration before a
+      Pazpar2 is restarted.
      </para>
+     <note>
+      <para>
+       In Pazpar2 1.2 and earlier releasese, option -t specified a
+       local target settings file.
+      </para>
+     </note>
     </listitem>
    </varlistentry>
+
    <varlistentry>
     <term><option>-T <replaceable>session_timeout</replaceable></option></term>
     <listitem>
index 5e8ef1a..c2d2227 100644 (file)
@@ -59,8 +59,9 @@
   
   <refsect2 id="config-server"><title>server</title>
    <para>
-    This section governs overall behavior of the client. The data
-    elements are described below.
+    This section governs overall behavior of the server. The data
+    elements are described below. From Pazpar2 version 1.2 this is
+    a repeatable element.
    </para>
    <variablelist> <!-- level 1 -->
     <varlistentry>
       </para>
      </listitem>
     </varlistentry>
-    
-    <varlistentry>
-     <term>relevance</term>
-     <listitem>
-      <para>
-       Specifies ICU tokenization and transformation rules
-       for tokens that are used in Pazpar2's relevance ranking.  The 'id'
-       attribute is currently not used, and the 'locale'
-       attribute must be set to one of the locale strings
-       defined in ICU. The child elements listed below can be
-       in any order, except the 'index' element which logically
-       belongs to the end of the list. The stated tokenization,
-       transformation and charmapping instructions are performed
-       in order from top to bottom. 
-      </para>
-      <variablelist> <!-- Level 2 -->
-       <varlistentry><term>casemap</term>
-       <listitem>
-        <para>
-         The attribute 'rule' defines the direction of the
-         per-character casemapping, allowed values are "l"
-         (lower), "u" (upper), "t" (title).  
-        </para>
-       </listitem>
-       </varlistentry>
-       <varlistentry><term>transform</term>
-       <listitem>
-        <para>
-         Normalization and transformation of tokens follows
-         the rules defined in the 'rule' attribute. For
-         possible values we refer to the extensive ICU
-         documentation found at the 
-         <ulink url="&url.icu.transform;">ICU
-          transformation</ulink> home page. Set filtering
-         principles are explained at the 
-         <ulink url="&url.icu.unicode.set;">ICU set and
-          filtering</ulink> page.
-        </para>
-       </listitem>
-       </varlistentry>
-       <varlistentry><term>tokenize</term>
-       <listitem>
-        <para>
-         Tokenization is the only rule in the ICU chain
-         which splits one token into multiple tokens. The
-         'rule' attribute may have the following values:
-         "s" (sentence), "l" (line-break), "w" (word), and
-         "c" (character), the later probably not being
-         very useful in a pruning Pazpar2 installation. 
-        </para>
-       </listitem>
-       </varlistentry>
-      </variablelist>
-     </listitem>
-    </varlistentry>
 
     <varlistentry>
-     <term>sort</term>
+     <term>relevance / sort / mergekey</term>
      <listitem>
       <para>
-       Specifies ICU tokenization and transformation rules
-       for tokens that are used in Pazpar2's sorting. The contents
-       is similar to that of <literal>relevance</literal>.
+       Specifies character set normalization for relevancy / sorting 
+       and the mergekey - for the server. These definitions serves as
+       default for services that don't have these given. For the meaning
+       of these settings refer to the "relevance" element inside service.
       </para>
      </listitem>
     </varlistentry>
     
     <varlistentry>
-     <term>mergekey</term>
+     <term>settings</term>
      <listitem>
       <para>
-       Specifies ICU tokenization and transformation rules
-       for tokens that are used in Pazpar2's mergekey. The contents
-       is similar to that of <literal>relevance</literal>.
+       Specifies target settings for the server.. These settings serves
+       as default for all services which don't have these given.
+       The settings element requires one attribute 'src' which specifies
+       a settings file or a directory . If a directory is given all
+       files with suffix <filename>.xml</filename> is read from this
+       directory. Refer to 
+       <xref linkend="target_settings"/> for more information.
       </para>
      </listitem>
     </varlistentry>
        extraction of data from the internal representation, primarily
        through the 'metadata' sub-element.
       </para>
-      
+      <para>
+       Pazpar2 version 1.2 and later allows multiple service elements.
+       Multiple services must be given a unique ID by specifying
+       attribute <literal>id</literal>.
+       A single service may be unnamed (service ID omitted). The
+       service ID is referred to in the
+       <link linkend="command-init"><literal>init</literal></link> webservice
+       command's <literal>service</literal> parameter.
+      </para>
+
       <variablelist> <!-- Level 2 -->
        <varlistentry><term>metadata</term>
        <listitem>
           </listitem>
          </varlistentry>
 
-
          <varlistentry><term>setting</term>
           <listitem>
            <para>
              the value to decide how to deal with other data values.
            </para>
            <para>
-           </para>
              The purpose of using settings in this way can either be to
              control the behavior of normalization stylesheet in a database-
              dependent way, or to easily make database-dependent values
              available to display-logic in your user interface, without having
              to implement complicated interactions between the user interface
              and your configuration system.
+           </para>
           </listitem>
          </varlistentry>
+         
         </variablelist> <!-- attributes to metadata -->
         
        </listitem>
        </varlistentry>
+       
+       <varlistentry>
+       <term>relevance</term>
+       <listitem>
+        <para>
+         Specifies ICU tokenization and transformation rules
+         for tokens that are used in Pazpar2's relevance ranking.
+         The 'id' attribute is currently not used, and the 'locale'
+         attribute must be set to one of the locale strings
+         defined in ICU. The child elements listed below can be
+         in any order, except the 'index' element which logically
+         belongs to the end of the list. The stated tokenization,
+         transformation and charmapping instructions are performed
+         in order from top to bottom. 
+        </para>
+        <variablelist> <!-- Level 2 -->
+         <varlistentry><term>casemap</term>
+          <listitem>
+           <para>
+            The attribute 'rule' defines the direction of the
+            per-character casemapping, allowed values are "l"
+            (lower), "u" (upper), "t" (title).  
+           </para>
+          </listitem>
+         </varlistentry>
+         <varlistentry><term>transform</term>
+          <listitem>
+           <para>
+            Normalization and transformation of tokens follows
+            the rules defined in the 'rule' attribute. For
+            possible values we refer to the extensive ICU
+            documentation found at the 
+            <ulink url="&url.icu.transform;">ICU
+             transformation</ulink> home page. Set filtering
+            principles are explained at the 
+            <ulink url="&url.icu.unicode.set;">ICU set and
+             filtering</ulink> page.
+           </para>
+          </listitem>
+         </varlistentry>
+         <varlistentry><term>tokenize</term>
+          <listitem>
+           <para>
+            Tokenization is the only rule in the ICU chain
+            which splits one token into multiple tokens. The
+            'rule' attribute may have the following values:
+            "s" (sentence), "l" (line-break), "w" (word), and
+            "c" (character), the later probably not being
+            very useful in a pruning Pazpar2 installation. 
+           </para>
+          </listitem>
+         </varlistentry>
+        </variablelist>
+        <para>
+         From Pazpar2 version 1.1 the ICU wrapper from YAZ is used.
+         Refer to the <ulink url="&url.yaz.yaz-icu;">yaz-icu</ulink>
+         utility for more information.
+        </para>
+       </listitem>
+       </varlistentry>
+       
+       <varlistentry>
+       <term>sort</term>
+       <listitem>
+        <para>
+         Specifies ICU tokenization and transformation rules
+         for tokens that are used in Pazpar2's sorting. The contents
+         is similar to that of <literal>relevance</literal>.
+        </para>
+       </listitem>
+       </varlistentry>
+       
+       <varlistentry>
+       <term>mergekey</term>
+       <listitem>
+        <para>
+         Specifies ICU tokenization and transformation rules
+         for tokens that are used in Pazpar2's mergekey. The contents
+         is similar to that of <literal>relevance</literal>.
+        </para>
+       </listitem>
+       </varlistentry>
+
+       <varlistentry>
+       <term>settings</term>
+       <listitem>
+        <para>
+         Specifies target settings for this service. Refer to
+         <xref linkend="target_settings"/>.
+        </para>
+       </listitem>
+       </varlistentry>
+
       </variablelist>     <!-- Data elements in service directive -->
      </listitem>
     </varlistentry>
+    
    </variablelist>           <!-- Data elements in server directive -->
   </refsect2>
-  
+
  </refsect1>
  
  <refsect1><title>EXAMPLE</title>
   <para>Below is a working example configuration:
-  <screen><![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-<pazpar2 xmlns="http://www.indexdata.com/pazpar2/1.0">
-
-<server>
-  <listen port="9004"/>
-  <proxy host="us1.indexdata.com" myurl="us1.indexdata.com"/>
-
-  <!-- optional ICU ranking configuration example -->
-  <!--
-  <icu_chain id="el:word" locale="el">
-    <normalize rule="[:Control:] Any-Remove"/>
-    <tokenize rule="l"/>
-    <normalize rule="[[:WhiteSpace:][:Punctuation:]] Remove"/>
-    <casemap rule="l"/>
-    <index/>
-  </icu_chain>
-  -->
-
-  <service>
-    <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
-    <metadata name="isbn" merge="unique"/>
-    <metadata name="date" brief="yes" sortkey="numeric" type="year" merge="range"
-           termlist="yes"/>
-    <metadata name="author" brief="yes" termlist="yes" merge="longest" rank="2"/>
-    <metadata name="subject" merge="unique" termlist="yes" rank="3"/>
-    <metadata name="url" merge="unique"/>
-  </service>
-</server>
-
-</pazpar2>
-]]></screen>
+   <screen><![CDATA[
+    <?xml version="1.0" encoding="UTF-8"?>
+    <pazpar2 xmlns="http://www.indexdata.com/pazpar2/1.0">
+    
+      <server>
+        <listen port="9004"/>
+        <service>
+          <metadata name="title" brief="yes" sortkey="skiparticle"
+             merge="longest" rank="6"/>
+          <metadata name="isbn" merge="unique"/>
+          <metadata name="date" brief="yes" sortkey="numeric"
+             type="year" merge="range" termlist="yes"/>
+          <metadata name="author" brief="yes" termlist="yes"
+             merge="longest" rank="2"/>
+          <metadata name="subject" merge="unique" termlist="yes" rank="3"/>
+          <metadata name="url" merge="unique"/>
+          <relevance>
+            <icu_chain id="relevance" locale="el">
+              <transform rule="[:Control:] Any-Remove"/>
+              <tokenize rule="l"/>
+              <transform rule="[[:WhiteSpace:][:Punctuation:]] Remove"/>
+              <casemap rule="l"/>
+             </icu_chain>
+           </relevance>
+           <settings src="mysettings"/>
+        <service>
+     </server>
+   </pazpar2>
+    ]]></screen>
   </para>
  </refsect1> 
+
+ <refsect1 id="config-include"><title>INCLUDE FACILITY</title>
+  <para>
+   The XML configuration may be partitioned into multiple files by using
+   the <literal>include</literal> element which takes a single attribute,
+   <literal>src</literal>. The of the <literal>src</literal> attribute is
+   regular Shell like glob-pattern. For example,
+   <screen><![CDATA[
+    <include src="/etc/pazpar2/conf.d/*.xml"/>
+    ]]></screen>
+  </para>
+  <para>
+   The include facility requires Pazpar2 version 1.2.
+  </para>
+ </refsect1>
+
  <refsect1 id="target_settings"><title>TARGET SETTINGS</title>
   <para>
    Pazpar2 features a cunning scheme by which you can associate various
    environment, where different end-users may need to be represented to
    some search targets in different ways. This, again, can be managed
    using an external database or other lookup mechanism. Setting overrides
-   can be performed either using the 'init' or the 'settings' webservice
+   can be performed either using the
+   <link linkend="command-init">init</link> or the 
+   <link linkend="command-settings">settings</link> webservice
    command.
   </para>
   
   
   <para>
    Finally, as an extreme case of this, the webservice client can
-   introduce entirely new targets, on the fly, as part of the init or
-   settings command. This is useful if you desire to manage information
+   introduce entirely new targets, on the fly, as part of the
+   <link linkend="command-init">init</link> or
+   <link linkend="command-settings">settings</link> command.
+   This is useful if you desire to manage information
    about your search targets in a separate application such as a database.
    You do not need any static settings file whatsoever to run Pazpar2 -- as
    long as the webservice client is prepared to supply the necessary
        </para>
       </listitem>
     </varlistentry>
+
+    <varlistentry>
+      <term>pz:sort</term>
+      <listitem>
+        <para>
+         Specifies sort criteria to be applied to the result set. Only works for targets
+         which support the sort service.
+       </para>
+      </listitem>
+    </varlistentry>
    </variablelist>
   </refsect2>
 
index 7b30ca8..924c6e7 100644 (file)
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+      <term>service</term>
+      <listitem>
+       <para>
+        If this is defined it specifies a service ID. Makes the session use
+        the service with this ID. If this is setting is omitted, the
+        session will use the unnamed service in the Pazpar2 configuration.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
index adba071..954d6ef 100644 (file)
@@ -40,9 +40,6 @@
   <set target="yulib001.mc.yu.edu:1111/DEFAULT" name="pz:name" value="Yeshiva U"/>
   <set target="z3950.fcla.edu:210/CF" name="pz:name" value="Florida CLA"/>
   <set target="z3950.library.wisc.edu:210/madison" name="pz:name" value="U of Wisconsin"/>
-  <set target="us1v1.indexdata.com/ruprime" name="pz:name" value="Reference Universe"/>
-  <set target="us1v1.indexdata.com/pdx" name="pz:name" value="Public Documents Masterfile"/>
-  <set target="us1.indexdata.com:9001/Default" name="pz:name" value="Open Content Alliance"/>
   <set target="opencontent.indexdata.com:210/oca-all" name="pz:name" value="OCA American Libraries"/>
   <set target="opencontent.indexdata.com:210/gutenberg" name="pz:name" value="Project Gutenberg"/>
   <set target="z3950.loc.gov:7090/voyager" name="pz:name" value="Library of Congress"/>
index 4f089a1..f290eec 100644 (file)
--- a/js/pz2.js
+++ b/js/pz2.js
@@ -98,6 +98,8 @@ var pz2 = function ( paramArray )
     this.showFastCount = 4;
     this.bytargetTime = paramArray.bytargettime || 1000;
     this.bytargetTimer = null;
+    this.recordTime = paramArray.recordtime || 500;
+    this.recordTimer = null;
 
     // counters for each command and applied delay
     this.dumpFactor = 500;
@@ -105,6 +107,7 @@ var pz2 = function ( paramArray )
     this.termCounter = 0;
     this.statCounter = 0;
     this.bytargetCounter = 0;
+    this.recordCounter = 0;
 
     // active clients, updated by stat and show
     // might be an issue since bytarget will poll accordingly
@@ -332,14 +335,14 @@ pz2.prototype =
                         "clients": 
                             Number( data.getElementsByTagName("clients")[0]
                                         .childNodes[0].nodeValue ),
-                        "unconnected": 
-                            Number( data.getElementsByTagName("unconnected")[0]
+                        "initializing": 
+                            Number( data.getElementsByTagName("initializing")[0]
                                         .childNodes[0].nodeValue ),
-                        "connecting": 
-                            Number( data.getElementsByTagName("connecting")[0]
+                        "searching": 
+                            Number( data.getElementsByTagName("searching")[0]
                                         .childNodes[0].nodeValue ),
-                        "working": 
-                            Number( data.getElementsByTagName("working")[0]
+                        "presenting": 
+                            Number( data.getElementsByTagName("presenting")[0]
                                         .childNodes[0].nodeValue ),
                         "idle": 
                             Number( data.getElementsByTagName("idle")[0]
@@ -349,9 +352,6 @@ pz2.prototype =
                                         .childNodes[0].nodeValue ),
                         "error": 
                             Number( data.getElementsByTagName("error")[0]
-                                        .childNodes[0].nodeValue ),
-                        "progress": 
-                            Number( data.getElementsByTagName("progress")[0]
                                         .childNodes[0].nodeValue )
                     };
                     
@@ -493,7 +493,7 @@ pz2.prototype =
            recordParams,
             function(data) {
                 var recordNode;
-                var record;
+                var record;                                
                 //raw record
                 if (context.currRecOffset !== null) {
                     record = new Array();
@@ -514,7 +514,21 @@ pz2.prototype =
                     //parse record
                     } else {
                         record = Element_parseChildNodes(recordNode);
-                    }                    
+                    }    
+                   var activeClients = 
+                      Number( data.getElementsByTagName("activeclients")[0]
+                               .childNodes[0].nodeValue );
+                   context.activeClients = activeClients; 
+                    context.recordCounter++;
+                    var delay = context.recordTime + context.recordCounter * context.dumpFactor;
+                    if ( activeClients > 0 )
+                        context.recordTimer = 
+                           setTimeout ( 
+                               function() {
+                                  context.record(id, offset, syntax, handler);
+                                  },
+                                  delay
+                               );                                    
                     callback(record, args);
                 }
                 else
index d7ce180..b810359 100644 (file)
@@ -1,6 +1,5 @@
 yaz
 pazpar2
-icu_chain_test
 Makefile
 Makefile.in
 config.h
@@ -11,8 +10,5 @@ config.h.in
 *.a
 *~
 stamp-h1
-test_config
-test_icu_I18N
-test_record
 test_sel_thread
 test_normalize
index 9df6ee1..b57ced2 100644 (file)
@@ -2,8 +2,7 @@
 
 sbin_PROGRAMS = pazpar2
 
-check_PROGRAMS = test_config \
-      test_record \
+check_PROGRAMS = \
       test_sel_thread \
       test_normalize
 
@@ -18,7 +17,7 @@ CONFIG_CLEAN_FILES=*.log
 AM_CFLAGS = $(YAZINC)
         
 libpazpar2_a_SOURCES = pazpar2_config.c pazpar2_config.h eventl.c eventl.h \
-       http.c http_command.c http_command.h http.h \
+       http.c http_command.c http.h \
        logic.c pazpar2.h \
        record.h record.c reclists.c reclists.h \
        relevance.c relevance.h termlists.c termlists.h \
@@ -32,12 +31,6 @@ libpazpar2_a_SOURCES = pazpar2_config.c pazpar2_config.h eventl.c eventl.h \
 pazpar2_SOURCES = pazpar2.c
 pazpar2_LDADD = libpazpar2.a $(YAZLIB)
 
-test_config_SOURCES = test_config.c
-test_config_LDADD = libpazpar2.a $(YAZLIB)
-
-test_record_SOURCES = test_record.c
-test_record_LDADD = libpazpar2.a $(YAZLIB)
-
 test_sel_thread_SOURCES = test_sel_thread.c
 test_sel_thread_LDADD = libpazpar2.a $(YAZLIB)
 
index 39ede26..9332aa0 100644 (file)
@@ -43,6 +43,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 struct pp2_charset_s {
     const char *(*token_next_handler)(pp2_relevance_token_t prt);
     const char *(*get_sort_handler)(pp2_relevance_token_t prt, int skip);
+    int ref_count;
 #if YAZ_HAVE_ICU
     struct icu_chain * icu_chn;
     UErrorCode icu_sts;
@@ -99,6 +100,10 @@ pp2_charset_t pp2_charset_create_xml(xmlNode *xml_node)
 #endif // YAZ_HAVE_ICU
 }
 
+void pp2_charset_incref(pp2_charset_t pct)
+{
+    (pct->ref_count)++;
+}
 
 pp2_charset_t pp2_charset_create(struct icu_chain * icu_chn)
 {
@@ -106,6 +111,7 @@ pp2_charset_t pp2_charset_create(struct icu_chain * icu_chn)
 
     pct->token_next_handler = pp2_relevance_token_a_to_z;
     pct->get_sort_handler  = pp2_get_sort_ascii;
+    pct->ref_count = 1;
 #if YAZ_HAVE_ICU
     pct->icu_chn = 0;
     if (icu_chn)
@@ -121,7 +127,18 @@ pp2_charset_t pp2_charset_create(struct icu_chain * icu_chn)
 
 void pp2_charset_destroy(pp2_charset_t pct)
 {
-    xfree(pct);
+    if (pct)
+    {
+        assert(pct->ref_count >= 1);
+        --(pct->ref_count);
+        if (pct->ref_count == 0)
+        {
+#if YAZ_HAVE_ICU
+            icu_chain_destroy(pct->icu_chn);
+#endif
+            xfree(pct);
+        }
+    }
 }
 
 pp2_relevance_token_t pp2_relevance_tokenize(pp2_charset_t pct,
index ef7e333..cb41404 100644 (file)
@@ -35,6 +35,7 @@ typedef struct pp2_relevance_token_s *pp2_relevance_token_t;
 pp2_charset_t pp2_charset_create_xml(xmlNode *xml_node);
 pp2_charset_t pp2_charset_create(struct icu_chain * icu_chn);
 void pp2_charset_destroy(pp2_charset_t pct);
+void pp2_charset_incref(pp2_charset_t pct);
 
 pp2_relevance_token_t pp2_relevance_tokenize(pp2_charset_t pct,
                                              const char *buf);
index 31c2543..775d0cd 100644 (file)
@@ -101,7 +101,7 @@ static const char *client_states[] = {
     "Client_Disconnected"
 };
 
-static struct client *client_freelist = 0;
+static struct client *client_freelist = 0; /* thread pr */
 
 const char *client_get_state_str(struct client *cl)
 {
@@ -488,6 +488,7 @@ void client_start_search(struct client *cl)
     const char *opt_requestsyn = session_setting_oneval(sdb, PZ_REQUESTSYNTAX);
     const char *opt_maxrecs = session_setting_oneval(sdb, PZ_MAXRECS);
     const char *opt_sru = session_setting_oneval(sdb, PZ_SRU);
+    const char *opt_sort = session_setting_oneval(sdb, PZ_SORT);
 
     assert(link);
 
@@ -526,6 +527,8 @@ void client_start_search(struct client *cl)
         ZOOM_query q = ZOOM_query_create();
         yaz_log(YLOG_LOG, "Search %s CQL: %s", sdb->database->url, cl->cqlquery);
         ZOOM_query_cql(q, cl->cqlquery);
+       if (*opt_sort)
+           ZOOM_query_sortby(q, opt_sort);
         rs = ZOOM_connection_search(link, q);
         ZOOM_query_destroy(q);
     }
@@ -643,17 +646,20 @@ static char *make_cqlquery(struct client *cl)
     char *r;
     WRBUF wrb = wrbuf_alloc();
     int status;
+    ODR odr_out = odr_createmem(ODR_ENCODE);
 
-    zquery = p_query_rpn(global_parameters.odr_out, cl->pquery);
+    zquery = p_query_rpn(odr_out, cl->pquery);
     if ((status = cql_transform_rpn2cql_wrbuf(cqlt, wrb, zquery)))
     {
         yaz_log(YLOG_WARN, "failed to generate CQL query, code=%d", status);
-        return 0;
+        r = 0;
     }
-    r = xstrdup(wrbuf_cstr(wrb));
-
+    else
+    {
+        r = xstrdup(wrbuf_cstr(wrb));
+    }     
     wrbuf_destroy(wrb);
-    odr_reset(global_parameters.odr_out); // releases the zquery
+    odr_destroy(odr_out);
     cql_transform_close(cqlt);
     return r;
 }
@@ -706,7 +712,7 @@ int client_parse_query(struct client *cl, const char *query)
         char *p[512];
         extract_terms(se->nmem, cn, p);
         se->relevance = relevance_create(
-            global_parameters.server->relevance_pct,
+            se->service->relevance_pct,
             se->nmem, (const char **) p,
             se->expected_maxrecs);
     }
index 18be84b..8d8d48f 100644 (file)
@@ -351,10 +351,8 @@ static int connection_connect(struct connection *con)
     assert(con);
 
     ZOOM_options_set(zoptions, "async", "1");
-    ZOOM_options_set(zoptions, "implementationName",
-            global_parameters.implementationName);
-    ZOOM_options_set(zoptions, "implementationVersion",
-            global_parameters.implementationVersion);
+    ZOOM_options_set(zoptions, "implementationName", PACKAGE_NAME);
+    ZOOM_options_set(zoptions, "implementationVersion", VERSION);
     if (zproxy && *zproxy)
     {
         con->zproxy = xstrdup(zproxy);
index 2b40874..e030ecc 100644 (file)
@@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "settings.h"
 #include "http.h"
 #include "zeerex.h"
+#include "database.h"
 
 #include <sys/types.h>
 #if HAVE_SYS_SOCKET_H
@@ -44,27 +45,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <netinet/in.h>
 #endif
 
-static struct host *hosts = 0;  // The hosts we know about 
-static struct database *databases = 0; // The databases we know about
-static NMEM nmem = 0;
+static struct host *hosts = 0;  /* thread pr */
 
-static xmlDoc *get_explain_xml(const char *id)
+static xmlDoc *get_explain_xml(struct conf_targetprofiles *targetprofiles,
+                               const char *id)
 {
     struct stat st;
     char *dir;
     char path[256];
     char ide[256];
-    if (!config || !config->targetprofiles)
-    {
-        yaz_log(YLOG_WARN, "Config must be loaded and specify targetprofiles");
-        return 0;
-    }
-    if (config->targetprofiles->type != Targetprofiles_local)
+    if (targetprofiles->type != Targetprofiles_local)
     {
         yaz_log(YLOG_FATAL, "Only supports local type");
         return 0;
     }
-    dir = config->targetprofiles->src;
+    dir = targetprofiles->src;
     urlencode(id, ide);
     sprintf(path, "%s/%s", dir, ide);
     if (!stat(path, &st))
@@ -103,24 +98,46 @@ static struct host *find_host(const char *hostport)
     return create_host(hostport);
 }
 
-static struct database *load_database(const char *id)
+int resolve_database(struct database *db)
+{
+    if (db->host == 0)
+    {
+        struct host *host;
+        char *p;
+        char hostport[256];
+        strcpy(hostport, db->url);
+        if ((p = strchr(hostport, '/')))
+            *p = '\0';
+        if (!(host = find_host(hostport)))
+            return -1;
+        db->host = host;
+    }
+    return 0;
+}
+
+void resolve_databases(struct conf_service *service)
+{
+    struct database *db = service->databases;
+    for (; db; db = db->next)
+        resolve_database(db);
+}
+
+static struct database *load_database(const char *id,
+    struct conf_service *service)
 {
     xmlDoc *doc = 0;
     struct zr_explain *explain = 0;
     struct database *db;
-    struct host *host;
     char hostport[256];
     char *dbname;
     struct setting *idset;
 
     yaz_log(YLOG_LOG, "New database: %s", id);
-    if (!nmem)
-        nmem = nmem_create();
 
-    if (config && config->targetprofiles 
-        && (doc = get_explain_xml(id)))
+    if (service->targetprofiles 
+        && (doc = get_explain_xml(service->targetprofiles, id)))
     {
-        explain = zr_read_xml(nmem, xmlDocGetRootElement(doc));
+        explain = zr_read_xml(service->nmem, xmlDocGetRootElement(doc));
         if (!explain)
             return 0;
     }
@@ -132,47 +149,47 @@ static struct database *load_database(const char *id)
         *(dbname++) = '\0';
     else
         dbname = "";
-    if (!(host = find_host(hostport)))
-        return 0;
-    db = nmem_malloc(nmem, sizeof(*db));
+    db = nmem_malloc(service->nmem, sizeof(*db));
     memset(db, 0, sizeof(*db));
-    db->host = host;
-    db->url = nmem_strdup(nmem, id);
-    db->databases = xmalloc(2 * sizeof(char *));
-    db->databases[0] = nmem_strdup(nmem, dbname);
+    db->host = 0;
+    db->url = nmem_strdup(service->nmem, id);
+    db->databases = nmem_malloc(service->nmem, 2 * sizeof(char *));
+    db->databases[0] = nmem_strdup(service->nmem, dbname);
     db->databases[1] = 0;
     db->errors = 0;
     db->explain = explain;
 
     db->settings = 0;
 
-    db->settings = nmem_malloc(nmem, sizeof(struct settings*) * settings_num());
-    memset(db->settings, 0, sizeof(struct settings*) * settings_num());
-    idset = nmem_malloc(nmem, sizeof(*idset));
+    db->settings = nmem_malloc(service->nmem, sizeof(struct settings*) * 
+                               settings_num(service));
+    memset(db->settings, 0, sizeof(struct settings*) * settings_num(service));
+    idset = nmem_malloc(service->nmem, sizeof(*idset));
     idset->precedence = 0;
     idset->name = "pz:id";
     idset->target = idset->value = db->url;
     idset->next = 0;
     db->settings[PZ_ID] = idset;
 
-    db->next = databases;
-    databases = db;
+    db->next = service->databases;
+    service->databases = db;
 
     return db;
 }
 
 // Return a database structure by ID. Load and add to list if necessary
 // new==1 just means we know it's not in the list
-struct database *find_database(const char *id, int new)
+struct database *find_database(const char *id, int new,
+                               struct conf_service *service)
 {
     struct database *p;
     if (!new)
     {
-        for (p = databases; p; p = p->next)
+        for (p = service->databases; p; p = p->next)
             if (!strcmp(p->url, id))
                 return p;
     }
-    return load_database(id);
+    return load_database(id, service);
 }
 
 // This whole session_grep database thing should be moved elsewhere
@@ -207,9 +224,11 @@ int match_zurl(const char *zurl, const char *pattern)
 }
 
 // This will be generalized at some point
-static int match_criterion(struct setting **settings, struct database_criterion *c)
+static int match_criterion(struct setting **settings,
+                           struct conf_service *service, 
+                           struct database_criterion *c)
 {
-    int offset = settings_offset(c->name);
+    int offset = settings_offset(service, c->name);
     struct database_criterion_value *v;
 
     if (offset < 0)
@@ -238,10 +257,12 @@ static int match_criterion(struct setting **settings, struct database_criterion
         return 0;
 }
 
-int database_match_criteria(struct setting **settings, struct database_criterion *cl)
+int database_match_criteria(struct setting **settings,
+                            struct conf_service *service,
+                            struct database_criterion *cl)
 {
     for (; cl; cl = cl->next)
-        if (!match_criterion(settings, cl))
+        if (!match_criterion(settings, service, cl))
             break;
     if (cl) // one of the criteria failed to match -- skip this db
         return 0;
@@ -263,7 +284,7 @@ int session_grep_databases(struct session *se, struct database_criterion *cl,
             continue;
         if (!p->settings[PZ_NAME])
             continue;
-        if (database_match_criteria(p->settings, cl))
+        if (database_match_criteria(p->settings, se->service, cl))
         {
             (*fun)(se, p);
             i++;
@@ -272,14 +293,15 @@ int session_grep_databases(struct session *se, struct database_criterion *cl,
     return i;
 }
 
-int predef_grep_databases(void *context, struct database_criterion *cl,
+int predef_grep_databases(void *context, struct conf_service *service,
+                          struct database_criterion *cl,
                           void (*fun)(void *context, struct database *db))
 {
     struct database *p;
     int i = 0;
 
-    for (p = databases; p; p = p->next)
-        if (database_match_criteria(p->settings, cl))
+    for (p = service->databases; p; p = p->next)
+        if (database_match_criteria(p->settings, service, cl))
         {
             (*fun)(context, p);
             i++;
index 82067e7..7631b55 100644 (file)
@@ -21,12 +21,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #define DATABASE_H
 
 void prepare_databases(void);
-struct database *find_database(const char *id, int new);
-int database_match_criteria(struct session_database *db, struct database_criterion *cl);
+struct database *find_database(const char *id, int new, struct conf_service *service);
 int session_grep_databases(struct session *se, struct database_criterion *cl,
         void (*fun)(void *context, struct session_database *db));
-int predef_grep_databases(void *context, struct database_criterion *cl,
+int predef_grep_databases(void *context, struct conf_service *service,
+                         struct database_criterion *cl,
                          void (*fun)(void *context, struct database *db));
 int match_zurl(const char *zurl, const char *pattern);
+int resolve_database(struct database *db);
+
 
 #endif
index 62233b2..0e1c47b 100644 (file)
@@ -66,20 +66,16 @@ typedef int socklen_t;
 #include "eventl.h"
 #include "pazpar2.h"
 #include "http.h"
-#include "http_command.h"
 
 #define MAX_HTTP_HEADER 4096
 
 static void proxy_io(IOCHAN i, int event);
-static struct http_channel *http_create(const char *addr);
+static struct http_channel *http_create(const char *addr,
+                                        struct conf_server *server);
 static void http_destroy(IOCHAN i);
 
-// If this is set, we proxy normal HTTP requests
-static struct sockaddr_in *proxy_addr = 0; 
-static char proxy_url[256] = "";
-static char myurl[256] = "";
-static struct http_buf *http_buf_freelist = 0;
-static struct http_channel *http_channel_freelist = 0;
+static struct http_buf *http_buf_freelist = 0;        /* thread pr */
+static struct http_channel *http_channel_freelist = 0; /* thread pr */
 
 struct http_channel_observer_s {
     void *data;
@@ -271,7 +267,7 @@ void http_addheader(struct http_response *r, const char *name, const char *value
     r->headers = h;
 }
 
-char *http_argbyname(struct http_request *r, char *name)
+const char *http_argbyname(struct http_request *r, const char *name)
 {
     struct http_argument *p;
     if (!name)
@@ -282,7 +278,7 @@ char *http_argbyname(struct http_request *r, char *name)
     return 0;
 }
 
-char *http_headerbyname(struct http_header *h, char *name)
+const char *http_headerbyname(struct http_header *h, const char *name)
 {
     for (; h; h = h->next)
         if (!strcmp(h->name, name))
@@ -665,7 +661,8 @@ static struct http_buf *http_serialize_request(struct http_request *r)
 
 static int http_weshouldproxy(struct http_request *rq)
 {
-    if (proxy_addr && !strstr(rq->path, "search.pz2"))
+    struct http_channel *c = rq->channel;
+    if (c->server->proxy_addr && !strstr(rq->path, "search.pz2"))
         return 1;
     return 0;
 }
@@ -733,9 +730,8 @@ static int http_proxy(struct http_request *rq)
     struct http_proxy *p = c->proxy;
     struct http_header *hp;
     struct http_buf *requestbuf;
-    char server_via[128] = "";
     char server_port[16] = "";
-    struct conf_server *ser = global_parameters.server;
+    struct conf_server *ser = c->server;
 
     if (!p) // This is a new connection. Create a proxy channel
     {
@@ -755,8 +751,8 @@ static int http_proxy(struct http_request *rq)
                         &one, sizeof(one)) < 0)
             abort();
         enable_nonblock(sock);
-        if (connect(sock, (struct sockaddr *) proxy_addr, 
-                    sizeof(*proxy_addr)) < 0)
+        if (connect(sock, (struct sockaddr *) c->server->proxy_addr, 
+                    sizeof(*c->server->proxy_addr)) < 0)
         {
             if (!is_inprogress()) 
             {
@@ -785,6 +781,8 @@ static int http_proxy(struct http_request *rq)
     
     // Add new header about paraz2 version, host, remote client address, etc.
     {
+        char server_via[128];
+
         hp = rq->headers;
         hp = http_header_append(c, hp, 
                                 "X-Pazpar2-Version", PACKAGE_VERSION);
@@ -793,9 +791,10 @@ static int http_proxy(struct http_request *rq)
         sprintf(server_port, "%d",  ser->port);
         hp = http_header_append(c, hp, 
                                 "X-Pazpar2-Server-Port", server_port);
-        sprintf(server_via,  "1.1 %s:%s (%s/%s)",  
-                ser->host ? ser->host : "@",
-                server_port, PACKAGE_NAME, PACKAGE_VERSION);
+        yaz_snprintf(server_via, sizeof(server_via), 
+                     "1.1 %s:%s (%s/%s)",  
+                     ser->host ? ser->host : "@",
+                     server_port, PACKAGE_NAME, PACKAGE_VERSION);
         hp = http_header_append(c, hp, "Via" , server_via);
         hp = http_header_append(c, hp, "X-Forwarded-For", c->addr);
     }
@@ -1064,7 +1063,8 @@ static void http_destroy(IOCHAN i)
     iochan_destroy(i);
 }
 
-static struct http_channel *http_create(const char *addr)
+static struct http_channel *http_create(const char *addr,
+                                        struct conf_server *server)
 {
     struct http_channel *r = http_channel_freelist;
 
@@ -1080,6 +1080,7 @@ static struct http_channel *http_create(const char *addr)
         r->nmem = nmem_create();
         r->wrbuf = wrbuf_alloc();
     }
+    r->server = server;
     r->proxy = 0;
     r->iochan = 0;
     r->iqueue = r->oqueue = 0;
@@ -1107,6 +1108,7 @@ static void http_accept(IOCHAN i, int event)
     int s;
     IOCHAN c;
     struct http_channel *ch;
+    struct conf_server *server = iochan_getdata(i);
 
     len = sizeof addr;
     if ((s = accept(fd, (struct sockaddr *) &addr, &len)) < 0)
@@ -1119,17 +1121,15 @@ static void http_accept(IOCHAN i, int event)
     yaz_log(YLOG_DEBUG, "New command connection");
     c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT);
     
-    ch = http_create(inet_ntoa(addr.sin_addr));
+    ch = http_create(inet_ntoa(addr.sin_addr), server);
     ch->iochan = c;
     iochan_setdata(c, ch);
 
     pazpar2_add_channel(c);
 }
 
-static int listener_socket = 0;
-
 /* Create a http-channel listener, syntax [host:]port */
-int http_init(const char *addr)
+int http_init(const char *addr, struct conf_server *server)
 {
     IOCHAN c;
     int l;
@@ -1146,17 +1146,19 @@ int http_init(const char *addr)
     pp = strchr(addr, ':');
     if (pp)
     {
-        int len = pp - addr;
-        char hostname[128];
+        WRBUF w = wrbuf_alloc();
         struct hostent *he;
 
-        strncpy(hostname, addr, len);
-        hostname[len] = '\0';
-        if (!(he = gethostbyname(hostname))){
-            yaz_log(YLOG_FATAL, "Unable to resolve '%s'", hostname);
+        wrbuf_write(w, addr, pp - addr);
+        wrbuf_puts(w, "");
+
+        he = gethostbyname(wrbuf_cstr(w));
+        wrbuf_destroy(w);
+        if (!he)
+        {
+            yaz_log(YLOG_FATAL, "Unable to resolve '%s'", addr);
             return 1;
         }
-        
         memcpy(&myaddr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
         port = atoi(pp + 1);
     }
@@ -1188,52 +1190,59 @@ int http_init(const char *addr)
         return 1;
     }
 
-    listener_socket = l;
+    server->listener_socket = l;
 
     c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT);
+    iochan_setdata(c, server);
     pazpar2_add_channel(c);
     return 0;
 }
 
-void http_close_server(void)
+void http_close_server(struct conf_server *server)
 {
     /* break the event_loop (select) by closing down the HTTP listener sock */
-    if (listener_socket)
+    if (server->listener_socket)
     {
 #ifdef WIN32
-        closesocket(listener_socket);
+        closesocket(server->listener_socket);
 #else
-        close(listener_socket);
+        close(server->listener_socket);
 #endif
     }
 }
 
-void http_set_proxyaddr(char *host, char *base_url)
+void http_set_proxyaddr(const char *host, struct conf_server *server)
 {
-    char *p;
+    const char *p;
     short port;
     struct hostent *he;
+    WRBUF w = wrbuf_alloc();
+
+    yaz_log(YLOG_LOG, "HTTP backend  %s", host);
 
-    strcpy(myurl, base_url);
-    strcpy(proxy_url, host);
     p = strchr(host, ':');
-    yaz_log(YLOG_DEBUG, "Proxying for %s", host);
-    yaz_log(YLOG_LOG, "HTTP backend  %s", proxy_url);
-    if (p) {
+    if (p)
+    {
         port = atoi(p + 1);
-        *p = '\0';
+        wrbuf_write(w, host, p - host);
+        wrbuf_puts(w, "");
     }
     else
+    {
         port = 80;
-    if (!(he = gethostbyname(host))) 
+        wrbuf_puts(w, host);
+    }
+    if (!(he = gethostbyname(wrbuf_cstr(w))))
     {
-        fprintf(stderr, "Failed to lookup '%s'\n", host);
+        fprintf(stderr, "Failed to lookup '%s'\n", wrbuf_cstr(w));
         exit(1);
     }
-    proxy_addr = xmalloc(sizeof(struct sockaddr_in));
-    proxy_addr->sin_family = he->h_addrtype;
-    memcpy(&proxy_addr->sin_addr.s_addr, he->h_addr_list[0], he->h_length);
-    proxy_addr->sin_port = htons(port);
+    wrbuf_destroy(w);
+
+    server->proxy_addr = xmalloc(sizeof(struct sockaddr_in));
+    server->proxy_addr->sin_family = he->h_addrtype;
+    memcpy(&server->proxy_addr->sin_addr.s_addr, he->h_addr_list[0], he->h_length);
+    server->proxy_addr->sin_port = htons(port);
 }
 
 static void http_fire_observers(struct http_channel *c)
index cacabb0..c93a85b 100644 (file)
@@ -52,6 +52,7 @@ struct http_channel
     struct http_channel *next; // for freelist
     char addr[20]; // forwarded address
     http_channel_observer_t observers;
+    struct conf_server *server;
 };
 
 struct http_proxy //  attached to iochan for proxy connection
@@ -99,17 +100,17 @@ struct http_response
     char *content_type;
 };
 
-void http_set_proxyaddr(char *url, char *baseurl);
-int http_init(const char *addr);
-void http_close_server(void);
+void http_set_proxyaddr(const char *url, struct conf_server *ser);
+int http_init(const char *addr, struct conf_server *ser);
+void http_close_server(struct conf_server *ser);
 void http_addheader(struct http_response *r, 
                     const char *name, const char *value);
 struct http_header * http_header_append(struct http_channel *ch, 
                                         struct http_header * hp, 
                                         const char *name, 
                                         const char *value);
-char *http_argbyname(struct http_request *r, char *name);
-char *http_headerbyname(struct http_header *r, char *name);
+const char *http_argbyname(struct http_request *r, const char *name);
+const char *http_headerbyname(struct http_header *r, const char *name);
 struct http_response *http_create_response(struct http_channel *c);
 void http_send_response(struct http_channel *c);
 void urlencode(const char *i, char *o);
@@ -123,6 +124,9 @@ void http_observer_set_data2(http_channel_observer_t obs, void *data2);
 
 void http_remove_observer(http_channel_observer_t obs);
 struct http_channel *http_channel_observer_chan(http_channel_observer_t obs);
+
+void http_command(struct http_channel *c);
+
 #endif
 
 /*
index ff35fdd..4b95b89 100644 (file)
@@ -37,7 +37,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "eventl.h"
 #include "pazpar2.h"
 #include "http.h"
-#include "http_command.h"
 #include "settings.h"
 #include "client.h"
 
@@ -53,7 +52,8 @@ struct http_session {
     struct http_session *next;
 };
 
-static struct http_session *session_list = 0;
+static struct http_session *session_list = 0; /* thread pr */
+
 void http_session_destroy(struct http_session *s);
 
 static void session_timeout(IOCHAN i, int event)
@@ -62,12 +62,12 @@ static void session_timeout(IOCHAN i, int event)
     http_session_destroy(s);
 }
 
-struct http_session *http_session_create(void)
+struct http_session *http_session_create(struct conf_service *service)
 {
     NMEM nmem = nmem_create();
     struct http_session *r = nmem_malloc(nmem, sizeof(*r));
 
-    r->psession = new_session(nmem);
+    r->psession = new_session(nmem, service);
     r->session_id = 0;
     r->timestamp = 0;
     r->nmem = nmem;
@@ -155,7 +155,7 @@ static void error(struct http_response *rs,
 
 unsigned int make_sessionid(void)
 {
-    static int seq = 0;
+    static int seq = 0; /* thread pr */
     unsigned int res;
 
     seq++;
@@ -185,7 +185,7 @@ unsigned int make_sessionid(void)
 static struct http_session *locate_session(struct http_request *rq, struct http_response *rs)
 {
     struct http_session *p;
-    char *session = http_argbyname(rq, "session");
+    const char *session = http_argbyname(rq, "session");
     unsigned int id;
 
     if (!session)
@@ -237,7 +237,7 @@ static int process_settings(struct session *se, struct http_request *rq,
 static void cmd_exit(struct http_channel *c)
 {
     yaz_log(YLOG_WARN, "exit");
-    http_close_server();
+    http_close_server(c->server);
 }
 
 static void cmd_init(struct http_channel *c)
@@ -245,9 +245,18 @@ static void cmd_init(struct http_channel *c)
     unsigned int sesid;
     char buf[1024];
     const char *clear = http_argbyname(c->request, "clear");
-    struct http_session *s = http_session_create();
+    const char *service_name = http_argbyname(c->request, "service");
+    struct conf_service *service = locate_service(c->server,
+                                                  service_name);
+    struct http_session *s = http_session_create(service);
     struct http_response *rs = c->response;
 
+    if (!service)
+    {
+        error(rs, PAZPAR2_MALFORMED_PARAMETER_VALUE, "service");
+        return;
+    }
+
     yaz_log(YLOG_DEBUG, "HTTP Session init");
     if (!clear || *clear == '0')
         session_init_databases(s->psession);
@@ -333,8 +342,8 @@ static void cmd_termlist(struct http_channel *c)
     struct termlist_score **p;
     int len;
     int i;
-    char *name = http_argbyname(rq, "name");
-    char *nums = http_argbyname(rq, "num");
+    const char *name = http_argbyname(rq, "name");
+    const char *nums = http_argbyname(rq, "num");
     int num = 15;
     int status;
 
@@ -357,7 +366,7 @@ static void cmd_termlist(struct http_channel *c)
     while (*name)
     {
         char tname[256];
-        char *tp;
+        const char *tp;
 
         if (!(tp = strchr(name, ',')))
             tp = name + strlen(name);
@@ -552,13 +561,14 @@ static void cmd_record(struct http_channel *c)
     struct http_session *s = locate_session(rq, rs);
     struct record_cluster *rec, *prev_r, *next_r;
     struct record *r;
-    struct conf_service *service = global_parameters.server->service;
+    struct conf_service *service;
     const char *idstr = http_argbyname(rq, "id");
     const char *offsetstr = http_argbyname(rq, "offset");
     const char *binarystr = http_argbyname(rq, "binary");
     
     if (!s)
         return;
+    service = s->psession->service;
     if (!idstr)
     {
         error(rs, PAZPAR2_MISSING_PARAMETER, "id");
@@ -567,7 +577,11 @@ static void cmd_record(struct http_channel *c)
     wrbuf_rewind(c->wrbuf);
     if (!(rec = show_single(s->psession, idstr, &prev_r, &next_r)))
     {
-        if (session_set_watch(s->psession, SESSION_WATCH_RECORD,
+        if (session_active_clients(s->psession) == 0)
+        {
+            error(rs, PAZPAR2_RECORD_MISSING, idstr);
+        }
+        else if (session_set_watch(s->psession, SESSION_WATCH_RECORD,
                               cmd_record_ready, c, c) != 0)
         {
             error(rs, PAZPAR2_RECORD_MISSING, idstr);
@@ -655,9 +669,9 @@ static void show_records(struct http_channel *c, int active)
     struct http_session *s = locate_session(rq, rs);
     struct record_cluster **rl;
     struct reclist_sortparms *sp;
-    char *start = http_argbyname(rq, "start");
-    char *num = http_argbyname(rq, "num");
-    char *sort = http_argbyname(rq, "sort");
+    const char *start = http_argbyname(rq, "start");
+    const char *num = http_argbyname(rq, "num");
+    const char *sort = http_argbyname(rq, "sort");
     int startn = 0;
     int numn = 20;
     int total;
@@ -677,7 +691,7 @@ static void show_records(struct http_channel *c, int active)
         numn = atoi(num);
     if (!sort)
         sort = "relevance";
-    if (!(sp = reclist_parse_sortparms(c->nmem, sort)))
+    if (!(sp = reclist_parse_sortparms(c->nmem, sort, s->psession->service)))
     {
         error(rs, PAZPAR2_MALFORMED_PARAMETER_VALUE, "sort");
         return;
@@ -698,7 +712,7 @@ static void show_records(struct http_channel *c, int active)
         int ccount;
         struct record *p;
         struct record_cluster *rec = rl[i];
-        struct conf_service *service = global_parameters.server->service;
+        struct conf_service *service = s->psession->service;
 
         wrbuf_puts(c->wrbuf, "<hit>\n");
         write_metadata(c->wrbuf, service, rec->metadata, 0);
@@ -729,7 +743,7 @@ static void cmd_show(struct http_channel *c)
     struct http_request *rq = c->request;
     struct http_response *rs = c->response;
     struct http_session *s = locate_session(rq, rs);
-    char *block = http_argbyname(rq, "block");
+    const char *block = http_argbyname(rq, "block");
     int status;
 
     if (!s)
@@ -795,8 +809,8 @@ static void cmd_search(struct http_channel *c)
     struct http_request *rq = c->request;
     struct http_response *rs = c->response;
     struct http_session *s = locate_session(rq, rs);
-    char *query = http_argbyname(rq, "query");
-    char *filter = http_argbyname(rq, "filter");
+    const char *query = http_argbyname(rq, "query");
+    const char *filter = http_argbyname(rq, "filter");
     enum pazpar2_error_code code;
     const char *addinfo = 0;
 
@@ -912,7 +926,7 @@ struct {
 
 void http_command(struct http_channel *c)
 {
-    char *command = http_argbyname(c->request, "command");
+    const char *command = http_argbyname(c->request, "command");
     struct http_response *rs = http_create_response(c);
     int i;
 
diff --git a/src/http_command.h b/src/http_command.h
deleted file mode 100644 (file)
index c460f34..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This file is part of Pazpar2.
-   Copyright (C) 2006-2009 Index Data
-
-Pazpar2 is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-*/
-
-#ifndef HTTP_COMMAND_H
-#define HTTP_COMMAND
-
-#include "http.h"
-
-void http_command(struct http_channel *c);
-
-#endif
index 07fac52..e927782 100644 (file)
@@ -77,21 +77,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 // Note: Some things in this structure will eventually move to configuration
 struct parameters global_parameters = 
 {
-    "",
-    "",
-    "", 
-    0,
     0,   // dump_records
     0,   // debug_mode
-    30,  // operations timeout 
-    "81",
-    "Index Data PazPar2",
-    VERSION,
     60,   // session timeout 
     100,
-    MAX_CHUNK,
-    0,
-    0,
     180, // Z39.50 session timeout
     15   // Connect timeout
 };
@@ -197,7 +186,7 @@ xmlDoc *record_to_xml(struct session_database *sdb, const char *rec)
 static void insert_settings_parameters(struct session_database *sdb,
                                        struct session *se, char **parms)
 {
-    struct conf_service *service = global_parameters.server->service;
+    struct conf_service *service = se->service;
     int i;
     int nparms = 0;
     int offset = 0;
@@ -208,7 +197,7 @@ static void insert_settings_parameters(struct session_database *sdb,
         int setting;
 
         if (md->setting == Metadata_setting_parameter &&
-            (setting = settings_offset(md->name)) > 0)
+            (setting = settings_offset(service, md->name)) > 0)
         {
             const char *val = session_setting_oneval(sdb, setting);
             if (val && nparms < MAX_XSLT_ARGS)
@@ -230,9 +219,9 @@ static void insert_settings_parameters(struct session_database *sdb,
 }
 
 // Add static values from session database settings if applicable
-static void insert_settings_values(struct session_database *sdb, xmlDoc *doc)
+static void insert_settings_values(struct session_database *sdb, xmlDoc *doc,
+    struct conf_service *service)
 {
-    struct conf_service *service = global_parameters.server->service;
     int i;
 
     for (i = 0; i < service->num_metadata; i++)
@@ -241,7 +230,7 @@ static void insert_settings_values(struct session_database *sdb, xmlDoc *doc)
         int offset;
 
         if (md->setting == Metadata_setting_postproc &&
-            (offset = settings_offset(md->name)) > 0)
+            (offset = settings_offset(service, md->name)) > 0)
         {
             const char *val = session_setting_oneval(sdb, offset);
             if (val)
@@ -297,7 +286,7 @@ xmlDoc *normalize_record(struct session_database *sdb, struct session *se,
             rdoc = new;
         }
 
-        insert_settings_values(sdb, rdoc);
+        insert_settings_values(sdb, rdoc, se->service);
 
         if (global_parameters.dump_records)
         {
@@ -371,7 +360,7 @@ static int prepare_map(struct session *se, struct session_database *sdb)
             if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-4], ".xsl")) 
             {    
                 (*m)->marcmap = NULL;
-                if (!((*m)->stylesheet = conf_load_stylesheet(stylesheets[i])))
+                if (!((*m)->stylesheet = conf_load_stylesheet(se->service->config, stylesheets[i])))
                 {
                     yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load stylesheet: %s",
                             stylesheets[i]);
@@ -539,7 +528,7 @@ static struct database_criterion *parse_filter(NMEM m, const char *buf)
 }
 
 enum pazpar2_error_code search(struct session *se,
-                               char *query, char *filter,
+                               const char *query, const char *filter,
                                const char **addinfo)
 {
     int live_channels = 0;
@@ -560,7 +549,7 @@ enum pazpar2_error_code search(struct session *se,
     live_channels = select_targets(se, criteria);
     if (live_channels)
     {
-        int maxrecs = live_channels * global_parameters.toget;
+        int maxrecs = live_channels * global_parameters.toget; // This is buggy!!!
         se->reclist = reclist_create(se->nmem, maxrecs);
         se->expected_maxrecs = maxrecs;
     }
@@ -598,8 +587,9 @@ enum pazpar2_error_code search(struct session *se,
 static void session_init_databases_fun(void *context, struct database *db)
 {
     struct session *se = (struct session *) context;
+    struct conf_service *service = se->service;
     struct session_database *new = nmem_malloc(se->session_nmem, sizeof(*new));
-    int num = settings_num();
+    int num = settings_num(service);
     int i;
 
     new->database = db;
@@ -632,7 +622,7 @@ static void session_database_destroy(struct session_database *sdb)
 void session_init_databases(struct session *se)
 {
     se->databases = 0;
-    predef_grep_databases(se, 0, session_init_databases_fun);
+    predef_grep_databases(se, se->service, 0, session_init_databases_fun);
 }
 
 // Probably session_init_databases_fun should be refactored instead of
@@ -640,7 +630,9 @@ void session_init_databases(struct session *se)
 static struct session_database *load_session_database(struct session *se, 
                                                       char *id)
 {
-    struct database *db = find_database(id, 0);
+    struct database *db = find_database(id, 0, se->service);
+
+    resolve_database(db);
 
     session_init_databases_fun((void*) se, db);
     // New sdb is head of se->databases list
@@ -664,8 +656,9 @@ void session_apply_setting(struct session *se, char *dbname, char *setting,
                            char *value)
 {
     struct session_database *sdb = find_session_database(se, dbname);
+    struct conf_service *service = se->service;
     struct setting *new = nmem_malloc(se->session_nmem, sizeof(*new));
-    int offset = settings_offset_cprefix(setting);
+    int offset = settings_offset_cprefix(service, setting);
 
     if (offset < 0)
     {
@@ -714,13 +707,14 @@ void destroy_session(struct session *s)
     wrbuf_destroy(s->wrbuf);
 }
 
-struct session *new_session(NMEM nmem) 
+struct session *new_session(NMEM nmem, struct conf_service *service) 
 {
     int i;
     struct session *session = nmem_malloc(nmem, sizeof(*session));
 
     yaz_log(YLOG_DEBUG, "New Pazpar2 session");
-    
+
+    session->service = service;
     session->relevance = 0;
     session->total_hits = 0;
     session->total_records = 0;
@@ -902,52 +896,10 @@ void statistics(struct session *se, struct statistics *stat)
     stat->num_clients = count;
 }
 
-int start_http_listener(void)
-{
-    char hp[128] = "";
-    struct conf_server *ser = global_parameters.server;
-
-    if (*global_parameters.listener_override)
-        strcpy(hp, global_parameters.listener_override);
-    else
-    {
-        strcpy(hp, ser->host ? ser->host : "");
-        if (ser->port)
-        {
-            if (*hp)
-                strcat(hp, ":");
-            sprintf(hp + strlen(hp), "%d", ser->port);
-        }
-    }
-    return http_init(hp);
-}
-
-void start_proxy(void)
-{
-    char hp[128] = "";
-    struct conf_server *ser = global_parameters.server;
-
-    if (*global_parameters.proxy_override)
-        strcpy(hp, global_parameters.proxy_override);
-    else if (ser->proxy_host || ser->proxy_port)
-    {
-        strcpy(hp, ser->proxy_host ? ser->proxy_host : "");
-        if (ser->proxy_port)
-        {
-            if (*hp)
-                strcat(hp, ":");
-            sprintf(hp + strlen(hp), "%d", ser->proxy_port);
-        }
-    }
-    else
-        return;
-
-    http_set_proxyaddr(hp, ser->myurl ? ser->myurl : "");
-}
-
 
 // Master list of connections we're handling events to
-static IOCHAN channel_list = 0; 
+static IOCHAN channel_list = 0;  /* thread pr */
+
 void pazpar2_add_channel(IOCHAN chan)
 {
     chan->next = channel_list;
@@ -989,8 +941,8 @@ static struct record_metadata *record_metadata_init(
     return rec_md;
 }
 
-const char *get_mergekey(xmlDoc *doc, struct client *cl, int record_no,
-                         struct conf_service *service, NMEM nmem)
+static const char *get_mergekey(xmlDoc *doc, struct client *cl, int record_no,
+                                struct conf_service *service, NMEM nmem)
 {
     char *mergekey_norm = 0;
     xmlNode *root = xmlDocGetRootElement(doc);
@@ -1004,7 +956,7 @@ const char *get_mergekey(xmlDoc *doc, struct client *cl, int record_no,
         const char *norm_str;
         pp2_relevance_token_t prt =
             pp2_relevance_tokenize(
-                global_parameters.server->mergekey_pct,
+                service->mergekey_pct,
                 (const char *) mergekey);
         
         while ((norm_str = pp2_relevance_token_next(prt)))
@@ -1048,7 +1000,7 @@ const char *get_mergekey(xmlDoc *doc, struct client *cl, int record_no,
                         const char *norm_str;
                         pp2_relevance_token_t prt =
                             pp2_relevance_tokenize(
-                                global_parameters.server->mergekey_pct,
+                                service->mergekey_pct,
                                 (const char *) value);
                         
                         while ((norm_str = pp2_relevance_token_next(prt)))
@@ -1101,7 +1053,7 @@ struct record *ingest_record(struct client *cl, const char *rec,
     const char *mergekey_norm;
     xmlChar *type = 0;
     xmlChar *value = 0;
-    struct conf_service *service = global_parameters.server->service;
+    struct conf_service *service = se->service;
 
     if (!xdoc)
         return 0;
@@ -1120,7 +1072,7 @@ struct record *ingest_record(struct client *cl, const char *rec,
                            record_no);
 
     cluster = reclist_insert(se->reclist, 
-                             global_parameters.server->service, 
+                             service, 
                              record, (char *) mergekey_norm, 
                              &se->total_merged);
     if (global_parameters.dump_records)
@@ -1234,7 +1186,7 @@ struct record *ingest_record(struct client *cl, const char *rec,
                                             sizeof(union data_types));
                          
                         prt = pp2_relevance_tokenize(
-                            global_parameters.server->sort_pct,
+                            service->sort_pct,
                             rec_md->data.text.disp);
 
                         pp2_relevance_token_next(prt);
index 3a73c31..3556626 100644 (file)
@@ -24,21 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 /** \brief global parameters */
 struct parameters {
-    char proxy_override[128];
-    char listener_override[128];
-    char settings_path_override[128];
-    struct conf_server *server;
     int dump_records;
     int debug_mode;
-    int timeout;               /* operations timeout, in seconds */
-    char implementationId[128];
-    char implementationName[128];
-    char implementationVersion[128];
     int session_timeout;
     int toget;
-    int chunk;
-    ODR odr_out;
-    ODR odr_in;
     int z3950_session_timeout;
     int z3950_connect_timeout;
 };
index 6c8251a..5070a10 100644 (file)
@@ -34,23 +34,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include <yaz/sc.h>
 
+static struct conf_config *sc_stop_config = 0;
+
 void child_handler(void *data)
 {
-    start_proxy();
-    init_settings();
-
-    if (*global_parameters.settings_path_override)
-        settings_read(global_parameters.settings_path_override);
-    else if (global_parameters.server->settings)
-        settings_read(global_parameters.server->settings);
-    else
-        yaz_log(YLOG_WARN, "No settings-directory specified");
-    global_parameters.odr_in = odr_createmem(ODR_DECODE);
-    global_parameters.odr_out = odr_createmem(ODR_ENCODE);
+    struct conf_config *config = (struct conf_config *) data;
 
+    config_start_databases(config);
 
     pazpar2_event_loop();
-
 }
 
 static void show_version(void)
@@ -99,6 +91,10 @@ static int sc_main(
     const char *pidfile = 0;
     const char *uid = 0;
     int session_timeout = 60;
+    const char *listener_override = 0;
+    const char *config_fname = 0;
+    struct conf_config *config = 0;
+    int test_mode = 0;
 
 #ifndef WIN32
     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
@@ -110,7 +106,7 @@ static int sc_main(
     yaz_log_init_prefix("pazpar2");
     yaz_log_xml_errors(0, YLOG_WARN);
 
-    while ((ret = options("dDf:h:l:p:t:T:u:VX", argv, argc, &arg)) != -2)
+    while ((ret = options("dDf:h:l:p:tT:u:VX", argv, argc, &arg)) != -2)
     {
        switch (ret)
         {
@@ -121,11 +117,10 @@ static int sc_main(
             daemon = 1;
             break;
         case 'f':
-            if (!read_config(arg))
-                exit(1);
+            config_fname = arg;
             break;
         case 'h':
-            strcpy(global_parameters.listener_override, arg);
+            listener_override = arg;
             break;
         case 'l':
             yaz_log_init_file(arg);
@@ -135,7 +130,7 @@ static int sc_main(
             pidfile = arg;
             break;
         case 't':
-            strcpy(global_parameters.settings_path_override, arg);
+            test_mode = 1;
             break;
         case 'T':
            session_timeout = atoi(arg);
@@ -157,58 +152,67 @@ static int sc_main(
             break;
         default:
             fprintf(stderr, "Usage: pazpar2\n"
-                    "    -d                      (show internal records)\n"
+                    "    -d                      Show internal records\n"
                     "    -D                      Daemon mode (background)\n"
-                    "    -f configfile\n"
-                    "    -h [host:]port          (REST protocol listener)\n"
-                    "    -l file                 log to file\n"
+                    "    -f configfile           Configuration\n"
+                    "    -h [host:]port          Listener port\n"
+                    "    -l file                 Log to file\n"
                     "    -p pidfile              PID file\n"
-                    "    -t settings\n"
-                    "    -T session_timeout\n"
-                    "    -u uid\n"
-                    "    -V                      show version\n"
-                    "    -X                      debug mode\n"
+                    "    -t                      Test configuration\n"
+                    "    -T session_timeout      Session timeout\n"
+                    "    -u uid                  Change user to uid\n"
+                    "    -V                      Show version\n"
+                    "    -X                      Debug mode\n"
 #ifdef WIN32
-                    "    -install                install windows service\n"
-                    "    -remove                 remove windows service\n"
+                    "    -install                Install windows service\n"
+                    "    -remove                 Remove windows service\n"
 #endif
                 );
             return 1;
        }
     }
-
-    yaz_log(YLOG_LOG, "Pazpar2 %s started", VERSION);
-    if (daemon && !log_file_in_use)
+    if (!config_fname)
     {
-        yaz_log(YLOG_FATAL, "Logfile must be given (option -l) for daemon "
-                "mode");
+        yaz_log(YLOG_FATAL, "Configuration must be given with option -f");
         return 1;
     }
+    config = config_create(config_fname, global_parameters.dump_records);
     if (!config)
-    {
-        yaz_log(YLOG_FATAL, "Load config with -f");
         return 1;
+    sc_stop_config = config;
+    if (test_mode)
+    {
+        yaz_log(YLOG_LOG, "Configuration OK");
+        config_destroy(config);
+    }
+    else
+    {
+        yaz_log(YLOG_LOG, "Pazpar2 %s started", VERSION);
+        if (daemon && !log_file_in_use)
+        {
+            yaz_log(YLOG_FATAL, "Logfile must be given (option -l) for daemon "
+                    "mode");
+            return 1;
+        }
+        ret = config_start_listeners(config, listener_override);
+        if (ret)
+            return ret; /* error starting http listener */
+        
+        yaz_sc_running(s);
+        
+        yaz_daemon("pazpar2",
+                   (global_parameters.debug_mode ? YAZ_DAEMON_DEBUG : 0) +
+                   (daemon ? YAZ_DAEMON_FORK : 0) + YAZ_DAEMON_KEEPALIVE,
+                   child_handler, config /* child_data */,
+                   pidfile, uid);
     }
-    global_parameters.server = config->servers;
-
-    ret = start_http_listener();
-    if (ret)
-        return ret; /* error starting http listener */
-
-    yaz_sc_running(s);
-
-    yaz_daemon("pazpar2",
-               (global_parameters.debug_mode ? YAZ_DAEMON_DEBUG : 0) +
-               (daemon ? YAZ_DAEMON_FORK : 0) + YAZ_DAEMON_KEEPALIVE,
-               child_handler, 0 /* child_data */,
-               pidfile, uid);
     return 0;
 }
 
 
 static void sc_stop(yaz_sc_t s)
 {
-    http_close_server();
+    config_stop_listeners(sc_stop_config);
 }
 
 int main(int argc, char **argv)
index 39f513d..caeba3f 100644 (file)
@@ -122,6 +122,7 @@ struct session_watchentry {
 
 // End-user session
 struct session {
+    struct conf_service *service; /* service in use for this session */
     struct session_database *databases;  // All databases, settings overriden
     struct client *clients;              // Clients connected for current search
     NMEM session_nmem;  // Nmem for session-permanent storage
@@ -164,13 +165,13 @@ struct hitsbytarget {
 
 struct hitsbytarget *hitsbytarget(struct session *s, int *count, NMEM nmem);
 int select_targets(struct session *se, struct database_criterion *crit);
-struct session *new_session(NMEM nmem);
+struct session *new_session(NMEM nmem, struct conf_service *service);
 void destroy_session(struct session *s);
 void session_init_databases(struct session *s);
 int load_targets(struct session *s, const char *fn);
 void statistics(struct session *s, struct statistics *stat);
-enum pazpar2_error_code search(struct session *s, char *query, 
-                               char *filter, const char **addinfo);
+enum pazpar2_error_code search(struct session *s, const char *query, 
+                               const char *filter, const char **addinfo);
 struct record_cluster **show(struct session *s, struct reclist_sortparms *sp, int start,
         int *num, int *total, int *sumhits, NMEM nmem_show);
 struct record_cluster *show_single(struct session *s, const char *id,
@@ -182,9 +183,6 @@ int session_active_clients(struct session *s);
 void session_apply_setting(struct session *se, char *dbname, char *setting, char *value);
 const char *session_setting_oneval(struct session_database *db, int offset);
 
-int start_http_listener(void);
-void start_proxy(void);
-
 void pazpar2_add_channel(IOCHAN c);
 void pazpar2_event_loop(void);
 
index 169de11..84fad66 100644 (file)
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #endif
 
 #include <string.h>
+#include <assert.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
@@ -34,31 +35,53 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/snprintf.h>
 #include <yaz/tpath.h>
 
-#define CONFIG_NOEXTERNS
-#include "pazpar2_config.h"
-
-
-static NMEM nmem = 0;
-static char confdir[256] = ".";
+#if HAVE_GLOB_H
+#define USE_POSIX_GLOB 1
+#else
+#define USE_POSIX_GLOB 0
+#endif
 
-struct conf_config *config = 0;
 
+#if USE_POSIX_GLOB
+#include <glob.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "pazpar2_config.h"
+#include "settings.h"
+#include "eventl.h"
+#include "http.h"
 
-static 
-struct conf_metadata * conf_metadata_assign(NMEM nmem, 
-                                            struct conf_metadata * metadata,
-                                            const char *name,
-                                            enum conf_metadata_type type,
-                                            enum conf_metadata_merge merge,
-                                            enum conf_setting_type setting,
-                                            int brief,
-                                            int termlist,
-                                            int rank,
-                                            int sortkey_offset,
-                                            enum conf_metadata_mergekey mt)
+struct conf_config
 {
-    if (!nmem || !metadata || !name)
-        return 0;
+    NMEM nmem; /* for conf_config and servers memory */
+    struct conf_server *servers;
+    WRBUF confdir;
+};
+
+
+static char *parse_settings(struct conf_config *config,
+                            NMEM nmem, xmlNode *node);
+
+static struct conf_targetprofiles *parse_targetprofiles(NMEM nmem,
+                                                        xmlNode *node);
+
+static void conf_metadata_assign(NMEM nmem, 
+                                 struct conf_metadata * metadata,
+                                 const char *name,
+                                 enum conf_metadata_type type,
+                                 enum conf_metadata_merge merge,
+                                 enum conf_setting_type setting,
+                                 int brief,
+                                 int termlist,
+                                 int rank,
+                                 int sortkey_offset,
+                                 enum conf_metadata_mergekey mt)
+{
+    assert(nmem && metadata && name);
     
     metadata->name = nmem_strdup(nmem, name);
 
@@ -76,35 +99,41 @@ struct conf_metadata * conf_metadata_assign(NMEM nmem,
     metadata->rank = rank;    
     metadata->sortkey_offset = sortkey_offset;
     metadata->mergekey = mt;
-    return metadata;
 }
 
 
-static
-struct conf_sortkey * conf_sortkey_assign(NMEM nmem, 
-                                          struct conf_sortkey * sortkey,
-                                          const char *name,
-                                          enum conf_sortkey_type type)
+static void conf_sortkey_assign(NMEM nmem, 
+                                struct conf_sortkey * sortkey,
+                                const char *name,
+                                enum conf_sortkey_type type)
 {
-    if (!nmem || !sortkey || !name)
-        return 0;
+    assert(nmem && sortkey && name);
     
     sortkey->name = nmem_strdup(nmem, name);
     sortkey->type = type;
-
-    return sortkey;
 }
 
 
-struct conf_service * conf_service_create(NMEM nmem,
-                                          int num_metadata, int num_sortkeys)
+static struct conf_service *service_init(struct conf_config *config,
+                                         int num_metadata, int num_sortkeys,
+                                         const char *service_id)
 {
     struct conf_service * service = 0;
+    NMEM nmem = nmem_create();
 
-    //assert(nmem);
-    
     service = nmem_malloc(nmem, sizeof(struct conf_service));
-
+    service->nmem = nmem;
+    service->next = 0;
+    service->settings = 0;
+    service->databases = 0;
+    service->targetprofiles = 0;
+    service->config = config;
+
+    service->relevance_pct = 0;
+    service->sort_pct = 0;
+    service->mergekey_pct = 0;
+
+    service->id = service_id ? nmem_strdup(nmem, service_id) : 0;
     service->num_metadata = num_metadata;
     service->metadata = 0;
     if (service->num_metadata)
@@ -117,12 +146,11 @@ struct conf_service * conf_service_create(NMEM nmem,
         service->sortkeys 
             = nmem_malloc(nmem, 
                           sizeof(struct conf_sortkey) * service->num_sortkeys);
-
+    service->dictionary = 0;
     return service; 
 }
 
-struct conf_metadata* conf_service_add_metadata(NMEM nmem, 
-                                                struct conf_service *service,
+struct conf_metadata* conf_service_add_metadata(struct conf_service *service,
                                                 int field_id,
                                                 const char *name,
                                                 enum conf_metadata_type type,
@@ -140,17 +168,15 @@ struct conf_metadata* conf_service_add_metadata(NMEM nmem,
         || field_id < 0  || !(field_id < service->num_metadata))
         return 0;
 
-    //md = &((service->metadata)[field_id]);
     md = service->metadata + field_id;
-    md = conf_metadata_assign(nmem, md, name, type, merge, setting,
-                              brief, termlist, rank, sortkey_offset,
-                              mt);
+    conf_metadata_assign(service->nmem, md, name, type, merge, setting,
+                         brief, termlist, rank, sortkey_offset,
+                         mt);
     return md;
 }
 
 
-struct conf_sortkey * conf_service_add_sortkey(NMEM nmem,
-                                               struct conf_service *service,
+struct conf_sortkey * conf_service_add_sortkey(struct conf_service *service,
                                                int field_id,
                                                const char *name,
                                                enum conf_sortkey_type type)
@@ -163,7 +189,7 @@ struct conf_sortkey * conf_service_add_sortkey(NMEM nmem,
 
     //sk = &((service->sortkeys)[field_id]);
     sk = service->sortkeys + field_id;
-    sk = conf_sortkey_assign(nmem, sk, name, type);
+    conf_sortkey_assign(service->nmem, sk, name, type);
 
     return sk;
 }
@@ -202,12 +228,31 @@ int conf_service_sortkey_field_id(struct conf_service *service,
     return -1;
 }
 
+static void conf_dir_path(struct conf_config *config, WRBUF w, const char *src)
+{
+    if (config->confdir && wrbuf_len(config->confdir) > 0 &&
+        !yaz_is_abspath(src))
+    {
+        wrbuf_printf(w, "%s/%s", wrbuf_cstr(config->confdir), src);
+    }
+    else
+        wrbuf_puts(w, src);
+}
 
+static void service_destroy(struct conf_service *service)
+{
+    if (service)
+    {
+        pp2_charset_destroy(service->relevance_pct);
+        pp2_charset_destroy(service->sort_pct);
+        pp2_charset_destroy(service->mergekey_pct);
+        nmem_destroy(service->nmem);
+    }
+}
 
-/* Code to parse configuration file */
-/* ==================================================== */
-
-static struct conf_service *parse_service(xmlNode *node)
+static struct conf_service *service_create(struct conf_config *config,
+                                           xmlNode *node,
+                                           const char *service_id)
 {
     xmlNode *n;
     int md_node = 0;
@@ -216,6 +261,7 @@ static struct conf_service *parse_service(xmlNode *node)
     struct conf_service *service = 0;
     int num_metadata = 0;
     int num_sortkeys = 0;
+    int got_settings = 0;
     
     // count num_metadata and num_sortkeys
     for (n = node->children; n; n = n->next)
@@ -229,13 +275,68 @@ static struct conf_service *parse_service(xmlNode *node)
             xmlFree(sortkey);
         }
 
-    service = conf_service_create(nmem, num_metadata, num_sortkeys);    
+    service = service_init(config, num_metadata, num_sortkeys, service_id);
 
     for (n = node->children; n; n = n->next)
     {
         if (n->type != XML_ELEMENT_NODE)
             continue;
-        if (!strcmp((const char *) n->name, (const char *) "metadata"))
+        if (!strcmp((const char *) n->name, "settings"))
+            got_settings++;
+        else if (!strcmp((const char *) n->name, (const char *) "targetprofiles"))
+        {
+            if (service->targetprofiles)
+            {
+                yaz_log(YLOG_FATAL, "Can't repeat targetprofiles");
+                return 0;
+            }
+            if (!(service->targetprofiles = 
+                  parse_targetprofiles(service->nmem, n)))
+                return 0;
+        }
+        else if (!strcmp((const char *) n->name, "relevance"))
+        {
+            if (service->relevance_pct)
+            {
+                yaz_log(YLOG_LOG, "relevance may not repeat in service");
+                return 0;
+            }
+            else
+            {
+                service->relevance_pct = pp2_charset_create_xml(n);
+                if (!service->relevance_pct)
+                    return 0;
+            }
+        }
+        else if (!strcmp((const char *) n->name, "sort"))
+        {
+            if (service->sort_pct)
+            {
+                yaz_log(YLOG_LOG, "sort may not repeat in service");
+                return 0;
+            }
+            else
+            {
+                service->sort_pct = pp2_charset_create_xml(n);
+                if (!service->sort_pct)
+                    return 0;
+            }
+        }
+        else if (!strcmp((const char *) n->name, "mergekey"))
+        {
+            if (service->mergekey_pct)
+            {
+                yaz_log(YLOG_LOG, "mergekey may not repeat in service");
+                return 0;
+            }
+            else
+            {
+                service->mergekey_pct = pp2_charset_create_xml(n);
+                if (!service->mergekey_pct)
+                    return 0;
+            }
+        }
+        else if (!strcmp((const char *) n->name, (const char *) "metadata"))
         {
             xmlChar *xml_name = xmlGetProp(n, (xmlChar *) "name");
             xmlChar *xml_brief = xmlGetProp(n, (xmlChar *) "brief");
@@ -372,7 +473,7 @@ static struct conf_service *parse_service(xmlNode *node)
                 }
                 sortkey_offset = sk_node;
 
-                conf_service_add_sortkey(nmem, service, sk_node,
+                conf_service_add_sortkey(service, sk_node,
                                          (const char *) xml_name, sk_type);
                 
                 sk_node++;
@@ -387,7 +488,7 @@ static struct conf_service *parse_service(xmlNode *node)
 
 
             // metadata known, assign values
-            conf_service_add_metadata(nmem, service, md_node,
+            conf_service_add_metadata(service, md_node,
                                       (const char *) xml_name,
                                       type, merge, setting,
                                       brief, termlist, rank, sortkey_offset,
@@ -409,24 +510,54 @@ static struct conf_service *parse_service(xmlNode *node)
             return 0;
         }
     }
+    if (got_settings)
+    {
+        int pass;
+        /* metadata has been read.. Consider now settings */
+        init_settings(service);
+        for (pass = 1; pass <= 2; pass++)
+        {
+            for (n = node->children; n; n = n->next)
+            {
+                if (n->type != XML_ELEMENT_NODE)
+                    continue;
+                if (!strcmp((const char *) n->name, "settings"))
+                {
+                    xmlChar *src = xmlGetProp(n, (xmlChar *) "src");
+                    if (src)
+                    {
+                        WRBUF w = wrbuf_alloc();
+                        conf_dir_path(config, w, (const char *) src);
+                        settings_read_file(service, wrbuf_cstr(w), pass);
+                        wrbuf_destroy(w);
+                        xmlFree(src);
+                    }
+                    else
+                    {
+                        settings_read_node(service, n, pass);
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+    }
     return service;
 }
 
-static char *parse_settings(xmlNode *node)
+static char *parse_settings(struct conf_config *config,
+                            NMEM nmem, xmlNode *node)
 {
     xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
     char *r;
 
     if (src)
     {
-        if (yaz_is_abspath((const char *) src))
-            r = nmem_strdup(nmem, (const char *) src);
-        else
-        {
-            r = nmem_malloc(nmem,
-                            strlen(confdir) + strlen((const char *) src) + 2);
-            sprintf(r, "%s/%s", confdir, src);
-        }
+        WRBUF w = wrbuf_alloc();
+        conf_dir_path(config, w, (const char *) src);
+        r = nmem_strdup(nmem, wrbuf_cstr(w));
+        wrbuf_destroy(w);
     }
     else
     {
@@ -437,7 +568,67 @@ static char *parse_settings(xmlNode *node)
     return r;
 }
 
-static struct conf_server *parse_server(xmlNode *node)
+static void inherit_server_settings(struct conf_server *server)
+{
+    struct conf_service *s;
+    for (s = server->service; s; s = s->next)
+    {
+        if (!s->dictionary) /* service has no config settings ? */
+        {
+            if (server->server_settings)
+            {
+                /* inherit settings from server */
+                init_settings(s);
+                settings_read_file(s, server->server_settings, 1);
+                settings_read_file(s, server->server_settings, 2);
+            }
+            else
+            {
+                yaz_log(YLOG_WARN, "service '%s' has no settings",
+                        s->id ? s->id : "unnamed");
+                init_settings(s);
+            }
+        }
+
+        /* use relevance/sort/mergekey from server if not defined
+           for this service.. */
+        if (!s->relevance_pct)
+        {
+            if (server->relevance_pct)
+            {
+                s->relevance_pct = server->relevance_pct;
+                pp2_charset_incref(s->relevance_pct);
+            }
+            else
+                s->relevance_pct = pp2_charset_create(0);
+        }
+        
+        if (!s->sort_pct)
+        {
+            if (server->sort_pct)
+            {
+                s->sort_pct = server->sort_pct;
+                pp2_charset_incref(s->sort_pct);
+            }
+            else
+                s->sort_pct = pp2_charset_create(0);
+        }
+        
+        if (!s->mergekey_pct)
+        {
+            if (server->mergekey_pct)
+            {
+                s->mergekey_pct = server->mergekey_pct;
+                pp2_charset_incref(s->mergekey_pct);
+            }
+            else
+                s->mergekey_pct = pp2_charset_create(0);
+        }
+    }
+}
+
+static struct conf_server *parse_server(struct conf_config *config,
+                                        NMEM nmem, xmlNode *node)
 {
     xmlNode *n;
     struct conf_server *server = nmem_malloc(nmem, sizeof(struct conf_server));
@@ -447,12 +638,13 @@ static struct conf_server *parse_server(xmlNode *node)
     server->proxy_host = 0;
     server->proxy_port = 0;
     server->myurl = 0;
+    server->proxy_addr = 0;
     server->service = 0;
     server->next = 0;
-    server->settings = 0;
     server->relevance_pct = 0;
     server->sort_pct = 0;
     server->mergekey_pct = 0;
+    server->server_settings = 0;
 
     for (n = node->children; n; n = n->next)
     {
@@ -486,12 +678,12 @@ static struct conf_server *parse_server(xmlNode *node)
         }
         else if (!strcmp((const char *) n->name, "settings"))
         {
-            if (server->settings)
+            if (server->server_settings)
             {
                 yaz_log(YLOG_FATAL, "Can't repeat 'settings'");
                 return 0;
             }
-            if (!(server->settings = parse_settings(n)))
+            if (!(server->server_settings = parse_settings(config, nmem, n)))
                 return 0;
         }
         else if (!strcmp((const char *) n->name, "relevance"))
@@ -514,10 +706,38 @@ static struct conf_server *parse_server(xmlNode *node)
         }
         else if (!strcmp((const char *) n->name, "service"))
         {
-            struct conf_service *s = parse_service(n);
-            if (!s)
+            char *service_id = (char *)
+                xmlGetProp(n, (xmlChar *) "id");
+
+            struct conf_service **sp = &server->service;
+            for (; *sp; sp = &(*sp)->next)
+                if ((*sp)->id && service_id &&
+                    0 == strcmp((*sp)->id, service_id))
+                {
+                    yaz_log(YLOG_FATAL, "Duplicate service: %s", service_id);
+                    break;
+                }
+                else if (!(*sp)->id && !service_id)
+                {
+                    yaz_log(YLOG_FATAL, "Duplicate unnamed service '%s'",
+                        service_id);
+                    break;
+                }
+
+            if (*sp)  /* service already exist */
+            {
+                xmlFree(service_id);
                 return 0;
-            server->service = s;
+            }
+            else
+            {
+                struct conf_service *s = service_create(config, n,
+                                                        service_id);
+                xmlFree(service_id);
+                if (!s)
+                    return 0;
+                *sp = s;
+            }
         }
         else
         {
@@ -525,26 +745,24 @@ static struct conf_server *parse_server(xmlNode *node)
             return 0;
         }
     }
-    if (!server->relevance_pct)
-        server->relevance_pct = pp2_charset_create(0);
-    if (!server->sort_pct)
-        server->sort_pct = pp2_charset_create(0);
-    if (!server->mergekey_pct)
-        server->mergekey_pct = pp2_charset_create(0);
+    inherit_server_settings(server);
     return server;
 }
 
-xsltStylesheet *conf_load_stylesheet(const char *fname)
+xsltStylesheet *conf_load_stylesheet(struct conf_config *config,
+                                     const char *fname)
 {
-    char path[256];
-    if (yaz_is_abspath(fname))
-        yaz_snprintf(path, sizeof(path), fname);
-    else
-        yaz_snprintf(path, sizeof(path), "%s/%s", confdir, fname);
-    return xsltParseStylesheetFile((xmlChar *) path);
+    WRBUF w = wrbuf_alloc();
+    xsltStylesheet *s;
+
+    conf_dir_path(config, w, fname);
+    s = xsltParseStylesheetFile((xmlChar *) wrbuf_cstr(w));
+    wrbuf_destroy(w);
+    return s;
 }
 
-static struct conf_targetprofiles *parse_targetprofiles(xmlNode *node)
+static struct conf_targetprofiles *parse_targetprofiles(NMEM nmem,
+                                                        xmlNode *node)
 {
     struct conf_targetprofiles *r = nmem_malloc(nmem, sizeof(*r));
     xmlChar *type = xmlGetProp(node, (xmlChar *) "type");
@@ -580,13 +798,22 @@ static struct conf_targetprofiles *parse_targetprofiles(xmlNode *node)
     return r;
 }
 
-static struct conf_config *parse_config(xmlNode *root)
+struct conf_service *locate_service(struct conf_server *server,
+                                    const char *service_id)
 {
-    xmlNode *n;
-    struct conf_config *r = nmem_malloc(nmem, sizeof(struct conf_config));
+    struct conf_service *s = server->service;
+    for (; s; s = s->next)
+        if (s->id && service_id && 0 == strcmp(s->id, service_id))
+            return s;
+        else if (!s->id && !service_id)
+            return s;
+    return 0;
+}
+
 
-    r->servers = 0;
-    r->targetprofiles = 0;
+static int parse_config(struct conf_config *config, xmlNode *root)
+{
+    xmlNode *n;
 
     for (n = root->children; n; n = n->next)
     {
@@ -594,48 +821,157 @@ static struct conf_config *parse_config(xmlNode *root)
             continue;
         if (!strcmp((const char *) n->name, "server"))
         {
-            struct conf_server *tmp = parse_server(n);
+            struct conf_server *tmp = parse_server(config, config->nmem, n);
             if (!tmp)
-                return 0;
-            tmp->next = r->servers;
-            r->servers = tmp;
+                return -1;
+            tmp->next = config->servers;
+            config->servers = tmp;
         }
         else if (!strcmp((const char *) n->name, "targetprofiles"))
         {
-            // It would be fun to be able to fix this sometime
-            if (r->targetprofiles)
-            {
-                yaz_log(YLOG_FATAL, "Can't repeat targetprofiles");
-                return 0;
-            }
-            if (!(r->targetprofiles = parse_targetprofiles(n)))
-                return 0;
+            yaz_log(YLOG_FATAL, "targetprofiles unsupported here. Must be part of service");
+            return -1;
+
         }
         else
         {
             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
-            return 0;
+            return -1;
         }
     }
-    return r;
+    return 0;
 }
 
-int read_config(const char *fname)
+static int process_config_includes(struct conf_config *config, xmlNode *n);
+
+static int config_include_one(struct conf_config *config, xmlNode **sib,
+    const char *path)
 {
-    xmlDoc *doc = xmlParseFile(fname);
-    const char *p;
+    struct stat st;
+    if (stat(path, &st) < 0)
+    {
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "stat %s", path);
+        return -1;
+    }
+    else
+    {
+        if ((st.st_mode & S_IFMT) == S_IFREG)
+        {
+            xmlDoc *doc = xmlParseFile(path);
+            if (doc)
+            {
+                xmlNodePtr t = xmlDocGetRootElement(doc);
+                int ret = process_config_includes(config, t);
+                *sib = xmlAddNextSibling(*sib, xmlCopyNode(t, 1));
+                xmlFreeDoc(doc);
+                if (ret)
+                    return -1;
+            }
+            else
+            {
+                yaz_log(YLOG_FATAL, "Could not parse %s", path);
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+static int config_include_src(struct conf_config *config, xmlNode **np,
+                              const char *src)
+{
+    int ret = 0; /* return code. OK so far */
+    WRBUF w = wrbuf_alloc();
+    xmlNodePtr sib; /* our sibling that we append */
+    xmlNodePtr c; /* tmp node */
+
+    wrbuf_printf(w, " begin include src=\"%s\" ", src);
+
+    /* replace include element with a 'begin' comment */
+    sib = xmlNewComment((const xmlChar *) wrbuf_cstr(w));
+    xmlReplaceNode(*np, sib);
+
+    xmlFreeNode(*np);
+
+    wrbuf_rewind(w);
+    conf_dir_path(config, w, src);
+#if USE_POSIX_GLOB
+    {
+        size_t i;
+        glob_t glob_res;
+        glob(wrbuf_cstr(w), 0 /* flags */, 0 /* errfunc */, &glob_res);
+        
+        for (i = 0; ret == 0 && i < glob_res.gl_pathc; i++)
+        {
+            const char *path = glob_res.gl_pathv[i];
+            ret = config_include_one(config, &sib, path);
+        }
+        globfree(&glob_res);
+    }
+#else
+    ret = config_include_one(config, &sib, wrbuf_cstr(w));
+#endif
+    wrbuf_rewind(w);
+    wrbuf_printf(w, " end include src=\"%s\" ", src);
+    c = xmlNewComment((const xmlChar *) wrbuf_cstr(w));
+    sib = xmlAddNextSibling(sib, c);
+    
+    *np = sib;
+    wrbuf_destroy(w);
+    return ret;
+}
 
-    if (!nmem)  // Initialize
+static int process_config_includes(struct conf_config *config, xmlNode *n)
+{
+    for (; n; n = n->next)
     {
-        nmem = nmem_create();
-        xmlSubstituteEntitiesDefault(1);
-        xmlLoadExtDtdDefaultValue = 1;
+        if (n->type == XML_ELEMENT_NODE)
+        {
+            if (!strcmp((const char *) n->name, "include"))
+            {
+                xmlChar *src = xmlGetProp(n, (xmlChar *) "src");
+                if (src)
+                {
+                    int ret = config_include_src(config, &n,
+                                                 (const char *) src);
+                    xmlFree(src);
+                    if (ret)
+                        return ret;
+                        
+                }
+            }
+            else
+            {
+                if (process_config_includes(config, n->children))
+                    return -1;
+            }
+        }
     }
+    return 0;
+}
+
+struct conf_config *config_create(const char *fname, int verbose)
+{
+    xmlDoc *doc = xmlParseFile(fname);
+    xmlNode *n;
+    const char *p;
+    int r;
+    NMEM nmem = nmem_create();
+    struct conf_config *config = nmem_malloc(nmem, sizeof(struct conf_config));
+
+    xmlSubstituteEntitiesDefault(1);
+    xmlLoadExtDtdDefaultValue = 1;
     if (!doc)
     {
         yaz_log(YLOG_FATAL, "Failed to read %s", fname);
-        exit(1);
+        nmem_destroy(nmem);
+        return 0;
     }
+
+    config->nmem = nmem;
+    config->servers = 0;
+
+    config->confdir = wrbuf_alloc();
     if ((p = strrchr(fname, 
 #ifdef WIN32
                      '\\'
@@ -645,20 +981,127 @@ int read_config(const char *fname)
              )))
     {
         int len = p - fname;
-        if (len >= sizeof(confdir))
-            len = sizeof(confdir)-1;
-        strncpy(confdir, fname, len);
-        confdir[len] = '\0';
+        wrbuf_write(config->confdir, fname, len);
+    }
+    wrbuf_puts(config->confdir, "");
+    
+    n = xmlDocGetRootElement(doc);
+    r = process_config_includes(config, n);
+    if (r == 0) /* OK */
+    {
+        if (verbose)
+        {
+            yaz_log(YLOG_LOG, "Configuration %s after include processing",
+                    fname);
+            xmlDocFormatDump(yaz_log_file(), doc, 0);
+        }
+        r = parse_config(config, n);
     }
-    config = parse_config(xmlDocGetRootElement(doc));
     xmlFreeDoc(doc);
 
-    if (config)
-        return 1;
-    else
+    if (r)
+    {
+        config_destroy(config);
         return 0;
+    }
+    return config;
+}
+
+void server_destroy(struct conf_server *server)
+{
+    struct conf_service *s = server->service;
+    while (s)
+    {
+        struct conf_service *s_next = s->next;
+        service_destroy(s);
+        s = s_next;
+    }
+    pp2_charset_destroy(server->relevance_pct);
+    pp2_charset_destroy(server->sort_pct);
+    pp2_charset_destroy(server->mergekey_pct);
 }
 
+void config_destroy(struct conf_config *config)
+{
+    if (config)
+    {
+        struct conf_server *server = config->servers;
+        while (server)
+        {
+            struct conf_server *s_next = server->next;
+            server_destroy(server);
+            server = s_next;
+        }
+        wrbuf_destroy(config->confdir);
+        nmem_destroy(config->nmem);
+    }
+}
+
+void config_stop_listeners(struct conf_config *conf)
+{
+    struct conf_server *ser;
+    for (ser = conf->servers; ser; ser = ser->next)
+        http_close_server(ser);
+}
+
+void config_start_databases(struct conf_config *conf)
+{
+    struct conf_server *ser;
+    for (ser = conf->servers; ser; ser = ser->next)
+    {
+        struct conf_service *s = ser->service;
+        for (;s ; s = s->next)
+            resolve_databases(s);
+    }
+}
+
+int config_start_listeners(struct conf_config *conf,
+                           const char *listener_override)
+{
+    struct conf_server *ser;
+    for (ser = conf->servers; ser; ser = ser->next)
+    {
+        WRBUF w = wrbuf_alloc();
+        int r;
+        if (listener_override)
+        {
+            wrbuf_puts(w, listener_override);
+            listener_override = 0; /* only first server is overriden */
+        }
+        else
+        {
+            if (ser->host)
+                wrbuf_puts(w, ser->host);
+            if (ser->port)
+            {
+                if (wrbuf_len(w))
+                    wrbuf_puts(w, ":");
+                wrbuf_printf(w, "%d", ser->port);
+            }
+        }
+        r = http_init(wrbuf_cstr(w), ser);
+        wrbuf_destroy(w);
+        if (r)
+            return -1;
+
+        w = wrbuf_alloc();
+        if (ser->proxy_host || ser->proxy_port)
+        {
+            if (ser->proxy_host)
+                wrbuf_puts(w, ser->proxy_host);
+            if (ser->proxy_port)
+            {
+                if (wrbuf_len(w))
+                    wrbuf_puts(w, ":");
+                wrbuf_printf(w, "%d", ser->proxy_port);
+            }
+        }
+        if (wrbuf_len(w))
+            http_set_proxyaddr(wrbuf_cstr(w), ser);
+        wrbuf_destroy(w);
+    }
+    return 0;
+}
 
 /*
  * Local variables:
index 1e71619..49adefb 100644 (file)
@@ -100,14 +100,27 @@ struct conf_service
     struct conf_metadata *metadata;
     int num_sortkeys;
     struct conf_sortkey *sortkeys;
+    struct setting_dictionary *dictionary;
+    struct conf_service *next;
+    char *id;
+    char *settings;
+    NMEM nmem;
 
+    /* duplicated from conf_server */
+    pp2_charset_t relevance_pct;
+    pp2_charset_t sort_pct;
+    pp2_charset_t mergekey_pct;
+
+    struct database *databases;
+    struct conf_targetprofiles *targetprofiles;
+    struct conf_config *config;
 };
 
-struct conf_service * conf_service_create(NMEM nmem, 
-                                          int num_metadata, int num_sortkeys);
+struct conf_service * conf_service_create(struct conf_config *config,
+                                          int num_metadata, int num_sortkeys,
+                                          const char *service_id);
 
-struct conf_metadata* conf_service_add_metadata(NMEM nmem, 
-                                                struct conf_service *service,
+struct conf_metadata* conf_service_add_metadata(struct conf_service *service,
                                                 int field_id,
                                                 const char *name,
                                                 enum conf_metadata_type type,
@@ -119,8 +132,7 @@ struct conf_metadata* conf_service_add_metadata(NMEM nmem,
                                                 int sortkey_offset,
                                                 enum conf_metadata_mergekey mt);
 
-struct conf_sortkey * conf_service_add_sortkey(NMEM nmem,
-                                               struct conf_service *service,
+struct conf_sortkey * conf_service_add_sortkey(struct conf_service *service,
                                                int field_id,
                                                const char *name,
                                                enum conf_sortkey_type type);
@@ -130,7 +142,6 @@ int conf_service_metadata_field_id(struct conf_service *service, const char * na
 
 int conf_service_sortkey_field_id(struct conf_service *service, const char * name);
 
-
 struct conf_server
 {
     char *host;
@@ -138,12 +149,13 @@ struct conf_server
     char *proxy_host;
     int proxy_port;
     char *myurl;
-    char *settings;
+    struct sockaddr_in *proxy_addr;
+    int listener_socket;
+    char *server_settings;
 
     pp2_charset_t relevance_pct;
     pp2_charset_t sort_pct;
     pp2_charset_t mergekey_pct;
-
     struct conf_service *service;
     struct conf_server *next;
 };
@@ -156,20 +168,21 @@ struct conf_targetprofiles
     char *src;
 };
 
-struct conf_config
-{
-    struct conf_server *servers;
-    struct conf_targetprofiles *targetprofiles;
-};
+struct conf_config *config_create(const char *fname, int verbose);
+void config_destroy(struct conf_config *config);
+xsltStylesheet *conf_load_stylesheet(struct conf_config *config,
+                                     const char *fname);
 
-#ifndef CONFIG_NOEXTERNS
+void config_start_databases(struct conf_config *config);
 
-extern struct conf_config *config;
+struct conf_service *locate_service(struct conf_server *server,
+                                    const char *service_id);
 
-#endif
 
-int read_config(const char *fname);
-xsltStylesheet *conf_load_stylesheet(const char *fname);
+int config_start_listeners(struct conf_config *conf,
+                           const char *listener_override);
+
+void config_stop_listeners(struct conf_config *conf);
 
 #endif
 
index afb4e3c..7d92643 100644 (file)
@@ -27,11 +27,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "pazpar2.h"
 #include "reclists.h"
+#include "parameters.h"
 
-extern struct parameters global_parameters;
-
-// Not threadsafe
-static struct reclist_sortparms *sortparms = 0;
+static struct reclist_sortparms *qsort_sortparms = 0; /* thread pr */
 
 struct reclist_bucket
 {
@@ -93,11 +91,11 @@ reclist_sortparms_insert(NMEM nmem,
 #endif
 
 
-struct reclist_sortparms *reclist_parse_sortparms(NMEM nmem, const char *parms)
+struct reclist_sortparms *reclist_parse_sortparms(NMEM nmem, const char *parms,
+    struct conf_service *service)
 {
     struct reclist_sortparms *res = 0;
     struct reclist_sortparms **rp = &res;
-    struct conf_service *service = config->servers->service;
 
     if (strlen(parms) > 256)
         return 0;
@@ -168,7 +166,7 @@ static int reclist_cmp(const void *p1, const void *p2)
     struct reclist_sortparms *s;
     int res = 0;
 
-    for (s = sortparms; s && res == 0; s = s->next)
+    for (s = qsort_sortparms; s && res == 0; s = s->next)
     {
         union data_types *ut1 = r1->sortkeys[s->offset];
         union data_types *ut2 = r2->sortkeys[s->offset];
@@ -214,7 +212,7 @@ static int reclist_cmp(const void *p1, const void *p2)
 
 void reclist_sort(struct reclist *l, struct reclist_sortparms *parms)
 {
-    sortparms = parms;
+    qsort_sortparms = parms;
     qsort(l->flatlist, l->num_records, 
           sizeof(struct record_cluster*), reclist_cmp);
     reclist_rewind(l);
index 51653b1..e75b5da 100644 (file)
@@ -70,7 +70,8 @@ struct record_cluster *reclist_insert( struct reclist *tl,
 void reclist_sort(struct reclist *l, struct reclist_sortparms *parms);
 struct record_cluster *reclist_read_record(struct reclist *l);
 void reclist_rewind(struct reclist *l);
-struct reclist_sortparms *reclist_parse_sortparms(NMEM nmem, const char *parms);
+struct reclist_sortparms *reclist_parse_sortparms(NMEM nmem, const char *parms,
+    struct conf_service *service);
 
 #endif
 
index 08b73f5..080822f 100644 (file)
@@ -26,12 +26,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <config.h>
 #endif
 
-//#define CONFIG_NOEXTERNS
 #include "pazpar2_config.h"
 #include "record.h"
 
-
-
 union data_types * data_types_assign(NMEM nmem, 
                                      union data_types ** data1, 
                                      union data_types data2)
index cbe8baf..3b7a923 100644 (file)
@@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 #include <string.h>
+#include <assert.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include "direntz.h"
@@ -44,8 +45,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "database.h"
 #include "settings.h"
 
-static NMEM nmem = 0;
-
 // Used for initializing setting_dictionary with pazpar2-specific settings
 static char *hard_settings[] = {
     "pz:piggyback",
@@ -66,6 +65,7 @@ static char *hard_settings[] = {
     "pz:sru",
     "pz:sru_version",
     "pz:pqf_prefix",
+    "pz:sort",
     0
 };
 
@@ -76,34 +76,32 @@ struct setting_dictionary
     int num;
 };
 
-static struct setting_dictionary *dictionary = 0;
-
 // This establishes the precedence of wildcard expressions
 #define SETTING_WILDCARD_NO     0 // No wildcard
 #define SETTING_WILDCARD_DB     1 // Database wildcard 'host:port/*'
 #define SETTING_WILDCARD_YES    2 // Complete wildcard '*'
 
 // Returns size of settings directory
-int settings_num(void)
+int settings_num(struct conf_service *service)
 {
-    return dictionary->num;
+    return service->dictionary->num;
 }
 
-int settings_offset(const char *name)
+int settings_offset(struct conf_service *service, const char *name)
 {
     int i;
 
     if (!name)
         name = "";
-    for (i = 0; i < dictionary->num; i++)
-        if (!strcmp(name, dictionary->dict[i]))
+    for (i = 0; i < service->dictionary->num; i++)
+        if (!strcmp(name, service->dictionary->dict[i]))
             return i;
     return -1;
 }
 
 // Ignores everything after second colon, if present
 // A bit of a hack to support the pz:cclmap: scheme (and more to come?)
-int settings_offset_cprefix(const char *name)
+int settings_offset_cprefix(struct conf_service *service, const char *name)
 {
     const char *p;
     int maxlen = 100;
@@ -111,15 +109,15 @@ int settings_offset_cprefix(const char *name)
 
     if (!strncmp("pz:", name, 3) && (p = strchr(name + 3, ':')))
         maxlen = (p - name) + 1;
-    for (i = 0; i < dictionary->num; i++)
-        if (!strncmp(name, dictionary->dict[i], maxlen))
+    for (i = 0; i < service->dictionary->num; i++)
+        if (!strncmp(name, service->dictionary->dict[i], maxlen))
             return i;
     return -1;
 }
 
-char *settings_name(int offset)
+char *settings_name(struct conf_service *service, int offset)
 {
-    return dictionary->dict[offset];
+    return service->dictionary->dict[offset];
 }
 
 static int isdir(const char *path)
@@ -128,26 +126,20 @@ static int isdir(const char *path)
 
     if (stat(path, &st) < 0)
     {
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "%s", path);
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "stat %s", path);
         exit(1);
     }
     return st.st_mode & S_IFDIR;
 }
 
 // Read settings from an XML file, calling handler function for each setting
-static void read_settings_file(const char *path,
-        void (*fun)(struct setting *set))
+static void read_settings_node(xmlNode *n,
+                               struct conf_service *service,
+                               void (*fun)(struct conf_service *service,
+                                           struct setting *set))
 {
-    xmlDoc *doc = xmlParseFile(path);
-    xmlNode *n;
     xmlChar *namea, *targeta, *valuea, *usera, *precedencea;
 
-    if (!doc)
-    {
-        yaz_log(YLOG_FATAL, "Failed to parse %s", path);
-        exit(1);
-    }
-    n = xmlDocGetRootElement(doc);
     namea = xmlGetProp(n, (xmlChar *) "name");
     targeta = xmlGetProp(n, (xmlChar *) "target");
     valuea = xmlGetProp(n, (xmlChar *) "value");
@@ -203,7 +195,7 @@ static void read_settings_file(const char *path,
                     strcpy(valueb, (const char *) valuea);
                 set.value = valueb;
                 set.next = 0;
-                (*fun)(&set);
+                (*fun)(service, &set);
             }
             xmlFree(name);
             xmlFree(precedence);
@@ -222,14 +214,34 @@ static void read_settings_file(const char *path,
     xmlFree(valuea);
     xmlFree(usera);
     xmlFree(targeta);
+}
+static void read_settings_file(const char *path,
+                               struct conf_service *service,
+                               void (*fun)(struct conf_service *service,
+                                           struct setting *set))
+{
+    xmlDoc *doc = xmlParseFile(path);
+    xmlNode *n;
+
+    if (!doc)
+    {
+        yaz_log(YLOG_FATAL, "Failed to parse %s", path);
+        exit(1);
+    }
+    n = xmlDocGetRootElement(doc);
+    read_settings_node(n, service, fun);
 
     xmlFreeDoc(doc);
 }
+
+
 // Recursively read files or directories, invoking a 
 // callback for each one
 static void read_settings(const char *path,
-               void (*fun)(struct setting *set))
+                          struct conf_service *service,
+                          void (*fun)(struct conf_service *service,
+                                      struct setting *set))
 {
     DIR *d;
     struct dirent *de;
@@ -248,12 +260,12 @@ static void read_settings(const char *path,
             if (*de->d_name == '.' || !strcmp(de->d_name, "CVS"))
                 continue;
             sprintf(tmp, "%s/%s", path, de->d_name);
-            read_settings(tmp, fun);
+            read_settings(tmp, service, fun);
         }
         closedir(d);
     }
     else if ((dot = strrchr(path, '.')) && !strcmp(dot + 1, "xml"))
-        read_settings_file(path, fun);
+        read_settings_file(path, service, fun);
 }
 
 // Determines if a ZURL is a wildcard, and what kind
@@ -272,15 +284,14 @@ static int zurl_wildcard(const char *zurl)
 // Callback. Adds a new entry to the dictionary if necessary
 // This is used in pass 1 to determine layout of dictionary
 // and to load any databases mentioned
-static void prepare_dictionary(struct setting *set)
+static void prepare_dictionary(struct conf_service *service,
+                               struct setting *set)
 {
+    struct setting_dictionary *dictionary = service->dictionary;
+
     int i;
     char *p;
 
-    // If target address is not wildcard, add the database
-    if (*set->target && !zurl_wildcard(set->target))
-        find_database(set->target, 0);
-
     // Determine if we already have a dictionary entry
     if (!strncmp(set->name, "pz:", 3) && (p = strchr(set->name + 3, ':')))
         *(p + 1) = '\0';
@@ -297,22 +308,33 @@ static void prepare_dictionary(struct setting *set)
     // Create a new dictionary entry
     // Grow dictionary if necessary
     if (!dictionary->size)
-        dictionary->dict = nmem_malloc(nmem, (dictionary->size = 50) * sizeof(char*));
+        dictionary->dict =
+            nmem_malloc(service->nmem, (dictionary->size = 50) * sizeof(char*));
     else if (dictionary->num + 1 > dictionary->size)
     {
-        char **tmp = nmem_malloc(nmem, dictionary->size * 2 * sizeof(char*));
+        char **tmp =
+            nmem_malloc(service->nmem, dictionary->size * 2 * sizeof(char*));
         memcpy(tmp, dictionary->dict, dictionary->size * sizeof(char*));
         dictionary->dict = tmp;
         dictionary->size *= 2;
     }
-    dictionary->dict[dictionary->num++] = nmem_strdup(nmem, set->name);
+    dictionary->dict[dictionary->num++] = nmem_strdup(service->nmem, set->name);
 }
 
+
+struct update_database_context {
+    struct setting *set;
+    struct conf_service *service;
+};
+
 // This is called from grep_databases -- adds/overrides setting for a target
 // This is also where the rules for precedence of settings are implemented
 static void update_database(void *context, struct database *db)
 {
-    struct setting *set = (struct setting *) context;
+    struct setting *set = ((struct update_database_context *)
+                           context)->set;
+    struct conf_service *service = ((struct update_database_context *) 
+                                    context)->service;
     struct setting *s, **sp;
     int offset;
 
@@ -320,8 +342,8 @@ static void update_database(void *context, struct database *db)
     if (!match_zurl(db->url, set->target))
         return;
 
-    if ((offset = settings_offset_cprefix(set->name)) < 0)
-        abort(); // Should never get here
+    if ((offset = settings_offset_cprefix(service, set->name)) < 0)
+        return ;
 
     // First we determine if this setting is overriding  any existing settings
     // with the same name.
@@ -344,13 +366,13 @@ static void update_database(void *context, struct database *db)
         }
     if (!s) // s will be null when there are no higher-priority settings -- we add one
     {
-        struct setting *new = nmem_malloc(nmem, sizeof(*new));
+        struct setting *new = nmem_malloc(service->nmem, sizeof(*new));
 
         memset(new, 0, sizeof(*new));
         new->precedence = set->precedence;
-        new->target = nmem_strdup(nmem, set->target);
-        new->name = nmem_strdup(nmem, set->name);
-        new->value = nmem_strdup(nmem, set->value);
+        new->target = nmem_strdup(service->nmem, set->target);
+        new->name = nmem_strdup(service->nmem, set->name);
+        new->value = nmem_strdup(service->nmem, set->value);
         new->next = db->settings[offset];
         db->settings[offset] = new;
     }
@@ -358,16 +380,21 @@ static void update_database(void *context, struct database *db)
 
 // Callback -- updates database records with dictionary entries as appropriate
 // This is used in pass 2 to assign name/value pairs to databases
-static void update_databases(struct setting *set)
+static void update_databases(struct conf_service *service, 
+                             struct setting *set)
 {
-    predef_grep_databases(set, 0, update_database);
+    struct update_database_context context;
+    context.set = set;
+    context.service = service;
+    predef_grep_databases(&context, service, 0, update_database);
 }
 
 // This simply copies the 'hard' (application-specific) settings
 // to the settings dictionary.
-static void initialize_hard_settings(struct setting_dictionary *dict)
+static void initialize_hard_settings(struct conf_service *service)
 {
-    dict->dict = nmem_malloc(nmem, sizeof(hard_settings) - sizeof(char*));
+    struct setting_dictionary *dict = service->dictionary;
+    dict->dict = nmem_malloc(service->nmem, sizeof(hard_settings) - sizeof(char*));
     dict->size = (sizeof(hard_settings) - sizeof(char*)) / sizeof(char*);
     memcpy(dict->dict, hard_settings, dict->size * sizeof(char*));
     dict->num = dict->size;
@@ -375,9 +402,8 @@ static void initialize_hard_settings(struct setting_dictionary *dict)
 
 // Read any settings names introduced in service definition (config) and add to dictionary
 // This is done now to avoid errors if user settings are declared in session overrides
-static void initialize_soft_settings(void)
+static void initialize_soft_settings(struct conf_service *service)
 {
-    struct conf_service *service = config->servers->service;
     int i;
 
     for (i = 0; i < service->num_metadata; i++)
@@ -393,31 +419,60 @@ static void initialize_soft_settings(void)
         set.name = md->name;
         set.value = "";
         set.next = 0;
-        prepare_dictionary(&set);
+        prepare_dictionary(service, &set);
     }
 }
 
-// If we ever decide we need to be able to specify multiple settings directories,
-// the two calls to read_settings must be split -- so the dictionary is prepared
-// for the contents of every directory before the databases are updated.
-void settings_read(const char *path)
+static void prepare_target_dictionary(struct conf_service *service,
+                                      struct setting *set)
 {
-    read_settings(path, prepare_dictionary);
-    read_settings(path, update_databases);
+    struct setting_dictionary *dictionary = service->dictionary;
+
+    int i;
+    char *p;
+
+    // If target address is not wildcard, add the database
+    if (*set->target && !zurl_wildcard(set->target))
+        find_database(set->target, 0, service);
+
+    // Determine if we already have a dictionary entry
+    if (!strncmp(set->name, "pz:", 3) && (p = strchr(set->name + 3, ':')))
+        *(p + 1) = '\0';
+    for (i = 0; i < dictionary->num; i++)
+        if (!strcmp(dictionary->dict[i], set->name))
+            return;
+    yaz_log(YLOG_WARN, "Setting '%s' not configured as metadata", set->name);
 }
 
-void init_settings(void)
+void init_settings(struct conf_service *service)
 {
     struct setting_dictionary *new;
-    if (!nmem)
-        nmem = nmem_create();
-    else
-        nmem_reset(nmem);
-    new = nmem_malloc(nmem, sizeof(*new));
+    
+    assert(service->nmem);
+    
+    new = nmem_malloc(service->nmem, sizeof(*new));
     memset(new, 0, sizeof(*new));
-    initialize_hard_settings(new);
-    dictionary = new;
-    initialize_soft_settings();
+    service->dictionary = new;
+    initialize_hard_settings(service);
+    initialize_soft_settings(service);
+}
+
+void settings_read_file(struct conf_service *service, const char *path,
+                        int pass)
+{
+    if (pass == 1)
+        read_settings(path, service, prepare_target_dictionary);
+    else
+        read_settings(path, service, update_databases);
+}
+
+void settings_read_node(struct conf_service *service, xmlNode *n,
+                        int pass)
+{
+    if (pass == 1)
+        read_settings_node(n, service, prepare_target_dictionary);
+    else
+        read_settings_node(n, service, update_databases);
 }
 
 /*
index 971c474..623a477 100644 (file)
@@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #define PZ_SRU           15
 #define PZ_SRU_VERSION   16
 #define PZ_PQF_PREFIX    17
+#define PZ_SORT                 18
 
 struct setting
 {
@@ -48,11 +49,15 @@ struct setting
     struct setting *next;
 };
 
-int settings_num(void);
-void settings_read(const char *path);
-int settings_offset(const char *name);
-int settings_offset_cprefix(const char *name);
-void init_settings(void);
+void settings_read_file(struct conf_service *service, const char *path,
+                        int pass);
+void settings_read_node(struct conf_service *service, xmlNode *n,
+                        int pass);
+int settings_num(struct conf_service *service);
+int settings_offset(struct conf_service *service, const char *name);
+int settings_offset_cprefix(struct conf_service *service, const char *name);
+void init_settings(struct conf_service *service);
+void resolve_databases(struct conf_service *service);
 
 #endif
 
diff --git a/src/test_config.c b/src/test_config.c
deleted file mode 100644 (file)
index 3d7e091..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* This file is part of Pazpar2.
-   Copyright (C) 2006-2009 Index Data
-
-Pazpar2 is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-*/
-
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define USE_TIMING 0
-#if USE_TIMING
-#include <yaz/timing.h>
-#endif
-
-#include <yaz/test.h>
-
-#include "pazpar2_config.h"
-
-
-
-void test_conf_service(int argc, char **argv)
-{
-  NMEM         nmem = nmem_create();
-
-  struct conf_service *service = 0;
-  service = conf_service_create(nmem, 4, 3);
-
-  YAZ_CHECK(service);
-
-  // expected metadata failures
-  YAZ_CHECK(!conf_service_add_metadata(0, service, 0, "dead_nmem",
-                                       Metadata_type_generic,
-                                       Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                       1, 1, 1, 0,
-                                       Metadata_mergekey_no));
-
-  YAZ_CHECK(!conf_service_add_metadata(nmem, 0, 0, "service_needed",
-                                       Metadata_type_generic, 
-                                       Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                       1, 1, 1, 0,
-                                       Metadata_mergekey_no));
-
-  YAZ_CHECK(!conf_service_add_metadata(nmem, service, -1, "out_of_bounds",
-                                       Metadata_type_generic,
-                                       Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                       1, 1, 1, 0,
-                                       Metadata_mergekey_no));
-
-  YAZ_CHECK(!conf_service_add_metadata(nmem, service, 4, "out_of_bounds",
-                                       Metadata_type_generic,
-                                       Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                       1, 1, 1, 0,
-                                       Metadata_mergekey_no));
-
-  YAZ_CHECK(!conf_service_add_metadata(nmem, service, 0, 0,  //missing name
-                                       Metadata_type_generic,
-                                       Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                       1, 1, 1, 0,
-                                       Metadata_mergekey_no));
-
-  // expected metadata sucesses
-  YAZ_CHECK(conf_service_add_metadata(nmem, service, 0, "title",
-                                      Metadata_type_generic,
-                                      Metadata_merge_unique,
-                                       Metadata_setting_no,
-                                      1, 1, 1, 0,
-                                      Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_metadata(nmem, service, 1, "author",
-                                      Metadata_type_generic,
-                                      Metadata_merge_longest,
-                                      Metadata_setting_no,
-                                      1, 1, 1, 0,
-                                      Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_metadata(nmem, service, 2, "isbn",
-                                      Metadata_type_number,
-                                      Metadata_merge_no,
-                                      Metadata_setting_no,
-                                      1, 1, 1, 0,
-                                      Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_metadata(nmem, service, 3, "year",
-                                      Metadata_type_year,
-                                      Metadata_merge_range,
-                                      Metadata_setting_no,
-                                      1, 1, 1, 0,
-                                      Metadata_mergekey_no));
-
-
-  // expected sortkey failures
-  YAZ_CHECK(!conf_service_add_sortkey(0, service, 0, "dead_nmem",
-                                     Metadata_sortkey_relevance));
-
-  YAZ_CHECK(!conf_service_add_sortkey(nmem, 0, 0, "service_neeeded",
-                                     Metadata_sortkey_numeric));
-
-  YAZ_CHECK(!conf_service_add_sortkey(nmem, service, -1, "out_of_bounds",
-                                     Metadata_sortkey_skiparticle));
-
-  YAZ_CHECK(!conf_service_add_sortkey(nmem, service, -1, "out_of_bounds",
-                                     Metadata_sortkey_string));
-
-  YAZ_CHECK(!conf_service_add_sortkey(nmem, service, 3, "out_of_bounds",
-                                     Metadata_sortkey_relevance));
-
-  YAZ_CHECK(!conf_service_add_sortkey(nmem, service, 0, 0, //missing name
-                                     Metadata_sortkey_relevance));
-
-
-  // expected sortkey sucess
-  YAZ_CHECK(conf_service_add_sortkey(nmem, service, 0, "relevance",
-                                     Metadata_sortkey_relevance));
-
-  YAZ_CHECK(conf_service_add_sortkey(nmem, service, 1, "title",
-                                     Metadata_sortkey_string));
-  
-  YAZ_CHECK(conf_service_add_sortkey(nmem, service, 2, "year",
-                                     Metadata_sortkey_numeric));
-  
-
-
-
-
-
-  nmem_destroy(nmem);
-
-  //YAZ_CHECK(0 == 0);
-  //YAZ_CHECK_EQ(0, 1);
-
-}
-
-
-int main(int argc, char **argv)
-{
-    YAZ_CHECK_INIT(argc, argv); 
-    YAZ_CHECK_LOG();
-
-    test_conf_service(argc, argv);
-    
-    YAZ_CHECK_TERM;
-}
-
-
-
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * c-file-style: "Stroustrup"
- * indent-tabs-mode: nil
- * End:
- * vim: shiftwidth=4 tabstop=8 expandtab
- */
-
diff --git a/src/test_record.c b/src/test_record.c
deleted file mode 100644 (file)
index b55aa7c..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/* This file is part of Pazpar2.
-   Copyright (C) 2006-2009 Index Data
-
-Pazpar2 is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-*/
-
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define USE_TIMING 0
-#if USE_TIMING
-#include <yaz/timing.h>
-#endif
-
-#include <yaz/test.h>
-
-#include "pazpar2_config.h"
-#include "record.h"
-
-
-
-void test_record(int argc, char **argv)
-{
-  NMEM         nmem = nmem_create();
-
-  struct conf_service *service = 0; 
-  struct record *record = 0;
-
-  struct client *client = 0;
-  char * bla = "blabla";
-  union data_types data_text;
-  union data_types data_num;
-  struct record_metadata * tmp_md = 0;
-
-  data_text.text.disp = bla;
-  data_text.text.sort = bla;
-
-  data_num.number.min = 2;
-  data_num.number.max = 5;
-
-
-  service =  conf_service_create(nmem, 4, 3);
-  YAZ_CHECK(service);
-
-  YAZ_CHECK(conf_service_add_metadata(
-                nmem, service, 0, "title",
-                Metadata_type_generic, Metadata_merge_unique,
-                Metadata_setting_no, 1, 1, 1, 0,
-                Metadata_mergekey_no
-                ));
-
-  YAZ_CHECK(conf_service_add_metadata(
-                nmem, service, 1, "author",
-                Metadata_type_generic, Metadata_merge_longest,
-                Metadata_setting_no,1, 1, 1, 0,
-                Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_metadata(
-                nmem, service, 2, "isbn",
-                Metadata_type_number, Metadata_merge_no,
-                Metadata_setting_no, 1, 1, 1, 0,
-                Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_metadata(
-                nmem, service, 3, "year",
-                Metadata_type_year, Metadata_merge_range,
-                Metadata_setting_no, 1, 1, 1, 0,
-                Metadata_mergekey_no));
-
-  YAZ_CHECK(conf_service_add_sortkey(
-                nmem, service, 0, "relevance",
-                Metadata_sortkey_relevance));
-  
-  YAZ_CHECK(conf_service_add_sortkey(
-                nmem, service, 1, "title",
-                Metadata_sortkey_string));
-  
-  YAZ_CHECK(conf_service_add_sortkey(
-                nmem, service, 2, "year",
-                Metadata_sortkey_numeric));
-  
-
-
-
-  // testing record things
-  record = record_create(nmem, 4, 3, client, 1);
-  YAZ_CHECK(record);
-
-  tmp_md = record_metadata_insert(nmem, &(record->metadata[0]), data_text);
-  YAZ_CHECK(tmp_md);
-  YAZ_CHECK(0 == record->metadata[0]->next);
-
-  tmp_md = record_metadata_insert(nmem, &(record->metadata[0]->next), 
-                                  data_text);
-  YAZ_CHECK(tmp_md);
-  YAZ_CHECK(record->metadata[0]->next);
-
-  YAZ_CHECK(record_add_metadata_field_id(nmem, record, 3, data_num));
-  YAZ_CHECK(0 == record->metadata[3]->next);
-  YAZ_CHECK(record_add_metadata_field_id(nmem, record, 3, data_num));
-  YAZ_CHECK(record->metadata[3]->next);
-
-  YAZ_CHECK(record_add_metadata(nmem, record, service, "author", data_text));
-  YAZ_CHECK(0 == record->metadata[1]->next);
-  YAZ_CHECK(record_add_metadata(nmem, record, service, "author", data_text));
-  YAZ_CHECK(record->metadata[1]->next);
-
-
-  YAZ_CHECK(0 == record->sortkeys[0]);
-  YAZ_CHECK(record_assign_sortkey_field_id(nmem, record, 0, data_text));
-  YAZ_CHECK(record->sortkeys[0]);
-  YAZ_CHECK(0 == record->sortkeys[1]);
-  YAZ_CHECK(record_assign_sortkey_field_id(nmem, record, 1, data_text));
-  YAZ_CHECK(record->sortkeys[1]);
-  YAZ_CHECK(0 == record->sortkeys[2]);
-  YAZ_CHECK(record_assign_sortkey_field_id(nmem, record, 2, data_num));
-  YAZ_CHECK(record->sortkeys[2]);
-
-
-  YAZ_CHECK(record_assign_sortkey(nmem, record, service, "relevance", data_text));
-  YAZ_CHECK(record_assign_sortkey(nmem, record, service, "title", data_text));
-  YAZ_CHECK(record_assign_sortkey(nmem, record, service, "year", data_num));
-
-
-
-
-  nmem_destroy(nmem);
-
-  //YAZ_CHECK(0 == 0);
-  //YAZ_CHECK_EQ(0, 1);
-}
-
-
-int main(int argc, char **argv)
-{
-    YAZ_CHECK_INIT(argc, argv); 
-    YAZ_CHECK_LOG(); 
-
-
-    test_record(argc, argv); 
-
-    
-    YAZ_CHECK_TERM;
-}
-
-
-
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * c-file-style: "Stroustrup"
- * indent-tabs-mode: nil
- * End:
- * vim: shiftwidth=4 tabstop=8 expandtab
- */
-
index e72fe53..dcfc4b7 100644 (file)
@@ -385,7 +385,7 @@ static struct zr_map *map(NMEM m, xmlNode *node)
 
 static Zr_setting *findsetting(NMEM m, xmlNode *node, char *name)
 {
-    static Zr_setting *r = 0;
+    static Zr_setting *r = 0; /* thread pr */
     xmlNode *n;
     for (n = node->children; n; n = n->next)
     {
index 9be0625..de29b11 100644 (file)
@@ -1,7 +1,9 @@
 # This file is part of Pazpar2.
 check_SCRIPTS = test_http.sh test_icu.sh
 
-EXTRA_DIST = run_pazpar2.sh marc21.xsl test_http.xml test_http.cfg \
+EXTRA_DIST = run_pazpar2.sh marc21.xsl z3950_indexdata_com_marc.xml \
+       z3950_indexdata_com_gils.xml test_http.cfg \
+       gils_service.xml marc_service.xml \
        test_http_urls test_icu.cfg test_icu_urls $(check_SCRIPTS)
 
 TESTS = $(check_SCRIPTS)
diff --git a/test/gils_service.xml b/test/gils_service.xml
new file mode 100644 (file)
index 0000000..879b202
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+    <service id="gils">
+      <settings src="z3950_indexdata_com_gils.xml"/>
+      <metadata name="url" merge="unique"/>
+      <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
+      <metadata name="title-remainder" brief="yes" merge="longest" rank="5"/>
+      <metadata name="isbn"/>
+      <metadata name="date" brief="yes" sortkey="numeric" type="year" merge="range"
+               termlist="yes"/>
+      <metadata name="author" brief="yes" termlist="yes" merge="longest" rank="2"/>
+      <metadata name="subject" merge="unique" termlist="yes" rank="3"/>
+      <metadata name="id"/>
+    </service>
diff --git a/test/marc_service.xml b/test/marc_service.xml
new file mode 100644 (file)
index 0000000..d0e9266
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+    <service id="marc">
+      <settings src="z3950_indexdata_com_marc.xml"/>
+      <metadata name="url" merge="unique"/>
+      <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
+      <metadata name="title-remainder" brief="yes" merge="longest" rank="5"/>
+      <metadata name="isbn"/>
+      <metadata name="date" brief="yes" sortkey="numeric" type="year" merge="range"
+               termlist="yes"/>
+      <metadata name="author" brief="yes" termlist="yes" merge="longest" rank="2"/>
+      <metadata name="subject" merge="unique" termlist="yes" rank="3"/>
+      <metadata name="id"/>
+    </service>
index 712282f..5b0c9b0 100755 (executable)
@@ -32,9 +32,9 @@ CFG=${PREFIX}.cfg
 URLS=${PREFIX}_urls
 
 if test "$usevalgrind"; then
-    valgrind --log-file=valgrind ../src/pazpar2 -X -l pazpar2.log -f ${CFG} -t ${srcdir}/test_http.xml >extra_pazpar2.log 2>&1 &
+    valgrind --log-file=valgrind ../src/pazpar2 -X -l pazpar2.log -f ${CFG} >extra_pazpar2.log 2>&1 &
 else
-    YAZ_LOG=zoom,zoomdetails,debug,log,fatal ../src/pazpar2 -d -X -l pazpar2.log -f ${srcdir}/${CFG} -t ${srcdir}/test_http.xml >extra_pazpar2.log 2>&1 &
+    YAZ_LOG=zoom,zoomdetails,debug,log,fatal ../src/pazpar2 -d -X -l pazpar2.log -f ${srcdir}/${CFG} >extra_pazpar2.log 2>&1 &
 fi
 
 
index 23de8a9..271efe9 100644 (file)
@@ -6,6 +6,8 @@
     <proxy host="localhost"/>
     
     <service>
+      <include src="z3950_indexdata_com_marc.xml"/>
+      <targetprofiles type="local" src="../zeerex/records/"/>
       <metadata name="url" merge="unique"/>
       <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
       <metadata name="title-remainder" brief="yes" merge="longest" rank="5"/>
       <metadata name="test" setting="parameter"/>
       <metadata name="test-usersetting-2" brief="yes"/>
     </service>
+
+    <include src="*_service.xml"/> 
+    <include src="no_such_service.xml"/>
+
   </server>
   
-  <targetprofiles type="local" src="../zeerex/records/"/>
   
 </pazpar2>
 <!-- Keep this comment at the end of the file
diff --git a/test/test_http.xml b/test/test_http.xml
deleted file mode 100644 (file)
index b713b3b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<settings target="z3950.indexdata.com/marc">
-
-  <!-- Used by test test_http.sh -->
-
-  <set name="pz:name" value="Local Test"/>
-
-  <!-- mapping for unqualified search -->
-  <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/>
-
-  <!-- field-specific mappings -->
-  <set name="pz:cclmap:ti" value="u=4 s=al"/>
-  <set name="pz:cclmap:su" value="u=21 s=al"/>
-  <set name="pz:cclmap:isbn" value="u=7"/>
-  <set name="pz:cclmap:issn" value="u=8"/>
-  <set name="pz:cclmap:date" value="u=30 r=r"/>
-
-  <!-- Retrieval settings -->
-
-  <set name="pz:requestsyntax" value="marc21"/>
-  <!-- <set name="pz:elements" value="F"/> NOT YET IMPLEMENTED -->
-
-  <!-- Result normalization settings -->
-
-  <set name="pz:nativesyntax" value="iso2709"/>
-  <set name="pz:xslt" value="auto"/>
-  
-  <set name="pz:apdulog" value="1"/>
-
-  <!-- Examples of application-specific setting -->
-  <!-- Available in output record and/or normalization stylesheet -->
-  <set name="test-usersetting" value="XXXXXXXXXX"/>
-  <set name="test" value="YYYYYYYYY"/>
-
-</settings>
diff --git a/test/test_http_26.res b/test/test_http_26.res
new file mode 100644 (file)
index 0000000..c610a3b
--- /dev/null
@@ -0,0 +1 @@
+<init><status>OK</status><session>3</session><protocol>1</protocol></init>
\ No newline at end of file
diff --git a/test/test_http_27.res b/test/test_http_27.res
new file mode 100644 (file)
index 0000000..d2e0e58
--- /dev/null
@@ -0,0 +1 @@
+<search><status>OK</status></search>
\ No newline at end of file
diff --git a/test/test_http_28.res b/test/test_http_28.res
new file mode 100644 (file)
index 0000000..4bb0e38
--- /dev/null
@@ -0,0 +1,194 @@
+<show>
+<status>OK</status>
+<activeclients>0</activeclients>
+<merged>17</merged>
+<total>17</total>
+<start>0</start>
+<num>17</num>
+<hit>
+
+<md-title>UTAH GEOLOGICAL ASSOCIATION PUBLICATIONS</md-title>
+<md-description>Guidebooks and field logs of selected Utah sites comprise this data set</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH GEOLOGICAL ASSOCIATION PUBLICATIONS</md-title>
+<md-description>Guidebooks and field logs of selected Utah sites comprise this data set</md-description>
+<md-description>1970-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah geological association publications author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH GEOLOGICAL SOCIETY PUBLICATIONS</md-title>
+<md-description>Guidebooks and field logs of selected areas in Utah and neighboring states comprise this data set</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH GEOLOGICAL SOCIETY PUBLICATIONS</md-title>
+<md-description>Guidebooks and field logs of selected areas in Utah and neighboring states comprise this data set</md-description>
+<md-description>1946-1970</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah geological society publications author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH GEOCHROMOMETRY</md-title>
+<md-description>Utah radiometric dates, formations, investigations, constants, references comprise this data set.  Searches by formation, age, location, constants, methodology, and rock type will be possible</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH GEOCHROMOMETRY</md-title>
+<md-description>Utah radiometric dates, formations, investigations, constants, references comprise this data set.  Searches by formation, age, location, constants, methodology, and rock type will be possible</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah geochromometry author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH CRIB FILE</md-title>
+<md-description>CRIB-UTAH is a data base covering mineral occurrences in Utah, including metals, non-metals, and fuels.  Each mineral occurrence is plotted on topographic maps and described in a six page report</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH CRIB FILE</md-title>
+<md-description>CRIB-UTAH is a data base covering mineral occurrences in Utah, including metals, non-metals, and fuels.  Each mineral occurrence is plotted on topographic maps and described in a six page report</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah crib file author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH GEOLOGICAL AND MINERAL SURVEY PUBLICATIONS</md-title>
+<md-description>Publications of the Utah Geological and Mineral Survey include reports of investigation, special studies, bulletins, open-file reports, geologic map of Utah, publications of geological societies, geologic and oil and mineral maps, coal monographs, circulars, water resource bulletins, and reprints of articles</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH GEOLOGICAL AND MINERAL SURVEY PUBLICATIONS</md-title>
+<md-description>Publications of the Utah Geological and Mineral Survey include reports of investigation, special studies, bulletins, open-file reports, geologic map of Utah, publications of geological societies, geologic and oil and mineral maps, coal monographs, circulars, water resource bulletins, and reprints of articles</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah geological and mineral survey publications author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH OIL FIELD FILE</md-title>
+<md-description>Complete Utah oil field data including geology, production, recovery methods, structure maps, index map of wells within field, type section logs, operations, field history, bibliography, references, reservoir data, and completion practices comprise this data set</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH OIL FIELD FILE</md-title>
+<md-description>Complete Utah oil field data including geology, production, recovery methods, structure maps, index map of wells within field, type section logs, operations, field history, bibliography, references, reservoir data, and completion practices comprise this data set</md-description>
+<md-description>1900-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah oil field file author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH GEOLOGIC MAP BIBLIOGRAPHY</md-title>
+<md-description>This collection consists of theses, dissertations, and other unpublished maps as well as published maps of the geology of Utah.  Some maps of the collection are xeroxed from limited collections.  Cross-sections are included in set.  Data file consists of map bibliography</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH GEOLOGIC MAP BIBLIOGRAPHY</md-title>
+<md-description>This collection consists of theses, dissertations, and other unpublished maps as well as published maps of the geology of Utah.  Some maps of the collection are xeroxed from limited collections.  Cross-sections are included in set.  Data file consists of map bibliography</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah geologic map bibliography author medium book</recid>
+</hit>
+<hit>
+
+<md-title>BIBLIOGRAPHY OF UTAH GEOLOGY</md-title>
+<md-description>Keyworded compilation of 11,300 bibliographic entries consisting of commodities, applied geology, investigation procedures and stratigraphic units related to Utah comprise this data set.  Entries are searchable by state, county, quadrangle, as well as keywords.  Entries include theses and dissertations referenced in GEOREF to 1980</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>BIBLIOGRAPHY OF UTAH GEOLOGY</md-title>
+<md-description>Keyworded compilation of 11,300 bibliographic entries consisting of commodities, applied geology, investigation procedures and stratigraphic units related to Utah comprise this data set.  Entries are searchable by state, county, quadrangle, as well as keywords.  Entries include theses and dissertations referenced in GEOREF to 1980</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title bibliography of utah geology author medium book</recid>
+</hit>
+<hit>
+
+<md-title>MEASURED GEOLOGIC SECTIONS</md-title>
+<md-description>Selected geologic sections and references to geologic sections concerning Utah geology comprise this data set.  Formation, lithologic description, fossils, thickness, location of section, and Utah type sections are included in this data set</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>MEASURED GEOLOGIC SECTIONS</md-title>
+<md-description>Selected geologic sections and references to geologic sections concerning Utah geology comprise this data set.  Formation, lithologic description, fossils, thickness, location of section, and Utah type sections are included in this data set</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title measured geologic sections author medium book</recid>
+</hit>
+<hit>
+
+<md-title>UTAH EARTHQUAKE EPICENTERS</md-title>
+<md-description>Five files of epicenter data arranged by date comprise this data set.  These files are searchable by magnitude and longitude/latitude.  Hardcopy of listing and plot of requested area available.  Epicenter location and date, magnitude, and focal depth available</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>UTAH EARTHQUAKE EPICENTERS</md-title>
+<md-description>Five files of epicenter data arranged by date comprise this data set.  These files are searchable by magnitude and longitude/latitude.  Hardcopy of listing and plot of requested area available.  Epicenter location and date, magnitude, and focal depth available</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title utah earthquake epicenters author medium book</recid>
+</hit>
+<hit>
+
+<md-title>COAL SAMPLE BANK</md-title>
+<md-description>This data set contains methane data, chemical analysis data, and petrographic analysis data on core samples in Utah</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>COAL SAMPLE BANK</md-title>
+<md-description>This data set contains methane data, chemical analysis data, and petrographic analysis data on core samples in Utah</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title coal sample bank author medium book</recid>
+</hit>
+<hit>
+
+<md-title>INTERMOUNTAIN ASSOCIATION OF PETROLEUM GEOLOGISTS/GEOLOGISTS PUBLICATIONS</md-title>
+<md-description>Guidebooks and field trip logs covering intermountain states: Utah, New Mexico, Colorado, Wyoming, Montana, Nevada, Idaho, Arizona comprise this data set</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>INTERMOUNTAIN ASSOCIATION OF PETROLEUM GEOLOGISTS/GEOLOGISTS PUBLICATIONS</md-title>
+<md-description>Guidebooks and field trip logs covering intermountain states: Utah, New Mexico, Colorado, Wyoming, Montana, Nevada, Idaho, Arizona comprise this data set</md-description>
+<md-description>1950-1970</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title intermountain association of petroleum geologists geologists publications author medium book</recid>
+</hit>
+<hit>
+
+<md-title>ELECTRIC LOG LIBRARY</md-title>
+<md-description>Logs for selected petroleum wells include electric (all varieties) and lithologic or hydrocarbon logs.  Duplicates from OG&amp;M well records file, supplied by private concerns.  The areal coverage is Utah and vicinity</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>ELECTRIC LOG LIBRARY</md-title>
+<md-description>Logs for selected petroleum wells include electric (all varieties) and lithologic or hydrocarbon logs.  Duplicates from OG&amp;M well records file, supplied by private concerns.  The areal coverage is Utah and vicinity</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title electric log library author medium book</recid>
+</hit>
+<hit>
+
+<md-title>APPLIED GEOLOGY FILE</md-title>
+<md-description>Reports and memorandums completed by the Site Investigation Section comprise this data set.  Subjects include geotechnical appraisal of public facility sites before and during construction and evaluations of hazardous waste problems</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>APPLIED GEOLOGY FILE</md-title>
+<md-description>Reports and memorandums completed by the Site Investigation Section comprise this data set.  Subjects include geotechnical appraisal of public facility sites before and during construction and evaluations of hazardous waste problems</md-description>
+<md-description>1970-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title applied geology file author medium book</recid>
+</hit>
+<hit>
+
+<md-title>MINE MAP INDEX</md-title>
+<md-description>Mine Map Index is an index of mine maps located in the UGMS energy section.  All maps are rescaled by hand to 1:24,000.  Maps show areal extent of mine and coal seams.  Maps are used for production, control, and resource calculations</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>MINE MAP INDEX</md-title>
+<md-description>Mine Map Index is an index of mine maps located in the UGMS energy section.  All maps are rescaled by hand to 1:24,000.  Maps show areal extent of mine and coal seams.  Maps are used for production, control, and resource calculations</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title mine map index author medium book</recid>
+</hit>
+<hit>
+
+<md-title>WELL SAMPLE LIBRARY</md-title>
+<md-description>Petroleum, mining, geothermal, and stratigraphic samples, including cores, core chips and drill cuttings comprise this data set.  This does not include logs or description.  These data are supplied by outside agencies and private organizations</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>WELL SAMPLE LIBRARY</md-title>
+<md-description>Petroleum, mining, geothermal, and stratigraphic samples, including cores, core chips and drill cuttings comprise this data set.  This does not include logs or description.  These data are supplied by outside agencies and private organizations</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title well sample library author medium book</recid>
+</hit>
+<hit>
+
+<md-title>OIL IMPREGNATED ROCK DEPOSITS</md-title>
+<md-description>High viscosity, low volatile content, hydrocarbon deposits which are developed using unconventional petroleum methods comprise this data set.  Deposits include tar sands, limestones, basalts but not shales or solid hydrocarbons.  This file includes outcrop maps, field notes, references, logs, stratigraphy, geologic report, and production from outside or in-house sources</md-description><location id="z3950.indexdata.com/gils" name="gils">
+<md-title>OIL IMPREGNATED ROCK DEPOSITS</md-title>
+<md-description>High viscosity, low volatile content, hydrocarbon deposits which are developed using unconventional petroleum methods comprise this data set.  Deposits include tar sands, limestones, basalts but not shales or solid hydrocarbons.  This file includes outcrop maps, field notes, references, logs, stratigraphy, geologic report, and production from outside or in-house sources</md-description>
+<md-description>-PRESENT</md-description>
+<md-test-usersetting-2>test-usersetting-2 data: 
+</md-test-usersetting-2></location>
+<recid>title oil impregnated rock deposits author medium book</recid>
+</hit>
+</show>
index d91243c..1361d16 100644 (file)
@@ -27,3 +27,7 @@ http://localhost:9763/search.pz2?session=1&command=search&query=computer
 http://localhost:9763/search.pz2?session=1&command=record&id=title+how+to+program+a+computer+author+jack+collins+medium+book
 http://localhost:9763/search.pz2?session=1&command=record&id=title+how+to+program+a+computer+author+jack+collins+medium+book&offset=0&binary=1
 http://localhost:9763/search.pz2?session=1&command=record&id=title+how+to+program+a+computer+author+jack+collins+medium+book&offset=0&binary=1&syntax=xml
+http://localhost:9763/search.pz2?command=init&service=gils
+http://localhost:9763/search.pz2?session=2&command=search&query=utah
+2
+http://localhost:9763/search.pz2?session=2&command=show&start=0&number=1&block=1
index b569ddf..f3bd2e5 100644 (file)
@@ -4,6 +4,7 @@
   <server>
     <listen port="9763"/>
     <proxy host="localhost"/>
+    <settings src="z3950_indexdata_com_marc.xml"/>
     
     <relevance>
       <icu_chain id="relevance" locale="el">
@@ -30,6 +31,7 @@
     </mergekey>
     
     <service>
+
       <metadata name="url" merge="unique"/>
       <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
       <metadata name="title-remainder" brief="yes" merge="longest" rank="5"/>
@@ -48,8 +50,6 @@
     </service>
   </server>
   
-  <targetprofiles type="local" src="../zeerex/records/"/>
-  
 </pazpar2>
 <!-- Keep this comment at the end of the file
      Local variables:
diff --git a/test/z3950_indexdata_com_gils.xml b/test/z3950_indexdata_com_gils.xml
new file mode 100644 (file)
index 0000000..462efc3
--- /dev/null
@@ -0,0 +1,29 @@
+<settings target="z3950.indexdata.com/gils">
+
+  <!-- Used by test test_http.sh -->
+
+  <set name="pz:name" value="Local Test"/>
+
+  <!-- mapping for unqualified search -->
+  <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/>
+
+  <!-- field-specific mappings -->
+  <set name="pz:cclmap:ti" value="u=4 s=al"/>
+  <set name="pz:cclmap:su" value="u=21 s=al"/>
+  <set name="pz:cclmap:isbn" value="u=7"/>
+  <set name="pz:cclmap:issn" value="u=8"/>
+  <set name="pz:cclmap:date" value="u=30 r=r"/>
+
+  <!-- Retrieval settings -->
+
+  <set name="pz:requestsyntax" value="marc21"/>
+  <!-- <set name="pz:elements" value="F"/> NOT YET IMPLEMENTED -->
+
+  <!-- Result normalization settings -->
+
+  <set name="pz:nativesyntax" value="iso2709"/>
+  <set name="pz:xslt" value="auto"/>
+  
+  <set name="pz:apdulog" value="1"/>
+
+</settings>
diff --git a/test/z3950_indexdata_com_marc.xml b/test/z3950_indexdata_com_marc.xml
new file mode 100644 (file)
index 0000000..b713b3b
--- /dev/null
@@ -0,0 +1,34 @@
+<settings target="z3950.indexdata.com/marc">
+
+  <!-- Used by test test_http.sh -->
+
+  <set name="pz:name" value="Local Test"/>
+
+  <!-- mapping for unqualified search -->
+  <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/>
+
+  <!-- field-specific mappings -->
+  <set name="pz:cclmap:ti" value="u=4 s=al"/>
+  <set name="pz:cclmap:su" value="u=21 s=al"/>
+  <set name="pz:cclmap:isbn" value="u=7"/>
+  <set name="pz:cclmap:issn" value="u=8"/>
+  <set name="pz:cclmap:date" value="u=30 r=r"/>
+
+  <!-- Retrieval settings -->
+
+  <set name="pz:requestsyntax" value="marc21"/>
+  <!-- <set name="pz:elements" value="F"/> NOT YET IMPLEMENTED -->
+
+  <!-- Result normalization settings -->
+
+  <set name="pz:nativesyntax" value="iso2709"/>
+  <set name="pz:xslt" value="auto"/>
+  
+  <set name="pz:apdulog" value="1"/>
+
+  <!-- Examples of application-specific setting -->
+  <!-- Available in output record and/or normalization stylesheet -->
+  <set name="test-usersetting" value="XXXXXXXXXX"/>
+  <set name="test" value="YYYYYYYYY"/>
+
+</settings>
index 9a35e1c..551397e 100644 (file)
@@ -4,7 +4,7 @@
 DEBUG=0   # 0 for release, 1 for debug
 USE_MANIFEST = 0 # Can be enabled Visual Studio 2005/2008
 PACKAGE_NAME=pazpar2
-PACKAGE_VERSION=1.1.1
+PACKAGE_VERSION=1.2.0
 
 # YAZ
 YAZ_DIR=..\..\yaz