#ifndef TAO_TRADER_INTERFACES_CPP #define TAO_TRADER_INTERFACES_CPP #include "orbsvcs/Trader/Trader_Interfaces.h" #include "orbsvcs/Trader/Trader_T.h" #include "ace/INET_Addr.h" #include "orbsvcs/Trader/Trader_Constraint_Visitors.h" #include "ace/OS_NS_time.h" #include "ace/OS_NS_unistd.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL template TAO_Lookup:: TAO_Lookup (TAO_Trader &trader) : TAO_Trader_Components (trader.trading_components ()), TAO_Support_Attributes (trader.support_attributes ()), TAO_Import_Attributes (trader.import_attributes ()), IDS_SAVED (100), trader_ (trader) { } template TAO_Lookup::~TAO_Lookup () { ACE_GUARD (TRADER_LOCK_TYPE, trader_mon, this->lock_); for (Request_Ids::ITERATOR riter (this->request_ids_); ! riter.done (); riter.advance ()) { const CosTrading::Admin::OctetSeq** old_seq = 0; riter.next (old_seq); delete *old_seq; } } template void TAO_Lookup:: query (const char *type, const char *constraint, const char *preferences, const CosTrading::PolicySeq &in_policies, const CosTrading::Lookup::SpecifiedProps &desired_props, CORBA::ULong how_many, CosTrading::OfferSeq_out returned_offers, CosTrading::OfferIterator_out returned_offer_iterator, CosTrading::PolicyNameSeq_out returned_limits_applied) { // Instantiate a class to help interpret query policies. TAO_Policies policies (this->trader_, in_policies); // If a federated query returns to us, ignore it to prevent // redundant results and infinite loops. const CosTrading::Admin::OctetSeq* request_id = 0; int check = this->seen_request_id (policies, request_id); if (check) { returned_offers = new CosTrading::OfferSeq; returned_limits_applied = new CosTrading::PolicyNameSeq; return; } // The presence of a link interface determines whether we should // attempt to forward or propagate queries. CosTrading::Link_ptr link_if = this->trader_.trading_components ().link_if (); // If the importer has specified a starting trader, foward the // query. const CosTrading::TraderName* trader_name = policies.starting_trader (); if (! CORBA::is_nil (link_if) && trader_name != 0) { CosTrading::PolicySeq policies_to_forward; policies.copy_to_forward (policies_to_forward, *trader_name); const char* next_hop = (*trader_name)[0]; this->forward_query (next_hop, type, constraint, preferences, policies_to_forward, desired_props, how_many, returned_offers, returned_offer_iterator, returned_limits_applied); return; } // Retrieve the type description struct from the Service Type Repos. const TAO_Support_Attributes_i& support_attrs = this->trader_.support_attributes (); CosTradingRepos::ServiceTypeRepository_ptr rep = support_attrs.service_type_repos (); CosTradingRepos::ServiceTypeRepository::TypeStruct_var type_struct = rep->fully_describe_type (type); // @@ Should throw a NO_MEMORY exception here... ACE_NEW (returned_offers, CosTrading::OfferSeq); // Obtain a reference to the offer database. TAO_Offer_Database& offer_database = this->trader_.offer_database (); // TAO_Offer_Filter -- ensures that we don't consider offers with // modifiable or dynamic properties if the Trader doesn't support // them, or the importer has turned them off using policies. // TAO_Constraint_Validator -- validates the constraint with the // property types in the supplied type. TAO_Constraint_Interpreter // -- parses the constraint string, and determines whether an offer // meets those constraints. TAO_Preference_Interpreter -- parses // the preference string and orders offers according to those // constraints. TAO_Offer_Filter offer_filter (policies); TAO_Trader_Constraint_Validator validator (type_struct.in ()); TAO_Constraint_Interpreter constr_inter (validator, constraint); TAO_Preference_Interpreter pref_inter (validator, preferences); // Try to find the map of offers of desired service type. offer_filter.configure_type (type_struct.ptr ()); this->lookup_one_type (type, offer_database, constr_inter, pref_inter, offer_filter); CORBA::Boolean result = policies.exact_type_match (); if (!result) { // If the importer hasn't demanded an exact match search, we // search all the subtypes of the supplied type. NOTE: Only the // properties belonging to the provided type are considered on // subtypes. Additional properties on the subtype are generally // ignored. This is as it should be, consistent with the notions // of type inheritence. this->lookup_all_subtypes (type, type_struct->incarnation, offer_database, rep, constr_inter, pref_inter, offer_filter); } // Take note of the limits applied in this query. returned_limits_applied = offer_filter.limits_applied (); // Fill the return sequence and iterator with the bountiful results. CORBA::ULong offers_returned = this->fill_receptacles (type, how_many, desired_props, policies, pref_inter, *returned_offers.ptr (), returned_offer_iterator); // The following steps are only appropriate for a linked trader. if (! CORBA::is_nil (link_if)) { // Determine if we should perform a federated query, and if so // construct a sequence of links to follow. CosTrading::LinkNameSeq_var links; CORBA::Boolean should_follow = this->retrieve_links (policies, offers_returned, CosTrading::LinkNameSeq_out (links.out ())); if (should_follow && links->length () != 0) { // Query those links we've accumulated! this->federated_query (links.in (), policies, *request_id, pref_inter, type, constraint, preferences, desired_props, how_many, *returned_offers.ptr (), returned_offer_iterator.ptr (), *returned_limits_applied.ptr ()); } } } template void TAO_Lookup:: lookup_one_type (const char* type, TAO_Offer_Database& offer_database, TAO_Constraint_Interpreter& constr_inter, TAO_Preference_Interpreter& pref_inter, TAO_Offer_Filter& offer_filter) { // Retrieve an iterator over the offers for a given type. // @@ Would have used Offer_Database::offer_iterator for less // coupling between TAO_Lookup and Offer_Database, but g++ barfs on // that. #if defined(_MSC_VER) && !defined (ACE_HAS_CPP20) TAO_Offer_Database::offer_iterator offer_iter (type, offer_database); #else // MSVC won't grok this for some reason, but it's necessary for the // HP compiler, which seriously requires the typename keyword // here. I apologize if this ifdef offends some ACE users' // sensibilities --- it certainly offends mine. typename TAO_Offer_Database::offer_iterator offer_iter (type, offer_database); #endif while (offer_filter.ok_to_consider_more () && offer_iter.has_more_offers ()) { // For each offer in the iterator, attempt to match it with // the constraints passed to the Query method. If it matches // the constraint, use the TAO_Preference_Interpreter to // order the matched offers with respect to the preference // string passed to the method. All the while the offer // filter ensures we don't exceed the match cardinality // constraints. CosTrading::Offer* offer = offer_iter.get_offer (); TAO_Trader_Constraint_Evaluator evaluator (offer); if (offer_filter.ok_to_consider (offer) && constr_inter.evaluate (evaluator)) { // Shove the offer and its id into the preference // ordering object, pref_inter. CosTrading::OfferId offer_id = offer_iter.get_id (); pref_inter.order_offer (evaluator, offer, offer_id); offer_filter.matched_offer (); } offer_iter.next_offer (); } } template void TAO_Lookup:: lookup_all_subtypes (const char* type, CosTradingRepos::ServiceTypeRepository::IncarnationNumber& inc_num, TAO_Offer_Database& offer_database, CosTradingRepos::ServiceTypeRepository_ptr rep, TAO_Constraint_Interpreter& constr_inter, TAO_Preference_Interpreter& pref_inter, TAO_Offer_Filter& offer_filter) { // BEGIN SPEC // The trader may return a service offer of a subtype of the "type" // requested. Sub-typing of service types is discussed in "Service // Types" on page 16-4. A service subtype can be described by the // properties of its supertypes. This ensures that a well-formed query // for the "type" is also a well-formed query with respect to any // subtypes. However, if the importer specifies the policy of // exact_type_match = TRUE, then only offers with the exact (no // subtype) service type requested are returned. // END SPEC CosTradingRepos::ServiceTypeRepository::SpecifiedServiceTypes sst; CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq_var all_types; // Optimization: Since a subtype can't have a higher incarnation // number than a supertype, we don't need to consider those // types with lower incarnation numbers. sst.incarnation (inc_num); all_types = rep->list_types (sst); // Scan all types inserted after the super types. If the transitive // closure of a type's super type relation includes the super type // being considered, then perform a search on that type. CORBA::ULong num_types = all_types->length (); CosTradingRepos::ServiceTypeRepository::TypeStruct_var type_struct; for (CORBA::ULong i = 0; i < num_types && offer_filter.ok_to_consider_more (); i++) { // Obtain a description of the prospective type. type_struct = rep->fully_describe_type (all_types[i]); CosTradingRepos::ServiceTypeRepository::ServiceTypeNameSeq& super_types = type_struct->super_types; CORBA::ULong num_super_types = super_types.length (); for (CORBA::ULong j = 0; j < num_super_types; j++) { if (ACE_OS::strcmp (type_struct->super_types[j], type) == 0) { // Egads, a subtype! This type has the type passed // to query in its list of super_types. offer_filter.configure_type (type_struct.ptr ()); this->lookup_one_type (all_types[i], offer_database, constr_inter, pref_inter, offer_filter); break; } } } } template int TAO_Lookup:: fill_receptacles (const char* /* type */, CORBA::ULong how_many, const CosTrading::Lookup::SpecifiedProps& desired_props, TAO_Policies& policies, TAO_Preference_Interpreter& pref_inter, CosTrading::OfferSeq& offers, CosTrading::OfferIterator_ptr& offer_itr) { // BEGIN SPEC // The returned offers are passed back in one of two ways (or a // combination of both). ?The "offers" return result conveys a list // of offers and the "offer_itr" is a reference to an interface at // which offers can be obtained. ?The "how_many" parameter states // how many offers are to be returned via the "offers" result, any // remaining offers are available via the iterator interface. If the // "how_many" exceeds the number of offers to be returned, then the // "offer_itr" will be nil. // END SPEC TAO_Property_Filter prop_filter (desired_props); // RETURNING: Calculate how many offers go into the sequence // Calculate how many go into the iterator CORBA::ULong return_card = policies.return_card (); CORBA::ULong i = 0; CORBA::ULong size = static_cast (pref_inter.num_offers ()); CORBA::ULong offers_in_sequence = (how_many < size) ? how_many : size; CORBA::ULong offers_in_iterator = size - offers_in_sequence; // Ensure the total number of offers returned doesn't exceed return_card. offers_in_sequence = offers_in_sequence > return_card ? return_card : offers_in_sequence; return_card -= offers_in_sequence; offers_in_iterator = offers_in_iterator > return_card ? return_card : offers_in_iterator; CORBA::ULong total_offers = offers_in_sequence + offers_in_iterator; offers.length (offers_in_sequence); // Add to the sequence, filtering out the undesired properties. for (i = 0; i < offers_in_sequence; i++) { CosTrading::Offer* offer = 0; CosTrading::OfferId offer_id = 0; // Pull the next ordered offer out of the preference // interpreter. pref_inter.remove_offer (offer, offer_id); // Filter out the undesired properties. prop_filter.filter_offer (offer, offers[i]); CORBA::string_free (offer_id); } // Any remaining offers under the return_card go into iterator if (offers_in_iterator > 0) { // Create an iterator implementation TAO_Offer_Iterator *oi = this->create_offer_iterator (prop_filter); // Register it with the POA. offer_itr = oi->_this (); oi->_remove_ref (); // Add to the iterator for (i = 0; i < offers_in_iterator; i++) { CosTrading::Offer* offer = 0; CosTrading::OfferId offer_id = 0; // Pull the next ordered offer out of the preference // intrerpreter and add it to the offer iterator. pref_inter.remove_offer (offer, offer_id); oi->add_offer (offer_id, offer); } } // Clear the preference intrerpreter of superfluous items. size_t num_offers = pref_inter.num_offers (); for (size_t j = 0; j < num_offers; j++) { CosTrading::Offer* offer = 0; CosTrading::OfferId offer_id = 0; pref_inter.remove_offer (offer, offer_id); CORBA::string_free (offer_id); } return total_offers; } template TAO_Offer_Iterator * TAO_Lookup:: create_offer_iterator (const TAO_Property_Filter& pfilter) { // This is the factory method that creates the appropriate type of // offer iterator. If there's no Register interface, then we can // just stick the offers directly into an iterator, since these // offers will never be removed from the Trader. If there's a // Register interface, then there's a chance that by the time the // importer calls the next_n method on the iterator that the offer // will have been withdrawn. So the Register_Offer_Iterator retains only // the offer ids, and will recognize when an offer id no longer // identifies an offer in the trader. // We pass the property filter to the iterators, so when the iterators // return the offers, they can remove the undesirable properties // from those offers. TAO_Offer_Iterator* iterator = 0; if (CORBA::is_nil (this->trader_.trading_components ().register_if ())) ACE_NEW_RETURN (iterator, TAO_Query_Only_Offer_Iterator (pfilter), 0); else ACE_NEW_RETURN (iterator, TAO_Register_Offer_Iterator (this->trader_.offer_database (), pfilter), 0); return iterator; } template CORBA::Boolean TAO_Lookup:: retrieve_links (TAO_Policies& policies, CORBA::ULong offers_returned, CosTrading::LinkNameSeq_out links) { CORBA::Boolean should_follow = 0; CosTrading::FollowOption follow_rule = policies.link_follow_rule (); // Determine whether or not a federated query is warranted. A query // is waranted if the follow_rule governing this query is 'always' // or if_no_local and the local query returned nothing. if ((follow_rule == CosTrading::always || (follow_rule == CosTrading::if_no_local && offers_returned == 0))) { CORBA::ULong hc = policies.hop_count (); if (hc > 0) should_follow = 1; } if (should_follow) { // Grab the names of all the links in the trader, and push // the suitable ones onto . CosTrading::Link_ptr link_if = this->trader_.trading_components ().link_if (); links = link_if->list_links (); // Determine which of the links registered with the Link // interface are suitable to follow. CORBA::ULong i = 0, j = 0, length = links->length (); for (i = 0; i < length; i++) { // Grab the link information. CosTrading::Link::LinkInfo_var link_info (link_if->describe_link (links[i])); // Compute the link follow rule. CosTrading::FollowOption link_rule = policies.link_follow_rule (link_info.in ()); // Determine if the link follow rule applies. if (link_rule == CosTrading::always || (link_rule == CosTrading::if_no_local && offers_returned == 0)) { // Add the link to the list of links to follow. if (i > j) links[j] = links[i]; j++; } } links->length (j); } return should_follow; } template void TAO_Lookup:: federated_query (const CosTrading::LinkNameSeq& links, const TAO_Policies& policies, const CosTrading::Admin::OctetSeq& request_id, TAO_Preference_Interpreter& pref_inter, const char *type, const char *constr, const char *pref, const CosTrading::Lookup::SpecifiedProps& desired_props, CORBA::ULong how_many, CosTrading::OfferSeq& offers, CosTrading::OfferIterator_ptr& offer_iter, CosTrading::PolicyNameSeq& limits) { // The general idea here is this: We've assembled a number of links // to follow, and we'll query each of them in turn. On each query we // adjust the policies for the new trader by reducing the hop_count, // changing the link_follow_rule etc..., and merge the results from // the new query with the results from the previous queries. // We'll need the link and admin interfaces for this part of the // federated query. It's ok to get the admin interface without // checking if it's nil, becase the conformance criteria dictate // that a trader can't implement the link interface without the // admin interface. CosTrading::Link_ptr link_interface = this->trader_.trading_components ().link_if (); // Begin collecting all the various offer_iterators into a // collection. The end result is a distributed tree of offer // iterators, which if traversed in its entirety is probably hugely // inefficient, but oh well, I can't think of a better solution. TAO_Offer_Iterator_Collection* offer_iter_collection = 0; ACE_NEW (offer_iter_collection, TAO_Offer_Iterator_Collection); offer_iter_collection->add_offer_iterator (offer_iter); CosTrading::PolicySeq policies_to_pass; policies.copy_to_pass (policies_to_pass, request_id); for (int i = links.length () - 1; i >= 0; i--) { CosTrading::OfferSeq *out_offers = 0; CosTrading::OfferIterator *out_offer_iter = 0; CosTrading::PolicyNameSeq *out_limits = 0; try { // Obtain information about the link we're traversing. CosTrading::Link::LinkInfo_var link_info = link_interface->describe_link (links[i]); // Set the link follow policy for the query over the link. policies.copy_in_follow_option (policies_to_pass, link_info.in ()); CosTrading::Lookup_var remote_lookup = CosTrading::Lookup::_duplicate (link_info->target.in ()); // Perform the federated query. remote_lookup->query (type, constr, pref, policies_to_pass, desired_props, how_many - offers.length (), CosTrading::OfferSeq_out (out_offers), CosTrading::OfferIterator_out (out_offer_iter), CosTrading::PolicyNameSeq_out (out_limits)); CORBA::ULong j = 0; CosTrading::OfferSeq_var out_offers_var (out_offers); CosTrading::PolicyNameSeq_var out_limits_var (out_limits); // Add another iterator to the collection. if (! CORBA::is_nil (out_offer_iter)) offer_iter_collection->add_offer_iterator (out_offer_iter); // Concatenate the limits applied. CORBA::ULong source_length = out_limits->length (), target_length = limits.length (), total_length = source_length + target_length; limits.length (total_length); for (j = 0; j < source_length; j++) limits[j + target_length] = out_limits_var[j]; // Concatenate the sequence offers. source_length = out_offers->length (); target_length = offers.length (); total_length = source_length + target_length; offers.length (total_length); for (j = 0; j < source_length; j++) offers[j + target_length] = out_offers_var[j]; } catch (const CORBA::Exception&) { // Ah, well, this query failed, move on to the next one. } } // Sort the sequence in preference order. this->order_merged_sequence (pref_inter, offers); // Return the collection of offer iterators. offer_iter = offer_iter_collection->_this (); offer_iter_collection->_remove_ref (); } template void TAO_Lookup:: order_merged_sequence (TAO_Preference_Interpreter& pref_inter, CosTrading::OfferSeq& offers) { CORBA::ULong j = 0; CORBA::ULong length = offers.length (); // Grab ownership of the offers already in the target sequence. CosTrading::Offer* target_buf = offers.get_buffer (1); // Order the sequence. for (j = 0; j < length; j++) pref_inter.order_offer (&target_buf[j]); //pref_inter.order_offer (&offers[j]); // Reallocate the sequence. offers.length (length); // CosTrading::OfferSeq copy; // copy.length (length); // Copy in the ordered offers. for (j = 0; j < length; j++) { CosTrading::Offer* offer = 0; pref_inter.remove_offer (offer); //copy[j] = *offer; offers[j] = *offer; } // Release the orphaned memory. CosTrading::OfferSeq::freebuf (target_buf); // offers = copy } template void TAO_Lookup:: forward_query (const char* next_hop, const char *type, const char *constr, const char *pref, const CosTrading::PolicySeq& policy_seq, const CosTrading::Lookup::SpecifiedProps& desired_props, CORBA::ULong how_many, CosTrading::OfferSeq_out offers, CosTrading::OfferIterator_out offer_itr, CosTrading::PolicyNameSeq_out limits_applied) { // Forward this query to the next link in the starting_trader sequence. CosTrading::Link_ptr link_interface = this->trader_.trading_components ().link_if (); try { CosTrading::Link::LinkInfo_var link_info = link_interface->describe_link (next_hop); CosTrading::Lookup_var remote_lookup = CosTrading::Lookup::_duplicate (link_info->target.in ()); CORBA::Object_var us = this->_this (); CORBA::Boolean self_loop = remote_lookup->_is_equivalent (us.in ()); if (! self_loop) { // Perform forwarding query. remote_lookup->query (type, constr, pref, policy_seq, desired_props, how_many, offers, offer_itr, limits_applied); } else { this->query (type, constr, pref, policy_seq, desired_props, how_many, offers, offer_itr, limits_applied); } } catch (const CORBA::Exception&) { CosTrading::Policy policy; policy.name = TAO_Policies::POLICY_NAMES[TAO_Policies::STARTING_TRADER]; policy.value <<= next_hop; throw CosTrading::Lookup::InvalidPolicyValue (policy); } } template CORBA::Boolean TAO_Lookup:: seen_request_id (TAO_Policies& policies, const CosTrading::Admin::OctetSeq*& seq) { CORBA::Boolean return_value = 0; seq = policies.request_id (); if (seq == 0) { CosTrading::Admin_ptr admin_if = this->trader_.trading_components ().admin_if (); seq = admin_if->request_id_stem (); } else { // Allocate memory so memory mangement is the same for both // cases. ACE_NEW_THROW_EX (seq, CosTrading::Admin::OctetSeq (*seq), CORBA::NO_MEMORY ()); } ACE_GUARD_RETURN (TRADER_LOCK_TYPE, trader_mon, this->lock_, 1); for (Request_Ids::ITERATOR riter (this->request_ids_); ! riter.done (); riter.advance ()) { const CosTrading::Admin::OctetSeq** old_seq = 0; riter.next (old_seq); if (**old_seq == *seq) { return_value = 1; break; } } if (return_value == 0) { if (this->request_ids_.size () == IDS_SAVED) { const CosTrading::Admin::OctetSeq* octet_seq = 0; this->request_ids_.dequeue_head (octet_seq); delete octet_seq; } this->request_ids_.enqueue_tail (seq); } return return_value; } template TAO_Register::TAO_Register (TAO_Trader &trader) : TAO_Trader_Components (trader.trading_components ()), TAO_Support_Attributes (trader.support_attributes ()), trader_ (trader) { } template TAO_Register::~TAO_Register () { } template CosTrading::OfferId TAO_Register:: _cxx_export (CORBA::Object_ptr reference, const char *type, const CosTrading::PropertySeq &properties) { // For robustness purposes -- if (CORBA::is_nil (reference)) throw CosTrading::Register::InvalidObjectRef (); // Get service type map TAO_Offer_Database &offer_database = this->trader_.offer_database (); CosTrading::Offer* offer = 0; TAO_Support_Attributes_i& support_attrs = this->trader_.support_attributes (); CosTradingRepos::ServiceTypeRepository_ptr rep = support_attrs.service_type_repos (); // Yank our friend, the type struct, and confirm that the given // properties match the type definition. CosTradingRepos::ServiceTypeRepository::TypeStruct_var type_struct = rep->fully_describe_type (type); // Oops the type is masked, we shouldn't let exporters know the type // exists. if (type_struct->masked) throw CosTrading::UnknownServiceType (type); // TAO-specific way to determine if an object is derived from or is // an interface type. int check = (! reference->_is_a (type_struct->if_name)); if (check) throw CosTrading::Register::InterfaceTypeMismatch (type, reference); // Validate that the properties defined for this offer are correct // to their types and strength. this->validate_properties (type, type_struct.ptr (), properties); // CORBA::ULong plength = properties.length (); ACE_NEW_THROW_EX (offer, CosTrading::Offer, CORBA::NO_MEMORY ()); // No copying, no memory leaks. Violates the "in" parameter semantics // when this object is colocated with the client, however. // CosTrading::PropertySeq* hack_seq = // const_cast (&properties); // CosTrading::Property* pbuf = hack_seq->get_buffer (1); // CosTrading::PropertySeq* hack_seq = // const_cast (&properties); // CosTrading::Property* pbuf = hack_seq->get_buffer (0); // offer->properties.replace (plength, plength, pbuf, 0); // offer->properties._allocate_buffer (plength); offer->properties = properties; offer->reference = reference->_duplicate (reference); // Insert the offer into the underlying type map. CosTrading::OfferId id = offer_database.insert_offer (type, offer); return id; } template void TAO_Register:: withdraw (const char *id) { // Get service type map. TAO_Offer_Database &offer_database = this->trader_.offer_database (); offer_database.remove_offer ((CosTrading::OfferId) id); } template CosTrading::Register::OfferInfo * TAO_Register:: describe (const char *id) { // Get service type map. char* type = 0; TAO_Offer_Database &offer_database = this->trader_.offer_database (); // Perform a lookup to find the offer. CosTrading::Offer* offer = offer_database.lookup_offer ((CosTrading::OfferId) id, type); CosTrading::Register::OfferInfo *offer_info = 0; ACE_NEW_THROW_EX (offer_info, CosTrading::Register::OfferInfo, CORBA::NO_MEMORY ()); offer_info->reference = CORBA::Object::_duplicate (offer->reference.in ()); offer_info->type = CORBA::string_dup (type); // Let the offer_info prop_seq "borrow" the sequence of properties. //CORBA::ULong length = offer->properties.length (); // CosTrading::Property* prop_buf = offer->properties.get_buffer (); offer_info->properties = offer->properties; return offer_info; } template void TAO_Register:: modify (const char *id, const CosTrading::PropertyNameSeq& del_list, const CosTrading::PropertySeq& modify_list) { // Throw an exception if the trader is not configured // to support properties modification. int check = (! this->supports_modifiable_properties ()); if (check) throw CosTrading::NotImplemented (); char* type = 0; TAO_Support_Attributes_i& support_attrs = this->trader_.support_attributes (); CosTradingRepos::ServiceTypeRepository_ptr rep = support_attrs.service_type_repos (); TAO_Offer_Database &offer_database = this->trader_.offer_database (); CosTrading::Offer* offer = offer_database. lookup_offer (const_cast (id), type); if (offer != 0) { // Yank our friend, the type struct. CosTradingRepos::ServiceTypeRepository::TypeStruct_var type_struct = rep->fully_describe_type (type); TAO_Offer_Modifier offer_mod (type, type_struct.in (), offer); // Delete, add, and change properties of the offer. offer_mod.delete_properties (del_list); offer_mod.merge_properties (modify_list); // Alter our reference to the offer. We do this last, since the // spec says: modify either suceeds completely or fails // completely. offer_mod.affect_change (modify_list); } } template void TAO_Register:: withdraw_using_constraint (const char *type, const char *constr) { TAO_Support_Attributes_i& support_attrs = this->trader_.support_attributes (); CosTradingRepos::ServiceTypeRepository_ptr rep = support_attrs.service_type_repos (); TAO_Offer_Database &offer_database = this->trader_.offer_database (); CORBA::Boolean dp_support = support_attrs.supports_dynamic_properties (); TAO_String_Queue ids; // Retrieve the type struct CosTradingRepos::ServiceTypeRepository::TypeStruct_var type_struct = rep->fully_describe_type (type); // Try to find the map of offers of desired service type. // @@ Again, should be Offer_Database::offer_iterator { #if defined (_MSC_VER) && !defined (ACE_HAS_CPP20) TAO_Offer_Database::offer_iterator offer_iter (type, offer_database); #else // MSVC won't grok this for some reason, but it's necessary for // the HP compiler, which seriously requires the typename keyword // here. I apologize if this ifdef offends some ACE users' // sensibilities --- it certainly offends mine. typename TAO_Offer_Database::offer_iterator offer_iter (type, offer_database); #endif /* _MSC_VER */ TAO_Trader_Constraint_Validator validator (type_struct.in ()); TAO_Constraint_Interpreter constr_inter (validator, constr); while (offer_iter.has_more_offers ()) { CosTrading::Offer* offer = offer_iter.get_offer (); // Add offer if it matches the constraints TAO_Trader_Constraint_Evaluator evaluator (offer, dp_support); if (constr_inter.evaluate (evaluator)) ids.enqueue_tail (offer_iter.get_id ()); offer_iter.next_offer (); } } if (ids.size () != 0) { while (! ids.is_empty ()) { char* offer_id = 0; ids.dequeue_head (offer_id); offer_database.remove_offer (offer_id); CORBA::string_free (offer_id); } } else throw CosTrading::Register::NoMatchingOffers (constr); } template CosTrading::Register_ptr TAO_Register:: resolve (const CosTrading::TraderName &name) { // Determine if the first link is a legal link name. if (! TAO_Trader_Base::is_valid_link_name (name[0])) throw CosTrading::Register::IllegalTraderName (name); // Grab a reference to the link interface, and get a link description. CosTrading::Link_ptr link_if = this->trader_.trading_components ().link_if (); // Ensure that the link interface is supported. if (! CORBA::is_nil (link_if)) return CosTrading::Register::_nil (); CosTrading::Link::LinkInfo_var link_info; CosTrading::Register_var remote_reg; try { // Ensure that the link to the next trader exists. link_info = link_if->describe_link (name[0]); remote_reg = CosTrading::Register::_narrow (link_info->target_reg.in ()); } catch (const CORBA::Exception&) { throw CosTrading::Register::UnknownTraderName (name); } // Ensure that the register pointer isn't nil. if (! CORBA::is_nil (remote_reg.in ())) throw CosTrading::Register::RegisterNotSupported (name); CosTrading::Register_ptr return_value = remote_reg.in (); if (name.length () > 1) { // Create a new Trader Name with the first link removed. CosTrading::TraderName trader_name (name.length () - 1); for (int i = trader_name.length () - 1; i >= 0; i--) trader_name[i] = name[i + 1]; return_value = remote_reg->resolve (trader_name); } return return_value; } template void TAO_Register:: validate_properties (const char* type, const CosTradingRepos::ServiceTypeRepository::TypeStruct* type_struct, const CosTrading::PropertySeq& properties) { CORBA::ULong length = properties.length (); const CosTradingRepos::ServiceTypeRepository::PropStructSeq& prop_types = type_struct->props; TAO_Property_Evaluator_By_Name prop_eval (properties); // Perform property validation length = prop_types.length (); for (CORBA::ULong i = 0; i < length; i++) { const CosTradingRepos::ServiceTypeRepository::PropStruct& prop_struct = prop_types[i]; const char* prop_name = prop_struct.name; // Obtain the type of the exported property. CORBA::TypeCode_var prop_type = prop_eval.property_type (prop_name); if (CORBA::is_nil (prop_type.in ())) { // Offer cannot have a missing mandatory property. if (prop_types[i].mode == CosTradingRepos::ServiceTypeRepository::PROP_MANDATORY) throw CosTrading::MissingMandatoryProperty (type, prop_name); } else { int check = (! prop_type->equal (prop_struct.value_type.in ())); if (check) { // Offer cannot redefine the type of an property. const CosTrading::Property* prop = prop_eval.get_property (prop_name); throw CosTrading::PropertyTypeMismatch (type, *prop); } else if (prop_struct.mode == CosTradingRepos::ServiceTypeRepository::PROP_READONLY && prop_eval.is_dynamic_property (prop_name)) throw CosTrading::ReadonlyDynamicProperty (type, prop_name); } } } template TAO_Admin:: TAO_Admin (TAO_Trader &trader) : TAO_Trader_Components (trader.trading_components ()), TAO_Support_Attributes (trader.support_attributes ()), TAO_Import_Attributes (trader.import_attributes ()), TAO_Link_Attributes (trader.link_attributes ()), trader_ (trader), sequence_number_ (0) { // A random 4-bytes will prefix the sequence number space for each // trader, making it extremely unlikely that the sequence spaces for // two traders will over lap. @@ TODO: This is a bad way to // generate pseudo random numbers. // Ok, then, Carlos, we'll do it a different way: ip addr + pid. ACE_UINT32 ip_addr = 0; ACE_TCHAR host_name[BUFSIZ]; if (ACE_OS::hostname (host_name, BUFSIZ) != -1) { ACE_INET_Addr addr ((u_short) 0, host_name); ip_addr = addr.get_ip_address (); } // The better way to do unique stem identifiers. this->stem_id_.length (12); if (ip_addr != 0) { pid_t pid = ACE_OS::getpid (); this->stem_id_[0] = static_cast ((ip_addr >> 24) & 0xff); this->stem_id_[1] = static_cast ((ip_addr >> 16) & 0xff); this->stem_id_[2] = static_cast ((ip_addr >> 8) & 0xff); this->stem_id_[3] = static_cast (ip_addr & 0xff); this->stem_id_[4] = static_cast ((pid >> 24) & 0xff); this->stem_id_[5] = static_cast ((pid >> 16) & 0xff); this->stem_id_[6] = static_cast ((pid >> 8) & 0xff); this->stem_id_[7] = static_cast (pid & 0xff); } // The default way -- eight random integers. else { time_t time_value = ACE_OS::time (); ACE_OS::srand (static_cast (time_value)); this->stem_id_[0] = static_cast (ACE_OS::rand () % 256); this->stem_id_[1] = static_cast (ACE_OS::rand () % 256); this->stem_id_[2] = static_cast (ACE_OS::rand () % 256); this->stem_id_[3] = static_cast (ACE_OS::rand () % 256); this->stem_id_[4] = static_cast (ACE_OS::rand () % 256); this->stem_id_[5] = static_cast (ACE_OS::rand () % 256); this->stem_id_[6] = static_cast (ACE_OS::rand () % 256); this->stem_id_[7] = static_cast (ACE_OS::rand () % 256); } } template TAO_Admin::~TAO_Admin () { } template CosTrading::Admin::OctetSeq * TAO_Admin::request_id_stem () { ACE_GUARD_RETURN (TRADER_LOCK_TYPE, trader_mon, this->lock_, 0); // Add one to the sequence_number and concatenate it to the unique // prefix. The sequence number is four octets long, the unique // prefix, also 4 bytes long. this->stem_id_[8] = static_cast (this->sequence_number_ & 0xff); this->stem_id_[9] = static_cast ((this->sequence_number_ >> 8) & 0xff); this->stem_id_[10] = static_cast ((this->sequence_number_ >> 16) & 0xff); this->stem_id_[11] = static_cast ((this->sequence_number_ >> 24) & 0xff); // Increment the sequence number and return a copy of the stem_id. this->sequence_number_++; return new CosTrading::Admin::OctetSeq (this->stem_id_); } template CORBA::ULong TAO_Admin:: set_def_search_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().def_search_card (); this->trader_.import_attributes ().def_search_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_max_search_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().max_search_card (); this->trader_.import_attributes ().max_search_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_def_match_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().def_match_card (); this->trader_.import_attributes ().def_match_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_max_match_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().max_match_card (); this->trader_.import_attributes ().max_match_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_def_return_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().def_return_card (); this->trader_.import_attributes ().def_return_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_max_return_card (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().max_return_card (); this->trader_.import_attributes ().max_return_card (value); return return_value; } template CORBA::ULong TAO_Admin:: set_max_list (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().max_list (); this->trader_.import_attributes ().max_list (value); return return_value; } template CORBA::Boolean TAO_Admin:: set_supports_modifiable_properties (CORBA::Boolean value ) { CORBA::Boolean return_value = this->trader_.support_attributes ().supports_modifiable_properties (); this->trader_.support_attributes ().supports_modifiable_properties (value); return return_value; } template CORBA::Boolean TAO_Admin:: set_supports_dynamic_properties (CORBA::Boolean value ) { CORBA::Boolean return_value = this->trader_.support_attributes ().supports_dynamic_properties (); this->trader_.support_attributes ().supports_dynamic_properties (value); return return_value; } template CORBA::Boolean TAO_Admin:: set_supports_proxy_offers (CORBA::Boolean value ) { CORBA::Boolean return_value = this->trader_.support_attributes ().supports_proxy_offers (); this->trader_.support_attributes ().supports_proxy_offers (value); return return_value; } template CORBA::ULong TAO_Admin:: set_def_hop_count (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().def_hop_count (); this->trader_.import_attributes ().def_hop_count (value); return return_value; } template CORBA::ULong TAO_Admin:: set_max_hop_count (CORBA::ULong value ) { CORBA::ULong return_value = this->trader_.import_attributes ().max_hop_count (); this->trader_.import_attributes ().max_hop_count (value); return return_value; } template CosTrading::FollowOption TAO_Admin:: set_def_follow_policy (CosTrading::FollowOption policy ) { CosTrading::FollowOption return_value = this->trader_.import_attributes ().def_follow_policy (); this->trader_.import_attributes ().def_follow_policy (policy); return return_value; } template CosTrading::FollowOption TAO_Admin:: set_max_follow_policy (CosTrading::FollowOption policy ) { CosTrading::FollowOption return_value = this->trader_.import_attributes ().max_follow_policy (); this->trader_.import_attributes ().max_follow_policy (policy); return return_value; } template CosTrading::FollowOption TAO_Admin:: set_max_link_follow_policy (CosTrading::FollowOption policy) { CosTrading::FollowOption return_value = this->trader_.link_attributes ().max_link_follow_policy (); this->trader_.link_attributes ().max_link_follow_policy (policy); return return_value; } template CosTrading::TypeRepository_ptr TAO_Admin:: set_type_repos (CosTrading::TypeRepository_ptr repository) { CosTrading::TypeRepository_ptr return_value = this->trader_.support_attributes ().type_repos (); this->trader_.support_attributes ().type_repos (repository); return return_value; } template CosTrading::Admin::OctetSeq* TAO_Admin:: set_request_id_stem (const CosTrading::Admin::OctetSeq& stem) { ACE_GUARD_RETURN (TRADER_LOCK_TYPE, trader_mon, this->lock_, &this->stem_id_); this->stem_id_ = stem; return &this->stem_id_; } template void TAO_Admin:: list_offers (CORBA::ULong how_many, CosTrading::OfferIdSeq_out ids, CosTrading::OfferIdIterator_out id_itr) { // This method only applies when the register interface is implemented if (CORBA::is_nil (this->trader_.trading_components().register_if())) throw CosTrading::NotImplemented(); TAO_Offer_Database& type_map = this->trader_.offer_database (); TAO_Offer_Id_Iterator* offer_id_iter = type_map.retrieve_all_offer_ids (); id_itr = CosTrading::OfferIdIterator::_nil (); if (how_many > 0) { int check = offer_id_iter->next_n (how_many, ids); if (check == 1) { id_itr = offer_id_iter->_this (); offer_id_iter->_remove_ref (); } else delete offer_id_iter; } else ids = new CosTrading::OfferIdSeq (0); } template void TAO_Admin:: list_proxies (CORBA::ULong, CosTrading::OfferIdSeq_out, CosTrading::OfferIdIterator_out) { throw CosTrading::NotImplemented (); } template TAO_Link::TAO_Link (TAO_Trader &trader) : TAO_Trader_Components (trader.trading_components ()), TAO_Support_Attributes (trader.support_attributes ()), TAO_Link_Attributes (trader.link_attributes ()), trader_ (trader) { } template TAO_Link::~TAO_Link () { } template void TAO_Link:: add_link (const char *name, CosTrading::Lookup_ptr target, CosTrading::FollowOption def_pass_on_follow_rule, CosTrading::FollowOption limiting_follow_rule) { // Ensure the link name is valid. if (! TAO_Trader_Base::is_valid_link_name (name)) throw CosTrading::Link::IllegalLinkName (name); // Ensure this isn't a duplicate link name. CORBA::String_var link_name (name); if (this->links_.find (link_name) == 0) throw CosTrading::Link::DuplicateLinkName (name); // Ensure the lookup_ptr isn't nil. if (CORBA::is_nil (target)) throw CosTrading::InvalidLookupRef (target); // Ensure that the default link behavior isn't stronger than the // limiting link behavior. if (def_pass_on_follow_rule > limiting_follow_rule) throw CosTrading::Link::DefaultFollowTooPermissive( def_pass_on_follow_rule, limiting_follow_rule); // Ensure that the limiting link behavior for this link doesn't // exceed the maximum allowed for a link. CosTrading::FollowOption follow_policy = this->max_link_follow_policy (); if (limiting_follow_rule < follow_policy) throw CosTrading::Link::LimitingFollowTooPermissive( limiting_follow_rule, follow_policy); // Create a link info structure for this link of the federation. CosTrading::Link::LinkInfo link_info; link_info.target = CosTrading::Lookup::_duplicate (target); link_info.def_pass_on_follow_rule = def_pass_on_follow_rule; link_info.limiting_follow_rule = limiting_follow_rule; // Insert this link into the collection of links. this->links_.bind (link_name, link_info); } template void TAO_Link:: remove_link (const char *name) { // Ensure the link name is valid. if (! TAO_Trader_Base::is_valid_link_name (name)) throw CosTrading::Link::IllegalLinkName (name); // Ensure this isn't a duplicate link name. CORBA::String_var link_name (name); if (this->links_.find (link_name) == -1) throw CosTrading::Link::UnknownLinkName (name); // Erase the link state from the map. this->links_.unbind (link_name); } template CosTrading::Link::LinkInfo * TAO_Link::describe_link (const char *name) { // Ensure the link name is valid. if (! TAO_Trader_Base::is_valid_link_name (name)) throw CosTrading::Link::IllegalLinkName (name); // Ensure this isn't a duplicate link name. typename Links::ENTRY* link_entry = 0; CORBA::String_var link_name (name); if (this->links_.find (link_name, link_entry) == -1) throw CosTrading::Link::UnknownLinkName (name); // Build a new Link Info structure. CosTrading::Link::LinkInfo* new_link_info = 0; CosTrading::Link::LinkInfo& old_link_info = link_entry->int_id_; ACE_NEW_THROW_EX (new_link_info, CosTrading::Link::LinkInfo, CORBA::NO_MEMORY ()); new_link_info->def_pass_on_follow_rule = old_link_info.def_pass_on_follow_rule; new_link_info->limiting_follow_rule = old_link_info.limiting_follow_rule; new_link_info->target = old_link_info.target; // Delayed retrieval of register interface. // This avoids the nested upcall that would occur were we to invoke // this method in the add_link method. new_link_info->target_reg = old_link_info.target->register_if (); // return the link information for this link name. return new_link_info; } template CosTrading::LinkNameSeq* TAO_Link::list_links () { // Allocate space for the link names. size_t size = this->links_.current_size (); CORBA::ULong i = 0; CosTrading::LinkName* link_seq = CosTrading::LinkNameSeq::allocbuf (static_cast (size)); // Copy the link names into the buffer. for (typename Links::iterator links_iter (this->links_); ! links_iter.done (); links_iter++) link_seq[i++] = CORBA::string_dup ((*links_iter).ext_id_.in ()); // Return a sequence of the buf names. return new CosTrading::LinkNameSeq (i, i, link_seq, 1); } template void TAO_Link:: modify_link (const char *name, CosTrading::FollowOption def_pass_on_follow_rule, CosTrading::FollowOption limiting_follow_rule) { // Ensure the link name is valid. if (! TAO_Trader_Base::is_valid_link_name (name)) throw CosTrading::Link::IllegalLinkName (name); // Ensure this isn't a duplicate link name. typename Links::ENTRY* link_entry = 0; CORBA::String_var link_name (name); if (this->links_.find (link_name, link_entry) == -1) throw CosTrading::Link::UnknownLinkName (name); // Ensure that the default link behavior isn't stronger than the // limiting link behavior. if (def_pass_on_follow_rule > limiting_follow_rule) throw CosTrading::Link::DefaultFollowTooPermissive( def_pass_on_follow_rule, limiting_follow_rule); // Ensure that the limiting link behavior for this link doesn't // exceed the maximum allowed for a link. CosTrading::FollowOption follow_policy = this->max_link_follow_policy (); if (limiting_follow_rule < follow_policy) throw CosTrading::Link::LimitingFollowTooPermissive( limiting_follow_rule, follow_policy); // Adjust the link settings CosTrading::Link::LinkInfo& link_info = link_entry->int_id_; link_info.def_pass_on_follow_rule = def_pass_on_follow_rule; link_info.limiting_follow_rule = limiting_follow_rule; } template TAO_Proxy:: TAO_Proxy (TAO_Trader &trader) : TAO_Trader_Components (trader.trading_components ()), TAO_Support_Attributes (trader.support_attributes ()), trader_ (trader) { } template TAO_Proxy::~TAO_Proxy () { } template CosTrading::OfferId TAO_Proxy:: export_proxy (CosTrading::Lookup_ptr, const char *, const CosTrading::PropertySeq&, CORBA::Boolean, const char *, const CosTrading::PolicySeq&) { throw CORBA::UNKNOWN (); ACE_NOTREACHED (return 0;) } template void TAO_Proxy:: withdraw_proxy (const char *) { throw CORBA::UNKNOWN (); } template CosTrading::Proxy::ProxyInfo * TAO_Proxy:: describe_proxy (const char *) { throw CORBA::UNKNOWN (); ACE_NOTREACHED (return 0;) } template void TAO_Proxy:: list_proxies (CORBA::ULong, CosTrading::OfferIdSeq*&, CosTrading::OfferIdIterator_ptr&) { throw CORBA::UNKNOWN (); } TAO_END_VERSIONED_NAMESPACE_DECL #endif /* TAO_TRADER_INTERFACES_CPP */