#include <yaz/timing.h>
#endif
-
+#include "parameters.h"
#include "pazpar2.h"
#include "eventl.h"
#include "http.h"
#include "client.h"
#include "settings.h"
#include "normalize7bit.h"
+#include "marcmap.h"
#define TERMLIST_HIGH_SCORE 25
// 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 log_xml_doc(xmlDoc *doc)
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)
insert_settings_parameters(sdb, se, parms);
- new = xsltApplyStylesheet(m->stylesheet, rdoc, (const char **) parms);
- root= xmlDocGetRootElement(new);
+ if (m->stylesheet)
+ {
+ new = xsltApplyStylesheet(m->stylesheet, rdoc, (const char **) parms);
+ }
+ else if (m->marcmap)
+ {
+ new = marcmap_apply(m->marcmap, rdoc);
+ }
+
+ root = xmlDocGetRootElement(new);
+
if (!new || !root || !(root->children))
{
yaz_log(YLOG_WARN, "XSLT transformation failed from %s",
rdoc = new;
}
- insert_settings_values(sdb, rdoc);
+ insert_settings_values(sdb, rdoc, se->service);
if (global_parameters.dump_records)
{
{
(*m) = nmem_malloc(se->session_nmem, sizeof(**m));
(*m)->next = 0;
- if (!((*m)->stylesheet = conf_load_stylesheet(stylesheets[i])))
+
+ // XSLT
+ if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-4], ".xsl"))
+ {
+ (*m)->marcmap = NULL;
+ if (!((*m)->stylesheet = conf_load_stylesheet(se->service, stylesheets[i])))
+ {
+ yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load stylesheet: %s",
+ stylesheets[i]);
+ return -1;
+ }
+ }
+ // marcmap
+ else if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-5], ".mmap"))
{
- yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load stylesheet: %s",
- stylesheets[i]);
- return -1;
+ (*m)->stylesheet = NULL;
+ if (!((*m)->marcmap = marcmap_load(stylesheets[i], se->session_nmem)))
+ {
+ yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load marcmap: %s",
+ stylesheets[i]);
+ return -1;
+ }
}
+
m = &(*m)->next;
}
}
}
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;
}
else
{
no_working++;
- if (client_prep_connection(cl))
+ if (client_prep_connection(cl, se->service->z3950_connect_timeout,
+ se->service->z3950_session_timeout))
client_start_search(cl);
}
}
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)
{
for (sdb = s->databases; sdb; sdb = sdb->next)
session_database_destroy(sdb);
nmem_destroy(s->nmem);
+ service_destroy(s->service);
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;
}
#endif
-struct record_cluster *show_single(struct session *s, const char *id)
+struct record_cluster *show_single(struct session *s, const char *id,
+ struct record_cluster **prev_r,
+ struct record_cluster **next_r)
{
struct record_cluster *r;
reclist_rewind(s->reclist);
+ *prev_r = 0;
+ *next_r = 0;
while ((r = reclist_read_record(s->reclist)))
+ {
if (!strcmp(r->recid, id))
+ {
+ *next_r = reclist_read_record(s->reclist);
return r;
+ }
+ *prev_r = r;
+ }
return 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;
}
+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);
+ WRBUF norm_wr = wrbuf_alloc();
+ xmlNode *n;
+
+ /* create mergekey based on mergekey attribute from XSL (if any) */
+ xmlChar *mergekey = xmlGetProp(root, (xmlChar *) "mergekey");
+ if (mergekey)
+ {
+ const char *norm_str;
+ pp2_relevance_token_t prt =
+ pp2_relevance_tokenize(
+ service->mergekey_pct,
+ (const char *) mergekey);
+
+ while ((norm_str = pp2_relevance_token_next(prt)))
+ {
+ if (*norm_str)
+ {
+ if (wrbuf_len(norm_wr))
+ wrbuf_puts(norm_wr, " ");
+ wrbuf_puts(norm_wr, norm_str);
+ }
+ }
+ pp2_relevance_token_destroy(prt);
+ xmlFree(mergekey);
+ }
+ /* append (if any) mergekey=yes metadata values */
+ for (n = root->children; n; n = n->next)
+ {
+ if (n->type != XML_ELEMENT_NODE)
+ continue;
+ if (!strcmp((const char *) n->name, "metadata"))
+ {
+ struct conf_metadata *ser_md = 0;
+ int md_field_id = -1;
+
+ xmlChar *type = xmlGetProp(n, (xmlChar *) "type");
+
+ if (!type)
+ continue;
+
+ md_field_id
+ = conf_service_metadata_field_id(service,
+ (const char *) type);
+ if (md_field_id >= 0)
+ {
+ ser_md = &service->metadata[md_field_id];
+ if (ser_md->mergekey == Metadata_mergekey_yes)
+ {
+ xmlChar *value = xmlNodeListGetString(doc, n->children, 1);
+ if (value)
+ {
+ const char *norm_str;
+ pp2_relevance_token_t prt =
+ pp2_relevance_tokenize(
+ service->mergekey_pct,
+ (const char *) value);
+
+ while ((norm_str = pp2_relevance_token_next(prt)))
+ {
+ if (*norm_str)
+ {
+ if (wrbuf_len(norm_wr))
+ wrbuf_puts(norm_wr, " ");
+ wrbuf_puts(norm_wr, norm_str);
+ }
+ }
+ xmlFree(value);
+ pp2_relevance_token_destroy(prt);
+ }
+ }
+ }
+ xmlFree(type);
+ }
+ }
+
+ /* generate unique key if none is not generated already or is empty */
+ if (wrbuf_len(norm_wr) == 0)
+ {
+ wrbuf_printf(norm_wr, "%s-%d",
+ client_get_database(cl)->database->url, record_no);
+ }
+ if (wrbuf_len(norm_wr) > 0)
+ mergekey_norm = nmem_strdup(nmem, wrbuf_cstr(norm_wr));
+ wrbuf_destroy(norm_wr);
+ return mergekey_norm;
+}
+
+
+
+/** \brief ingest XML record
+ \param cl client holds the result set for record
+ \param rec record buffer (0 terminated)
+ \param record_no record position (1, 2, ..)
+ \returns resulting record or NULL on failure
+*/
struct record *ingest_record(struct client *cl, const char *rec,
int record_no)
{
struct record *record;
struct record_cluster *cluster;
struct session *se = client_get_session(cl);
- xmlChar *mergekey, *mergekey_norm;
+ const char *mergekey_norm;
xmlChar *type = 0;
xmlChar *value = 0;
- struct conf_service *service = global_parameters.server->service;
- const char *norm_str = 0;
- pp2_relevance_token_t prt = 0;
- WRBUF norm_wr = 0;
+ struct conf_service *service = se->service;
if (!xdoc)
return 0;
root = xmlDocGetRootElement(xdoc);
- if (!(mergekey = xmlGetProp(root, (xmlChar *) "mergekey")))
+
+ mergekey_norm = get_mergekey(xdoc, cl, record_no, service, se->nmem);
+ if (!mergekey_norm)
{
- yaz_log(YLOG_WARN, "No mergekey found in record");
+ yaz_log(YLOG_WARN, "Got no mergekey");
xmlFreeDoc(xdoc);
return 0;
}
-
record = record_create(se->nmem,
service->num_metadata, service->num_sortkeys, cl,
record_no);
- prt = pp2_relevance_tokenize(
- global_parameters.server->mergekey_pct, (const char *) mergekey);
-
-
- norm_wr = wrbuf_alloc();
-
- while ((norm_str = pp2_relevance_token_next(prt)))
- {
- if (*norm_str)
- {
- if (wrbuf_len(norm_wr))
- wrbuf_puts(norm_wr, " ");
- wrbuf_puts(norm_wr, norm_str);
- }
- }
-
- mergekey_norm = (xmlChar *)nmem_strdup(se->nmem, wrbuf_cstr(norm_wr));
- wrbuf_destroy(norm_wr);
-
- pp2_relevance_token_destroy(prt);
-
- xmlFree(mergekey);
-
cluster = reclist_insert(se->reclist,
- global_parameters.server->service,
+ service,
record, (char *) mergekey_norm,
&se->total_merged);
if (global_parameters.dump_records)
}
relevance_newrec(se->relevance, cluster);
-
// now parsing XML record and adding data to cluster or record metadata
for (n = root->children; n; n = n->next)
{
+ pp2_relevance_token_t prt;
if (type)
xmlFree(type);
if (value)
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);