Tidied up various things:
authorscottmk <scottmk@9efc2488-bf62-4759-914b-345cdb29e865>
Sat, 14 Nov 2009 05:32:55 +0000 (05:32 +0000)
committerscottmk <scottmk@9efc2488-bf62-4759-914b-345cdb29e865>
Sat, 14 Nov 2009 05:32:55 +0000 (05:32 +0000)
1. Miscellaneous adjustments to white space.

2. Added doxygen-style comments to document all functions.  Removed most
comments from the header so that they won't override those in the
implementation file.

3. Slightly rearranged or otherwise tweaked the logic here and there
for clarity.

4. osrf_messasge_set_locale() now returns a const pointer, to discourage
the calling code from changing or freeing the message's copy of the
locale.

5. Eliminated the full_param_string member of osrfMessage.  We weren't
using it for anything, except to initialize it to NULL.

6. Plugged several memory leaks (potential but not actual).

7. Made osrfMessageToJSON a static function.  No other source file
needs to call it.

8. Replaced a couple of calls to jsonObjectToSimpleString() with calls
to jsonObjectGetString(), in order to eliminate a malloc and free.

M    include/opensrf/osrf_message.h
M    src/libopensrf/osrf_message.c

git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1849 9efc2488-bf62-4759-914b-345cdb29e865

include/opensrf/osrf_message.h
src/libopensrf/osrf_message.c

index d3e0b15..407a6a3 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef osrf_message_h
 #define osrf_message_h
 
+/**
+       @file osrf_message.h
+       @brief Header for osrfMessage
+*/
+
 #include <opensrf/string_array.h>
 #include <opensrf/utils.h>
 #include <opensrf/log.h>
@@ -75,8 +80,6 @@ struct osrf_message_struct {
                we won't touch this variable */
        struct osrf_message_struct* next;
 
-       char* full_param_string;
-
        /* magical LOCALE hint */
        char* sender_locale;
 
@@ -86,56 +89,37 @@ struct osrf_message_struct {
 };
 typedef struct osrf_message_struct osrfMessage;
 
-/* Set the locale hint for this message.
-   default_locale is used if not set.
-   Returns NULL if msg or locale is not set, char* to msg->sender_locale on success.
-*/
-char* osrf_message_set_locale( osrfMessage* msg, const char* locale );
+const char* osrf_message_set_locale( osrfMessage* msg, const char* locale );
 
-/* Set the default locale hint to be used for future outgoing messages.
-   Returns NULL if locale is NULL, const char* to default_locale otherwise.
-*/
 const char* osrf_message_set_default_locale( const char* locale );
 
-/* Get the current locale hint -- either the default or most recently received locale.
-   Returns const char* to current_locale.
-*/
 const char* osrf_message_get_last_locale(void);
 
 osrfMessage* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol );
-//void osrf_message_set_request_info( osrfMessage*, char* param_name, json* params );
+
 void osrf_message_set_status_info( osrfMessage*,
                const char* status_name, const char* status_text, int status_code );
+
 void osrf_message_set_result_content( osrfMessage*, const char* json_string );
+
 void osrfMessageFree( osrfMessage* );
+
 char* osrf_message_to_xml( osrfMessage* );
+
 char* osrf_message_serialize(const osrfMessage*);
 
-/* count is the max number of messages we'll put into msgs[] */
 int osrf_message_deserialize(const char* json, osrfMessage* msgs[], int count);
 
-
-
-/** Pushes any message retreived from the xml into the 'msgs' array.
-  * it is assumed that 'msgs' has beenn pre-allocated.
-  * Returns the number of message that are in the buffer.
-  */
-int osrf_message_from_xml( char* xml, osrfMessage* msgs[] );
-
 void osrf_message_set_params( osrfMessage* msg, const jsonObject* o );
+
 void osrf_message_set_method( osrfMessage* msg, const char* method_name );
