blob: ca0790c9ac924bc522ec6b7405d97017d94b4079 [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_structval.c -- etch_structvalue implementation.
*/
#include "etch_runtime.h"
#include "etch_structval.h"
#include "etch_validator.h"
#include "etch_encoding.h"
#include "etch_exception.h"
#include "etch_map.h"
#include "etch_log.h"
#include "etch_objecttypes.h"
#include "etch_mem.h"
char* ETCHSVAL = "SVAL";
etch_structvalue* new_structvalue_init();
/*
* structvalue_clear_handler()
* this callback is set to handle freeing of key and value memory during a clear()
* of the structvalue map. structs own all their memory, so if there is a problem
* here, it should be resolved at the source, not by modifying this code.
*/
int structvalue_clear_handler (void* data1, void* data2)
{
etch_field* key = (etch_field*)data1;
etch_object* value = (etch_object*)data2;
etch_object_destroy(value);
destroy_field(key);
return TRUE;
}
/**
* new_structvalue()
* primary constructor for etch_structvalue.
* @param etch_type object, caller retains ownership of the type as usual
*/
etch_structvalue* new_structvalue(etch_type* type, const int initialsize)
{
etch_structvalue* newobj = new_structvalue_init(initialsize);
newobj->struct_type = type;
return newobj;
}
/**
* destroy_structvalue()
* destructor for an etch_structvalue object
*
* a structvalue owns all its memory *except* its type object, which is global
* to the vf. this means that (a) the etch_type supplied on construction must be
* a reference to a type owned by the service vf (or the unit test); and (b) all
* struct keys must be etch_field* allocated on the heap and not referenced again
* outside of that structvalue scope; and (c) all struct values must be etch object
* references allocated on the heap and not referenced again outside of the
* structvalue scope.
*/
int destroy_structvalue(void* data)
{
etch_structvalue* thisp = (etch_structvalue*)data;
if (NULL == thisp) return 0;
if (!is_etchobj_static_content(thisp)){
etch_object_destroy(thisp->items);
thisp->items = NULL;
}
/* see comments above as to why we don't destroy type */
destroy_objectex((etch_object*)thisp);
return 0;
}
/**
* new_structvalue_init() (private)
* common initialization on etch_structvalue construction.
*/
etch_structvalue* new_structvalue_init(const int initialsize)
{
etch_structvalue* newobj = etch_malloc(sizeof(etch_structvalue), ETCHTYPEB_STRUCTVAL);
memset(newobj, 0, sizeof(etch_structvalue));
((etch_object*)newobj)->obj_type = ETCHTYPEB_STRUCTVAL;
((etch_object*)newobj)->class_id = CLASSID_STRUCTVALUE; /* for now anyway */
((etch_object*)newobj)->destroy = destroy_structvalue;
((etch_object*)newobj)->clone = clone_null;
newobj->items = new_structvalue_hashtable(initialsize);
/* mark map such that it knows its keys and values are etch objects */
newobj->items->content_type = ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
return newobj;
}
/*
* new_structvalue_hashtable
* create the backing store for a struct value
*/
etch_hashtable* new_structvalue_hashtable(const int initialsize)
{
etch_hashtable* ht = new_hashtable(initialsize);
if (ht == NULL) return NULL;
ht->content_type = ETCH_STRUCT_DEFAULT_CONTENT_TYPE;
ht->is_tracked_memory = ETCH_STRUCT_DEFAULT_TRACKED_MEM;
ht->is_readonly_keys = ETCH_STRUCT_DEFAULT_READONLY_KEY;
ht->is_readonly_values = ETCH_STRUCT_DEFAULT_READONLY_VAL;
ht->freehook = structvalue_clear_handler;
return ht;
}
/**
* structvalue_put()
* inserts (or removes) specified key/value pair to/from struct store.
* @param key an etch_field whose destructor will be invoked when the struct is
* destroyed. presumably this etch_field is disposable; if not, the object must
* be marked as immutable using set_etchobj_static_all.
* @param value a *disposable* object which is the value of the key/val pair.
* this object's destructor will be invoked when the struct is destroyed.
* presumably this object and its content are disposable; if not, the object must
* be marked accordingly using set_etchobj_static_all or set_etchobj_static_content.
* returns 0 or -1.
*/
int structvalue_put(etch_structvalue* thisp, etch_field* key, etch_object* value)
{
etch_config_t* config = NULL;
int32 propvalue = 0;
etch_hashtable* map = NULL;
etch_runtime_get_config(&config);
ETCH_ASSERT(config);
map = thisp->items;
if (NULL == key) return -1;
if (NULL == value) /* per contract, no value implies removal desired */
return ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh (map->realtable, ((etch_object*)key)->get_hashkey(key), key, 0);
etch_config_get_property_int(config, "etch.validate.write", &propvalue);
if(propvalue == 1) {
etch_type* thistype = thisp->struct_type;
char *errmsg = NULL;
etch_validator* vtor = (etch_validator*)
etchtype_get_validator_by_name(thistype, key->name);
if (NULL == vtor)
errmsg = "validator missing";
else
if (0 != vtor->validate (vtor, (etch_object*) value))
errmsg = "validation failed";
if (errmsg)
{ ETCH_LOG(ETCHSVAL, ETCH_LOG_ERROR, "%s for type '%s' field '%s'\n", errmsg, thistype->aname, key->aname);
return -1;
}
}
return ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth (map->realtable, key, value, map, 0);
}
/**
* structvalue_get()
* access an element from the struct.
* returns a reference not a copy.
*/
etch_object* structvalue_get (etch_structvalue* thisp, etch_field* key)
{
int result = 0;
etch_hashitem hashbucket;
etch_hashitem* thisitem = &hashbucket;
etch_hashtable* map = thisp? thisp->items: NULL;
if (NULL == map) return NULL;
result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, ((etch_object*)key)->get_hashkey(key), map, (void**)&thisitem);
return result == 0? thisitem->value: NULL;
}
/**
* structvalue_remove
* removes an element from the struct, returning the element.
* if the element is found, its key is destroyed, and the object is returned.
* caller owns returned object.
*/
etch_object* structvalue_remove(etch_structvalue* thisp, etch_field* key)
{
int result = 0;
etch_hashitem hashbucket;
etch_hashitem* thisitem = &hashbucket;
etch_hashtable* map = thisp? thisp->items: NULL;
memset(thisitem,0,sizeof(etch_hashitem));
if (NULL == map) return NULL;
/* remove specified item from hashtable without destroying content */
result = ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh(map->realtable, ((etch_object*)key)->get_hashkey(key), map, (void**)&thisitem);
if (-1 == result) return NULL;
/* free entry key */
if (thisitem->key)
if (etchmap_is_object_key(map))
((etch_object*)thisitem->key)->destroy(thisitem->key);
else etch_free(thisitem->key);
return (etch_object*) thisitem->value;
}
/**
* structvalue_is_type()
* indicates if type of this struct is the same as the specified type
*/
int structvalue_is_type(etch_structvalue* thisp, etch_type* type)
{
return is_equal_types(thisp->struct_type, type);
}
/**
* structvalue_count()
* returns number of pairs in the struct
*/
int structvalue_count(etch_structvalue* sv)
{
return etchmap_count(sv->items);
}