diff options
Diffstat (limited to 'TAO/orbsvcs/orbsvcs/PortableGroup/PG_ObjectGroupManager.cpp')
-rw-r--r-- | TAO/orbsvcs/orbsvcs/PortableGroup/PG_ObjectGroupManager.cpp | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_ObjectGroupManager.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_ObjectGroupManager.cpp new file mode 100644 index 00000000000..e0b7e54be74 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_ObjectGroupManager.cpp @@ -0,0 +1,752 @@ +#include "orbsvcs/PortableGroup/PG_ObjectGroupManager.h" +#include "orbsvcs/PortableGroup/PG_GenericFactory.h" +#include "orbsvcs/PortableGroup/PG_conf.h" +#include "orbsvcs/PortableGroup/PG_Operators.h" + +#include "tao/debug.h" +#include "tao/ORB_Constants.h" + +#include "ace/Auto_Ptr.h" +#include "ace/Reverse_Lock_T.h" + +ACE_RCSID (PortableGroup, + PG_ObjectGroupManager, + "$Id$") + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO_PG_ObjectGroupManager::TAO_PG_ObjectGroupManager (void) + : poa_ (), + object_group_map_ (TAO_PG_MAX_OBJECT_GROUPS), + location_map_ (TAO_PG_MAX_LOCATIONS), + generic_factory_ (0), + lock_ () +{ +} + +TAO_PG_ObjectGroupManager::~TAO_PG_ObjectGroupManager (void) +{ + for (TAO_PG_Location_Map::iterator i = this->location_map_.begin (); + i != this->location_map_.end (); + ++i) + { + // Destroy the group array + delete (*i).int_id_; + } + (void) this->location_map_.close (); + + for (TAO_PG_ObjectGroup_Map::iterator j = this->object_group_map_.begin (); + j != this->object_group_map_.end (); + ++j) + { + // Destroy the object group entry + delete (*j).int_id_; + } + (void) this->object_group_map_.close (); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::create_member ( + PortableGroup::ObjectGroup_ptr /* object_group */, + const PortableGroup::Location & /* the_location */, + const char * /* type_id */, + const PortableGroup::Criteria & /* the_criteria */) +{ + throw CORBA::NO_IMPLEMENT (); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::add_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CORBA::Object_ptr member) +{ + if (CORBA::is_nil (member)) + throw CORBA::BAD_PARAM (); + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + PortableGroup::ObjectGroup::_nil ()); + + // Verify that the member's RepositoryId matches the object group's + // type ID. + const CORBA::Boolean check_type_id = 1; + + return this->add_member_i (object_group, + the_location, + member, + check_type_id); + +} + + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::_tao_add_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CORBA::Object_ptr member, + const char * type_id, + const CORBA::Boolean propagate_member_already_present) +{ + if (CORBA::is_nil (member)) + throw CORBA::BAD_PARAM (); + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + PortableGroup::ObjectGroup::_nil ()); + + PortableGroup::ObjectGroup_var new_group; + + try + { + // TypeId already checked by GenericFactory. + const CORBA::Boolean check_type_id = 0; + + new_group = this->add_member_i (object_group, + the_location, + member, + check_type_id); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + throw CORBA::INTERNAL (); + } + catch (const PortableGroup::MemberAlreadyPresent&) + { + if (propagate_member_already_present) + throw; + else + throw CORBA::INTERNAL (); + } + catch (const PortableGroup::ObjectNotAdded&) + { + throw PortableGroup::NoFactory (the_location, type_id); + } + + return new_group._retn (); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::add_member_i ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CORBA::Object_ptr member, + const CORBA::Boolean check_type_id) +{ + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + if (check_type_id) + { + CORBA::Boolean right_type_id = + this->valid_type_id (object_group, + group_entry, + member); + + if (!right_type_id) + { + // The member's type_id does not match the object group's + // type_id. + throw PortableGroup::ObjectNotAdded (); + } + } + + TAO_PG_ObjectGroup_Array * groups = 0; + if (this->location_map_.find (the_location, groups) == 0 + && this->member_already_present (*groups, group_entry)) + throw PortableGroup::MemberAlreadyPresent (); + + TAO_PG_MemberInfo member_info; + member_info.member = CORBA::Object::_duplicate (member); + member_info.location = the_location; + + if (groups == 0) + { + ACE_NEW_THROW_EX (groups, + TAO_PG_ObjectGroup_Array, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + auto_ptr<TAO_PG_ObjectGroup_Array> safe_groups (groups); + + // This should not fail! + if (this->location_map_.bind (the_location, groups) != 0) + { + throw PortableGroup::ObjectNotAdded (); + } + + (void) safe_groups.release (); + } + + // No object group member of the object group with the given + // ObjectGroupId resides at the location. Add the object group + // entry to array of object groups residing at the location. + const size_t groups_len = groups->size (); + groups->size (groups_len + 1); + (*groups)[groups_len] = group_entry; + + // Don't bother checking for duplicates since a check is already + // performed when binding to the location map above. + if (group_entry->member_infos.insert_tail (member_info) != 0) + throw PortableGroup::ObjectNotAdded (); + + return PortableGroup::ObjectGroup::_duplicate (object_group); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::remove_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + TAO_PG_ObjectGroup_Array * groups = 0; + if (this->location_map_.find (the_location, groups) != 0) + throw PortableGroup::ObjectGroupNotFound (); + + // Multiple members from different object groups may reside at the + // same location. Iterate through the list to attempt to find a + // match for the exact object group. + size_t to_be_removed = 0; + + // get the position of the object group in the object_group_array + to_be_removed = this->get_object_group_position (*groups, group_entry); + + // remove the element from the array and resize the array. + const size_t groups_len = groups->size (); + size_t j; + for (size_t i = to_be_removed; i < groups_len - 1; ++i) + { + j = i + 1; + (*groups)[i] = (*groups)[j]; + } + + groups->size (groups_len - 1); + + TAO_PG_MemberInfo_Set & member_infos = group_entry->member_infos; + + TAO_PG_MemberInfo_Set::iterator end = member_infos.end (); + + for (TAO_PG_MemberInfo_Set::iterator iter = member_infos.begin (); + iter != end; + ++iter) + { + const TAO_PG_MemberInfo & info = *iter; + + if (info.location == the_location) + { + // Give the GenericFactory a chance to delete a member if + // its membership is under infrastructure control. + if (this->generic_factory_) + { + this->generic_factory_->delete_member (group_entry->group_id, + the_location); + } + + if (member_infos.remove (info) == 0) + { + if (this->generic_factory_) + { + this->generic_factory_->check_minimum_number_members ( + object_group, + group_entry->group_id, + group_entry->type_id.in ()); + } + + return PortableGroup::ObjectGroup::_duplicate (object_group); + } + else + break; + } + } + + throw PortableGroup::MemberNotFound (); +} + +PortableGroup::Locations * +TAO_PG_ObjectGroupManager::locations_of_members ( + PortableGroup::ObjectGroup_ptr object_group) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + PortableGroup::Locations *temp = 0; + ACE_NEW_THROW_EX (temp, + PortableGroup::Locations, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + PortableGroup::Locations_var locations = temp; + + TAO_PG_MemberInfo_Set & member_infos = group_entry->member_infos; + + locations->length (static_cast<CORBA::ULong> (member_infos.size ())); + + CORBA::ULong loc = 0; + TAO_PG_MemberInfo_Set::iterator end = member_infos.end (); + + for (TAO_PG_MemberInfo_Set::iterator i = member_infos.begin (); + i != end; + ++i) + locations[loc++] = (*i).location; + + return locations._retn (); +} + +PortableGroup::ObjectGroups * +TAO_PG_ObjectGroupManager::groups_at_location ( + const PortableGroup::Location & the_location) +{ + PortableGroup::ObjectGroups * ogs; + ACE_NEW_THROW_EX (ogs, + PortableGroup::ObjectGroups, + CORBA::NO_MEMORY ()); + + PortableGroup::ObjectGroups_var object_groups = ogs; + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0); + + TAO_PG_ObjectGroup_Array * groups; + if (this->location_map_.find (the_location, groups) == 0) + { + CORBA::ULong len = static_cast<CORBA::ULong> (groups->size ()); + + ogs->length (len); + + for (CORBA::ULong i = 0; i < len; ++i) + { + object_groups[i] = + PortableGroup::ObjectGroup::_duplicate ( + (*groups)[i]->object_group.in ()); + } + } + + return object_groups._retn (); +} + +PortableGroup::ObjectGroupId +TAO_PG_ObjectGroupManager::get_object_group_id ( + PortableGroup::ObjectGroup_ptr object_group) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + TAO_PG_ObjectGroup_Map_Entry * entry = + this->get_group_entry (object_group); + + if (entry == 0) + throw CORBA::INTERNAL (); + + // Only the lower 32 bits of the 64 bit PortableGroup::ObjectGroupId + // are ever used. + return entry->group_id; +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::get_object_group_ref ( + PortableGroup::ObjectGroup_ptr object_group) +{ + TAO_PG_ObjectGroup_Map_Entry * entry = 0; + + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + PortableGroup::ObjectGroup::_nil ()); + + + entry = this->get_group_entry (object_group); + } + + if (entry == 0) + throw CORBA::INTERNAL (); + + // This implemenation does not change the object group reference. + return PortableGroup::ObjectGroup::_duplicate (object_group); +} + +CORBA::Object_ptr +TAO_PG_ObjectGroupManager::get_member_ref ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & loc) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + CORBA::Object::_nil ()); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + // This method assumes that it is faster to check for non-existence + // of an object group (and hence the member) at a given location, + // instead of existence of a member at a given location. + + TAO_PG_ObjectGroup_Array * groups = 0; + if (this->location_map_.find (loc, groups) == 0 + && this->member_already_present (*groups, group_entry)) + { + TAO_PG_MemberInfo_Set & member_infos = group_entry->member_infos; + + TAO_PG_MemberInfo_Set::iterator end = member_infos.end (); + + // @todo If the object group contains a large number of members, + // this loop could take a while. Explore potentially + // faster containers for the list of PG_MemberInfos in the + // future. + for (TAO_PG_MemberInfo_Set::iterator i = member_infos.begin (); + i != end; + ++i) + if ((*i).location == loc) + return CORBA::Object::_duplicate ((*i).member.in ()); + } + + // No member of the given object group is present at the given + // location. + throw PortableGroup::MemberNotFound (); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::get_object_group_ref_from_id ( + PortableGroup::ObjectGroupId group_id + ) +{ + //@@ If we change the PG's concept of ObjectGroupId from + // PortableServer::ObjectId to PortableGroup::ObjectGroupId, can + // just call TAO_PG_ObjectGroupManager::object_group() here. + + TAO_PG_ObjectGroup_Map_Entry * group_entry = 0; + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + PortableGroup::ObjectGroup::_nil ()); + + if (this->object_group_map_.find (ACE_U64_TO_U32 (group_id), + group_entry) + != 0) + { + throw PortableGroup::ObjectGroupNotFound (); + } + } + + if (group_entry == 0) + { + throw CORBA::INTERNAL (); + } + + return + PortableGroup::ObjectGroup::_duplicate (group_entry->object_group.in ()); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::create_object_group ( + CORBA::ULong group_id, + const PortableServer::ObjectId &oid, + const char * type_id, + const PortableGroup::Criteria & the_criteria) +{ + if (CORBA::is_nil (this->poa_.in ())) + throw CORBA::INTERNAL (); + + // Create a reference for the ObjectGroup corresponding to the + // RepositoryId of the object being created. + CORBA::Object_var object_group = + this->poa_->create_reference_with_id (oid, + type_id); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = 0; + ACE_NEW_THROW_EX (group_entry, + TAO_PG_ObjectGroup_Map_Entry, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + auto_ptr<TAO_PG_ObjectGroup_Map_Entry> safe_group_entry (group_entry); + + // Set the RepositoryId associated with the created ObjectGroup_Map + // entry. + group_entry->type_id = CORBA::string_dup (type_id); + + group_entry->group_id = group_id; + + group_entry->object_group = object_group; + + CORBA::ULong len = the_criteria.length (); + group_entry->properties.length (len); + for (CORBA::ULong i = 0; i < len; ++i) + group_entry->properties[i] = the_criteria[i]; + + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + if (this->object_group_map_.bind (oid, group_entry) != 0) + throw PortableGroup::ObjectNotCreated (); + } + + (void) safe_group_entry.release (); + + return object_group._retn (); +} + +void +TAO_PG_ObjectGroupManager::destroy_object_group ( + const PortableServer::ObjectId & oid) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = 0; + if (this->object_group_map_.unbind (oid, group_entry) != 0) + throw PortableGroup::ObjectNotFound (); + + delete group_entry; +} + +char * +TAO_PG_ObjectGroupManager::type_id ( + PortableGroup::ObjectGroup_ptr object_group) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + return CORBA::string_dup (group_entry->type_id.in ()); +} + +PortableGroup::ObjectGroup_ptr +TAO_PG_ObjectGroupManager::object_group (const PortableServer::ObjectId & oid) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + PortableGroup::ObjectGroup::_nil ()); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = 0; + if (this->object_group_map_.find (oid, group_entry) == 0) + return + PortableGroup::ObjectGroup::_duplicate (group_entry->object_group.in ()); + else + return PortableGroup::ObjectGroup::_nil (); +} + +CORBA::ULong +TAO_PG_ObjectGroupManager::member_count ( + PortableGroup::ObjectGroup_ptr group) +{ +// ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, +// guard, +// this->lock_, +// 0); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (group); + + return static_cast<CORBA::ULong> (group_entry->member_infos.size ()); +} + +void +TAO_PG_ObjectGroupManager::poa (PortableServer::POA_ptr p) +{ + this->poa_ = PortableServer::POA::_duplicate (p); +} + + +PortableGroup::Properties * +TAO_PG_ObjectGroupManager::get_properties ( + PortableGroup::ObjectGroup_ptr object_group) +{ + PortableGroup::Properties * properties = 0; + ACE_NEW_THROW_EX (properties, + PortableGroup::Properties, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + PortableGroup::Properties_var safe_properties = properties; + + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + TAO_PG_ObjectGroup_Map_Entry * group_entry = + this->get_group_entry (object_group); + + *properties = group_entry->properties; + } + + return safe_properties._retn (); +} + +TAO_PG_ObjectGroup_Map_Entry * +TAO_PG_ObjectGroupManager::get_group_entry ( + CORBA::Object_ptr object_group) +{ + if (CORBA::is_nil (this->poa_.in ())) + throw CORBA::INTERNAL (); + + PortableServer::ObjectId_var oid; + try + { + oid = this->poa_->reference_to_id (object_group); + } + catch (const PortableServer::POA::WrongAdapter& ex) + { + if (TAO_debug_level > 0) + ex._tao_print_exception ("TAO_PG (%P|%t) Unexpected exception\n"); + + throw CORBA::INTERNAL (); + } + catch (const PortableServer::POA::WrongPolicy& ex) + { + if (TAO_debug_level > 0) + ex._tao_print_exception ("TAO_PG (%P|%t) Unexpected exception\n"); + + throw CORBA::INTERNAL (); + } + + TAO_PG_ObjectGroup_Map_Entry * group_entry = 0; + if (this->object_group_map_.find (oid.in (), group_entry) != 0) + throw PortableGroup::ObjectGroupNotFound (); + + return group_entry; +} + +CORBA::Boolean +TAO_PG_ObjectGroupManager::member_already_present ( + const TAO_PG_ObjectGroup_Array &groups, + TAO_PG_ObjectGroup_Map_Entry * group_entry) +{ + // Multiple members from different object groups may reside at the + // same location. Iterate through the list to attempt to find a + // match. + size_t len = groups.size (); + for (size_t i = 0; i < len; ++i) + { + // It should be enough just to compare the group_entry pointers, + // but that seems brittle. Better to check a controlled value, + // like the ObjectGroupId. + if (groups[i]->group_id == group_entry->group_id) + { + // Member with given type ID exists at the given + // location. + return 1; + } + } + + // No member with given type ID present at the given location. + return 0; +} + +size_t +TAO_PG_ObjectGroupManager::get_object_group_position ( + const TAO_PG_ObjectGroup_Array &groups, + TAO_PG_ObjectGroup_Map_Entry * group_entry) +{ + // Multiple members from different object groups may reside at the + // same location. Iterate through the list to attempt to find a + // match. + size_t len = groups.size (); + for (size_t i = 0; i < len; ++i) + { + // It should be enough just to compare the group_entry pointers, + // but that seems brittle. Better to check a controlled value, + // like the ObjectGroupId. + if (groups[i]->group_id == group_entry->group_id) + { + // Member with given type ID exists at the given + // location. + return i; + } + } + + // No member with given type ID present at the given location. + return 0; +} + +CORBA::Boolean +TAO_PG_ObjectGroupManager::valid_type_id ( + PortableGroup::ObjectGroup_ptr object_group, + TAO_PG_ObjectGroup_Map_Entry * group_entry, + CORBA::Object_ptr member) +{ + // @todo Strategize this -- e.g. strict type checking. + + if (CORBA::is_nil (member)) + throw CORBA::BAD_PARAM (); + + // Before we can use this code, i.e. the reverse lock, the + // TAO_PG_ObjectGroup_Entry should be made so that it is reference + // counted. This is necessary since releasing the lock would + // allow other threads to destroy/unbind the object group entry. + // Another alternative is to simply attempt to reacquire the + // object group map entry once the lock is reacquired, which is + // easier to implement. + + // Copy the type_id before releasing the lock to avoid a race + // condition. + CORBA::String_var type_id = + CORBA::string_dup (group_entry->type_id.in ()); + + CORBA::Boolean right_type_id = 0; + { + // Release the lock during the type_id check. No need to block + // other threads during the invocation. + ACE_Reverse_Lock<TAO_SYNCH_MUTEX> reverse_lock (this->lock_); + + ACE_GUARD_RETURN (ACE_Reverse_Lock<TAO_SYNCH_MUTEX>, + reverse_guard, + reverse_lock, + right_type_id); + + // Make sure an Object of the correct type was created. It is + // possible that an object of the wrong type was created if the + // type_id parameter does not match the type of object the + // GenericFactory creates. + right_type_id = + member->_is_a (type_id.in ()); + } + + // Make sure the group entry still exists. It may have been + // destroyed by another thread. + group_entry = this->get_group_entry (object_group); + + return right_type_id; +} + +void +TAO_PG_ObjectGroupManager::generic_factory ( + TAO_PG_GenericFactory * generic_factory) +{ + this->generic_factory_ = generic_factory; +} + +TAO_END_VERSIONED_NAMESPACE_DECL |