+
 void osrf_message_add_object_param( osrfMessage* msg, const jsonObject* o );
-void osrf_message_add_param( osrfMessage*, const char* param_string );
 
+void osrf_message_add_param( osrfMessage*, const char* param_string );
 
 jsonObject* osrfMessageGetResult( osrfMessage* msg );
 
-/**
-  Returns the message as a jsonObject
-  @return The jsonObject which must be freed by the caller.
-  */
-jsonObject* osrfMessageToJSON( const osrfMessage* msg );
-
 char* osrfMessageSerializeBatch( osrfMessage* msgs [], int count );
 
 #ifdef __cplusplus
index ed1e620..4b9567c 100644 (file)
 #include <opensrf/osrf_message.h>
 
+/**
+       @file osrf_message.c
+       @brief Implementation of osrfMessage.
+*/
+
+static jsonObject* osrfMessageToJSON( const osrfMessage* msg );
+
 static char default_locale[17] = "en-US\0\0\0\0\0\0\0\0\0\0\0\0";
 static char* current_locale = NULL;
 
+/**
+       @brief Allocate and initialize an osrfMessage.
+       @param type One of CONNECT, REQUEST, RESULT, STATUS, or DISCONNECT.
+       @param thread_trace Thread trace.
+       @param protocol Protocol.
+       @return Pointer to the newly allocated osrfMessage.
+
+       The calling code is responsible for freeing the osrfMessage by calling osrfMessageFree().
+*/
 osrfMessage* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ) {
 
-       osrfMessage* msg                        = (osrfMessage*) safe_malloc(sizeof(osrfMessage));
-       msg->m_type                                     = type;
-       msg->thread_trace                       = thread_trace;
-       msg->protocol                           = protocol;
-       msg->status_name                        = NULL;
-       msg->status_text                        = NULL;
-       msg->status_code                        = 0;
-       msg->next                                       = NULL;
-       msg->is_exception                       = 0;
-       msg->_params                            = NULL;
-       msg->_result_content            = NULL;
-       msg->result_string                      = NULL;
-       msg->method_name                        = NULL;
-       msg->full_param_string          = NULL;
-       msg->sender_locale              = NULL;
-       msg->sender_tz_offset           = 0;
+       osrfMessage* msg            = (osrfMessage*) safe_malloc(sizeof(osrfMessage));
+       msg->m_type                 = type;
+       msg->thread_trace           = thread_trace;
+       msg->protocol               = protocol;
+       msg->status_name            = NULL;
+       msg->status_text            = NULL;
+       msg->status_code            = 0;
+       msg->next                   = NULL;
+       msg->is_exception           = 0;
+       msg->_params                = NULL;
+       msg->_result_content        = NULL;
+       msg->result_string          = NULL;
+       msg->method_name            = NULL;
+       msg->sender_locale          = NULL;
+       msg->sender_tz_offset       = 0;
 
        return msg;
 }
 
 
+/**
+       @brief Return the previous locale.
+       @return A pointer to the locale specified by the last message to have been deserialized,
+               or NULL.
+
+       A JSON message may specify a locale string, which is saved as the current locale.  If
+       the message does not specify a locale string, then the current locale becomes NULL.
+
+       This function returns a pointer to an internal buffer.  Since both the address and the
+       contents of this buffer may change from one call to the next, the calling code should
+       either use the result immediately or make a copy of the string for later use.
+*/
 const char* osrf_message_get_last_locale() {
        return current_locale;
 }
 
