TAO_DIOP_Profile Class Reference

This class defines the protocol specific attributes required for locating ORBs over a TCP/IP network. More...

#include <DIOP_Profile.h>

Inheritance diagram for TAO_DIOP_Profile:

Inheritance graph
[legend]
Collaboration diagram for TAO_DIOP_Profile:

Collaboration graph
[legend]
List of all members.

Public Member Functions

virtual char object_key_delimiter (void) const
 TAO_DIOP_Profile (const ACE_INET_Addr &addr, const TAO::ObjectKey &object_key, const TAO_GIOP_Message_Version &version, TAO_ORB_Core *orb_core)
 TAO_DIOP_Profile (const char *host, CORBA::UShort port, const TAO::ObjectKey &object_key, const ACE_INET_Addr &addr, const TAO_GIOP_Message_Version &version, TAO_ORB_Core *orb_core)
 TAO_DIOP_Profile (TAO_ORB_Core *orb_core)
 Profile constructor, default.

 ~TAO_DIOP_Profile (void)
 Destructor is to be called only through .

virtual char * to_string ()
 Template methods. Please tao/Profile.h for documentation.

virtual int encode_endpoints (void)
virtual TAO_Endpointendpoint (void)
virtual CORBA::ULong endpoint_count (void) const
virtual CORBA::ULong hash (CORBA::ULong max)
void add_endpoint (TAO_DIOP_Endpoint *endp)

Static Public Member Functions

const char * prefix (void)
 Return the char string prefix.


Static Public Attributes

const char object_key_delimiter_ = '/'
 The object key delimiter that DIOP uses or expects.


Protected Member Functions

virtual int decode_profile (TAO_InputCDR &cdr)
 Template methods. Please see tao/Profile.h for documentation.

virtual void parse_string_i (const char *string)
virtual void create_profile_body (TAO_OutputCDR &cdr) const
virtual int decode_endpoints (void)
virtual CORBA::Boolean do_is_equivalent (const TAO_Profile *other_profile)

Protected Attributes

TAO_DIOP_Endpoint endpoint_
CORBA::ULong count_
 Number of endpoints in the list headed by .


Detailed Description

This class defines the protocol specific attributes required for locating ORBs over a TCP/IP network.

This class defines the DIOP profile as specified in the CORBA specification.

Definition at line 45 of file DIOP_Profile.h.


Constructor & Destructor Documentation

TAO_DIOP_Profile::TAO_DIOP_Profile const ACE_INET_Addr addr,
const TAO::ObjectKey object_key,
const TAO_GIOP_Message_Version version,
TAO_ORB_Core orb_core
 

Profile constructor, same as above except the object_key has already been marshaled.

Definition at line 35 of file DIOP_Profile.cpp.

References TAO_TAG_DIOP_PROFILE.

00039   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00040                  orb_core,
00041                  object_key,
00042                  version),
00043     endpoint_ (addr,
00044                orb_core->orb_params ()->use_dotted_decimal_addresses ()),
00045     count_ (1)
00046 {
00047 }

TAO_DIOP_Profile::TAO_DIOP_Profile const char *  host,
CORBA::UShort  port,
const TAO::ObjectKey object_key,
const ACE_INET_Addr addr,
const TAO_GIOP_Message_Version version,
TAO_ORB_Core orb_core
 

Profile constructor, this is the most efficient since it doesn't require any address resolution processing.

Definition at line 49 of file DIOP_Profile.cpp.

References TAO_TAG_DIOP_PROFILE.

00055   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00056                  orb_core,
00057                  object_key,
00058                  version),
00059     endpoint_ (host, port, addr),
00060     count_ (1)
00061 {
00062 }

TAO_DIOP_Profile::TAO_DIOP_Profile TAO_ORB_Core orb_core  ) 
 

Profile constructor, default.

Definition at line 64 of file DIOP_Profile.cpp.

References TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR, and TAO_TAG_DIOP_PROFILE.

00065   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00066                  orb_core,
00067                  TAO_GIOP_Message_Version (TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR)),
00068     endpoint_ (),
00069     count_ (1)
00070 {
00071 }

TAO_DIOP_Profile::~TAO_DIOP_Profile void   ) 
 

Destructor is to be called only through .

