/* * Copyright (C) 2005 Network Applied Communication Laboratory Co., Ltd. * * This file is part of Rast. * See the file COPYING for redistribution information. * */ #include #include #include #include #include #include "rast/error.h" #include "rast/rast.h" #include "rast/merger.h" #include "rast/xmlrpc_server.h" static const char * rast_error_type_t_to_str(rast_error_type_t type) { switch (type) { case RAST_ERROR_TYPE_RAST: return "rast"; case RAST_ERROR_TYPE_APR: return "apr"; case RAST_ERROR_TYPE_BDB: return "bdb"; case RAST_ERROR_TYPE_XMLRPC: return "xmlrpc"; case RAST_ERROR_TYPE_RUBY: return "ruby"; } return NULL; } static const char * rast_type_e_to_str(rast_type_e type) { switch (type) { case RAST_TYPE_STRING: return "string"; case RAST_TYPE_DATE: return "date"; case RAST_TYPE_DATETIME: return "datetime"; case RAST_TYPE_UINT: return "uint"; } return NULL; } static rast_sort_order_e str_to_rast_sort_order_e(const char *str) { if (strcmp("ascending", str) == 0) { return RAST_SORT_ORDER_ASCENDING; } if (strcmp("descending", str) == 0) { return RAST_SORT_ORDER_DESCENDING; } return RAST_SORT_ORDER_DEFAULT; } static rast_score_method_e str_to_rast_score_method_e(const char *str) { if (strcmp("tfidf", str) == 0) { return RAST_SCORE_METHOD_TFIDF; } return RAST_SCORE_METHOD_NONE; } static rast_sort_method_e str_to_rast_sort_method_e(const char *str) { if (strcmp("property", str) == 0) { return RAST_SORT_METHOD_PROPERTY; } return RAST_SORT_METHOD_SCORE; } static int get_int_option(xmlrpc_env *env, xmlrpc_value *options, char *key, int *value) { if (xmlrpc_struct_has_key(env, options, key)) { xmlrpc_int32 rpc_value; xmlrpc_parse_value(env, options, "{s:i,*}", key, &rpc_value); if (env->fault_occurred) { return 0; } *value = (int) rpc_value; } return 1; } static int get_string_option(xmlrpc_env *env, xmlrpc_value *options, char *key, const char **value) { if (xmlrpc_struct_has_key(env, options, key)) { xmlrpc_parse_value(env, options, "{s:s,*}", key, value); if (env->fault_occurred) { return 0; } } return 1; } static int get_bool_option(xmlrpc_env *env, xmlrpc_value *options, char *key, int *value) { if (xmlrpc_struct_has_key(env, options, key)) { xmlrpc_bool rpc_value; xmlrpc_parse_value(env, options, "{s:b,*}", key, &rpc_value); if (env->fault_occurred) { return 0; } *value = (int) rpc_value; } return 1; } static rast_error_t * set_terms_option(xmlrpc_env *env, xmlrpc_value *rpc_options, rast_search_option_t *options, apr_pool_t *pool) { xmlrpc_value *rpc_terms; int i; if (!xmlrpc_struct_has_key(env, rpc_options, "terms")) { return RAST_OK; } xmlrpc_parse_value(env, rpc_options, "{s:V,*}", "terms", &rpc_terms); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } options->num_terms = xmlrpc_array_size(env, rpc_terms); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } options->terms = (int *) apr_palloc(pool, sizeof(int) * options->num_terms); for (i = 0; i < options->num_terms; i++) { xmlrpc_value *rpc_term_count; xmlrpc_int32 term_count; rpc_term_count = xmlrpc_array_get_item(env, rpc_terms, i); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } xmlrpc_parse_value(env, rpc_term_count, "i", &term_count); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } options->terms[i] = (int) term_count; } return RAST_OK; } static rast_error_t * set_properties_option(xmlrpc_env *env, xmlrpc_value *rpc_options, rast_search_option_t *options, apr_pool_t *pool) { int properties_nbytes, i; xmlrpc_value *str_ary; if (!xmlrpc_struct_has_key(env, rpc_options, "properties")) { return RAST_OK; } xmlrpc_parse_value(env, rpc_options, "{s:V,*}", "properties", &str_ary); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } options->num_properties = xmlrpc_array_size(env, str_ary); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } properties_nbytes = sizeof(char *) * options->num_properties; options->properties = (const char **) apr_palloc(pool, properties_nbytes); for (i = 0; i < options->num_properties; i++) { xmlrpc_value *value; value = xmlrpc_array_get_item(env, str_ary, i); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } xmlrpc_parse_value(env, value, "s", &options->properties[i]); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } } return RAST_OK; } static rast_search_option_t * create_search_options(apr_pool_t *pool, xmlrpc_env *env, xmlrpc_value *rpc_options) { rast_search_option_t *options = rast_search_option_create(pool); rast_error_t *error; const char *option; if (!get_bool_option(env, rpc_options, "need_summary", &options->need_summary)) { return NULL; } if (!get_int_option(env, rpc_options, "summary_nchars", &options->summary_nchars)) { return NULL; } option = NULL; if (!get_string_option(env, rpc_options, "sort_order", &option)) { return NULL; } if (option != NULL) { options->sort_order = str_to_rast_sort_order_e(option); } option = NULL; if (!get_string_option(env, rpc_options, "score_method", &option)) { return NULL; } if (option != NULL) { options->score_method = str_to_rast_score_method_e(option); } option = NULL; if (!get_string_option(env, rpc_options, "sort_method", &option)) { return NULL; } if (option != NULL) { options->sort_method = str_to_rast_sort_method_e(option); } if (!get_string_option(env, rpc_options, "sort_property", &options->sort_property)) { return NULL; } if (!get_int_option(env, rpc_options, "start_no", (int *) &options->start_no)) { return NULL; } if (!get_int_option(env, rpc_options, "num_items", (int *) &options->num_items)) { return NULL; } if (!get_int_option(env, rpc_options, "all_num_docs", (int *) &options->all_num_docs)) { return NULL; } error = set_terms_option(env, rpc_options, options, pool); if (error != RAST_OK) { /* return error; */ return NULL; } error = set_properties_option(env, rpc_options, options, pool); if (error != RAST_OK) { /* return error; */ return NULL; } return options; } static xmlrpc_value * create_result_properties(xmlrpc_env *env, rast_result_item_t *item, int num_properties) { int i; xmlrpc_value *properties = xmlrpc_build_value(env, "()"); for (i = 0; i < num_properties; i++) { xmlrpc_value *property, *rpc_value; rast_value_t *value = item->properties + i; switch (value->type) { case RAST_TYPE_STRING: rpc_value = xmlrpc_build_value(env, "s", rast_value_string(value)); break; case RAST_TYPE_DATE: rpc_value = xmlrpc_build_value(env, "s", rast_value_date(value)); break; case RAST_TYPE_DATETIME: rpc_value = xmlrpc_build_value(env, "s", rast_value_datetime(value)); break; case RAST_TYPE_UINT: rpc_value = xmlrpc_build_value(env, "i", (xmlrpc_int32) rast_value_uint(value)); break; default: return NULL; } if (env->fault_occurred) { xmlrpc_DECREF(properties); return NULL; } property = xmlrpc_build_value(env, "{s:s,s:V}", "type", rast_type_e_to_str(value->type), "value", rpc_value); xmlrpc_DECREF(rpc_value); if (env->fault_occurred) { xmlrpc_DECREF(properties); return NULL; } xmlrpc_array_append_item(env, properties, property); } return properties; } static xmlrpc_value * create_result_items(xmlrpc_env *env, rast_search_option_t *options, rast_result_t *result) { int i; xmlrpc_value *items = xmlrpc_build_value(env, "()"); if (env->fault_occurred) { return NULL; } for (i = 0; i < result->num_items; i++) { xmlrpc_value *item, *properties; properties = create_result_properties(env, result->items[i], options->num_properties); if (properties == NULL) { xmlrpc_DECREF(items); return NULL; } item = xmlrpc_build_value(env, "{s:i,s:i,s:i,s:V}", "doc_id", (xmlrpc_int32) result->items[i]->doc_id, "db_index", (xmlrpc_int32) result->items[i]->db_index, "score", (xmlrpc_int32) result->items[i]->score, "properties", properties); if (env->fault_occurred) { xmlrpc_DECREF(items); return NULL; } if (options->need_summary) { xmlrpc_value *summary; summary = xmlrpc_build_value(env, "s#", result->items[i]->summary, result->items[i]->summary_nbytes); if (env->fault_occurred) { xmlrpc_DECREF(item); xmlrpc_DECREF(items); return NULL; } xmlrpc_struct_set_value(env, item, "summary", summary); xmlrpc_DECREF(summary); if (env->fault_occurred) { xmlrpc_DECREF(item); xmlrpc_DECREF(items); return NULL; } } xmlrpc_array_append_item(env, items, item); xmlrpc_DECREF(item); if (env->fault_occurred) { xmlrpc_DECREF(items); return NULL; } } return items; } static xmlrpc_value * create_result_terms(xmlrpc_env *env, rast_search_option_t *options, rast_result_t *result) { int i; xmlrpc_value *terms = xmlrpc_build_value(env, "()"); if (env->fault_occurred) { return NULL; } for (i = 0; i < result->num_terms; i++) { xmlrpc_value *term; term = xmlrpc_build_value(env, "{s:s,s:i}", "term", result->terms[i].term, "doc_count", (xmlrpc_int32) result->terms[i].doc_count); if (env->fault_occurred) { xmlrpc_DECREF(terms); return NULL; } xmlrpc_array_append_item(env, terms, term); xmlrpc_DECREF(term); if (env->fault_occurred) { xmlrpc_DECREF(terms); return NULL; } } return terms; } static xmlrpc_value * rast_error_to_xmlrpc_value(xmlrpc_env *env, rast_error_t *error) { xmlrpc_value *result; if (error == RAST_OK) { return xmlrpc_struct_new(env); } result = xmlrpc_build_value(env, "{s:{s:s,s:i,s:s}}", "error", "type", rast_error_type_t_to_str(error->type), "code", error->code, "message", error->message); rast_error_destroy(error); return result; } static rast_error_t * get_doc_id(rast_db_t *db, xmlrpc_env *env, xmlrpc_value *rpc_params, rast_doc_id_t *doc_id) { xmlrpc_int32 rpc_doc_id; xmlrpc_parse_value(env, rpc_params, "{s:i,*}", "doc_id", &rpc_doc_id); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, "doc_id is required"); } *doc_id = (rast_doc_id_t) rpc_doc_id; return RAST_OK; } static rast_error_t * get_text(rast_db_t *db, xmlrpc_env *env, xmlrpc_value *rpc_params, char **text, rast_size_t *nbytes) { xmlrpc_parse_value(env, rpc_params, "{s:s#,*}", "text", text, nbytes); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, "text is required"); } return RAST_OK; } static rast_error_t * get_properties(rast_db_t *db, xmlrpc_env *env, xmlrpc_value *rpc_params, rast_value_t **properties, apr_pool_t *sub_pool) { if (xmlrpc_struct_has_key(env, rpc_params, "properties")) { int num_properties, db_num_properties, i; const rast_property_t *db_properties; xmlrpc_value *rpc_properties; rpc_properties = xmlrpc_struct_get_value(env, rpc_params, "properties"); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, "properties are required"); } num_properties = xmlrpc_array_size(env, rpc_properties); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, ""); } *properties = (rast_value_t *) apr_palloc(sub_pool, sizeof(rast_value_t) * num_properties); db_properties = rast_db_properties(db, &db_num_properties); for (i = 0; i < num_properties; i++) { xmlrpc_value *rpc_property; char *str_property, *date_property; int int_property; rpc_property = xmlrpc_array_get_item(env, rpc_properties, i); if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, "property are required"); } switch (db_properties[i].type) { case RAST_TYPE_STRING: xmlrpc_parse_value(env, rpc_property, "s", &str_property); rast_value_set_string(*properties + i, str_property); break; case RAST_TYPE_DATE: xmlrpc_parse_value(env, rpc_property, "s", &date_property); rast_value_set_date(*properties + i, date_property); break; case RAST_TYPE_DATETIME: xmlrpc_parse_value(env, rpc_property, "s", &date_property); rast_value_set_datetime(*properties + i, date_property); break; case RAST_TYPE_UINT: xmlrpc_parse_value(env, rpc_property, "i", &int_property); rast_value_set_uint(*properties + i, int_property); break; } if (env->fault_occurred) { return xmlrpc_error_to_rast_error(env, "doc_id is required"); } rast_value_set_type(*properties + i, db_properties[i].type); } } return RAST_OK; } static rast_error_t * build_doc_id_value(xmlrpc_env *env, rast_doc_id_t doc_id, xmlrpc_value **result) { *result = xmlrpc_build_value(env, "{s:i}", "doc_id", (xmlrpc_int32) doc_id); return xmlrpc_error_to_rast_error(env, "doc_id is required"); } xmlrpc_value * xmlrpc_server_register(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; apr_pool_t *sub_pool; xmlrpc_value *rpc_result, *rpc_params; rast_error_t *error; char *text; xmlrpc_int32 nbytes; rast_doc_id_t new_doc_id; rast_value_t *properties = NULL; server = (xmlrpc_server_t *) user_data; rpc_params = xmlrpc_array_get_item(env, param_array, 0); if (env->fault_occurred) { return NULL; } error = get_text(server->db, env, rpc_params, &text, &nbytes); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } apr_pool_create(&sub_pool, server->pool); error = get_properties(server->db, env, rpc_params, &properties, sub_pool); if (error != RAST_OK) { apr_pool_destroy(sub_pool); return rast_error_to_xmlrpc_value(env, error); } error = rast_db_register(server->db, text, (rast_size_t) nbytes, properties, &new_doc_id); apr_pool_destroy(sub_pool); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } /* todo: must be without sync */ rast_db_sync(server->db); error = build_doc_id_value(env, new_doc_id, &rpc_result); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } return rpc_result; } xmlrpc_value * xmlrpc_server_search(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; apr_pool_t *sub_pool; xmlrpc_value *rpc_options, *rpc_result; xmlrpc_value *rpc_result_items, *rpc_result_terms; rast_error_t *error; char *query; rast_search_option_t *options; rast_result_t *result; server = (xmlrpc_server_t *) user_data; apr_pool_create(&sub_pool, server->pool); xmlrpc_parse_value(env, param_array, "({s:s,s:S,*})", "query", &query, "options", &rpc_options); if (env->fault_occurred) { return NULL; } options = create_search_options(sub_pool, env, rpc_options); if (options == NULL) { return NULL; } error = rast_db_search(server->db, query, options, &result, sub_pool); if (error != RAST_OK) { apr_pool_destroy(sub_pool); return rast_error_to_xmlrpc_value(env, error); } rpc_result_terms = create_result_terms(env, options, result); rpc_result_items = create_result_items(env, options, result); if (rpc_result_items == NULL) { xmlrpc_DECREF(rpc_result_terms); apr_pool_destroy(sub_pool); return NULL; } rpc_result = xmlrpc_build_value(env, "{s:i,s:i,s:i,s:V,s:V}", "num_indices", result->num_indices, "num_docs", result->num_docs, "hit_count", result->hit_count, "terms", rpc_result_terms, "items", rpc_result_items); xmlrpc_DECREF(rpc_result_terms); xmlrpc_DECREF(rpc_result_items); apr_pool_destroy(sub_pool); if (env->fault_occurred) { return NULL; } return rpc_result; } xmlrpc_value * xmlrpc_server_delete(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; rast_doc_id_t doc_id; xmlrpc_value *rpc_params; rast_error_t *error; server = (xmlrpc_server_t *) user_data; rpc_params = xmlrpc_array_get_item(env, param_array, 0); if (env->fault_occurred) { return NULL; } error = get_doc_id(server->db, env, rpc_params, &doc_id); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } error = rast_db_delete(server->db, (rast_doc_id_t) doc_id); return rast_error_to_xmlrpc_value(env, error); } xmlrpc_value * xmlrpc_server_update(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; xmlrpc_value *rpc_params, *rpc_result; char *text; rast_size_t nbytes; rast_value_t *properties; rast_doc_id_t doc_id, new_doc_id; apr_pool_t *sub_pool; rast_error_t *error; server = (xmlrpc_server_t *) user_data; rpc_params = xmlrpc_array_get_item(env, param_array, 0); if (env->fault_occurred) { return NULL; } error = get_doc_id(server->db, env, rpc_params, &doc_id); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } error = get_text(server->db, env, rpc_params, &text, &nbytes); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } apr_pool_create(&sub_pool, server->pool); error = get_properties(server->db, env, rpc_params, &properties, sub_pool); if (error != RAST_OK) { apr_pool_destroy(sub_pool); return rast_error_to_xmlrpc_value(env, error); } error = rast_db_update(server->db, doc_id, text, nbytes, properties, &new_doc_id); apr_pool_destroy(sub_pool); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } /* todo: must be without sync */ rast_db_sync(server->db); error = build_doc_id_value(env, new_doc_id, &rpc_result); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } return rpc_result; } xmlrpc_value * xmlrpc_server_get_text(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; xmlrpc_value *rpc_params, *rpc_result; char *text; rast_size_t nbytes; rast_doc_id_t doc_id; apr_pool_t *sub_pool; rast_error_t *error; server = (xmlrpc_server_t *) user_data; rpc_params = xmlrpc_array_get_item(env, param_array, 0); if (env->fault_occurred) { return NULL; } error = get_doc_id(server->db, env, rpc_params, &doc_id); if (error != RAST_OK) { return rast_error_to_xmlrpc_value(env, error); } apr_pool_create(&sub_pool, server->pool); error = rast_db_get_text(server->db, doc_id, &text, &nbytes, sub_pool); if (error != RAST_OK) { apr_pool_destroy(sub_pool); return rast_error_to_xmlrpc_value(env, error); } rpc_result = xmlrpc_build_value(env, "{s:s#}", "text", text, nbytes); apr_pool_destroy(sub_pool); if (env->fault_occurred) { return NULL; } return rpc_result; } xmlrpc_value * xmlrpc_server_encoding(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; xmlrpc_value *result; server = (xmlrpc_server_t *) user_data; result = xmlrpc_build_value(env, "{s:s}", "encoding", rast_db_encoding(server->db)); if (env->fault_occurred) { return NULL; } return result; } xmlrpc_value * xmlrpc_server_properties(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) { xmlrpc_server_t *server; const rast_property_t *properties; xmlrpc_value *result; int i, db_num_properties; server = (xmlrpc_server_t *) user_data; properties = rast_db_properties(server->db, &db_num_properties); result = xmlrpc_build_value(env, "()"); if (env->fault_occurred) { return NULL; } for (i = 0; i < db_num_properties; i++) { xmlrpc_value *property; property = xmlrpc_build_value(env, "{s:s,s:s,s:i}", "name", properties[i].name, "type", rast_type_e_to_str(properties[i].type), "flags", properties[i].flags); if (env->fault_occurred) { return NULL; } xmlrpc_array_append_item(env, result, property); xmlrpc_DECREF(property); if (env->fault_occurred) { return NULL; } } return result; }