| /* $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_defvalufact.c | |
| * default value factory from which all others inherit | |
| */ | |
| #include "etch_defvalufact.h" | |
| #include "etch_serializer.h" | |
| #include "etch_global.h" | |
| #include "etchutl.h" | |
| #include "etchmap.h" | |
| #include "etchlog.h" | |
| char* ETCHVALF = "VALF"; | |
| void etchvf_instantiate_builtins(); | |
| etch_type* defvf_add_type (default_value_factory*, etch_type*); | |
| etch_id_name* get_idname_by_id (etch_hashtable* map, const unsigned id); | |
| etch_type* defvf_get_type_by_id (default_value_factory*, const unsigned id); | |
| etch_type* defvf_get_type_by_name(default_value_factory*, const wchar_t* name); | |
| etch_type* defvf_get_type_by_name(default_value_factory*, const wchar_t* name); | |
| wchar_t* defvf_get_string_encoding (etch_value_factory*); | |
| etch_type* defvf_get_custom_struct_type (default_value_factory*, const unsigned); | |
| etch_int64* defvf_get_message_id (default_value_factory*, etch_message*); | |
| int defvf_set_message_id (default_value_factory*, etch_message*, etch_int64* id); | |
| etch_int64* defvf_get_in_reply_to (default_value_factory*, etch_message*); | |
| int defvf_set_in_reply_to (default_value_factory*, etch_message*, etch_int64* id); | |
| etch_type* defvf_get_mt_exception(default_value_factory*); | |
| etch_type* defvf_get_mt_rutime_exception(default_value_factory*); | |
| etch_type* defvf_get_mt_auth_exception(default_value_factory*); | |
| objmask* defvf_import_custom_value (default_value_factory*, etch_structvalue*); | |
| etch_structvalue* defvf_export_custom_value (default_value_factory*, objmask* value); | |
| etch_arraylist* new_vf_mixin_collection(default_value_factory*); | |
| etch_arraylist* defvf_get_types (default_value_factory*); | |
| int defvf_init_types(default_value_factory*, vf_idname_map*, class_to_type_map*); | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * constructors/destructors | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /** | |
| * new_default_value_factory() | |
| * constructor for default_value_factory | |
| * @param typemap the types map. if caller supplies this object, caller | |
| * retains ownership, unless vf.is_own_types flag is subsequently set false. | |
| * @param c2tmap the class to type map. if caller supplies this object, caller | |
| * retains ownership, unless vf.is_own_class_to_type flag is subsequently set false. | |
| */ | |
| default_value_factory* new_default_value_factory(vf_idname_map* typemap, | |
| class_to_type_map* c2tmap) | |
| { | |
| return new_default_value_factory_a(sizeof(default_value_factory), | |
| typemap, c2tmap); | |
| } | |
| /** | |
| * new_default_value_factory_a() | |
| * constructor for default_value_factory | |
| * @param objsize size of the object footprint in bytes. | |
| * @param typemap the types map. if caller supplies this object, caller | |
| * retains ownership, unless vf.is_own_types flag is subsequently set false. | |
| * @param c2tmap the class to type map. if caller supplies this object, caller | |
| * retains ownership, unless vf.is_own_class_to_type flag is subsequently set false. | |
| */ | |
| default_value_factory* new_default_value_factory_a(const int objsize, | |
| vf_idname_map* typemap, class_to_type_map* c2tmap) | |
| { | |
| i_value_factory* vtab; | |
| default_value_factory* newvf = (default_value_factory*) new_value_factory(objsize); | |
| newvf->destroy = destroy_default_value_factory; | |
| vtab = newvf->vtab; | |
| vtab->add_type = defvf_add_type; | |
| vtab->export_custom_value = defvf_export_custom_value; | |
| vtab->get_custom_struct_type= defvf_get_custom_struct_type; | |
| vtab->get_in_reply_to = defvf_get_in_reply_to; | |
| vtab->get_message_id = defvf_get_message_id; | |
| vtab->get_string_encoding = defvf_get_string_encoding; | |
| vtab->get_type_by_id = defvf_get_type_by_id; | |
| vtab->get_type_by_name = defvf_get_type_by_name; | |
| vtab->get_types = defvf_get_types; | |
| vtab->import_custom_value = defvf_import_custom_value; | |
| vtab->set_in_reply_to = defvf_set_in_reply_to; | |
| vtab->set_message_id = defvf_set_message_id; | |
| defvf_init_types(newvf, typemap, c2tmap); | |
| newvf->mixins = new_vf_mixin_collection(newvf); | |
| return newvf; | |
| } | |
| /** | |
| * destroy_default_value_factory() | |
| * destructor for default_value_factory | |
| */ | |
| int destroy_default_value_factory(default_value_factory* vf) | |
| { | |
| if (vf->refcount > 0 && --vf->refcount > 0) return -1; | |
| if (!is_etchobj_static_content(vf)) | |
| { | |
| if (vf->mixins) | |
| vf->mixins->destroy(vf->mixins); | |
| /* class_to_type map must be destroyed prior to types map | |
| * since class_to_type holds references to types map objects */ | |
| if (vf->is_own_class_to_type) | |
| vf->class_to_type->destroy(vf->class_to_type); | |
| if (vf->is_own_types) | |
| vf->types ->destroy(vf->types); | |
| if (vf->impl) /* inheritor's instance object */ | |
| vf->impl->destroy(vf->impl); | |
| } | |
| return destroy_objectex((objmask*) vf); | |
| } | |
| /** | |
| * defvf_init_types() | |
| * initialize a value factory object with fields and types. | |
| */ | |
| int defvf_init_types(default_value_factory* newvf, | |
| vf_idname_map* typemap, class_to_type_map* c2tmap) | |
| { | |
| etch_hashtable* c2t = NULL; | |
| if (typemap) | |
| newvf->types = typemap; | |
| else | |
| { newvf->types = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE); | |
| newvf->is_own_types = TRUE; | |
| } | |
| if (c2tmap) | |
| newvf->class_to_type = c2tmap; | |
| else | |
| { newvf->class_to_type = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE); | |
| newvf->is_own_class_to_type = TRUE; | |
| } | |
| etchvf_instantiate_builtins(); | |
| defvf_add_type(newvf, builtins._mt__etch_runtime_exception); | |
| defvf_add_type(newvf, builtins._mt__etch_auth_exception); | |
| defvf_add_type(newvf, builtins._mt__exception); | |
| defvf_add_type(newvf, builtins._mt__etch_list); | |
| defvf_add_type(newvf, builtins._mt__etch_map); | |
| defvf_add_type(newvf, builtins._mt__etch_set); | |
| defvf_add_type(newvf, builtins._mt__etch_datetime); | |
| c2t = newvf->class_to_type; | |
| etch_serializer_exception_init(builtins._mt__exception, c2t); | |
| etch_serializer_authxcp_init (builtins._mt__etch_auth_exception, c2t); | |
| etch_serializer_rtxcp_init (builtins._mt__etch_runtime_exception, c2t); | |
| etch_serializer_list_init (builtins._mt__etch_list,c2t); | |
| etch_serializer_map_init (builtins._mt__etch_map, c2t); | |
| etch_serializer_set_init (builtins._mt__etch_set, c2t); | |
| etch_serializer_date_init (builtins._mt__etch_datetime, c2t); | |
| return 0; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * vf class methods | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /** | |
| * defvf_add_type() | |
| * adds a type to set of types | |
| * @param type a non-disposable etch_type object | |
| * @return the effective type. if there was a name collision, the existing type | |
| * is returned in place of the supplied type, AND the supplied type is destroyed. | |
| * this simplifies logic up the line, and is consistent with caller expecting to | |
| * relinquish memory management of the type passed. | |
| */ | |
| etch_type* defvf_add_type (default_value_factory* vf, etch_type* type) | |
| { | |
| etch_type *effective_type = type; | |
| const int result = vf->types->vtab->inserth | |
| (vf->types->realtable, type, NULL, vf->types, 0); | |
| if (-1 == result) | |
| effective_type = defvf_get_type_by_name(vf, type->name); | |
| if (effective_type != type && NULL != effective_type) | |
| destroy_static_type(type); | |
| #ifdef ETCH_DEBUG_VF | |
| if (effective_type) | |
| wprintf(L"add type %08x '%s'\n", | |
| (size_t) (void*) effective_type, effective_type->name); | |
| else wprintf(L"error adding type '%s'\n", type->name); | |
| #endif | |
| return effective_type; | |
| } | |
| /** | |
| * get_idname_by_id() | |
| * given a id_name map and a numeric id, return the id_name for that key. | |
| * @return a non-disposable *reference*, not a copy, or null if not found. | |
| */ | |
| etch_id_name* get_idname_by_id (etch_hashtable* map, const unsigned id) | |
| { | |
| etch_iterator iterator; | |
| set_iterator(&iterator, map, &map->iterable); | |
| while(iterator.has_next(&iterator)) | |
| { | |
| etch_id_name* this_idname = (etch_id_name*) iterator.current_key; | |
| if (this_idname->id == id) return this_idname; | |
| iterator.next(&iterator); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * defvf_get_type_by_id() | |
| * @return a non-disposable reference to the type matching the supplied id, | |
| * or null if no match. all mixed-in vfs are recursed for a match. | |
| */ | |
| etch_type* defvf_get_type_by_id (default_value_factory* vf, const unsigned id) | |
| { | |
| etch_type* type = get_idname_by_id(vf->types, id); | |
| if (type) return type; | |
| if (vf->mixins->count) | |
| { | |
| etch_iterator iterator; | |
| set_iterator(&iterator, vf->mixins, &vf->mixins->iterable); | |
| while(iterator.has_next(&iterator)) | |
| { | |
| default_value_factory* mvf | |
| = (default_value_factory*) iterator.current_value; | |
| if (is_etch_valuefact(mvf) && (mvf != vf)) | |
| { | |
| type = defvf_get_type_by_id(mvf, id); | |
| if (type) return type; | |
| } | |
| iterator.next(&iterator); | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * get_idname_by_name() | |
| * given a id_name map and a name string, return the id_name for that name. | |
| * @return a non-disposable *reference*, not a copy, or null if not found. | |
| * recall that etch_type and etch_field each are typedefs of etch_id_name. | |
| */ | |
| etch_id_name* get_idname_by_name(etch_hashtable* map, const wchar_t* name) | |
| { | |
| etch_hashitem hashbucket, *thisitem = &hashbucket; | |
| const unsigned hash = etch_get_wchar_hashkey(name); | |
| const int result = map->vtab->findh(map->realtable, hash, map, &thisitem); | |
| return result == 0? (etch_id_name*) thisitem->key: NULL; | |
| } | |
| /** | |
| * etchtypemap_get_by_name() | |
| * given a type map and a name, looks up the type matching that name, | |
| * adding a new type to the map if no match was found. | |
| * @return a non-disposable reference to the type matching the supplied | |
| * name, or null if no match. | |
| */ | |
| etch_type* etchtypemap_get_by_name(etch_hashtable* map, const wchar_t* name) | |
| { | |
| etch_type* thistype = get_idname_by_name(map, name); | |
| if (NULL == thistype) | |
| { | |
| int result = map->vtab->inserth(map->realtable, | |
| thistype = new_type(name), NULL, map, 0); | |
| } | |
| return thistype; | |
| } | |
| /** | |
| * defvf_get_type_by_name() | |
| * searches vf and all mixed-in vfs for type matching specified name. | |
| * @return a non-disposable reference to the type corresponding to | |
| * specified name, or null if no match. | |
| */ | |
| etch_type* defvf_get_type_by_name (default_value_factory* vf, const wchar_t* name) | |
| { | |
| etch_type* type = get_idname_by_name(vf->types, name); | |
| if (type) return type; | |
| if (vf->mixins->count) | |
| { | |
| etch_iterator iterator; | |
| set_iterator(&iterator, vf->mixins, &vf->mixins->iterable); | |
| while(iterator.has_next(&iterator)) | |
| { | |
| default_value_factory* mvf | |
| = (default_value_factory*) iterator.current_value; | |
| if (is_etch_valuefact(mvf) && (mvf != vf)) | |
| { | |
| type = defvf_get_type_by_name(mvf, name); | |
| if (type) return type; | |
| } | |
| iterator.next(&iterator); | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * defvf_get_types() | |
| * @return a disposable arraylist of non-disposable references to all types | |
| * resident in this vf, and in all its mixed-in vfs. caller should invoke | |
| * the returned list's destructor, which will destroy the list shell. | |
| */ | |
| etch_arraylist* defvf_get_types (default_value_factory* vf) | |
| { | |
| etch_arraylist* typeslist = get_map_keys(vf->types); | |
| if (vf->mixins->count) | |
| { | |
| int newmixintypes = 0; | |
| etch_iterator iterator; | |
| set_iterator(&iterator, vf->mixins, &vf->mixins->iterable); | |
| while(iterator.has_next(&iterator)) | |
| { | |
| etch_arraylist* mvflist; | |
| default_value_factory* mvf | |
| = (default_value_factory*) iterator.current_value; | |
| if (is_etch_valuefact(mvf) && (mvf != vf)) | |
| { | |
| mvflist = get_map_keys(mvf->types); | |
| newmixintypes += arraylist_add_from | |
| (typeslist, mvflist, etchtypelist_comparator); | |
| mvflist->destroy(mvflist); | |
| } | |
| iterator.next(&iterator); | |
| } | |
| } | |
| return typeslist; /* caller must dispose */ | |
| } | |
| /** | |
| * defvf_get_string_encoding() | |
| * @returns a non-disposable reference to the encoding type | |
| */ | |
| wchar_t* defvf_get_string_encoding (etch_value_factory* vf) | |
| { | |
| return (wchar_t*) str_utf8; | |
| } | |
| /** | |
| * get_etch_string_encoding() | |
| * return etch code indicating current string encoding | |
| */ | |
| int get_etch_string_encoding(etch_value_factory* vf) | |
| { | |
| wchar_t* encoding = vf->vtab->get_string_encoding(vf); | |
| if (0 == wcscmp(encoding, L"utf-8")) return ETCH_ENCODING_UTF8; | |
| if (0 == wcscmp(encoding, L"utf-16")) return ETCH_ENCODING_UTF16; | |
| return ETCH_ENCODING_ASCII; | |
| } | |
| /** | |
| * defvf_get_custom_struct_type() | |
| * @return a non-disposable reference to the etch type type corresponding | |
| * to the specified class. invoked recursively via mixed in vfs. | |
| */ | |
| etch_type* defvf_get_custom_struct_type(default_value_factory* vf, | |
| const unsigned etchclass) | |
| { | |
| etch_type* type = (etch_type*) etchmap_find(vf->class_to_type, etchclass, 0); | |
| if (type) return type; | |
| if (vf->mixins->count) | |
| { | |
| etch_iterator iterator; | |
| set_iterator(&iterator, vf->mixins, &vf->mixins->iterable); | |
| while(iterator.has_next(&iterator)) | |
| { | |
| default_value_factory* mvf | |
| = (default_value_factory*) iterator.current_value; | |
| if (is_etch_valuefact(mvf) && (mvf != vf)) /* ensure no cycle */ | |
| { | |
| type = mvf->vtab->get_custom_struct_type(mvf, etchclass); | |
| if (type) break; | |
| } | |
| iterator.next(&iterator); | |
| } | |
| } | |
| return type; | |
| } | |
| /** | |
| * defvf_import_custom_value() | |
| * get helper method from the struct's type to import the custom value associated | |
| * with the type. if found, invoke the method to create the custom object. | |
| * @param sv the *disposable* raw key-value pairs read in by tdi, | |
| * from which to reconstruct the expected custom value object. | |
| * caller relinquishes ownership of this object regardless of outcome. | |
| * @return the *disposable* custom object, which must be cast by caller, or null. | |
| */ | |
| objmask* defvf_import_custom_value (default_value_factory* vf, etch_structvalue* sv) | |
| { | |
| objmask* custom_value = NULL; | |
| etch_serializer* impxhelper = etchtype_get_impexphelper(sv->struct_type); | |
| if (impxhelper) | |
| custom_value = impxhelper->import_value(impxhelper, (objmask*) sv); | |
| sv->destroy(sv); | |
| return custom_value; | |
| } | |
| /** | |
| * defvf_export_custom_value() | |
| * establishes the etch type of the custom struct to be exported to, gets the | |
| * export helper method from the type, and invokes that method to do the export. | |
| * @param value the custom value object to be exported to a struct for tdo. | |
| * caller retains ownership of this object. | |
| * @return the exported struct, or null. caller owns the returned struct. | |
| */ | |
| etch_structvalue* defvf_export_custom_value(default_value_factory* vf, objmask* value) | |
| { | |
| etch_type* custom_type = NULL; | |
| etch_serializer* impxhelper = NULL; | |
| etch_structvalue* exported_value = NULL; | |
| if (NULL == value) return NULL; | |
| custom_type = defvf_get_custom_struct_type(vf, ETCHOBJCLASS(value)); | |
| if (NULL == custom_type) | |
| { | |
| switch(value->obj_type) | |
| { | |
| case ETCHTYPEB_STRUCTVAL: | |
| custom_type = ((etch_structvalue*)value)->struct_type; | |
| break; | |
| case ETCHTYPEB_EXCEPTION: | |
| custom_type = builtins._mt__etch_runtime_exception; | |
| break; | |
| case ETCHTYPEB_ETCHLIST: | |
| custom_type = builtins._mt__etch_list; | |
| break; | |
| case ETCHTYPEB_ETCHMAP: | |
| custom_type = builtins._mt__etch_map; | |
| break; | |
| case ETCHTYPEB_ETCHSET: | |
| custom_type = builtins._mt__etch_set; | |
| break; | |
| } | |
| } | |
| /* fetch non-disposable helper object from custom type */ | |
| impxhelper = etchtype_get_impexphelper(custom_type); | |
| if (impxhelper && value) | |
| { /* export value object to struct */ | |
| exported_value = (etch_structvalue*) | |
| impxhelper->export_value(impxhelper, value); | |
| /* changed to not destroy value 6/23, since the tdo itself does not own | |
| * the value, and the export custom value is invoked from tdo write_value. */ | |
| /* value->destroy(value); */ | |
| } | |
| return exported_value; | |
| } | |
| /** | |
| * defvf_add_mixin() | |
| * add a mixed in value factory to this value factory. | |
| * @return 0 or -1. | |
| */ | |
| int defvf_add_mixin(default_value_factory* vf, etch_value_factory* mixedin_vf) | |
| { | |
| return arraylist_add(vf->mixins, mixedin_vf); | |
| } | |
| /** | |
| * defvf_get_message_id() | |
| * valuefactory.get_message_id() implementation. | |
| * @return a non-disposable reference to the etch_int64 id object, or null. | |
| */ | |
| etch_int64* defvf_get_message_id (default_value_factory* vf, etch_message* msg) | |
| { | |
| return (etch_int64*) message_get(msg, builtins._mf__message_id); | |
| } | |
| /** | |
| * message_get_id32() | |
| * get and return message id in 32 bits. used for debugging, logging, etc. | |
| */ | |
| unsigned message_get_id32 (etch_message* msg) | |
| { | |
| default_value_factory* vf = (default_value_factory*) msg->vf; | |
| etch_int64* id64 = (etch_int64*) message_get (msg, builtins._mf__message_id); | |
| const int id32 = id64? (unsigned) id64->value: 0; | |
| return id32; | |
| } | |
| /** | |
| * defvf_set_message_id() | |
| * valuefactory.set_message_id() implementation. | |
| * @param id a *disposable* etch_int64* wrapping the message id. | |
| * regardless of outcome, caller relinquishes ownership of this object. | |
| * @return 0 or -1. | |
| */ | |
| int defvf_set_message_id (default_value_factory* vf, etch_message* msg, etch_int64* id) | |
| { | |
| return message_put(msg, clone_field(builtins._mf__message_id), (objmask*) id); | |
| } | |
| /** | |
| * defvf_get_in_reply_to() | |
| * gets the id of the message to which this message is a reply. | |
| * returns a non-disposable reference to an etch_int64*, not a copy, or null. | |
| */ | |
| etch_int64* defvf_get_in_reply_to (default_value_factory* vf, etch_message* msg) | |
| { | |
| return (etch_int64*) message_get(msg, builtins._mf__in_reply_to); | |
| } | |
| /** | |
| * defvf_set_in_reply_to() | |
| * sets the id of the message to which this message is a reply. | |
| * @param id a *disposable* etch_int64* wrapping the message id. | |
| * regardless of outcome, caller relinquishes ownership of this object. | |
| * @return 0 or -1. | |
| */ | |
| int defvf_set_in_reply_to (default_value_factory* vf, etch_message* msg, etch_int64* id) | |
| { | |
| return message_put (msg, clone_field(builtins._mf__in_reply_to), (objmask*) id); | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * vf types collection | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /* | |
| * defvf_typescollection_clear_handler() | |
| * callback set to handle freeing of key memory during a clear() of the vf | |
| * types collection. such a map owns its content, which consists of both builtin | |
| * types, which are marked static, and of user types, which are generally not | |
| * marked static. the type's destructor is invoked here; however the destructor | |
| * will take no action on the static types (these being freed later when the | |
| * builtins are destroyed. those types which are added as a result of a runtime | |
| * get() call, e.g., etchtypemap_get_by_name(vf->types, L"my_newtype"), | |
| * are not marked static and so will be destroyed with this map. | |
| */ | |
| int defvf_typescollection_clear_handler (objmask* key, objmask* value) | |
| { | |
| #if(0) | |
| etch_type* type = (etch_type*) key; | |
| if (is_etchobj_static_shell(type)) | |
| wprintf(L"vf types map NOT destroying %s\n", type->name); | |
| else wprintf(L"vf types map destroying %s\n", type->name); | |
| fflush(stdout); | |
| #endif | |
| key->destroy(key); /* see comments above re static and nonstatic types */ | |
| return TRUE; | |
| } | |
| /** | |
| * new_vf_types_collection() | |
| * return a hashtable configured as expected for a set of types | |
| */ | |
| etch_set* new_vf_types_collection(const int initialsize) | |
| { | |
| etch_set* map = new_set(initialsize); | |
| map->content_obj_type = ETCHTYPEB_TYPE; | |
| map->content_class_id = CLASSID_ID_TYPE; | |
| map->freehook = defvf_typescollection_clear_handler; | |
| return map; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * vf_idname_map | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /* | |
| * defvf_idnmap_clear_handler() | |
| * callback set to handle freeing of key memory during a clear() of a vf | |
| * id_name map. map keys are etch_field owned by the map. however the map does | |
| * not know how to destroy such a key so we handle that here. values in this | |
| * map are etch_type owned elsewhere (presumably quasi-static built-in types). | |
| */ | |
| int defvf_idnmap_clear_handler (objmask* key, objmask* value) | |
| { | |
| #ifdef ETCH_DEBUG_VF | |
| etch_id_name* idn = (etch_id_name*) key; | |
| wprintf(L"destroy idn %08x '%s'\n", (size_t) (void*) key, idn->name); | |
| #endif | |
| key->destroy(key); | |
| return TRUE; | |
| } | |
| /** | |
| * new_vf_idname_map() | |
| * return a hashtable configured as expected for a vf | |
| * todo lose this method and the clear handler we don't use it | |
| */ | |
| etch_hashtable* new_vf_idname_map(const int initialsize) | |
| { | |
| etch_hashtable* map = new_hashtable(initialsize); | |
| map->is_tracked_memory = TRUE; | |
| map->is_readonly_keys = FALSE; /* keys are etch_field* owned by the map */ | |
| map->is_readonly_values = FALSE; /* values are etch_type* owned elsewhere */ | |
| map->content_type = ETCHHASHTABLE_CONTENT_OBJECT; | |
| map->content_obj_type = ETCHTYPEB_TYPE; | |
| map->content_class_id = CLASSID_ID_TYPE; | |
| map->freehook = defvf_idnmap_clear_handler; /* key memory free hook */ | |
| return map; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * class_to_type_map | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /** | |
| * class_to_type_map_put() | |
| * put the specified type to the supplied map, keyed by specified class. | |
| * the map does not own the specified type object. | |
| * @return 0 or -1; | |
| */ | |
| int class_to_type_map_put(class_to_type_map* map, const unsigned thisclass, | |
| etch_type* type) | |
| { | |
| int hashvalue = etchmap_insert (map, thisclass, type, TRUE); | |
| return hashvalue? 0: -1; | |
| } | |
| /** | |
| * class_to_type_map_get() | |
| * get the type associated with the specified class from the supplied map. | |
| * @return a non-disposable reference to the matching type, or null. | |
| */ | |
| etch_type* class_to_type_map_get(class_to_type_map* map, const unsigned thisclass) | |
| { | |
| etch_type* foundobj = (etch_type*) etchmap_find (map, thisclass, NULL); | |
| return foundobj; | |
| } | |
| /** | |
| * new_class_to_type_map() | |
| * class_to_type_map constructor. | |
| * such a map associates a "class", which in this context is a 32-bit unsigned | |
| * integer whose high 16 bits is the etch object obj_type, and the low 16 bits | |
| * the etch object class_id, to an etch_type. | |
| */ | |
| class_to_type_map* new_class_to_type_map(const int initialsize) | |
| { | |
| /* this map calls no etch destructors when destroyed. the key strings are | |
| * freed automatically by the etch_hashtable, and the values are pointers | |
| * to etch_type objects owned elsewhere. it obviously follows that this | |
| * map should be destroyed prior to any such referenced type object. | |
| */ | |
| class_to_type_map* map = new_hashtable(initialsize); | |
| map->is_tracked_memory = TRUE; | |
| map->is_readonly_keys = TRUE; /* keys are strings owned by the hashtable */ | |
| map->is_readonly_values = TRUE; /* values are non-disposable etch_type* */ | |
| map->content_type = ETCHHASHTABLE_CONTENT_OBJECT; | |
| map->content_obj_type = ETCHTYPEB_TYPE; | |
| map->content_class_id = CLASSID_ID_TYPE; | |
| return map; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - - - - | |
| * built-in (etch-global, quasi-static) objects | |
| * - - - - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /* these objects are global to all vfs. | |
| * for each such object, a corresponding entry should exist both in | |
| * etchvf_instantiate_builtins(), and in etchvf_free_builtins() | |
| */ | |
| const wchar_t* str_etch_runtime_exception = L"_Etch_RuntimeException"; | |
| const wchar_t* str_etch_auth_exception = L"_Etch_AuthException"; | |
| const wchar_t* str_exception = L"_exception"; | |
| const wchar_t* str_etch_list = L"_Etch_List"; | |
| const wchar_t* str_etch_map = L"_Etch_Map"; | |
| const wchar_t* str_etch_set = L"_Etch_Set"; | |
| const wchar_t* str_etch_datetime = L"_Etch_Datetime"; | |
| const wchar_t* str_msg = L"msg"; | |
| const wchar_t* str_message_id = L"_messageId"; | |
| const wchar_t* str_in_reply_to = L"_inReplyTo"; | |
| const wchar_t* str_result = L"result"; | |
| const wchar_t* str_utf8 = L"utf-8"; | |
| const wchar_t* str_keys = L"keys"; | |
| const wchar_t* str_values = L"values"; | |
| const wchar_t* str_date_time = L"dateTime"; | |
| const wchar_t* str_keys_values = L"keys_values"; | |
| const wchar_t* str_msgizervf = L"Messagizer.valueFactory"; | |
| const wchar_t* str_msgizerfmt = L"Messagizer.format"; | |
| /* | |
| * etchvf_free_builtins() | |
| * frees memory for etch-global quasi-static builtin objects, | |
| * and for the validators cache and its validator content. | |
| * it should be invoked at etch teardown, after last vf is destroyed. | |
| * unit tests will show memory leaks unless they invoke this post-test. | |
| */ | |
| void etchvf_free_builtins() | |
| { | |
| if (is_builtins_instantiated) | |
| { | |
| destroy_static_type(builtins._mt__etch_runtime_exception); | |
| destroy_static_type(builtins._mt__etch_auth_exception); | |
| destroy_static_type(builtins._mt__exception); | |
| destroy_static_type(builtins._mt__etch_list); | |
| destroy_static_type(builtins._mt__etch_map); | |
| destroy_static_type(builtins._mt__etch_set); | |
| destroy_static_type(builtins._mt__etch_datetime); | |
| destroy_static_field(builtins._mf_msg); | |
| destroy_static_field(builtins._mf_result); | |
| destroy_static_field(builtins._mf__message_id); | |
| destroy_static_field(builtins._mf__in_reply_to); | |
| } | |
| etchvtor_clear_cache(); /* destroy cached validators */ | |
| is_builtins_instantiated = FALSE; | |
| } | |
| /** | |
| * etchvf_instantiate_builtins() | |
| * instantiate built-in objects such as default types and fields. | |
| * these singleton objects are destroyed explicitly by invoking | |
| * etchvf_free_builtins(). | |
| * todo: mark these objects immutable and unmark in destructor. | |
| * todo: determine how we handle case of multiple vfs. | |
| */ | |
| void etchvf_instantiate_builtins() | |
| { | |
| if (is_builtins_instantiated) return; | |
| builtins._mt__etch_runtime_exception = new_static_type(str_etch_runtime_exception); | |
| builtins._mt__etch_auth_exception = new_static_type(str_etch_auth_exception); | |
| builtins._mt__exception = new_static_type(str_exception); | |
| builtins._mt__etch_list = new_static_type(str_etch_list); | |
| builtins._mt__etch_map = new_static_type(str_etch_map); | |
| builtins._mt__etch_set = new_static_type(str_etch_set); | |
| builtins._mt__etch_datetime = new_static_type(str_etch_datetime); | |
| builtins._mf_msg = new_static_field(str_msg); | |
| builtins._mf_result = new_static_field(str_result); | |
| builtins._mf__message_id = new_static_field(str_message_id); | |
| builtins._mf__in_reply_to = new_static_field(str_in_reply_to); | |
| etchtype_put_validator(builtins._mt__exception, | |
| clone_field(builtins._mf_result), (objmask*) etchvtor_exception_get()); | |
| etchtype_put_validator(builtins._mt__exception, | |
| clone_field(builtins._mf__message_id), (objmask*) etchvtor_int64_get(0)); | |
| etchtype_put_validator(builtins._mt__exception, | |
| clone_field(builtins._mf__in_reply_to),(objmask*) etchvtor_int64_get(0)); | |
| is_builtins_instantiated = TRUE; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - | |
| * other methods | |
| * - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /** | |
| * etchtypelist_comparator() | |
| * etch_comparator comparing two etch_types | |
| * hook for arraylist_add_from to determine if a type from list b | |
| * already exists in list a. | |
| */ | |
| int etchtypelist_comparator(void* a, void* b) | |
| { | |
| return a && b && (((etch_type*)a)->id == ((etch_type*)b)->id); | |
| } | |
| /** | |
| * new_vf_mixin_collection() | |
| * instantiate and return a collection configured appropriately for the | |
| * storage of value factory objects of mixed-in classes. | |
| */ | |
| etch_arraylist* new_vf_mixin_collection(default_value_factory* vf) | |
| { | |
| etch_arraylist* list = new_arraylist(ETCH_DEVVF_MIXINS_DEFINITSIZE, 0); | |
| list->content_type = ETCHARRAYLIST_CONTENT_OBJECT; | |
| list->is_readonly = TRUE; /* list dtor will not destroy list content */ | |
| list->content_obj_type = vf->obj_type; | |
| list->content_class_id = vf->class_id; | |
| return list; | |
| } | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| * serializable exception tossing | |
| * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| */ | |
| /** | |
| * message_throw() | |
| * instantiate a serializable exception object from the exception indicated by | |
| * the specified parameters, and add that exception to the specified message. | |
| * @param msg the message. | |
| * @param xtype type of exception, excptype enumeration. | |
| * @param xtext the exception text, caller retains. | |
| * @return 0 success, -1 failure. | |
| */ | |
| int message_throw (etch_message* msg, excptype xtype, wchar_t* xtext) | |
| { | |
| int result = 0; | |
| etch_exception* excpobj = NULL; | |
| if (NULL == msg) return -1; | |
| excpobj = new_etch_exception (xtype, xtext, ETCHEXCP_COPYTEXT); | |
| result = message_put (msg, clone_field(builtins._mf_result), (objmask*) excpobj); | |
| return result; | |
| } | |
| /** | |
| * message_throw_from() | |
| * instantiate a serializable exception object from the exception in the | |
| * specified etch object, and add that exception to the specified message. | |
| * @param msg the message. | |
| * @param obj the object wrapping the exception, or which is the exception, | |
| * caller retains. | |
| * @return 0 success, -1 failure. | |
| */ | |
| int message_throw_from (etch_message* msg, objmask* obj) | |
| { | |
| etchexception* x = get_exception_from (obj); | |
| if (NULL == x) return NULL; | |
| return message_throw (msg, x->excptype, x->excptext); | |
| } | |