Definition at line 73 of file DIOP_Profile.cpp.

References endpoint(), and TAO_Endpoint::next().

00074 {
00075   // Clean up the list of endpoints since we own it.
00076   // Skip the head, since it is not dynamically allocated.
00077   TAO_Endpoint *tmp = 0;
00078 
00079   for (TAO_Endpoint *next = this->endpoint ()->next ();
00080        next != 0;
00081        next = tmp)
00082     {
00083       tmp = next->next ();
00084       delete next;
00085     }
00086 }


Member Function Documentation

void TAO_DIOP_Profile::add_endpoint TAO_DIOP_Endpoint endp  ) 
 

Add to this profile's list of endpoints (it is inserted next to the head of the list). This profiles takes ownership of .

Definition at line 283 of file DIOP_Profile.cpp.

References TAO_DIOP_Endpoint::next_.

Referenced by TAO_DIOP_Acceptor::create_shared_profile(), and decode_endpoints().

00284 {
00285   endp->next_ = this->endpoint_.next_;
00286   this->endpoint_.next_ = endp;
00287 
00288   this->count_++;
00289 }

void TAO_DIOP_Profile::create_profile_body TAO_OutputCDR cdr  )  const [protected, virtual]
 

Implements TAO_Profile.

Definition at line 336 of file DIOP_Profile.cpp.

References ACE_ERROR, TAO_Tagged_Components::encode(), LM_ERROR, TAO_GIOP_Message_Version::major, TAO_GIOP_Message_Version::minor, TAO::Refcounted_ObjectKey::object_key(), TAO_Profile::tagged_components(), TAO_ENCAP_BYTE_ORDER, ACE_OutputCDR::write_octet(), ACE_OutputCDR::write_string(), and ACE_OutputCDR::write_ushort().

00337 {
00338   encap.write_octet (TAO_ENCAP_BYTE_ORDER);
00339 
00340   // The GIOP version
00341   encap.write_octet (this->version_.major);
00342   encap.write_octet (this->version_.minor);
00343 
00344   // STRING hostname from profile
00345   encap.write_string (this->endpoint_.host ());
00346 
00347   // UNSIGNED SHORT port number
00348   encap.write_ushort (this->endpoint_.port ());
00349 
00350   // OCTET SEQUENCE for object key
00351   if (this->ref_object_key_)
00352     encap << this->ref_object_key_->object_key ();
00353   else
00354     {
00355       ACE_ERROR ((LM_ERROR,
00356                   "(%P|%t) TAO - UIOP_Profile::create_profile_body "
00357                   "no object key marshalled \n"));
00358     }
00359 
00360   if (this->version_.major > 1
00361       || this->version_.minor > 0)
00362     this->tagged_components ().encode (encap);
00363 }

int TAO_DIOP_Profile::decode_endpoints void   )  [protected, virtual]
 

Implements TAO_Profile.

Definition at line 422 of file DIOP_Profile.cpp.

References ACE_NEW_RETURN, add_endpoint(), IOP::TaggedComponent::component_data, TAO::unbounded_value_sequence< T >::get_buffer(), TAO_Tagged_Components::get_component(), TAO::unbounded_value_sequence< IIOP_Endpoint_Info >::length(), TAO::unbounded_value_sequence< T >::length(), TAO_Endpoint::priority(), ACE_InputCDR::reset_byte_order(), and IOP::TaggedComponent::tag.

