--- /dev/null
+#!/usr/bin/perl
+use strict;
+use lib '../perlmods/';
+
+my $map = {};
+eval "
+ use lib '../perlmods/';
+ use OpenILS::Utils::Fieldmapper;
+";
+$map = $Fieldmapper::fieldmap unless ($@);
+
+die $@ if ($@);
+
+
+if(!$ARGV[0]) {
+ print "usage: $0 <source_file>\n";
+ exit;
+}
+
+warn "Generating fieldmapper-c code...\n";
+
+
+print $ARGV[0] . "\n";
+
+open(SOURCE, ">$ARGV[0]");
+
+print SOURCE <<C;
+#include "fieldmapper_lookup.h"
+
+
+char * fm_pton(char * class, int pos) {
+ if (class == NULL) return NULL;
+C
+
+
+for my $object (keys %$map) {
+ my $short_name= $map->{$object}->{hint};
+ print SOURCE <<" C";
+ else if (!strcmp(class, "$short_name")) {
+ switch (pos) {
+ C
+ for my $field (keys %{$map->{$object}->{fields}}) {
+ my $position = $map->{$object}->{fields}->{$field}->{position};
+ print SOURCE <<" C";
+ case $position:
+ return strdup("$field");
+ break;
+ C
+ }
+ print SOURCE " }\n";
+ print SOURCE " }\n";
+}
+print SOURCE <<C;
+ return strdup("datum");
+}
+
+int isFieldmapper(char* class) {
+ if (class == NULL) return NULL;
+C
+
+for my $object (keys %$map) {
+ my $short_name= $map->{$object}->{hint};
+ print SOURCE " else if (!strcmp(class, \"$short_name\")) return 1;";
+}
+print SOURCE <<C;
+ return NULL;
+}
+
+int fm_ntop(char* class, char* field);
+ if (class == NULL) return NULL;
+C
+
+
+for my $object (keys %$map) {
+ my $short_name= $map->{$object}->{hint};
+ print SOURCE " else if (!strcmp(class, \"$short_name\")) {\n";
+ for my $field (keys %{$map->{$object}->{fields}}) {
+ my $position = $map->{$object}->{fields}->{$field}->{position};
+ print SOURCE " if (!strcmp(field,\"$field\")) return $position;\n";
+ }
+ print SOURCE " }\n"
+}
+
+print SOURCE " return -1;\n}";
+warn "done\n";
+
--- /dev/null
+
+#include <string.h>
+#include <stdio.h>
+
+/* the JSON parser, so we can read the response we're XMLizing */
+#include "objson/object.h"
+#include "objson/json_parser.h"
+#include "utils.h"
+
+int isFieldmapper(char*);
+int fm_ntop(char*,char*);
+char* fm_pton(char*,int);
+
--- /dev/null
+#include "json_xml.h"
+#include "fieldmapper_lookup.h"
+
+void _rest_xml_output(growing_buffer*, object*, char*, int, int);
+char* _escape_xml (char*);
+
+char* json_string_to_xml(char* content) {
+ object * obj;
+ growing_buffer * res_xml;
+ char * output;
+ int i;
+
+ obj = json_parse_string( content );
+ res_xml = buffer_init(1024);
+
+ if (!obj)
+ return NULL;
+
+ buffer_add(res_xml, "<response>");
+
+ if(obj->is_array) {
+ for( i = 0; i!= obj->size; i++ ) {
+ _rest_xml_output(res_xml, obj->get_index(obj,i), NULL, 0,0);
+ }
+ } else {
+ _rest_xml_output(res_xml, obj, NULL, 0,0);
+ }
+
+ buffer_add(res_xml, "</response>");
+
+ output = buffer_data(res_xml);
+ buffer_free(res_xml);
+ free_object(obj);
+
+ return output;
+}
+
+char* _escape_xml (char* text) {
+ char* out;
+ growing_buffer* b = buffer_init(256);
+ int len = strlen(text);
+ int i;
+ for (i = 0; i < len; i++) {
+ if (text[i] == '&')
+ buffer_add(b,"&");
+ else if (text[i] == '<')
+ buffer_add(b,"<");
+ else if (text[i] == '>')
+ buffer_add(b,">");
+ else
+ buffer_add_char(b,text[i]);
+ }
+ out = buffer_data(b);
+ buffer_free(b);
+ return out;
+}
+
+void _rest_xml_output(growing_buffer* buf, object* obj, char * obj_class, int arr_index, int notag) {
+ char * tag;
+ int i;
+
+ if(!obj) return;
+
+ if (obj->classname)
+ notag = 1;
+
+ if(isFieldmapper(obj_class)) {
+ tag = fm_pton(obj_class,arr_index);
+ } else if(obj_class) {
+ tag = strdup(obj_class);
+ } else {
+ tag = strdup("datum");
+ }
+
+
+ /* add class hints if we have a class name */
+ if(obj->classname) {
+ if(obj->is_null) {
+ buffer_fadd(buf,"<%s><Object class_hint=\\\"%s\\\"/></%s>", tag, obj->classname, tag);
+ return;
+ } else {
+ buffer_fadd(buf,"<%s><Object class_hint=\\\"%s\\\">", tag, obj->classname);
+ }
+ }
+
+
+ /* now add the data */
+ if(obj->is_null) {
+ if (!notag)
+ buffer_fadd(buf, "<%s/>",tag);
+ } else if(obj->is_bool && obj->bool_value) {
+ if (notag)
+ buffer_add(buf, "true");
+ else
+ buffer_fadd(buf, "<%s>true</%s>",tag,tag);
+
+ } else if(obj->is_bool && ! obj->bool_value) {
+ if (notag)
+ buffer_add(buf, "false");
+ else
+ buffer_fadd(buf, "<%s>false</%s>",tag,tag);
+
+ } else if (obj->is_string) {
+ if (notag) {
+ char * t = _escape_xml(obj->string_data);
+ buffer_add(buf,t);
+ free(t);
+ } else {
+ char * t = _escape_xml(obj->string_data);
+ buffer_fadd(buf,"<%s>%s</%s>",tag,t,tag);
+ free(t);
+ }
+
+ } else if(obj->is_number) {
+
+ if (notag)
+ buffer_fadd(buf,"%ld",obj->num_value);
+ else
+ buffer_fadd(buf,"<%s>%ld</%s>",tag,obj->num_value,tag);
+
+
+ } else if(obj->is_double) {
+ if (notag)
+ buffer_fadd(buf,"%lf",tag,obj->double_value,tag);
+ else
+ buffer_fadd(buf,"<%s>%lf</%s>",tag,obj->double_value,tag);
+
+
+ } else if (obj->is_array) {
+ if (!notag) {
+ if(!isFieldmapper(obj_class))
+ buffer_add(buf,"<array>");
+ else
+ buffer_fadd(buf,"<%s>",tag);
+ }
+
+ for( i = 0; i!= obj->size; i++ ) {
+ _rest_xml_output(buf, obj->get_index(obj,i), obj->classname, i,0);
+ }
+
+ if (!notag) {
+ if(!isFieldmapper(obj_class))
+ buffer_add(buf,"</array>");
+ else
+ buffer_fadd(buf,"</%s>",tag);
+ }
+
+ } else if (obj->is_hash) {
+
+ if (!notag) {
+ if(!obj_class)
+ buffer_add(buf,"<hash>");
+ else
+ buffer_fadd(buf,"<%s>",tag);
+ }
+
+ object_iterator* itr = new_iterator(obj);
+ object_node* tmp;
+ while( (tmp = itr->next(itr)) ) {
+ if (notag) {
+ buffer_fadd(buf,"<%s>",tmp->key);
+ } else {
+ buffer_add(buf,"<pair>");
+ buffer_fadd(buf,"<key>%s</key><value>",tmp->key);
+ }
+
+ _rest_xml_output(buf, tmp->item, NULL,0,notag);
+
+ if (notag) {
+ buffer_fadd(buf,"</%s>",tmp->key);
+ } else {
+ buffer_add(buf,"</value></pair>");
+ }
+ }
+ free_iterator(itr);
+
+ if (!notag) {
+ if(!obj_class)
+ buffer_add(buf,"</hash>");
+ else
+ buffer_fadd(buf,"</%s>",tag);
+ }
+
+ }
+
+ if (obj->classname)
+ buffer_fadd(buf,"</Object></%s>",tag);
+
+ free(tag);
+}
+
--- /dev/null
+
+#include <string.h>
+#include <stdio.h>
+
+/* the JSON parser, so we can read the response we're XMLizing */
+#include "objson/object.h"
+#include "objson/json_parser.h"
+#include "utils.h"
+
+char* json_string_to_xml(char*);
--- /dev/null
+#include "mod_ils_gateway.h"
+
+char* ils_rest_gateway_config_file;
+
+static const char* ils_gateway_set_config(cmd_parms *parms, void *config, const char *arg) {
+ ils_gateway_config *cfg;
+
+ cfg = ap_get_module_config(parms->server->module_config, &ils_rest_gateway_module);
+
+ cfg->configfile = (char*) arg;
+ ils_rest_gateway_config_file = (char*) arg;
+
+ return NULL;
+}
+
+/* tell apache about our commands */
+static const command_rec ils_gateway_cmds[] = {
+ AP_INIT_TAKE1( GATEWAY_CONFIG, ils_gateway_set_config, NULL, RSRC_CONF, "gateway config file"),
+ {NULL}
+};
+
+/* build the config object */
+static void* ils_gateway_create_config( apr_pool_t* p, server_rec* s) {
+ ils_gateway_config* cfg = (ils_gateway_config*) apr_palloc(p, sizeof(ils_gateway_config));
+ cfg->configfile = GATEWAY_DEFAULT_CONFIG;
+ return (void*) cfg;
+}
+
+
+static void mod_ils_gateway_child_init(apr_pool_t *p, server_rec *s) {
+
+ char* cfg = ils_rest_gateway_config_file;
+
+ if( ! osrf_system_bootstrap_client( cfg, CONFIG_CONTEXT) )
+ fatal_handler("Unable to load gateway config file...");
+ fprintf(stderr, "Bootstrapping %d\n", getpid() );
+ fflush(stderr);
+}
+
+static int mod_ils_gateway_method_handler (request_rec *r) {
+
+ /* make sure we're needed first thing*/
+ if (strcmp(r->handler, MODULE_NAME ))
+ return DECLINED;
+
+ apr_pool_t *p = r->pool; /* memory pool */
+ char* arg = r->args; /* url query string */
+
+ char* service = NULL; /* service to connect to */
+ char* method = NULL; /* method to perform */
+
+ //json* exception = NULL; /* returned in error conditions */
+ object* exception = NULL; /* returned in error conditions */
+ string_array* sarray = init_string_array(12); /* method parameters */
+
+ growing_buffer* buffer = NULL; /* POST data */
+ growing_buffer* tmp_buf = NULL; /* temp buffer */
+
+ char* key = NULL; /* query item name */
+ char* val = NULL; /* query item value */
+
+
+
+ /* verify we are connected */
+ if(!osrf_system_get_transport_client()) {
+ fatal_handler("Bootstrap Failed, no transport client");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+
+
+ /* gather the post args and append them to the url query string */
+ if( !strcmp(r->method,"POST") ) {
+
+ ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
+
+ if(! ap_should_client_block(r)) {
+ warning_handler("No Post Body");
+ }
+
+ char body[1025];
+ memset(body,0,1025);
+ buffer = buffer_init(1025);
+
+ while(ap_get_client_block(r, body, 1024)) {
+ debug_handler("Apache read POST block data: %s\n", body);
+ buffer_add( buffer, body );
+ memset(body,0,1025);
+ }
+
+ if(arg && arg[0]) {
+ tmp_buf = buffer_init(1024);
+ buffer_add(tmp_buf,arg);
+ buffer_add(tmp_buf,buffer->buf);
+ arg = (char*) apr_pstrdup(p, tmp_buf->buf);
+ buffer_free(tmp_buf);
+ } else {
+ arg = (char*) apr_pstrdup(p, buffer->buf);
+ }
+ buffer_free(buffer);
+
+ }
+
+ debug_handler("params args are %s", arg);
+
+
+ if( ! arg || !arg[0] ) { /* we received no request */
+ warning_handler("No Args");
+ return OK;
+ }
+
+ r->allowed |= (AP_METHOD_BIT << M_GET);
+ r->allowed |= (AP_METHOD_BIT << M_POST);
+
+
+ while( arg && (val = ap_getword(p, (const char**) &arg, '&'))) {
+
+ key = ap_getword(r->pool, (const char**) &val, '=');
+ if(!key || !key[0])
+ break;
+
+ ap_unescape_url((char*)key);
+ ap_unescape_url((char*)val);
+
+ if(!strcmp(key,"service"))
+ service = val;
+
+ if(!strcmp(key,"method"))
+ method = val;
+
+ if(!strcmp(key,"param"))
+ string_array_add(sarray, val);
+
+ }
+
+ info_handler("Performing(%d): service %s | method %s | \n",
+ getpid(), service, method );
+
+ int k;
+ for( k = 0; k!= sarray->size; k++ ) {
+ info_handler( "param %s", string_array_get_string(sarray,k));
+ }
+
+ osrf_app_session* session = osrf_app_client_session_init(service);
+
+ debug_handler("MOD session service: %s", session->remote_service );
+
+ int req_id = osrf_app_session_make_req( session, NULL, method, 1, sarray );
+ string_array_destroy(sarray);
+
+ osrf_message* omsg = NULL;
+
+ growing_buffer* result_data = buffer_init(256);
+ buffer_add(result_data, "[");
+
+ /* gather result data */
+ while((omsg = osrf_app_session_request_recv( session, req_id, 60 ))) {
+
+ if( omsg->_result_content ) {
+ char* content = object_to_json(omsg->_result_content);
+ buffer_add(result_data, content);
+ buffer_add( result_data, ",");
+ free(content);
+
+ } else {
+
+
+ /* build the exception information */
+ growing_buffer* exc_buffer = buffer_init(256);
+ buffer_add( exc_buffer, "\nReceived Exception:\nName: " );
+ buffer_add( exc_buffer, omsg->status_name );
+ buffer_add( exc_buffer, "\nStatus: " );
+ buffer_add( exc_buffer, omsg->status_text );
+ buffer_add( exc_buffer, "\nStatus: " );
+
+ char code[16];
+ memset(code, 0, 16);
+ sprintf( code, "%d", omsg->status_code );
+ buffer_add( exc_buffer, code );
+
+ exception = json_parse_string("{}");
+ exception->add_key(exception, "is_err", json_parse_string("1"));
+ exception->add_key(exception, "err_msg", new_object(exc_buffer->buf) );
+
+ warning_handler("*** Looks like we got a "
+ "server exception\n%s", exc_buffer->buf );
+
+ buffer_free(exc_buffer);
+ osrf_message_free(omsg);
+ break;
+ }
+
+ osrf_message_free(omsg);
+ omsg = NULL;
+ }
+
+ /* remove trailing comma */
+ if( result_data->buf[strlen(result_data->buf)-1] == ',') {
+ result_data->buf[strlen(result_data->buf)-1] = '\0';
+ result_data->n_used--;
+ }
+
+ buffer_add(result_data,"]");
+
+ char* content = NULL;
+
+ if(exception) {
+ content = exception->to_json(exception);
+ free_object(exception);
+ }
+
+ /* set content type to text/xml for passing around XML objects */
+ ap_set_content_type(r, "text/xml");
+ if(content) { /* exception... */
+ char* tmp = content;
+ content = json_string_to_xml( tmp );
+ free(tmp);
+ } else {
+ content = json_string_to_xml( result_data->buf );
+ }
+
+ buffer_free(result_data);
+
+ if(content) {
+ debug_handler( "APACHE writing data to web client: %s", content );
+ ap_rputs(content,r);
+ free(content);
+ }
+
+ osrf_app_session_request_finish( session, req_id );
+ debug_handler("gateway process message successfully");
+
+
+ osrf_app_session_destroy(session);
+ return OK;
+
+}
+
+static void mod_ils_gateway_register_hooks (apr_pool_t *p) {
+ ap_hook_handler(mod_ils_gateway_method_handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(mod_ils_gateway_child_init,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+
+module AP_MODULE_DECLARE_DATA ils_rest_gateway_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL,
+ NULL,
+ ils_gateway_create_config,
+ NULL,
+ ils_gateway_cmds,
+ mod_ils_gateway_register_hooks,
+};
+
--- /dev/null
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "apr_compat.h"
+#include "apr_strings.h"
+
+/* our stuff */
+#include "opensrf/transport_client.h"
+#include "opensrf/osrf_message.h"
+#include "opensrf/osrf_app_session.h"
+#include "string_array.h"
+#include "md5.h"
+#include "objson/object.h"
+#include "objson/json_parser.h"
+
+#include "rest_xml.h"
+#define GATEWAY_CONFIG "ILSRestGatewayConfig"
+#define MODULE_NAME "ils_rest_gateway_module"
+#define CONFIG_CONTEXT "rest_gateway"
+
+#define GATEWAY_DEFAULT_CONFIG "/openils/conf/opensrf_core.xml"
+
+
+/* our config structure */
+typedef struct {
+ char* configfile; /* our bootstrap config file */
+} ils_gateway_config;
+
+module AP_MODULE_DECLARE_DATA ils_rest_gateway_module;
+