-char* osrf_message_set_locale( osrfMessage* msg, const char* locale ) {
-       if( msg == NULL || locale == NULL ) return NULL;
+/**
+       @brief Set the locale for a specified osrfMessage.
+       @param msg Pointer to the osrfMessage.
+       @param locale Pointer to the locale string to be installed in the osrfMessage.
+       @return Pointer to the new locale string for the osrfMessage, or NULL if either
+               parameter is NULL.
+
+       If no locale is specified for an osrfMessage, we use the default locale.
+
+       Used for a REQUEST message.
+*/
+const char* osrf_message_set_locale( osrfMessage* msg, const char* locale ) {
+       if( msg == NULL || locale == NULL )
+               return NULL;
+       if( msg->sender_locale )
+               free( msg->sender_locale );
        return msg->sender_locale = strdup( locale );
 }
 
+/**
+       @brief Change the default locale.
+       @param locale The new default locale.
+       @return A pointer to the new default locale if successful, or NULL if not.
+
+       The function returns NULL if the parameter is NULL, or if the proposed new locale is
+       longer than 16 characters.
+
+       At this writing, nothing calls this function.
+*/
 const char* osrf_message_set_default_locale( const char* locale ) {
        if( locale == NULL ) return NULL;
        if( strlen(locale) > sizeof(default_locale) - 1 ) return NULL;
 
        strcpy( default_locale, locale );
-       return (const char*) default_locale;
+       return default_locale;
 }
 
+/**
+       @brief Populate the method_name member of an osrfMessage.
+       @param msg Pointer to the osrfMessage.
+       @param method_name The method name.
+
+       Used for a REQUEST message to specify what method to invoke.
+*/
 void osrf_message_set_method( osrfMessage* msg, const char* method_name ) {
-       if( msg == NULL || method_name == NULL ) return;
+       if( msg == NULL || method_name == NULL )
+               return;
+       if( msg->method_name )
+               free( msg->method_name );
        msg->method_name = strdup( method_name );
 }
 
 
 /**
-       @brief Wrap a copy of a jsonObject in a JSON_ARRAY and store it in an osrfMessage.
+       @brief Add a copy of a jsonObject to an osrfMessage as a parameter for a method call.
        @param msg Pointer to the osrfMessage.
        @param o Pointer to the jsonObject of which a copy is to be stored.
 
-       Make a copy of the input jsonObject, with all classnames encoded with
-       JSON_CLASS_KEY and JSON_DATA_KEY.  Append it to a JSON_ARRAY stored at
-       msg->_params.
+       Make a copy of the input jsonObject, with all classnames encoded with JSON_CLASS_KEY and
+       JSON_DATA_KEY.  Append it to a JSON_ARRAY stored at msg->_params.
 
-       If there is nothing at msg->_params, create a new JSON_ARRAY
-       for it and add the new object as the first element.
+       If there is nothing at msg->_params, create a new JSON_ARRAY for it and add the new object
+       as the first element.
+
+       If the jsonObject is raw (i.e. the class information has not been decoded into classnames),
+       decode it.  If the class information has already been decoded, discard it.
+
+       See also osrf_message_add_param().
+
+       At this writing, nothing calls this function.
 */
 void osrf_message_add_object_param( osrfMessage* msg, const jsonObject* o ) {
        if(!msg|| !o) return;
@@ -68,24 +135,58 @@ void osrf_message_add_object_param( osrfMessage* msg, const jsonObject* o ) {
        jsonObjectPush(msg->_params, jsonObjectDecodeClass( o ));
 }
 
+/**
+       @brief Populate the params member of an osrfMessage.
+       @param msg Pointer to the osrfMessage.
+       @param o Pointer to a jsonObject representing the parameter(s) to a method.
+
+       Make a copy of a jsonObject and install it as the parameter list for a method call.
+
+       If the osrfMessage already has any parameters, discard them.
+
+       The @a o parameter should point to a jsonObject of type JSON_ARRAY, with each element
+       of the array being a parameter.  If @a o points to any other type of jsonObject, create
+       a JSON_ARRAY as a wrapper for it, and install a copy of @a o as its only element.
+
+       Used for a REQUEST message, to pass parameters to a method.  The alternative is to call
+       osrf_message_add_param() or osrf_message_add_object_param() repeatedly as needed to add
+       one parameter at a time.
+*/
 void osrf_message_set_params( osrfMessage* msg, const jsonObject* o ) {
        if(!msg || !o) return;
 
-       if(o->type != JSON_ARRAY) {
+       if(msg->_params)
+               jsonObjectFree(msg->_params);
+
+       if(o->type == JSON_ARRAY) {
+               msg->_params = jsonObjectClone(o);
+       } else {
                osrfLogDebug( OSRF_LOG_MARK, "passing non-array to osrf_message_set_params(), fixing...");
-               if(msg->_params) jsonObjectFree(msg->_params);
                jsonObject* clone = jsonObjectClone(o);
-               msg->_params = jsonNewObject(NULL);
+               msg->_params = jsonNewObjectType( JSON_ARRAY );
                jsonObjectPush(msg->_params, clone);
                return;
        }
-
-       if(msg->_params) jsonObjectFree(msg->_params);
-       msg->_params = jsonObjectClone(o);
 }
 
 
-/* only works if parse_json_params is false */
+/**
+       @brief Add a JSON string to an osrfMessage as a parameter for a method call.
+       @param msg Pointer to the osrfMessage.
+       @param param_string A JSON string encoding the parameter to be added.
+
+       Translate the JSON string into a jsonObject, and append it to the parameter list.
+       If the parameter list doesn't already exist, create an empty one and add the new
+       parameter to it.
+
+       Decode any class information in the raw JSON into classnames.
+
+       If the JSON string is not valid JSON, append a new jsonObject of type JSON_NULL.
+
+       Used for a REQUEST message, to pass a parameter to a method,  The alternative is to
+       call osrf_message_set_params() to provide all the parameters at once.  See also
+       osrf_message_add_object_param().
+*/
 void osrf_message_add_param( osrfMessage* msg, const char* param_string ) {
        if(msg == NULL || param_string == NULL) return;
        if(!msg->_params) msg->_params = jsonNewObjectType( JSON_ARRAY );
@@ -93,28 +194,61 @@ void osrf_message_add_param( osrfMessage* msg, const char* param_string ) {
 }
 
 
+/**
+       @brief Set the status_name, status_text, and status_code members of an osrfMessage.
+       @param msg Pointer to the osrfMessage to be populated.
+       @param status_name Status name (may be NULL).
+       @param status_text Status text (may be NULL).
+       @param status_code Status code.
+
+       If the @a status_name or @a status_text parameter is NULL, the corresponding member
+       is left unchanged.
+
+       Used for a RESULT or STATUS message.
+*/
 void osrf_message_set_status_info( osrfMessage* msg,
                const char* status_name, const char* status_text, int status_code ) {
        if(!msg) return;
 
-       if( status_name != NULL ) 
+       if( status_name != NULL ) {
+               if( msg->status_name )
+                       free( msg->status_name );
                msg->status_name = strdup( status_name );
+       }
 
-       if( status_text != NULL )
+       if( status_text != NULL ) {
+               if( msg->status_text )
+                       free( msg->status_text );
                msg->status_text = strdup( status_text );
+       }
 
        msg->status_code = status_code;
 }
 
 
+/**
+       @brief Populate the result_string and _result_content members of an osrfMessage.
+       @param msg Pointer to the osrfMessage to be populated.
+       @param json_string A JSON string encoding a result set.
+
+       Used for a RESULT message to return the results of a request, such as a database lookup.
+*/
 void osrf_message_set_result_content( osrfMessage* msg, const char* json_string ) {
        if( msg == NULL || json_string == NULL) return;
-       msg->result_string =    strdup(json_string);
+       if( msg->result_string )
+               free( msg->result_string );
+       if( msg->_result_content )
+               jsonObjectFree( msg->_result_content );
+
+       msg->result_string   = strdup(json_string);
        msg->_result_content = jsonParseString(json_string);
 }
 
 
-
+/**
+       @brief Free an osrfMessage and everything it owns.
+       @param msg Pointer to the osrfMessage to be freed.
+*/
 void osrfMessageFree( osrfMessage* msg ) {
        if( msg == NULL )
                return;
@@ -144,24 +278,47 @@ void osrfMessageFree( osrfMessage* msg ) {
 }
 
 
+/**
+       @brief Turn a collection of osrfMessages into one big JSON string.
+       @param msgs Pointer to an array of osrfMessages.
+       @param count Maximum number of messages to serialize.
+       @return Pointer to the JSON string.
+
+       Traverse the array, adding each osrfMessage in turn to a JSON_ARRAY.  Stop when you have added the
+       maximum number of messages, or when you encounter a NULL pointer in the array.  Then translate the
+       JSON_ARRAY into a JSON string.
+
+       The calling code is responsible for freeing the returned string.
+*/
 char* osrfMessageSerializeBatch( osrfMessage* msgs [], int count ) {
        if( !msgs ) return NULL;
 
-       char* j;
-       int i = 0;
-       const osrfMessage* msg = NULL;
-       jsonObject* wrapper = jsonNewObject(NULL);
+       jsonObject* wrapper = jsonNewObjectType(JSON_ARRAY);
 
-       while( ((msg = msgs[i]) && (i++ < count)) ) 
-               jsonObjectPush(wrapper, osrfMessageToJSON( msg ));
+       int i = 0;
+       while( (i < count) && msgs[i] ) {
+               jsonObjectPush(wrapper, osrfMessageToJSON( msgs[i] ));
+               ++i;
+       }
 
-       j = jsonObjectToJSON(wrapper);
+       char* j = jsonObjectToJSON(wrapper);
        jsonObjectFree(wrapper);
 
-       return j;       
+       return j;
 }
 
 
+/**
+       @brief Turn a single osrfMessage into a JSON string.
+       @param msg Pointer to the osrfMessage to be serialized.
+       @return Pointer to the resulting JSON string.
+
+       Translate the osrfMessage into JSON, wrapped in a JSON array.
+
+       This function is equivalent to osrfMessageSerializeBatch() for an array of one pointer.
+
+       The calling code is responsible for freeing the returned string.
+*/
 char* osrf_message_serialize(const osrfMessage* msg) {
 
        if( msg == NULL ) return NULL;
@@ -170,7 +327,7 @@ char* osrf_message_serialize(const osrfMessage* msg) {
        jsonObject* json = osrfMessageToJSON( msg );
 
        if(json) {
-               jsonObject* wrapper = jsonNewObject(NULL);
+               jsonObject* wrapper = jsonNewObjectType(JSON_ARRAY);
                jsonObjectPush(wrapper, json);
                j = jsonObjectToJSON(wrapper);
                jsonObjectFree(wrapper);
@@ -180,9 +337,34 @@ char* osrf_message_serialize(const osrfMessage* msg) {
 }
 
 
-jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
+/**
+       @brief Translate an osrfMessage into a jsonObject.
+       @param msg Pointer to the osrfMessage to be translated.
+       @return Pointer to a newly created jsonObject.
+
+       The resulting jsonObject is a JSON_HASH with a classname of "osrfMessage", and the following keys:
+       - "threadTrace"
+       - "locale"
+       - "type"
+       - "payload" (only for STATUS, REQUEST, and RESULT messages)
+
+       The data for "payload" is also a JSON_HASH, whose structure depends on the message type:
+
+       For a STATUS message, the payload's classname is msg->status_name.  The keys are "status" (carrying
+       msg->status_text) and "statusCode" (carrying the status code as a string).
+
+       For a REQUEST message, the payload's classname is "osrfMethod".  The keys are "method" (carrying
+       msg->method_name) and "params" (carrying a jsonObject to pass any parameters to the method call).
 
-       jsonObject* json = jsonNewObject(NULL);
+       For a RESULT message, the payload's classname is "osrfResult".  The keys are "status" (carrying
+       msg->status_text), "statusCode" (carrying the status code as a string), and "content" (carrying a jsonObject 
+       to return any results from the method call).
+
+       The calling code is responsible for freeing the returned jsonObject.
+*/
+static jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
+
+       jsonObject* json = jsonNewObjectType(JSON_HASH);
        jsonObjectSetClass(json, "osrfMessage");
        jsonObject* payload;
        char sc[64];
@@ -200,12 +382,12 @@ jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
        }
 
        switch(msg->m_type) {
-               
-               case CONNECT: 
+
+               case CONNECT:
                        jsonObjectSetKey(json, "type", jsonNewObject("CONNECT"));
                        break;
 
-               case DISCONNECT: 
+               case DISCONNECT:
                        jsonObjectSetKey(json, "type", jsonNewObject("DISCONNECT"));
                        break;
 
@@ -245,26 +427,39 @@ jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
 }
 
 
+/**
+       @brief Translate a JSON array into an array of osrfMessages.
+       @param string The JSON string to be translated.
+       @param msgs Pointer to an array of pointers to osrfMessage, to receive the results.
+       @param count How many slots are available in the @a msgs array.
+       @return The number of osrfMessages created.
+
+       The JSON string is expected to be a JSON array, with each element encoding an osrfMessage.
+
+       If there are too many messages in the JSON array to fit into the pointer array, we
+       silently ignore the excess.
+*/
 int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count) {
 
        if(!string || !msgs || count <= 0) return 0;
        int numparsed = 0;
 
+       // Parse the JSON
        jsonObject* json = jsonParseString(string);
 
        if(!json) {
-               osrfLogWarning( OSRF_LOG_MARK, 
+               osrfLogWarning( OSRF_LOG_MARK,
                        "osrf_message_deserialize() unable to parse data: \n%s\n", string);
                return 0;
        }
 
+       // Traverse the JSON_ARRAY, turning each element into an osrfMessage
        int x;
-
        for( x = 0; x < json->size && x < count; x++ ) {
 
                const jsonObject* message = jsonObjectGetIndex(json, x);
 
-               if(message && message->type != JSON_NULL && 
+               if(message && message->type != JSON_NULL &&
                        message->classname && !strcmp(message->classname, "osrfMessage")) {
 
                        osrfMessage* new_msg = safe_malloc(sizeof(osrfMessage));
@@ -280,32 +475,32 @@ int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count)
                        new_msg->method_name = NULL;
                        new_msg->_params = NULL;
                        new_msg->next = NULL;
-                       new_msg->full_param_string = NULL;
                        new_msg->sender_locale = NULL;
                        new_msg->sender_tz_offset = 0;
 
+                       // Get the message type.  If not specified, default to CONNECT.
                        const jsonObject* tmp = jsonObjectGetKeyConst(message, "type");
 
                        const char* t;
                        if( ( t = jsonObjectGetString(tmp)) ) {
 
-                               if(!strcmp(t, "CONNECT"))               new_msg->m_type = CONNECT;
-                               else if(!strcmp(t, "DISCONNECT"))       new_msg->m_type = DISCONNECT;
-                               else if(!strcmp(t, "STATUS"))           new_msg->m_type = STATUS;
-                               else if(!strcmp(t, "REQUEST"))          new_msg->m_type = REQUEST;
-                               else if(!strcmp(t, "RESULT"))           new_msg->m_type = RESULT;
+                               if(!strcmp(t, "CONNECT"))           new_msg->m_type = CONNECT;
+                               else if(!strcmp(t, "DISCONNECT"))   new_msg->m_type = DISCONNECT;
+                               else if(!strcmp(t, "STATUS"))       new_msg->m_type = STATUS;
+                               else if(!strcmp(t, "REQUEST"))      new_msg->m_type = REQUEST;
+                               else if(!strcmp(t, "RESULT"))       new_msg->m_type = RESULT;
                        }
 
+                       // Get the thread trace, defaulting to zero.
                        tmp = jsonObjectGetKeyConst(message, "threadTrace");
                        if(tmp) {
-                               char* tt = jsonObjectToSimpleString(tmp);
+                               const char* tt = jsonObjectGetString(tmp);
                                if(tt) {
                                        new_msg->thread_trace = atoi(tt);
-                                       free(tt);
                                }
                        }
 
-                       /* use the sender's locale, or the global default */
+                       // Get the sender's locale, or leave it NULL if not specified.
                        if (current_locale)
                                free( current_locale );
 
@@ -317,21 +512,19 @@ int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count)
                                current_locale = NULL;
                        }
 
+                       // Get the protocol, defaulting to zero.
                        tmp = jsonObjectGetKeyConst(message, "protocol");
 
                        if(tmp) {
-                               char* proto = jsonObjectToSimpleString(tmp);
+                               const char* proto = jsonObjectGetString(tmp);
                                if(proto) {
                                        new_msg->protocol = atoi(proto);
-                                       free(proto);
                                }
                        }
 
                        tmp = jsonObjectGetKeyConst(message, "payload");
                        if(tmp) {
-                               if(tmp->classname)
-                                       new_msg->status_name = strdup(tmp->classname);
-
+                               // Get method name and parameters for a REQUEST
                                const jsonObject* tmp0 = jsonObjectGetKeyConst(tmp,"method");
                                const char* tmp_str = jsonObjectGetString(tmp0);
                                if(tmp_str)
@@ -339,11 +532,18 @@ int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count)
 
                                tmp0 = jsonObjectGetKeyConst(tmp,"params");
                                if(tmp0) {
+                                       // Note that we use jsonObjectDecodeClass() instead of
+                                       // jsonObjectClone().  The classnames are already decoded,
+                                       // but jsonObjectDecodeClass removes the decoded classnames.
                                        new_msg->_params = jsonObjectDecodeClass( tmp0 );
-                                       if(new_msg->_params && new_msg->_params->type == JSON_NULL) 
+                                       if(new_msg->_params && new_msg->_params->type == JSON_NULL)
                                                new_msg->_params->type = JSON_ARRAY;
                                }
 
+                               // Get status fields for a RESULT or STATUS
+                               if(tmp->classname)
+                                       new_msg->status_name = strdup(tmp->classname);
+
                                tmp0 = jsonObjectGetKeyConst(tmp,"status");
                                tmp_str = jsonObjectGetString(tmp0);
                                if(tmp_str)
@@ -358,8 +558,12 @@ int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count)
                                                new_msg->status_code = (int) jsonObjectGetNumber(tmp0);
                                }
 
+                               // Get the content for a RESULT
                                tmp0 = jsonObjectGetKeyConst(tmp,"content");
                                if(tmp0) {
+                                       // Note that we use jsonObjectDecodeClass() instead of
+                                       // jsonObjectClone().  The classnames are already decoded,
+                                       // but jsonObjectDecodeClass removes the decoded classnames.
                                        new_msg->_result_content = jsonObjectDecodeClass( tmp0 );
                                }
 
@@ -374,6 +578,14 @@ int osrf_message_deserialize(const char* string, osrfMessage* msgs[], int count)
 
 
 
+/**
+       @brief Return a pointer to the result content of an osrfMessage.
+       @param msg Pointer to the osrfMessage whose result content is to be returned.
+       @return Pointer to the result content (or NULL if there is no such content, or if @a msg is NULL).
+
+       The returned pointer points into the innards of the osrfMessage.  The calling code should @em not call
+       jsonObjectFree() on it, because the osrfMessage still owns it.
+*/
 jsonObject* osrfMessageGetResult( osrfMessage* msg ) {
        if(msg) return msg->_result_content;
        return NULL;