1 #include "openils/oils_event.h"
2 #include <libxml/parser.h>
3 #include <libxml/tree.h>
4 #include "opensrf/osrf_settings.h"
6 static void _oilsEventParseEvents();
8 // The following two osrfHashes are created when we
9 // create the first osrfEvent, and are never freed.
12 @brief Lookup store mapping event names to event numbers.
14 - Key: textcode from the events config file.
15 - Data: numeric code (as a string) from the events config file.
17 static osrfHash* _oilsEventEvents = NULL;
20 @brief Lookup store mapping event numbers to descriptive text.
22 - Key: numeric code (as a string) of the event.
23 - Data: another layer of lookup, as follows:
24 - Key: numeric code (as a string) of the event.
25 - Data: text message describing the event.
27 static osrfHash* _oilsEventDescriptions = NULL;
30 @brief Allocate and initialize a new oilsEvent.
31 @param file The name of the source file where oilsNewEvent is called.
32 @param line The line number in the source code where oilsNewEvent is called.
33 @param event A name or label for the event.
34 @return Pointer to the newly allocated oilsEvent.
36 The first two parameters are normally passed as the OSRF_LOG_MARK macro.
38 The calling code is responsible for freeing the oilsEvent by calling oilsEventFree().
40 oilsEvent* oilsNewEvent( const char* file, int line, const char* event ) {
41 if(!event) return NULL;
43 osrfLogInfo(OSRF_LOG_MARK, "Creating new event: %s", event);
46 _oilsEventParseEvents();
48 oilsEvent* evt = safe_malloc( sizeof(oilsEvent) );
49 evt->event = strdup(event);
56 evt->file = strdup(file);
65 @brief Allocate and initialize a new oilsEvent with a payload.
66 @param file The name of the source file where oilsNewEvent is called.
67 @param line The line number in the source code where oilsNewEvent is called.
68 @param event A name or label for the event.
69 @param payload The payload, of which a copy will be incorporated into the oilsEvent.
70 @return Pointer to the newly allocated oilsEvent.
72 The first two parameters are normally passed as the OSRF_LOG_MARK macro.
74 The calling code is responsible for freeing the oilsEvent by calling oilsEventFree().
76 oilsEvent* oilsNewEvent2( const char* file, int line, const char* event,
77 const jsonObject* payload ) {
78 oilsEvent* evt = oilsNewEvent(file, line, event);
81 evt->payload = jsonObjectClone(payload);
87 @brief Create a new oilsEvent with a permission and a permission location.
88 @param file The name of the source file where oilsNewEvent is called.
89 @param line The line number in the source code where oilsNewEvent is called.
90 @param event A name or label for the event.
91 @param perm The permission name.
92 @param permloc The permission location.
93 @return Pointer to the newly allocated oilsEvent.
95 The first two parameters are normally passed as the OSRF_LOG_MARK macro.
97 The calling code is responsible for freeing the oilsEvent by calling oilsEventFree().
99 oilsEvent* oilsNewEvent3( const char* file, int line, const char* event,
100 const char* perm, int permloc ) {
101 oilsEvent* evt = oilsNewEvent(file, line, event);
103 evt->perm = strdup(perm);
104 evt->permloc = permloc;
110 @brief Create a new oilsEvent with a permission and a permission location.
111 @param file The name of the source file where oilsNewEvent is called.
112 @param line The line number in the source code where oilsNewEvent is called.
113 @param event A name or label for the event.
114 @param perm The permission name.
115 @param permloc The permission location.
116 @param payload Pointer to the payload.
117 @return Pointer to the newly allocated oilsEvent.
119 The first two parameters are normally passed as the OSRF_LOG_MARK macro.
121 The calling code is responsible for freeing the oilsEvent by calling oilsEventFree().
123 oilsEvent* oilsNewEvent4( const char* file, int line, const char* event,
124 const char* perm, int permloc, const jsonObject* payload ) {
125 oilsEvent* evt = oilsNewEvent3( file, line, event, perm, permloc );
128 evt->payload = jsonObjectClone(payload);
134 @brief Set the permission and permission location of an oilsEvent.
135 @param event Pointer the oilsEvent whose permission and permission location are to be set.
136 @param perm The permission name.
137 @param permloc The permission location.
139 void oilsEventSetPermission( oilsEvent* event, const char* perm, int permloc ) {
140 if(!(event && perm)) return;
145 event->perm = strdup(perm);
146 event->permloc = permloc;
150 @brief Install a payload in an oilsEvent.
151 @param event The oilsEvent in which the payload is to be installed.
152 @param payload The payload, a copy of which will be installed in the oilsEvent.
154 If @a payload is NULL, install a JSON_NULL as the payload.
156 void oilsEventSetPayload( oilsEvent* event, const jsonObject* payload ) {
157 if(!(event && payload)) return;
160 jsonObjectFree(event->payload);
162 event->payload = jsonObjectClone(payload);
166 @brief Free an OilsEvent.
167 @param event Pointer to the oilsEvent to be freed.
169 void oilsEventFree( oilsEvent* event ) {
175 // If present, the jsonObject to which event->json will include a pointer to
176 // event->payload. Hence we must avoid trying to free the payload twice.
178 jsonObjectFree(event->json);
180 jsonObjectFree(event->payload);
186 @brief Package the contents of an oilsEvent into a jsonObject.
187 @param event Pointer to the oilsEvent whose contents are to be packaged.
188 @return Pointer to the newly created jsonObject if successful, or NULL if not.
190 The jsonObject will include a textual description of the event, as loaded from the
191 events file. Although the events file may include text in multiple languages,
192 oilsEventToJSON() uses only those marked as "en-US".
194 A pointer to the resulting jsonObject will be stored in the oilsEvent. Hence the calling
195 code should @em not free the returned jsonObject directly. It will be freed by
198 jsonObject* oilsEventToJSON( oilsEvent* event ) {
199 if(!event) return NULL;
201 char* code = osrfHashGet( _oilsEventEvents, event->event );
203 osrfLogError(OSRF_LOG_MARK, "No such event name: %s", event->event );
207 // Search for the right language
208 char* lang = "en-US"; /* assume this for now */
210 osrfHash* h = osrfHashGet(_oilsEventDescriptions, lang);
212 // Within that language, search for the right message
213 osrfLogDebug(OSRF_LOG_MARK, "Loaded event lang hash for %s",lang);
214 desc = osrfHashGet(h, code);
215 osrfLogDebug(OSRF_LOG_MARK, "Found event description %s", desc);
219 desc = ""; // Not found? Message defaults to empty string.
221 jsonObject* json = jsonNewObject(NULL);
222 jsonObjectSetKey( json, "ilsevent", jsonNewNumberObject(atoi(code)) );
223 jsonObjectSetKey( json, "textcode", jsonNewObject(event->event) );
224 jsonObjectSetKey( json, "desc", jsonNewObject(desc) );
225 jsonObjectSetKey( json, "pid", jsonNewNumberObject(getpid()) );
228 memset(buf, '\0', sizeof(buf));
229 snprintf(buf, sizeof(buf), "%s:%d", event->file, event->line);
230 jsonObjectSetKey( json, "stacktrace", jsonNewObject(buf) );
233 jsonObjectSetKey( json, "ilsperm", jsonNewObject(event->perm) );
235 if(event->permloc != -1)
236 jsonObjectSetKey( json, "ilspermloc", jsonNewNumberObject(event->permloc) );
239 jsonObjectSetKey( json, "payload", event->payload );
242 jsonObjectFree(event->json);
249 @brief Parse and load the events file.
251 Get the name of the events file from previously loaded settings. Open it and load
252 it into an xmlDoc. Based on the contents of the xmlDoc, build two osrfHashes: one to
253 map event names to event numbers, and another to map event numbers to descriptive
254 text messages (actually one such hash for each supported language).
256 static void _oilsEventParseEvents() {
258 char* xml = osrf_settings_host_value("/ils_events");
261 osrfLogError(OSRF_LOG_MARK, "Unable to find ILS Events file: %s", xml);
265 xmlDocPtr doc = xmlParseFile(xml);
268 _oilsEventEvents = osrfNewHash();
269 _oilsEventDescriptions = osrfNewHash();
272 xmlNodePtr root = xmlDocGetRootElement(doc);
274 xmlNodePtr child = root->children;
276 if( !strcmp((char*) child->name, "event") ) {
277 xmlChar* code = xmlGetProp( child, BAD_CAST "code");
278 xmlChar* textcode = xmlGetProp( child, BAD_CAST "textcode");
279 if( code && textcode ) {
280 osrfHashSet( _oilsEventEvents, code, (char*) textcode );
284 /* here we collect all of the <desc> nodes on the event
285 * element and store them based on the xml:lang attribute
287 xmlNodePtr desc = child->children;
289 if( !strcmp((char*) desc->name, "desc") ) {
290 xmlChar* lang = xmlGetProp( desc, BAD_CAST "lang");
292 osrfLogInternal( OSRF_LOG_MARK,
293 "Loaded event lang: %s", (char*) lang );
294 osrfHash* langHash = osrfHashGet(
295 _oilsEventDescriptions, (char*) lang);
297 langHash = osrfNewHash();
298 osrfHashSet(_oilsEventDescriptions, langHash, (char*) lang);
302 && (content = (char*) desc->children->content) ) {
303 osrfLogInternal( OSRF_LOG_MARK,
304 "Loaded event desc: %s", content);
305 osrfHashSet( langHash, content, (char*) code );
318 osrfLogError(OSRF_LOG_MARK, " ! Unable to parse events file: %s", xml );