00423 {
00424   IOP::TaggedComponent tagged_component;
00425   tagged_component.tag = TAO_TAG_ENDPOINTS;
00426 
00427   if (this->tagged_components_.get_component (tagged_component))
00428     {
00429       const CORBA::Octet *buf =
00430         tagged_component.component_data.get_buffer ();
00431 
00432       TAO_InputCDR in_cdr (reinterpret_cast<const char*> (buf),
00433                            tagged_component.component_data.length ());
00434 
00435       // Extract the Byte Order.
00436       CORBA::Boolean byte_order;
00437       if ((in_cdr >> ACE_InputCDR::to_boolean (byte_order)) == 0)
00438         return -1;
00439       in_cdr.reset_byte_order (static_cast<int> (byte_order));
00440 
00441       // Extract endpoints sequence.
00442       TAO::IIOPEndpointSequence endpoints;
00443 
00444       if ((in_cdr >> endpoints) == 0)
00445         return -1;
00446 
00447       // Get the priority of the first endpoint (head of the list.
00448       // It's other data is extracted as part of the standard profile
00449       // decoding.
00450       this->endpoint_.priority (endpoints[0].priority);
00451 
00452       // Use information extracted from the tagged component to
00453       // populate the profile.  Skip the first endpoint, since it is
00454       // always extracted through standard profile body.  Also, begin
00455       // from the end of the sequence to preserve endpoint order,
00456       // since <add_endpoint> method reverses the order of endpoints
00457       // in the list.
00458       for (CORBA::ULong i = endpoints.length () - 1;
00459            i > 0;
00460            --i)
00461         {
00462           TAO_DIOP_Endpoint *endpoint = 0;
00463           ACE_NEW_RETURN (endpoint,
00464                           TAO_DIOP_Endpoint (endpoints[i].host,
00465                                              endpoints[i].port,
00466                                              endpoints[i].priority),
00467                           -1);
00468 
00469           this->add_endpoint (endpoint);
00470         }
00471     }
00472 
00473   return 0;
00474 }

int TAO_DIOP_Profile::decode_profile TAO_InputCDR cdr  )  [protected, virtual]
 

Template methods. Please see tao/Profile.h for documentation.

Implements TAO_Profile.

Definition at line 94 of file DIOP_Profile.cpp.

References ACE_DEBUG, ACE_TEXT, ACE_InputCDR::good_bit(), LM_DEBUG, TAO_DIOP_Endpoint::object_addr_, ACE_InputCDR::read_string(), ACE_InputCDR::read_ushort(), ACE_Addr::set_type(), and TAO_debug_level.

00095 {
00096   // @@ NOTE: This code is repeated thrice. Need to factor out in a
00097   // better manner.
00098   // Decode host and port into the <endpoint_>.
00099   if (cdr.read_string (this->endpoint_.host_.out ()) == 0
00100       || cdr.read_ushort (this->endpoint_.port_) == 0)
00101     {
00102       if (TAO_debug_level > 0)
00103         ACE_DEBUG ((LM_DEBUG,
00104                     ACE_TEXT ("TAO (%P|%t) DIOP_Profile::decode - ")
00105                     ACE_TEXT ("error while decoding host/port")));
00106       return -1;
00107     }
00108 
00109   if (cdr.good_bit ())
00110     {
00111       // Invalidate the object_addr_ until first access.
00112       this->endpoint_.object_addr_.set_type (-1);
00113 
00114       return 1;
00115     }
00116 
00117   return -1;
00118 }

CORBA::Boolean TAO_DIOP_Profile::do_is_equivalent const TAO_Profile other_profile  )  [protected, virtual]
 

Implements TAO_Profile.

Definition at line 220 of file DIOP_Profile.cpp.

References endpoint_, TAO_DIOP_Endpoint::is_equivalent(), and TAO_DIOP_Endpoint::next_.

00221 {
00222   const TAO_DIOP_Profile *op =
00223     dynamic_cast<const TAO_DIOP_Profile *> (other_profile);
00224 
00225   // Check endpoints equivalence.
00226   const TAO_DIOP_Endpoint *other_endp = &op->endpoint_;
00227   for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
00228        endp != 0;
00229        endp = endp->next_)
00230     {
00231       if (endp->is_equivalent (other_endp))
00232         other_endp = other_endp->next_;
00233       else
00234         return 0;
00235     }
00236 
00237   return 1;
00238 }

int TAO_DIOP_Profile::encode_endpoints void   )  [virtual]
 

Implements TAO_Profile.

Definition at line 366 of file DIOP_Profile.cpp.

References ACE_OutputCDR::begin(), IOP::TaggedComponent::component_data, ACE_Message_Block::cont(), TAO::unbounded_value_sequence< T >::get_buffer(), TAO_DIOP_Endpoint::host(), ACE_Message_Block::length(), TAO::unbounded_value_sequence< T >::length(), TAO::unbounded_value_sequence< IIOP_Endpoint_Info >::length(), ACE_OS::memcpy(), TAO_DIOP_Endpoint::next_, TAO_DIOP_Endpoint::port(), TAO_Endpoint::priority(), ACE_Message_Block::rd_ptr(), TAO_Tagged_Components::set_component(), IOP::TaggedComponent::tag, TAO_ENCAP_BYTE_ORDER, and ACE_OutputCDR::total_length().

