done; \
done; exit 0
+.PHONY:debian
+debian:
+ dpkg-buildpackage -rfakeroot
+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
# 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)
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
+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.
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:
<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>
<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>
<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>
</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>
<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"/>
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;
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
"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]
.childNodes[0].nodeValue ),
"error":
Number( data.getElementsByTagName("error")[0]
- .childNodes[0].nodeValue ),
- "progress":
- Number( data.getElementsByTagName("progress")[0]
.childNodes[0].nodeValue )
};
recordParams,
function(data) {
var recordNode;
- var record;
+ var record;
//raw record
if (context.currRecOffset !== null) {
record = new Array();
//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
yaz
pazpar2
-icu_chain_test
Makefile
Makefile.in
config.h
*.a
*~
stamp-h1
-test_config
-test_icu_I18N
-test_record
test_sel_thread
test_normalize
sbin_PROGRAMS = pazpar2
-check_PROGRAMS = test_config \
- test_record \
+check_PROGRAMS = \
test_sel_thread \
test_normalize
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 \
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)
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;
#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)
{
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)
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,
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);
"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)
{
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);
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);
}
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;
}
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);
}
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);
#include "settings.h"
#include "http.h"
#include "zeerex.h"
+#include "database.h"
#include <sys/types.h>
#if HAVE_SYS_SOCKET_H
#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))
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;
}
*(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
}
// 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)
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;
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++;
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++;
#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
#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;
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)
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))
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;
}
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
{
&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())
{
// 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);
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);
}
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;
r->nmem = nmem_create();
r->wrbuf = wrbuf_alloc();
}
+ r->server = server;
r->proxy = 0;
r->iochan = 0;
r->iqueue = r->oqueue = 0;
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)
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;
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);
}
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)
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
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);
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
/*
#include "eventl.h"
#include "pazpar2.h"
#include "http.h"
-#include "http_command.h"
#include "settings.h"
#include "client.h"
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)
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;
unsigned int make_sessionid(void)
{
- static int seq = 0;
+ static int seq = 0; /* thread pr */
unsigned int res;
seq++;
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)
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)
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);
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;
while (*name)
{
char tname[256];
- char *tp;
+ const char *tp;
if (!(tp = strchr(name, ',')))
tp = name + strlen(name);
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");
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);
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;
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;
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);
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)
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;
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;
+++ /dev/null
-/* 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
// 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
};
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;
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)
}
// 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++)
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)
rdoc = new;
}
- insert_settings_values(sdb, rdoc);
+ insert_settings_values(sdb, rdoc, se->service);
if (global_parameters.dump_records)
{
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]);
}
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;
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;
}
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;
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
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
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)
{
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;
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;
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);
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)))
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)))
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;
record_no);
cluster = reclist_insert(se->reclist,
- global_parameters.server->service,
+ service,
record, (char *) mergekey_norm,
&se->total_merged);
if (global_parameters.dump_records)
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);
/** \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;
};
#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)
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)
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)
{
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);
pidfile = arg;
break;
case 't':
- strcpy(global_parameters.settings_path_override, arg);
+ test_mode = 1;
break;
case 'T':
session_timeout = atoi(arg);
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)
// 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
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,
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);
#endif
#include <string.h>
+#include <assert.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#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);
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)
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,
|| 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)
//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;
}
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;
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)
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");
}
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++;
// 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,
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
{
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));
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)
{
}
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"))
}
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
{
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");
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)
{
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
'\\'
)))
{
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:
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,
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);
int conf_service_sortkey_field_id(struct conf_service *service, const char * name);
-
struct conf_server
{
char *host;
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;
};
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
#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
{
#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;
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];
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);
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
#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)
#include <string.h>
+#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include "direntz.h"
#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",
"pz:sru",
"pz:sru_version",
"pz:pqf_prefix",
+ "pz:sort",
0
};
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;
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)
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");
strcpy(valueb, (const char *) valuea);
set.value = valueb;
set.next = 0;
- (*fun)(&set);
+ (*fun)(service, &set);
}
xmlFree(name);
xmlFree(precedence);
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;
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
// 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';
// 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;
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.
}
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;
}
// 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;
// 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++)
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);
}
/*
#define PZ_SRU 15
#define PZ_SRU_VERSION 16
#define PZ_PQF_PREFIX 17
+#define PZ_SORT 18
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
+++ /dev/null
-/* 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
- */
-
+++ /dev/null
-/* 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
- */
-
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)
{
# 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)
--- /dev/null
+<?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>
--- /dev/null
+<?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>
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
<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
+++ /dev/null
-<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>
--- /dev/null
+<init><status>OK</status><session>3</session><protocol>1</protocol></init>
\ No newline at end of file
--- /dev/null
+<search><status>OK</status></search>
\ No newline at end of file
--- /dev/null
+<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&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&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>
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
<server>
<listen port="9763"/>
<proxy host="localhost"/>
+ <settings src="z3950_indexdata_com_marc.xml"/>
<relevance>
<icu_chain id="relevance" locale="el">
</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"/>
</service>
</server>
- <targetprofiles type="local" src="../zeerex/records/"/>
-
</pazpar2>
<!-- Keep this comment at the end of the file
Local variables:
--- /dev/null
+<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>
--- /dev/null
+<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>
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