blob: 93cc84a7b006762eac27647b13fa20cef8b4a5d8 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* etch_message.c
* message object
*/
#include "etch_message.h"
#include "etch_log.h"
#include "etch_objecttypes.h"
static const char* LOG_CATEGORY = "etch_message";
etch_message* new_message_init(etch_type*, const int);
/**
* new_message()
* constructor for etch_message
* the value factory is a reference, the type is a copy to be passed through
* to the underlying struct, which will then own the type memory.
*/
etch_message* new_message (etch_type* type, const int size, etch_value_factory* vf)
{
etch_message* newmsg = NULL;
if (!type || !vf) return NULL;
newmsg = new_message_init(type, size);
if (newmsg == NULL) return NULL;
newmsg->vf = vf;
ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "creating message %x\n", newmsg);
return newmsg;
}
/**
* destroy_message()
* destructor for etch_message
*/
int destroy_message (void* data)
{
etch_message* msg = (etch_message*)data;
int result = 0;
if (!is_etchobj_static_content(msg))
{
ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "destroying message %x\n", msg);
result = destroy_structvalue(msg->sv);
}
destroy_objectex((etch_object*)msg);
return result;
}
/**
* new_message_init()
* common initialization on etch_message construction.
*/
etch_message* new_message_init(etch_type* type, const int initialsize)
{
etch_message* newmsg = NULL;
if (NULL == type) return NULL;
newmsg = (etch_message*) new_object(sizeof(etch_message),
ETCHTYPEB_MESSAGE, CLASSID_ETCHMESSAGE);
((etch_object*)newmsg)->destroy = destroy_message;
newmsg->sv = new_structvalue(type, initialsize);
return newmsg;
}
/**
* message_remove()
* removes an element from the message struct, returning the element.
* if the element is found, its key is destroyed, and the object is returned.
* caller owns returned object.
*/
etch_object* message_remove(etch_message* msg, etch_field* key)
{
return structvalue_remove(msg->sv, key);
}
/**
* message_put()
* insert key/value pair
*
* @param key an etch_field whose destructor will be invoked when the struct is
* destroyed.
*
* @param value a *disposable* object which is the value of the key/val pair.
* if passed as null, specified key is removed from the message, per java binding.
* otherwise this object's destructor will be invoked when its struct is destroyed.
*
* @return 0 or -1.
* on failure, destructors are invoked here on both key and value.
*
* remarks: to simplify caller logic under normal circumstances, caller
* relinquishes ownership of parameters (other than this of course), regardless
* of outcome. should caller wish to retain ownership on failure, the parameter
* object could be marked such that the destructor invoked here becomes benign.
*/
int message_put(etch_message* msg, etch_field* key, etch_object* value)
{
/* on success, struct owns key and value */
if (0 == structvalue_put(msg->sv, key, value))
return 0;
etch_object_destroy(value);
value = NULL;
destroy_field(key); /* note we are often passed protected vf keys */
return -1;
}
/**
* message_putc()
* insert key/value pair and clear value reference
*
* @param key an etch_field whose destructor will be invoked when the struct is
* destroyed.
*
* @param value an indirect reference to a *disposable* object which is the value
* of the key/val pair.
* caller's reference is nulled out once this object is relinquished; thus caller
* can safely test for null and then destroy the object.
*
* @return 0 or -1.
* on failure, destructors are invoked here on both key and value.
*
* remarks: to simplify caller logic under normal circumstances, caller
* relinquishes ownership of parameters (other than this of course), regardless
* of outcome. should caller wish to retain ownership on failure, the parameter
* object could be marked such that the destructor invoked here becomes benign.
*/
int message_putc(etch_message* msg, etch_field* key, void** valref)
{
etch_object* value = NULL;
if (valref)
{ value = (etch_object*) *valref;
*valref = NULL; /* clear caller's reference as we now own value */
}
if (value){ /* on success, struct owns key and value */
if (0 == structvalue_put (msg->sv, key, value)){
return 0;
}
}
/* a struct put was not successful so destroy parameter objects */
etch_object_destroy(value);
value = NULL;
destroy_field(key); /* note we are often passed protected vf keys */
return -1;
}
/**
* message_get()
* fetch value for key.
* @return a non-disposable reference to the value, not a copy, or null.
*/
etch_object* message_get(etch_message* msg, etch_field* key)
{
etch_object* retobj = NULL;
if (msg && key && msg->sv)
retobj = structvalue_get(msg->sv, key);
#if(0)
if (NULL == msg || NULL == key || NULL == msg->sv)
return throw_from(EXCPTYPE_ILLEGALARG, ETCHTYPEB_UNDEFINED, 0, 0);
retobj = structvalue_get(msg->sv, key);
#endif
return retobj;
}
/**
* message_type()
* return etch type of specified message
*/
etch_type* message_type(etch_message* msg)
{
return msg && msg->sv? msg->sv->struct_type: NULL;
}
/**
* message_aname()
* return name of specified message in 8-bit encoding.
* @return a reference to the message name, caller does not own it.
*/
char* message_aname (etch_message* msg)
{
etch_type* msgtype = message_type(msg);
char* msgname = msgtype && msgtype->aname? msgtype->aname: "";
return msgname;
}
/**
* message_reply()
* creates a message which is a reply to the current message.
* the current message's value factory is copied to the new message.
* message id of the current message (if any) is copied into the
* in-reply-to field of the new message.
* @param newtype the type of the reply. caller retains ownership.
* @return a reply message, which will contain exception if error.
*/
etch_message* message_reply (etch_message* msg, etch_type* newtype)
{
int result = -1;
etch_int64* msgid = NULL;
etch_message* newmsg = NULL;
if (NULL == msg) return NULL;
if (NULL == newtype) /* use message type's result type */
newtype = etchtype_get_result_type (msg->sv->struct_type);
if (NULL == newtype) return NULL;
/* construct message. caller retains ownership of type */
newmsg = new_message (newtype, 0, msg->vf);
msgid = message_get_id (msg); /* get back a ref to ID or null */
if (msgid)
result = message_set_in_reply_to (newmsg, ((etch_object*)msgid)->clone(msgid));
if (0 != result)
{
etch_object_destroy(newmsg);
newmsg = NULL;
}
return newmsg;
}
/**
* message_set_id()
* sets the message-id field of this message.
* @param id a *disposable* long object wrapping the connection specific
* unique identifier of this message, or NULL if the message has not yet
* been sent. NOTE that the send process overwrites any value which might
* otherwise be set here.
*/
int message_set_id(etch_message* msg, etch_int64* id)
{
int result = 0;
if (!id) return -1;
/* id object ownership is relinquished here even if the call fails */
result = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->set_message_id(msg->vf, msg, id);
return result;
}
/**
* message_get_id()
* @return a non-disposable reference to the connection specific unique
* identifier of this message, or null if there was no such identifier.
*/
etch_int64* message_get_id(etch_message* msg)
{
etch_int64* id = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->get_message_id(msg->vf, msg);
return id;
}
/**
* message_get_in_reply_to()
* @return a non-disposable reference to the message-id of the message that
* this message is a response to, or null if this is an original message
* or if the original message did not have a message-id.
* caller does not own the returned object.
*/
etch_int64* message_get_in_reply_to(etch_message* msg)
{
/* vf returns to us a reference to its value */
etch_int64* id = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->get_in_reply_to(msg->vf, msg);
return id;
}
/**
* message_set_in_reply_to()
* sets the in-reply-to field of this message.
* @param msgid a *disposable* long object wrapping the message-id of the
* message that this message is a response to. note that caller must clone
* or otherwise supply a disposable object as this parameter.
*/
int message_set_in_reply_to(etch_message* msg, etch_int64* msgid)
{
int result = 0;
if (!msgid) return -1;
/* msgid ownership is relinquished here even if the call fails */
result = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->set_in_reply_to(msg->vf, msg, msgid);
return result;
}
/**
* message_size()
*/
int message_size (etch_message* msg)
{
return msg? structvalue_count(msg->sv): 0;
}
/* - - - - - - - - - - -
* etch_unwanted_message
* - - - - - - - - - - -
*/
/**
* destroy_unwanted_message()
* etch_unwanted_message destructor
*/
int destroy_unwanted_message(void* data)
{
etch_unwanted_message* msg = (etch_unwanted_message*)data;
if (msg->message != NULL && !is_etchobj_static_content(msg))
{
msg->message->sv->items->is_readonly_keys = 0;
msg->message->sv->items->is_readonly_values = 0;
etch_object_destroy(msg->message);
}
return destroy_objectex((etch_object*) msg);
}
/**
* new_unwanted_message()
* etch_unwanted_message constructor
* @param whofrom caller retains
* @param msg caller relinquishes
*/
etch_unwanted_message* new_unwanted_message(etch_who* whofrom, etch_message* msg)
{
etch_unwanted_message* newmsg = (etch_unwanted_message*) new_object
(sizeof(etch_unwanted_message), ETCHTYPEB_EVENT, CLASSID_EVENT_UNWANTMSG);
((etch_object*)newmsg)->destroy = destroy_unwanted_message;
((etch_object*)newmsg)->clone = clone_null;
newmsg->message = msg;
newmsg->whofrom = whofrom;
return newmsg;
}