00367 {
00368   // Create a data structure and fill it with endpoint info for wire
00369   // transfer.
00370   // We include information for the head of the list
00371   // together with other endpoints because even though its addressing
00372   // info is transmitted using standard ProfileBody components, its
00373   // priority is not!
00374 
00375   TAO::IIOPEndpointSequence endpoints;
00376   endpoints.length (this->count_);
00377 
00378   const TAO_DIOP_Endpoint *endpoint = &this->endpoint_;
00379   for (CORBA::ULong i = 0;
00380        i < this->count_;
00381        ++i)
00382     {
00383       endpoints[i].host = endpoint->host ();
00384       endpoints[i].port = endpoint->port ();
00385       endpoints[i].priority = endpoint->priority ();
00386 
00387       endpoint = endpoint->next_;
00388     }
00389 
00390   // Encode the data structure.
00391   TAO_OutputCDR out_cdr;
00392   if ((out_cdr << ACE_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER)
00393        == 0)
00394       || (out_cdr << endpoints) == 0)
00395     return -1;
00396   size_t length = out_cdr.total_length ();
00397 
00398   IOP::TaggedComponent tagged_component;
00399   tagged_component.tag = TAO_TAG_ENDPOINTS;
00400   tagged_component.component_data.length (static_cast<CORBA::ULong> (length));
00401   CORBA::Octet *buf =
00402     tagged_component.component_data.get_buffer ();
00403 
00404   for (const ACE_Message_Block *iterator = out_cdr.begin ();
00405        iterator != 0;
00406        iterator = iterator->cont ())
00407     {
00408       size_t i_length = iterator->length ();
00409       ACE_OS::memcpy (buf, iterator->rd_ptr (), i_length);
00410 
00411       buf += i_length;
00412     }
00413 
00414   // Add component with encoded endpoint data to this profile's
00415   // TaggedComponents.
00416   tagged_components_.set_component (tagged_component);
00417 
00418   return  0;
00419 }

TAO_Endpoint * TAO_DIOP_Profile::endpoint void   )  [virtual]
 

Implements TAO_Profile.

Definition at line 271 of file DIOP_Profile.cpp.

Referenced by TAO_DIOP_Acceptor::create_new_profile(), TAO_DIOP_Acceptor::create_shared_profile(), and ~TAO_DIOP_Profile().

00272 {
00273   return &this->endpoint_;
00274 }

CORBA::ULong TAO_DIOP_Profile::endpoint_count void   )  const [virtual]
 

Implements TAO_Profile.

Definition at line 277 of file DIOP_Profile.cpp.

00278 {
00279   return this->count_;
00280 }

CORBA::ULong TAO_DIOP_Profile::hash CORBA::ULong  max  )  [virtual]
 

Implements TAO_Profile.

Definition at line 241 of file DIOP_Profile.cpp.

References TAO_DIOP_Endpoint::hash(), TAO_Profile::hash_service_i(), TAO::unbounded_value_sequence< T >::length(), TAO_GIOP_Message_Version::minor, TAO_DIOP_Endpoint::next_, TAO::Refcounted_ObjectKey::object_key(), and TAO_Profile::tag().

00243 {
00244   // Get the hashvalue for all endpoints.
00245   CORBA::ULong hashval = 0;
00246   for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
00247        endp != 0;
00248        endp = endp->next_)
00249     {
00250       hashval += endp->hash ();
00251     }
00252 
00253   hashval += this->version_.minor;
00254   hashval += this->tag ();
00255 
00256   const TAO::ObjectKey &ok =
00257     this->ref_object_key_->object_key ();
00258 
00259   if (ok.length () >= 4)
00260     {
00261       hashval += ok[1];
00262       hashval += ok[3];
00263     }
00264 
00265   hashval += this->hash_service_i (max);
00266 
00267   return hashval % max;
00268 }

char TAO_DIOP_Profile::object_key_delimiter void   )  const [virtual]
 

