X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Flogic.c;h=697da4d50ef95859c8a50121d653ed5a2f5df9fe;hb=8cea11ee29fe71f11f61d1d05295b4e4290f6a98;hp=96a13ed4d4c6d852ffb247e5fb9885da58533ecb;hpb=b485fddaff33e8aa6ee0e8f8c8673a1ef8f786b3;p=pazpar2-moved-to-github.git diff --git a/src/logic.c b/src/logic.c index 96a13ed..697da4d 100644 --- a/src/logic.c +++ b/src/logic.c @@ -1,5 +1,5 @@ /* This file is part of Pazpar2. - Copyright (C) 2006-2008 Index Data + 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 @@ -57,7 +57,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #endif - +#include "parameters.h" #include "pazpar2.h" #include "eventl.h" #include "http.h" @@ -68,6 +68,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "client.h" #include "settings.h" #include "normalize7bit.h" +#include "marcmap.h" #define TERMLIST_HIGH_SCORE 25 @@ -76,23 +77,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Note: Some things in this structure will eventually move to configuration struct parameters global_parameters = { - "", - "", - "", - 0, 0, // dump_records 0, // debug_mode - 30, // operations timeout - "81", - "Index Data PazPar2", - VERSION, - 60, // session timeout 100, - MAX_CHUNK, - 0, - 0, - 180, // Z39.50 session timeout - 15 // Connect timeout }; static void log_xml_doc(xmlDoc *doc) @@ -196,7 +183,7 @@ xmlDoc *record_to_xml(struct session_database *sdb, const char *rec) static void insert_settings_parameters(struct session_database *sdb, struct session *se, char **parms) { - struct conf_service *service = global_parameters.server->service; + struct conf_service *service = se->service; int i; int nparms = 0; int offset = 0; @@ -207,7 +194,7 @@ static void insert_settings_parameters(struct session_database *sdb, int setting; if (md->setting == Metadata_setting_parameter && - (setting = settings_offset(md->name)) > 0) + (setting = settings_offset(service, md->name)) > 0) { const char *val = session_setting_oneval(sdb, setting); if (val && nparms < MAX_XSLT_ARGS) @@ -229,9 +216,9 @@ static void insert_settings_parameters(struct session_database *sdb, } // Add static values from session database settings if applicable -static void insert_settings_values(struct session_database *sdb, xmlDoc *doc) +static void insert_settings_values(struct session_database *sdb, xmlDoc *doc, + struct conf_service *service) { - struct conf_service *service = global_parameters.server->service; int i; for (i = 0; i < service->num_metadata; i++) @@ -240,7 +227,7 @@ static void insert_settings_values(struct session_database *sdb, xmlDoc *doc) int offset; if (md->setting == Metadata_setting_postproc && - (offset = settings_offset(md->name)) > 0) + (offset = settings_offset(service, md->name)) > 0) { const char *val = session_setting_oneval(sdb, offset); if (val) @@ -271,8 +258,17 @@ xmlDoc *normalize_record(struct session_database *sdb, struct session *se, 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", @@ -287,7 +283,7 @@ xmlDoc *normalize_record(struct session_database *sdb, struct session *se, rdoc = new; } - insert_settings_values(sdb, rdoc); + insert_settings_values(sdb, rdoc, se->service); if (global_parameters.dump_records) { @@ -354,14 +350,37 @@ static int prepare_map(struct session *se, struct session_database *sdb) nmem_strsplit(se->session_nmem, ",", s, &stylesheets, &num); for (i = 0; i < num; i++) { + WRBUF fname = conf_get_fname(se->service, stylesheets[i]); + (*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 = + xsltParseStylesheetFile((xmlChar *) wrbuf_cstr(fname)))) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load stylesheet: %s", + stylesheets[i]); + wrbuf_destroy(fname); + 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(wrbuf_cstr(fname), se->session_nmem))) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Unable to load marcmap: %s", + stylesheets[i]); + wrbuf_destroy(fname); + return -1; + } } + wrbuf_destroy(fname); m = &(*m)->next; } } @@ -486,10 +505,14 @@ static struct database_criterion *parse_filter(NMEM m, const char *buf) int subnum; int subi; struct database_criterion *new = nmem_malloc(m, sizeof(*new)); - char *eq = strchr(values[i], '='); + char *eq; + if (eq = strchr(values[i], '=')) + new->type = PAZPAR2_STRING_MATCH; + if (eq = strchr(values[i], '~')) + new->type = PAZPAR2_SUBSTRING_MATCH; if (!eq) { - yaz_log(YLOG_WARN, "Missing equal-sign in filter"); + yaz_log(YLOG_WARN, "Missing equal-signi/tilde in filter"); return 0; } *(eq++) = '\0'; @@ -511,7 +534,7 @@ static struct database_criterion *parse_filter(NMEM m, const char *buf) } enum pazpar2_error_code search(struct session *se, - char *query, char *filter, + const char *query, const char *filter, const char **addinfo) { int live_channels = 0; @@ -532,7 +555,7 @@ enum pazpar2_error_code search(struct session *se, live_channels = select_targets(se, criteria); if (live_channels) { - int maxrecs = live_channels * global_parameters.toget; + int maxrecs = live_channels * global_parameters.toget; // This is buggy!!! se->reclist = reclist_create(se->nmem, maxrecs); se->expected_maxrecs = maxrecs; } @@ -552,7 +575,8 @@ enum pazpar2_error_code search(struct session *se, else { no_working++; - if (client_prep_connection(cl)) + if (client_prep_connection(cl, se->service->z3950_operation_timeout, + se->service->z3950_session_timeout)) client_start_search(cl); } } @@ -570,8 +594,9 @@ enum pazpar2_error_code search(struct session *se, static void session_init_databases_fun(void *context, struct database *db) { struct session *se = (struct session *) context; + struct conf_service *service = se->service; struct session_database *new = nmem_malloc(se->session_nmem, sizeof(*new)); - int num = settings_num(); + int num = settings_num(service); int i; new->database = db; @@ -604,7 +629,7 @@ static void session_database_destroy(struct session_database *sdb) void session_init_databases(struct session *se) { se->databases = 0; - predef_grep_databases(se, 0, session_init_databases_fun); + predef_grep_databases(se, se->service, 0, session_init_databases_fun); } // Probably session_init_databases_fun should be refactored instead of @@ -612,7 +637,9 @@ void session_init_databases(struct session *se) static struct session_database *load_session_database(struct session *se, char *id) { - struct database *db = find_database(id, 0); + struct database *db = find_database(id, 0, se->service); + + resolve_database(db); session_init_databases_fun((void*) se, db); // New sdb is head of se->databases list @@ -636,8 +663,9 @@ void session_apply_setting(struct session *se, char *dbname, char *setting, char *value) { struct session_database *sdb = find_session_database(se, dbname); + struct conf_service *service = se->service; struct setting *new = nmem_malloc(se->session_nmem, sizeof(*new)); - int offset = settings_offset_cprefix(setting); + int offset = settings_offset_cprefix(service, setting); if (offset < 0) { @@ -683,16 +711,18 @@ void destroy_session(struct session *s) 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; @@ -765,14 +795,24 @@ void report_nmem_stats(void) } #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; } @@ -864,52 +904,10 @@ void statistics(struct session *se, struct statistics *stat) stat->num_clients = count; } -int start_http_listener(void) -{ - char hp[128] = ""; - struct conf_server *ser = global_parameters.server; - - if (*global_parameters.listener_override) - strcpy(hp, global_parameters.listener_override); - else - { - strcpy(hp, ser->host ? ser->host : ""); - if (ser->port) - { - if (*hp) - strcat(hp, ":"); - sprintf(hp + strlen(hp), "%d", ser->port); - } - } - return http_init(hp); -} - -void start_proxy(void) -{ - char hp[128] = ""; - struct conf_server *ser = global_parameters.server; - - if (*global_parameters.proxy_override) - strcpy(hp, global_parameters.proxy_override); - else if (ser->proxy_host || ser->proxy_port) - { - strcpy(hp, ser->proxy_host ? ser->proxy_host : ""); - if (ser->proxy_port) - { - if (*hp) - strcat(hp, ":"); - sprintf(hp + strlen(hp), "%d", ser->proxy_port); - } - } - else - return; - - http_set_proxyaddr(hp, ser->myurl ? ser->myurl : ""); -} - // Master list of connections we're handling events to -static IOCHAN channel_list = 0; +static IOCHAN channel_list = 0; /* thread pr */ + void pazpar2_add_channel(IOCHAN chan) { chan->next = channel_list; @@ -951,68 +949,206 @@ static struct record_metadata *record_metadata_init( 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; + + /* consider mergekey from XSL first */ + 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); + } + else + { + /* no mergekey defined in XSL. Look for mergekey metadata instead */ + 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 see if metadata for pz:recordfilter exists + \param root xml root element of normalized record + \param sdb session database for client + \retval 0 if there is no metadata for pz:recordfilter + \retval 1 if there is metadata for pz:recordfilter + + If there is no pz:recordfilter defined, this function returns 1 + as well. +*/ + +static int check_record_filter(xmlNode *root, struct session_database *sdb) +{ + int match = 0; + xmlNode *n; + const char *s; + s = session_setting_oneval(sdb, PZ_RECORDFILTER); + + if (!s || !*s) + return 1; + + for (n = root->children; n; n = n->next) + { + if (n->type != XML_ELEMENT_NODE) + continue; + if (!strcmp((const char *) n->name, "metadata")) + { + xmlChar *type = xmlGetProp(n, (xmlChar *) "type"); + if (type) + { + size_t len; + const char *eq = strchr(s, '='); + if (eq) + len = eq - s; + else + len = strlen(s); + if (len == strlen((const char *)type) && + !memcmp((const char *) type, s, len)) + { + xmlChar *value = xmlNodeGetContent(n); + if (value && *value) + { + if (!eq || strstr((const char *) value, eq+1)) + match = 1; + } + xmlFree(value); + } + xmlFree(type); + } + } + } + return match; +} + + +/** \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) { - xmlDoc *xdoc = normalize_record(client_get_database(cl), - client_get_session(cl), rec); + struct session_database *sdb = client_get_database(cl); + struct session *se = client_get_session(cl); + xmlDoc *xdoc = normalize_record(sdb, se, rec); xmlNode *root, *n; 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"))) + + if (!check_record_filter(root, sdb)) { - yaz_log(YLOG_WARN, "No mergekey found in record"); + yaz_log(YLOG_WARN, "Filtered out record no %d from %s", record_no, + sdb->database->url); 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))) + mergekey_norm = get_mergekey(xdoc, cl, record_no, service, se->nmem); + if (!mergekey_norm) { - if (*norm_str) - { - if (wrbuf_len(norm_wr)) - wrbuf_puts(norm_wr, " "); - wrbuf_puts(norm_wr, norm_str); - } + yaz_log(YLOG_WARN, "Got no mergekey"); + xmlFreeDoc(xdoc); + return 0; } - - mergekey_norm = (xmlChar *)nmem_strdup(se->nmem, wrbuf_cstr(norm_wr)); - wrbuf_destroy(norm_wr); - - pp2_relevance_token_destroy(prt); + record = record_create(se->nmem, + service->num_metadata, service->num_sortkeys, cl, + record_no); - xmlFree(mergekey); - cluster = reclist_insert(se->reclist, - global_parameters.server->service, + service, record, (char *) mergekey_norm, &se->total_merged); if (global_parameters.dump_records) yaz_log(YLOG_LOG, "Cluster id %s from %s (#%d)", cluster->recid, - client_get_database(cl)->database->url, record_no); + sdb->database->url, record_no); if (!cluster) { /* no room for record */ @@ -1021,10 +1157,10 @@ struct record *ingest_record(struct client *cl, const char *rec, } 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) @@ -1121,7 +1257,7 @@ struct record *ingest_record(struct client *cl, const char *rec, sizeof(union data_types)); prt = pp2_relevance_tokenize( - global_parameters.server->sort_pct, + service->sort_pct, rec_md->data.text.disp); pp2_relevance_token_next(prt); @@ -1228,7 +1364,9 @@ struct record *ingest_record(struct client *cl, const char *rec, /* * Local variables: * c-basic-offset: 4 + * c-file-style: "Stroustrup" * indent-tabs-mode: nil * End: * vim: shiftwidth=4 tabstop=8 expandtab */ +