]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/c-apps/oils_cstore.c
adding new open-ils.cstore app; moving new IDL generator to a better home; added...
[Evergreen.git] / Open-ILS / src / c-apps / oils_cstore.c
1 #include "opensrf/osrf_application.h"
2 #include "opensrf/osrf_settings.h"
3 #include "opensrf/utils.h"
4 #include "objson/object.h"
5 #include "opensrf/log.h"
6 #include "oils_utils.h"
7 #include "oils_constants.h"
8 #include "oils_event.h"
9 #include <dbi/dbi.h>
10
11 #include <string.h>
12 #include <libxml/globals.h>
13 #include <libxml/xmlerror.h>
14 #include <libxml/parser.h>
15 #include <libxml/tree.h>
16 #include <libxml/debugXML.h>
17 #include <libxml/xmlmemory.h>
18 #include <openils/fieldmapper_lookup.h>
19
20 #define OILS_AUTH_CACHE_PRFX "oils_cstore_"
21 #define MODULENAME "open-ils.cstore"
22
23 int osrfAppChildInit();
24 int osrfAppInitialize();
25
26 int dispatchCRUDMethod ( osrfMethodContext* ctx );
27 jsonObject* doCreate ( osrfHash* metadata, jsonObject* params );
28 jsonObject* doRetrieve ( osrfHash* metadata, jsonObject* params );
29 jsonObject* doUpdate ( osrfHash* metadata, jsonObject* params );
30 jsonObject* doDelete ( osrfHash* metadata, jsonObject* params );
31 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta);
32
33 dbi_conn dbhandle; /* our db connection */
34 xmlDocPtr idlDoc = NULL; // parse and store the IDL here
35
36 /* handy NULL json object to have around */
37 static jsonObject* oilsNULL = NULL;
38
39 int osrfAppInitialize() {
40         osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server...");
41         osrfLogInfo(OSRF_LOG_MARK, "Finding XML file...");
42
43         char * idl_filename = osrf_settings_host_value("/apps/%s/app_settings/IDL", MODULENAME);
44         osrfLogInfo(OSRF_LOG_MARK, "Found file:");
45         osrfLogInfo(OSRF_LOG_MARK, idl_filename);
46
47         osrfLogInfo(OSRF_LOG_MARK, "Parsing the IDL XML...");
48         idlDoc = xmlReadFile( idl_filename, NULL, XML_PARSE_XINCLUDE );
49         
50         if (!idlDoc) {
51                 osrfLogError(OSRF_LOG_MARK, "Could not load or parse the IDL XML file!");
52                 exit(1);
53         }
54
55         osrfLogInfo(OSRF_LOG_MARK, "...IDL XML parsed");
56
57         osrfStringArray* global_methods = osrfNewStringArray(1);
58
59         //osrfStringArrayAdd( global_methods, "create" );
60         osrfStringArrayAdd( global_methods, "retrieve" );
61         //osrfStringArrayAdd( global_methods, "update" );
62         //osrfStringArrayAdd( global_methods, "delete" );
63
64         xmlNodePtr docRoot = xmlDocGetRootElement(idlDoc);
65         xmlNodePtr kid = docRoot->children;
66         while (kid) {
67                 if (!strcmp( (char*)kid->name, "class" )) {
68                         int i = 0; 
69                         char* method_type;
70                         while ( (method_type = osrfStringArrayGetString(global_methods, i)) ) {
71
72                                 osrfHash * usrData = osrfNewHash();
73                                 osrfHashSet( usrData, xmlGetProp(kid, "id"), "classname");
74                                 osrfHashSet( usrData, xmlGetNsProp(kid, "tablename", "http://open-ils.org/spec/opensrf/IDL/persistance/v1"), "tablename");
75                                 osrfHashSet( usrData, xmlGetNsProp(kid, "fieldmapper", "http://open-ils.org/spec/opensrf/IDL/objects/v1"), "fieldmapper");
76
77                                 xmlNodePtr _cur = kid->children;
78                                 while (_cur) {
79                                         if (!strcmp( (char*)_cur->name, "fields" )) osrfHashSet( usrData, _cur, "fields");
80                                         if (!strcmp( (char*)_cur->name, "links" )) osrfHashSet( usrData, _cur, "links");
81                                         _cur = _cur->next;
82                                 }
83
84
85                                 char* _fm = strdup( (char*)osrfHashGet(usrData, "fieldmapper") );
86                                 char* part = strtok(_fm, ":");
87
88                                 growing_buffer* method_name =  buffer_init(64);
89                                 buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part);
90
91                                 while ((part = strtok(NULL, ":"))) {
92                                         buffer_fadd(method_name, ".%s", part);
93                                 }
94                                 buffer_fadd(method_name, ".%s", method_type);
95
96                                 char* method = buffer_data(method_name);
97                                 buffer_free(method_name);
98
99                                 osrfHashSet( usrData, method, "methodname" );
100                                 osrfHashSet( usrData, strdup(method_type), "methodtype" );
101
102                                 osrfAppRegisterExtendedMethod(
103                                         MODULENAME,
104                                         method,
105                                         "dispatchCRUDMethod",
106                                         "",
107                                         1,
108                                         0,
109                                         (void*)usrData
110                                 );
111
112                                 i++;
113                         }
114                 }
115                 kid = kid->next;
116         }
117
118         return 0;
119 }
120
121 /**
122  * Connects to the database 
123  */
124 int osrfAppChildInit() {
125
126         dbi_initialize(NULL);
127
128         char* driver    = osrf_settings_host_value("/apps/%s/app_settings/driver", MODULENAME);
129         char* user      = osrf_settings_host_value("/apps/%s/app_settings/database/user", MODULENAME);
130         char* host      = osrf_settings_host_value("/apps/%s/app_settings/database/host", MODULENAME);
131         char* port      = osrf_settings_host_value("/apps/%s/app_settings/database/port", MODULENAME);
132         char* db        = osrf_settings_host_value("/apps/%s/app_settings/database/db", MODULENAME);
133         char* pw        = osrf_settings_host_value("/apps/%s/app_settings/database/pw", MODULENAME);
134
135         dbhandle = dbi_conn_new(driver);
136
137         if(!dbhandle) {
138                 osrfLogError(OSRF_LOG_MARK, "Error creating database driver %s", driver);
139                 return -1;
140         }
141
142         osrfLogInfo(OSRF_LOG_MARK, "oils_fetch connecting to database.  host=%s, "
143                 "port=%s, user=%s, pw=%s, db=%s", host, port, user, pw, db );
144
145         if(host) dbi_conn_set_option(dbhandle, "host", host );
146         if(port) dbi_conn_set_option_numeric( dbhandle, "port", atoi(port) );
147         if(user) dbi_conn_set_option(dbhandle, "username", user);
148         if(pw) dbi_conn_set_option(dbhandle, "password", pw );
149         if(db) dbi_conn_set_option(dbhandle, "dbname", db );
150
151         free(user);
152         free(host);
153         free(port);
154         free(db);
155         free(pw);
156
157         if (dbi_conn_connect(dbhandle) < 0) {
158                 const char* err;
159                 dbi_conn_error(dbhandle, &err);
160                 osrfLogError( OSRF_LOG_MARK, "Error connecting to database: %s", err);
161                 return -1;
162         }
163
164         osrfLogInfo(OSRF_LOG_MARK, "%s successfully connected to the database", MODULENAME);
165
166         return 0;
167 }
168
169
170 int dispatchCRUDMethod ( osrfMethodContext* ctx ) {
171         OSRF_METHOD_VERIFY_CONTEXT(ctx);
172
173         osrfHash* meta = (osrfHash*) ctx->method->userData;
174
175         jsonObject * obj = NULL;
176         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "create"))
177                 obj = doCreate(meta, ctx->params);
178
179         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "retrieve"))
180                 obj = doRetrieve(meta, ctx->params);
181
182         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "update"))
183                 obj = doUpdate(meta, ctx->params);
184
185         if (!strcmp( (char*)osrfHashGet(meta, "methodtype"), "delete"))
186                 obj = doDelete(meta, ctx->params);
187
188         osrfAppRespondComplete( ctx, obj );
189
190         jsonObjectFree(obj);
191
192         return 0;
193 }
194
195 jsonObject* doCreate( osrfHash* meta, jsonObject* params ) { return NULL; }
196
197 jsonObject* doRetrieve( osrfHash* meta, jsonObject* params ) {
198
199         char* id        = jsonObjectToSimpleString(jsonObjectGetIndex(params, 0));
200
201         osrfLogDebug(
202                 OSRF_LOG_MARK,
203                 "%s retrieving %s object with id %s",
204                 MODULENAME,
205                 osrfHashGet(meta, "fieldmapper"),
206                 id
207         );
208
209
210
211         growing_buffer* sql_buf = buffer_init(128);
212         buffer_fadd(
213                 sql_buf,
214                 "SELECT * FROM %s WHERE %s = %d;",
215                 osrfHashGet(meta, "tablename"),
216                 xmlGetNsProp( (xmlNode*)osrfHashGet(meta, "fields"), "primary", "http://open-ils.org/spec/opensrf/IDL/persistance/v1" ),
217                 atoi(id)
218         );
219
220         char* sql = buffer_data(sql_buf);
221         buffer_free(sql_buf);
222         
223         osrfLogDebug(OSRF_LOG_MARK, "%s SQL =  %s", MODULENAME, sql);
224
225         dbi_result result = dbi_conn_query(dbhandle, sql);
226
227         jsonObject* obj = NULL;
228         if(result) {
229
230                 /* there should be one row at the most  */
231                 if (!dbi_result_first_row(result)) {
232                         osrfLogDebug(OSRF_LOG_MARK, "%s: Error retrieving %s with key %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id);
233                         dbi_result_free(result); 
234                         return oilsNULL;
235                 }
236
237                 /* JSONify the result */
238                 obj = oilsMakeJSONFromResult( result, meta );
239
240                 /* clean up the query */
241                 dbi_result_free(result); 
242
243         } else {
244                 osrfLogDebug(OSRF_LOG_MARK, "%s returned no results for query %s", MODULENAME, sql);
245         }
246
247         free(id);
248
249         return obj;
250 }
251
252
253 jsonObject* doUpdate( osrfHash* meta, jsonObject* params ) { return NULL; }
254
255 jsonObject* doDelete( osrfHash* meta, jsonObject* params ) { return NULL; }
256
257
258 jsonObject* oilsMakeJSONFromResult( dbi_result result, osrfHash* meta) {
259         if(!(result && meta)) return NULL;
260
261         jsonObject* object = jsonParseString("[]");
262         jsonObjectSetClass(object, osrfHashGet(meta, "classname"));
263
264         int attr;
265         int fmIndex;
266         int columnIndex = 1;
267         unsigned short type;
268         const char* columnName;
269
270         /* cycle through the column list */
271         while( (columnName = dbi_result_get_field_name(result, columnIndex++)) ) {
272
273                 /* determine the field type and storage attributes */
274                 type = dbi_result_get_field_type(result, columnName);
275                 attr = dbi_result_get_field_attribs(result, columnName);
276
277                 /* fetch the fieldmapper index */
278                 if( (fmIndex = fm_ntop(object->classname, (char*) columnName)) < 0 ) continue;
279
280                 switch( type ) {
281
282                         case DBI_TYPE_INTEGER :
283
284                                 if( attr & DBI_INTEGER_SIZE8 ) 
285                                         jsonObjectSetIndex( object, fmIndex, 
286                                                 jsonNewNumberObject(dbi_result_get_longlong(result, columnName)));
287                                 else 
288                                         jsonObjectSetIndex( object, fmIndex, 
289                                                 jsonNewNumberObject(dbi_result_get_long(result, columnName)));
290
291                                 break;
292
293                         case DBI_TYPE_DECIMAL :
294                                 jsonObjectSetIndex( object, fmIndex, 
295                                                 jsonNewNumberObject(dbi_result_get_double(result, columnName)));
296                                 break;
297
298                         case DBI_TYPE_STRING :
299                                 jsonObjectSetIndex( object, fmIndex, 
300                                         jsonNewObject(dbi_result_get_string(result, columnName)));
301                                 break;
302
303                         case DBI_TYPE_DATETIME :
304                                 jsonObjectSetIndex( object, fmIndex, 
305                                         jsonNewNumberObject(dbi_result_get_datetime(result, columnName)));
306                                 break;
307
308                         case DBI_TYPE_BINARY :
309                                 osrfLogError( OSRF_LOG_MARK, 
310                                         "Can't do binary at column %s : index %d", columnName, columnIndex - 1);
311                 }
312         }
313
314         return object;
315 }
316
317
318
319