Implements TAO_Profile.

Definition at line 29 of file DIOP_Profile.cpp.

References object_key_delimiter_.

00030 {
00031   return TAO_DIOP_Profile::object_key_delimiter_;
00032 }

void TAO_DIOP_Profile::parse_string_i const char *  string  )  [protected, virtual]
 

Implements TAO_Profile.

Definition at line 121 of file DIOP_Profile.cpp.

References ACE_DEBUG, ACE_TEXT, ACE_THROW, ACE_OS::atoi(), TAO::ObjectKey_Table::bind(), TAO::ObjectKey::decode_string_to_sequence(), ACE_INET_Addr::get_host_name(), TAO_DIOP_Endpoint::host_, LM_DEBUG, MAXHOSTNAMELEN, TAO_ORB_Core::object_key_table(), TAO_Profile::orb_core(), TAO_DIOP_Endpoint::port_, ACE_OS::strchr(), ACE_OS::strcmp(), CORBA::string_alloc(), CORBA::string_dup(), ACE_OS::strncpy(), and TAO_debug_level.

00123 {
00124   // Pull off the "hostname:port/" part of the objref
00125   // Copy the string because we are going to modify it...
00126   const char *okd =
00127     ACE_OS::strchr (ior, this->object_key_delimiter_);
00128 
00129   if (okd == 0 || okd == ior)
00130     {
00131       // No object key delimiter or no hostname specified.
00132       ACE_THROW (CORBA::INV_OBJREF (
00133                    CORBA::SystemException::_tao_minor_code (
00134                      TAO::VMCID,
00135                      EINVAL),
00136                    CORBA::COMPLETED_NO));
00137     }
00138 
00139   // Length of host string.
00140   CORBA::ULong length_host = 0;
00141 
00142   const char *cp_pos = ACE_OS::strchr (ior, ':');  // Look for a port
00143 
00144   if (cp_pos == ior)
00145     {
00146       // No hostname specified!  It is required by the spec.
00147       ACE_THROW (CORBA::INV_OBJREF (
00148                    CORBA::SystemException::_tao_minor_code (
00149                      TAO::VMCID,
00150                      EINVAL),
00151                    CORBA::COMPLETED_NO));
00152     }
00153   else if (cp_pos != 0)
00154     {
00155       // A port number or port name was specified.
00156       CORBA::ULong length_port = okd - cp_pos - 1;
00157 
00158       CORBA::String_var tmp = CORBA::string_alloc (length_port);
00159 
00160       ACE_OS::strncpy (tmp.inout (), cp_pos + 1, length_port);
00161       tmp[length_port] = '\0';
00162 
00163       this->endpoint_.port_ =
00164         static_cast<CORBA::UShort> (ACE_OS::atoi (tmp.in ()));
00165 
00166       length_host = cp_pos - ior;
00167     }
00168   else
00169     length_host = okd - ior;
00170 
00171   CORBA::String_var tmp = CORBA::string_alloc (length_host);
00172 
00173   // Skip the trailing '/'
00174   ACE_OS::strncpy (tmp.inout (), ior, length_host);
00175   tmp[length_host] = '\0';
00176 
00177   this->endpoint_.host_ = tmp._retn ();
00178 
00179   if (ACE_OS::strcmp (this->endpoint_.host_.in (), "") == 0)
00180     {
00181       ACE_INET_Addr host_addr;
00182 
00183       char tmp_host [MAXHOSTNAMELEN + 1];
00184 
00185       // If no host is specified: assign the default host, i.e. the
00186       // local host.
00187       if (host_addr.get_host_name (tmp_host,
00188                                    sizeof (tmp_host)) != 0)
00189         {
00190           // Can't get the IP address since the INET_Addr wasn't
00191           // initialized.  Just throw an exception.
00192 
00193           if (TAO_debug_level > 0)
00194             ACE_DEBUG ((LM_DEBUG,
00195                         ACE_TEXT ("\n\nTAO (%P|%t) ")
00196                         ACE_TEXT ("IIOP_Profile::parse_string ")
00197                         ACE_TEXT ("- %p\n\n"),
00198                         ACE_TEXT ("cannot determine hostname")));
00199 
00200           // @@ What's the right exception to throw here?
00201           ACE_THROW (CORBA::INV_OBJREF (
00202                        CORBA::SystemException::_tao_minor_code (
00203                          TAO::VMCID,
00204                          EINVAL),
00205                        CORBA::COMPLETED_NO));
00206         }
00207       else
00208         this->endpoint_.host_ = CORBA::string_dup (tmp_host);
00209     }
00210 
00211   TAO::ObjectKey ok;
00212   TAO::ObjectKey::decode_string_to_sequence (ok,
00213                                              okd + 1);
00214 
00215   (void) this->orb_core ()->object_key_table ().bind (ok,
00216                                                       this->ref_object_key_);
00217 }

