// $Id$ #include "orbsvcs/Trader/Service_Type_Repository.h" #include "ace/Lock_Adapter_T.h" ACE_RCSID (Trader, Service_Type_Repository, "$Id$") TAO_BEGIN_VERSIONED_NAMESPACE_DECL TAO_Service_Type_Repository:: TAO_Service_Type_Repository (ACE_Lock* lock) : lock_ (lock) { this->incarnation_.low = 0; this->incarnation_.high = 0; // If a lock wasn't provided, let's assume the user doesn't want any // kind of lock at all. if (this->lock_ == 0) ACE_NEW (this->lock_, ACE_Lock_Adapter); } TAO_Service_Type_Repository::~TAO_Service_Type_Repository (void) { { // Make sure not to throw exceptions in destructors... ACE_WRITE_GUARD (ACE_Lock, ace_mon, *this->lock_); for (Service_Type_Map_Iterator service_map_iterator (this->type_map_); service_map_iterator.done () == 0; service_map_iterator++) { Type_Info *type_info = (*service_map_iterator).int_id_; delete type_info; } } delete this->lock_; } CosTradingRepos::ServiceTypeRepository::IncarnationNumber TAO_Service_Type_Repository::incarnation (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) ACE_THROW_SPEC ((CORBA::SystemException)) { CosTradingRepos::ServiceTypeRepository::IncarnationNumber inc_num; if (this->lock_->acquire_read () == -1) { inc_num = this->incarnation_; this->lock_->release (); } else { inc_num.high = 0; inc_num.low = 0; } return inc_num; } CosTradingRepos::ServiceTypeRepository::IncarnationNumber TAO_Service_Type_Repository:: add_type (const char *name, const char *if_name, const CosTradingRepos::ServiceTypeRepository::PropStructSeq &props, const CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq &super_types ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTradingRepos::ServiceTypeRepository::ServiceTypeExists, CosTradingRepos::ServiceTypeRepository::InterfaceTypeMismatch, CosTrading::IllegalPropertyName, CosTrading::DuplicatePropertyName, CosTradingRepos::ServiceTypeRepository::ValueTypeRedefinition, CosTrading::UnknownServiceType, CosTradingRepos::ServiceTypeRepository::DuplicateServiceTypeName)) { Prop_Map prop_map; Service_Type_Map super_map; CosTradingRepos::ServiceTypeRepository::IncarnationNumber inc_num; inc_num.low = 0; inc_num.high = 0; // With exceptions enabled, inc_num isn't used. ACE_UNUSED_ARG (inc_num); ACE_WRITE_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); ACE_CHECK_RETURN (inc_num); // Make sure Type name is valid. if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW_RETURN (CosTrading::IllegalServiceType (name), this->incarnation_); // Check if the service type already exists. TAO_String_Hash_Key type_name (name); if (this->type_map_.find (type_name) == 0) ACE_THROW_RETURN (CosTradingRepos::ServiceTypeRepository::ServiceTypeExists (), this->incarnation_); // Make sure all property names are valid and appear only once. this->validate_properties (prop_map, props ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (this->incarnation_); // Check that all super_types exist, and none are duplicated. this->validate_supertypes (super_map, super_types ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (this->incarnation_); // NOTE: I don't really know a way to do this without an Interface // Repository, since the Interface Repository IDs don't contain // information about supertypes. // // make sure interface name is legal. // this->validate_interface (if_name, super_types ACE_ENV_ARG_PARAMETER); // ACE_CHECK_RETURN (this->incarnation); // // Instead, we do this: // if (if_name == 0) ACE_THROW_RETURN (CosTradingRepos::ServiceTypeRepository::InterfaceTypeMismatch (), this->incarnation_); // Collect and make sure that properties of all supertypes and this // type are compatible. We can use prop_map and super_types_map for // the job. this->validate_inheritance (prop_map, super_types ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (this->incarnation_); // We can now use prop_map to construct a sequence of all properties // the this type. this->update_type_map (name, if_name, props, super_types, prop_map, super_map); CosTradingRepos::ServiceTypeRepository::IncarnationNumber return_value = this->incarnation_; // Increment incarnation number. this->incarnation_.low++; // If we wrapped around in lows... if (this->incarnation_.low == 0) this->incarnation_.high++; return return_value; } void TAO_Service_Type_Repository::remove_type (const char *name ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTrading::UnknownServiceType, CosTradingRepos::ServiceTypeRepository::HasSubTypes)) { if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW (CosTrading::IllegalServiceType (name)); ACE_WRITE_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); ACE_CHECK; // Check if the type exists. Service_Type_Map::ENTRY* type_entry = 0; ; if (this->type_map_.find (name, type_entry) == -1) ACE_THROW (CosTrading::UnknownServiceType (name)); // Check if it has any subtypes. Type_Info *type_info = type_entry->int_id_; if (type_info->has_subtypes_) ACE_THROW (CosTradingRepos::ServiceTypeRepository::HasSubTypes (name, "")); // Remove the type from the map. this->type_map_.unbind (type_entry); delete type_info; } CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq * TAO_Service_Type_Repository:: list_types (const CosTradingRepos::ServiceTypeRepository::SpecifiedServiceTypes &which_types ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { ACE_READ_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); ACE_CHECK_RETURN (0); CORBA::ULong i = 0; CORBA::ULong length = static_cast (this->type_map_.current_size ()); CosTrading::ServiceTypeName *types = CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq::allocbuf (length); if (types == 0) return 0; int all = which_types._d () == CosTradingRepos::ServiceTypeRepository::all; CosTradingRepos::ServiceTypeRepository::IncarnationNumber num = which_types.incarnation (); for (Service_Type_Map_Iterator itr (this->type_map_); itr.done () == 0; itr++) { Type_Info* type_info = (*itr).int_id_; const char* type_name = (*itr).ext_id_.in (); if (all || num < type_info->type_struct_.incarnation) types[i++] = CORBA::string_dup (type_name); } CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq *tmp = 0; ACE_NEW_RETURN (tmp, CosTradingRepos::ServiceTypeRepository:: ServiceTypeNameSeq (length, i, types, 1), 0); return tmp; } CosTradingRepos::ServiceTypeRepository::TypeStruct * TAO_Service_Type_Repository:: describe_type (const char * name ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTrading::UnknownServiceType)) { if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW_RETURN (CosTrading::IllegalServiceType (name), (CosTradingRepos::ServiceTypeRepository::TypeStruct *) 0); ACE_READ_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); ACE_CHECK_RETURN (0); // Make sure the type exists. TAO_String_Hash_Key type_name (name); Service_Type_Map::ENTRY *type_entry = 0; if (this->type_map_.find (type_name, type_entry) == -1) ACE_THROW_RETURN (CosTrading::UnknownServiceType (name), (CosTradingRepos::ServiceTypeRepository::TypeStruct *) 0); // Return appropriate information about the type. CosTradingRepos::ServiceTypeRepository::TypeStruct *descr = 0; ACE_NEW_RETURN (descr, CosTradingRepos::ServiceTypeRepository::TypeStruct, 0); CosTradingRepos::ServiceTypeRepository::TypeStruct &s = type_entry->int_id_->type_struct_; descr->if_name = s.if_name; descr->masked = s.masked; descr->incarnation = s.incarnation; descr->super_types = s.super_types; descr->props = s.props; /* CORBA::ULong length = s.props.length (); CosTradingRepos::ServiceTypeRepository::PropStruct* pstructs = s.props.get_buffer (0); descr->props.replace (length, length, pstructs, 0); */ return descr; } CosTradingRepos::ServiceTypeRepository::TypeStruct * TAO_Service_Type_Repository:: fully_describe_type (const char *name ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTrading::UnknownServiceType)) { if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW_RETURN (CosTrading::IllegalServiceType (name), 0); ACE_READ_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); ACE_CHECK_RETURN (0); // Make sure the type exists. TAO_String_Hash_Key type_name (name); Service_Type_Map::ENTRY *type_entry = 0; if (this->type_map_.find (type_name, type_entry) == -1) ACE_THROW_RETURN (CosTrading::UnknownServiceType (name), 0); // Return appropriate information about the type. CosTradingRepos::ServiceTypeRepository::TypeStruct *descr = 0; ACE_NEW_RETURN (descr, CosTradingRepos::ServiceTypeRepository::TypeStruct, 0); CosTradingRepos::ServiceTypeRepository::TypeStruct &s = type_entry->int_id_->type_struct_; // Aggregate the Properties of this type and all its supertypes. // Compute the transitive closure of all supertypes. this->fully_describe_type_i (s, descr->props, descr->super_types); // We do the explicit copy, since otherwise we'd have excessive // properties copying. descr->if_name = s.if_name; descr->masked = s.masked; descr->incarnation = s.incarnation; return descr; } void TAO_Service_Type_Repository:: mask_type (const char *name ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTrading::UnknownServiceType, CosTradingRepos::ServiceTypeRepository::AlreadyMasked)) { if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW (CosTrading::IllegalServiceType (name)); ACE_WRITE_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); // Make sure the type exists. TAO_String_Hash_Key type_name (name); Service_Type_Map::ENTRY *type_entry = 0; if (this->type_map_.find (type_name, type_entry) != -1) ACE_THROW (CosTrading::UnknownServiceType (name)); // Make sure the type is unmasked. CORBA::Boolean &mask = type_entry->int_id_->type_struct_.masked; if (mask == 1) ACE_THROW (CosTradingRepos::ServiceTypeRepository::AlreadyMasked (name)); else mask = 1; } void TAO_Service_Type_Repository:: unmask_type (const char *name ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosTrading::IllegalServiceType, CosTrading::UnknownServiceType, CosTradingRepos::ServiceTypeRepository::NotMasked)) { if (TAO_Trader_Base::is_valid_identifier_name (name) == 0) ACE_THROW (CosTrading::IllegalServiceType (name)); ACE_WRITE_GUARD_THROW_EX (ACE_Lock, ace_mon, *this->lock_, CORBA::INTERNAL ()); // Make sure the type exists. TAO_String_Hash_Key type_name (name); Service_Type_Map::ENTRY *type_entry = 0; if (this->type_map_.find (type_name, type_entry) != -1) ACE_THROW (CosTrading::UnknownServiceType (name)); // Make sure the type is masked. CORBA::Boolean &mask = type_entry->int_id_->type_struct_.masked; if (mask == 0) ACE_THROW (CosTradingRepos::ServiceTypeRepository::NotMasked (name)); else mask = 0; } void TAO_Service_Type_Repository:: fully_describe_type_i (const CosTradingRepos::ServiceTypeRepository::TypeStruct &type_struct, CosTradingRepos::ServiceTypeRepository::PropStructSeq &props, CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq &super_types) { TAO_String_Queue service_type_queue; this->collect_inheritance_hierarchy (type_struct, service_type_queue); // Count the total number of properties. CORBA::ULong num_props = 0; CORBA::ULong num_types = static_cast (service_type_queue.size ()); TAO_String_Queue::ITERATOR iterator (service_type_queue); for (; iterator.done () == 0; iterator.advance ()) { char **next_type_name = 0; Service_Type_Map::ENTRY *type_entry = 0; iterator.next (next_type_name); TAO_String_Hash_Key hash_key (const_cast (*next_type_name)); this->type_map_.find (hash_key, type_entry); CosTradingRepos::ServiceTypeRepository::TypeStruct &tstruct = type_entry->int_id_->type_struct_; num_props += tstruct.props.length (); } num_props += type_struct.props.length (); props.length (num_props); super_types.length (num_types); // Copy in all properties. int i = 0; CORBA::ULong prop_index = 0; CORBA::ULong type_index = 0; for (i = type_struct.props.length () - 1; i >= 0; i--) props[prop_index++] = type_struct.props[i]; for (iterator.first (); iterator.done () == 0; iterator.advance ()) { char **next_type_name = 0; Service_Type_Map::ENTRY *type_entry = 0; iterator.next (next_type_name); TAO_String_Hash_Key hash_key (const_cast (*next_type_name)); this->type_map_.find (hash_key, type_entry); // Should never be zero. if (type_entry != 0) { CosTradingRepos::ServiceTypeRepository::TypeStruct& tstruct = type_entry->int_id_->type_struct_; for (i = tstruct.props.length () - 1; i >= 0; i--) props[prop_index++] = tstruct.props[i]; super_types[type_index++] = hash_key.in (); } } } void TAO_Service_Type_Repository:: collect_inheritance_hierarchy (const CosTradingRepos::ServiceTypeRepository::TypeStruct &type_struct, TAO_String_Queue &target) { // Recurse for each super_type for (int i = type_struct.super_types.length () - 1; i >= 0; i--) { Service_Type_Map::ENTRY *next_type_entry = 0; TAO_String_Hash_Key next_type_name (type_struct.super_types[i]); if (this->type_map_.find (next_type_name, next_type_entry) != -1) { CosTradingRepos::ServiceTypeRepository::TypeStruct &next_type_struct = next_type_entry->int_id_->type_struct_; const char *type_name = type_struct.super_types[i]; target.enqueue_tail (const_cast (type_name)); this->collect_inheritance_hierarchy (next_type_struct, target); } } } void TAO_Service_Type_Repository:: validate_properties (Prop_Map &prop_map, const CosTradingRepos::ServiceTypeRepository::PropStructSeq &props ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CosTrading::IllegalPropertyName, CosTrading::DuplicatePropertyName)) { for (CORBA::ULong i = 0; i < props.length (); i++) { const char *n = props[i].name; if (TAO_Trader_Base::is_valid_property_name (n) == 0) ACE_THROW (CosTrading::IllegalPropertyName (n)); else { TAO_String_Hash_Key prop_name (n); CosTradingRepos::ServiceTypeRepository::PropStruct *prop_val = const_cast (&props[i]); if (prop_map.bind (prop_name, prop_val) == 1) ACE_THROW (CosTrading::DuplicatePropertyName (n)); } } } void TAO_Service_Type_Repository:: validate_supertypes (Service_Type_Map &super_map, const CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq &super_types ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CosTrading::IllegalServiceType, CosTrading::UnknownServiceType, CosTradingRepos::ServiceTypeRepository::DuplicateServiceTypeName)) { for (CORBA::ULong i = 0; i < super_types.length (); i++) { const char *type = super_types[i]; if (TAO_Trader_Base::is_valid_identifier_name (type) == 0) ACE_THROW (CosTrading::IllegalServiceType (type)); else { TAO_String_Hash_Key hash_type (type); Service_Type_Map::ENTRY *type_entry = 0; if (this->type_map_.find (hash_type, type_entry) == -1) ACE_THROW (CosTrading::UnknownServiceType (type)); else { if (super_map.bind (hash_type, type_entry->int_id_) == 1) ACE_THROW (CosTradingRepos::ServiceTypeRepository::DuplicateServiceTypeName (type)); } } } } void TAO_Service_Type_Repository:: validate_inheritance (Prop_Map &prop_map, const CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq &super_types ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CosTradingRepos::ServiceTypeRepository::ValueTypeRedefinition)) { CORBA::ULong num_super_types = super_types.length (); for (CORBA::ULong i = 0; i < num_super_types; i++) { Service_Type_Map::ENTRY *super_type_entry = 0; TAO_String_Hash_Key super_type (super_types[i]); CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq place_holder; CosTradingRepos::ServiceTypeRepository::PropStructSeq super_props; this->type_map_.find (super_type, super_type_entry); // Super_type_entry should never be zero. if (super_type_entry != 0) this->fully_describe_type_i (super_type_entry->int_id_->type_struct_, super_props, place_holder); else continue; CORBA::ULong num_props = super_props.length (); for (CORBA::ULong j = 0; j < num_props; j++) { Prop_Map::ENTRY *existing_prop = 0; TAO_String_Hash_Key prop_name (super_props[j].name); if (prop_map.bind (prop_name, &super_props[j], existing_prop) == 1) { // If already there, check that it is compatible with // properties of other types. Value Types have to be the // same. const CosTradingRepos::ServiceTypeRepository::PropStruct &property_in_map = *existing_prop->int_id_; CORBA::TypeCode_ptr prop_type = property_in_map.value_type.in (); int compare = 0; ACE_TRY { compare = super_props[j].value_type->equal (prop_type ACE_ENV_ARG_PARAMETER); ACE_TRY_CHECK; } ACE_CATCHANY { ACE_TRY_THROW (CosTradingRepos::ServiceTypeRepository::ValueTypeRedefinition (super_props[j].name, super_props[j], property_in_map.name, property_in_map)); } ACE_ENDTRY; ACE_CHECK; if (compare == 0 || super_props[j].mode > property_in_map.mode) ACE_THROW (CosTradingRepos::ServiceTypeRepository::ValueTypeRedefinition (super_props[j].name, super_props[j], property_in_map.name, property_in_map)); } } } } void TAO_Service_Type_Repository:: update_type_map (const char *name, const char *if_name, const CosTradingRepos::ServiceTypeRepository::PropStructSeq &props, const CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq &super_types, Prop_Map &, Service_Type_Map &super_map) { // Update entries for all supertypes to include this type as a // subtype. we can use the super_types_map we have constructed. for (Service_Type_Map_Iterator super_map_iterator (super_map); super_map_iterator.done () == 0; super_map_iterator++) { Type_Info *super_type_info = (*super_map_iterator).int_id_; super_type_info->has_subtypes_ = 0; } // All parameters are valid, create an entry for this service type // in the this->type_map_. Type_Info *type = 0; ACE_NEW (type, Type_Info); type->type_struct_.props = props; type->type_struct_.if_name = if_name; type->type_struct_.super_types = super_types; type->type_struct_.incarnation = this->incarnation_; type->type_struct_.masked = 0; type->has_subtypes_ = 0; // Move the prop struct sequences and super type names from the in // params to the internal storage. /* CORBA::ULong pslength = props.length (); CosTradingRepos::ServiceTypeRepository::PropStructSeq* pstructs = const_cast (&props); CosTradingRepos::ServiceTypeRepository::PropStruct* psbuf = pstructs->get_buffer (1); type->type_struct_.props.replace (pslength, pslength, psbuf, 1); */ TAO_String_Hash_Key type_name (name); this->type_map_.bind (type_name, type); } TAO_END_VERSIONED_NAMESPACE_DECL