const char * TAO_DIOP_Profile::prefix void   )  [static]
 

Return the char string prefix.

Definition at line 330 of file DIOP_Profile.cpp.

00331 {
00332   return ::the_prefix;
00333 }

char * TAO_DIOP_Profile::to_string  )  [virtual]
 

Template methods. Please tao/Profile.h for documentation.

Implements TAO_Profile.

Definition at line 292 of file DIOP_Profile.cpp.

References TAO::ObjectKey::encode_sequence_to_string(), TAO::Refcounted_ObjectKey::object_key(), object_key_delimiter_, TAO_DIOP_Endpoint::port(), ACE_OS::sprintf(), CORBA::string_alloc(), ACE_OS::strlen(), and the_prefix.

00293 {
00294   CORBA::String_var key;
00295   TAO::ObjectKey::encode_sequence_to_string (key.inout(),
00296                                             this->ref_object_key_->object_key ());
00297 
00298   size_t buflen = (8 /* "corbaloc" */ +
00299                    1 /* colon separator */ +
00300                    ACE_OS::strlen (::the_prefix) +
00301                    1 /* colon separator */ +
00302                    1 /* major version */ +
00303                    1 /* decimal point */ +
00304                    1 /* minor version */ +
00305                    1 /* `@' character */ +
00306                    ACE_OS::strlen (this->endpoint_.host ()) +
00307                    1 /* colon separator */ +
00308                    5 /* port number */ +
00309                    1 /* object key separator */ +
00310                    ACE_OS::strlen (key.in ()));
00311 
00312   char * buf = CORBA::string_alloc (static_cast<CORBA::ULong> (buflen));
00313 
00314   static const char digits [] = "0123456789";
00315 
00316   ACE_OS::sprintf (buf,
00317                    "corbaloc:%s:%c.%c@%s:%d%c%s",
00318                    ::the_prefix,
00319                    digits [this->version_.major],
00320                    digits [this->version_.minor],
00321                    this->endpoint_.host (),
00322                    this->endpoint_.port (),
00323                    this->object_key_delimiter_,
00324                    key.in ());
00325 
00326   return buf;
00327 }


Member Data Documentation

CORBA::ULong TAO_DIOP_Profile::count_ [protected]
 

Number of endpoints in the list headed by .

Definition at line 123 of file DIOP_Profile.h.

TAO_DIOP_Endpoint TAO_DIOP_Profile::endpoint_ [protected]
 

Head of this profile's list of endpoints. This endpoint is not dynamically allocated because a profile always contains at least one endpoint.

Currently, a profile contains more than one endpoint, i.e., list contains more than just the head, only when RTCORBA is enabled. However, in the near future, this will be used in nonRT mode as well, e.g., to support TAG_ALTERNATE_DIOP_ADDRESS feature. Addressing info of the default endpoint, i.e., head of the list, is transmitted using standard DIOP ProfileBody components. See method documentation above for how the rest of the endpoint list is transmitted.

Definition at line 120 of file DIOP_Profile.h.

Referenced by do_is_equivalent().

TAO_BEGIN_VERSIONED_NAMESPACE_DECL const char TAO_DIOP_Profile::object_key_delimiter_ = '/' [static]
 

The object key delimiter that DIOP uses or expects.

Definition at line 26 of file DIOP_Profile.cpp.

Referenced by object_key_delimiter(), and to_string().


The documentation for this class was generated from the following files:
Generated on Thu Nov 9 13:41:10 2006 for TAO_Strategies by doxygen 1.3.6