Remove dynamic exceptions
[anna.git] / include / anna / diameter / codec / Message.hpp
index 376fa39..3c8a4f7 100644 (file)
@@ -86,7 +86,7 @@ class Message {
   int a_insertionPositionForChilds; // used with childrens
   anna::DataBlock a_forCode;
 
-  const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException);
+  const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const noexcept(false);
 
   // --- Developer notes ---
   // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length'
@@ -103,23 +103,23 @@ class Message {
   // Children helpers
 
   // Own
-  avp_iterator avp_begin() throw() { return a_avps.begin(); }
-  avp_iterator avp_end() throw() { return a_avps.end(); }
-  const_avp_iterator avp_begin() const throw() { return a_avps.begin(); }
-  const_avp_iterator avp_end() const throw() { return a_avps.end(); }
+  avp_iterator avp_begin() { return a_avps.begin(); }
+  avp_iterator avp_end() { return a_avps.end(); }
+  const_avp_iterator avp_begin() const { return a_avps.begin(); }
+  const_avp_iterator avp_end() const { return a_avps.end(); }
 
   /**
   * Gets avp total message length.
   */
-  U24 getLength() const throw();
+  U24 getLength() const ;
 
 
   // Internal
-  bool flagsOK(int &rc) const throw(); // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary.
-  int addChild(Avp *avp) throw() { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); }
-  const anna::diameter::stack::Command *getStackCommand(CommandId id) const throw(anna::RuntimeException);
+  bool flagsOK(int &rc) const ; // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary.
+  int addChild(Avp *avp) { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); }
+  const anna::diameter::stack::Command *getStackCommand(CommandId id) const noexcept(false);
 
-  void setFailedAvp(const parent_t &parent, AvpId wrong, const char *wrongName = NULL) throw(anna::RuntimeException);
+  void setFailedAvp(const parent_t &parent, AvpId wrong, const char *wrongName = NULL) noexcept(false);
   // During message decoding and validation, the first wrong avp is stored and all the tracking is managed to find out its
   //  nested path for the case of grouped avps with wrong avps inside. Remember the RFC 6733, section 7.5:
   //
@@ -150,13 +150,13 @@ protected:
   mutable Engine *a_engine;
 
   /** Codec Engine getter: avoids have to create base engine when using its child */
-  virtual Engine * getEngine() const throw(anna::RuntimeException);
+  virtual Engine * getEngine() const noexcept(false);
 
   /**
   * Initializes Message class information.
   * Any reimplementation must first invoke base class method.
   */
-  virtual void initialize() throw();
+  virtual void initialize() ;
 
 
 public:
@@ -196,7 +196,7 @@ public:
   * about #clear. The needed cleanup will be done automatically from decoding and xml
   * loading procedures, and initialized engine will be kept along message operations.
   */
-  void setEngine(Engine *engine) throw();
+  void setEngine(Engine *engine) ;
 
 
   // Length references
@@ -223,7 +223,8 @@ public:
   /**
   * Destructor
   */
-  ~Message();
+  virtual ~Message();
+
   // Virtual destructors are useful when you can delete an instance of a derived class through a pointer to base class:
   // This destructor is not virtual, then a pointer to base class (even pointing to a children one) will invoke this destructor, not the derived one.
   // My current solution: virtualizing method 'clear'
@@ -238,19 +239,19 @@ public:
 
      @param id Command identifier as pair (code,request-indicator).
   */
-  void setId(CommandId id) throw(anna::RuntimeException);
+  void setId(CommandId id) noexcept(false);
 
   /**
      Same as #setId but providing dictionary logical name for Avp searched
   */
-  void setId(const char *name) throw(anna::RuntimeException);
+  void setId(const char *name) noexcept(false);
 
   /**
      Sets the command version. By default, messages initializes with value 1.
 
      @param version Version provided
   */
-  void setVersion(U8 version) throw() { a_version = version; }
+  void setVersion(U8 version) { a_version = version; }
 
   /**
      Sets/unsets P bit activation.
@@ -258,7 +259,7 @@ public:
 
      @param activate Activates/deactivates the bit. True by default.
   */
-  void setProxiableBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
+  void setProxiableBit(bool activate = true) { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
 
   /**
      Sets/unsets E bit activation.
@@ -267,7 +268,7 @@ public:
 
      @param activate Activates/deactivates the bit. True by default.
   */
-  void setErrorBit(bool activate = true) throw() { if(isRequest()) return; if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
+  void setErrorBit(bool activate = true) { if(isRequest()) return; if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
 
   /**
      Sets/unsets T bit activation.
@@ -276,7 +277,7 @@ public:
 
      @param activate Activates/deactivates the bit. True by default.
   */
-  void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { if(isAnswer()) return; if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
+  void setPotentiallyReTransmittedMessageBit(bool activate = true) { if(isAnswer()) return; if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
 
   /**
      Sets the message application id.
@@ -293,19 +294,19 @@ public:
 
      @param aid Application-id.
   */
-  void setApplicationId(U32 aid) throw(anna::RuntimeException);
+  void setApplicationId(U32 aid) noexcept(false);
 
   /**
      Sets the message hop-by-hop
      @param hbh Hop-by-hop identifier.
   */
-  void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; }
+  void setHopByHop(U32 hbh) { a_hopByHop = hbh; }
 
   /**
      Sets the message end-to-end
      @param ete End-to-end identifier.
   */
-  void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; }
+  void setEndToEnd(U32 ete) { a_endToEnd = ete; }
 
 
   /**
@@ -316,7 +317,7 @@ public:
 
      @warning Request provided must be a request, in other case method do nothing.
   */
-  void setHeaderToAnswer(const Message &request) throw(anna::RuntimeException) {
+  void setHeaderToAnswer(const Message &request) noexcept(false) {
     if(!request.getId().second) return;
 
     a_engine = request.getEngine(); // we know this will be
@@ -396,7 +397,7 @@ public:
 
    @warning Request provided must be a request, in other case method do nothing.
   */
-  void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
+  void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) noexcept(false);
 
 
   /**
@@ -434,7 +435,7 @@ public:
 
      @param rc Result-Code value. DIAMETER_SUCCESS by default.
   */
-  void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
+  void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) noexcept(false);
 
 
   /**
@@ -443,7 +444,7 @@ public:
 
      @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside
   */
-  int getResultCode() const throw();
+  int getResultCode() const ;
 
 
   /**
@@ -453,13 +454,13 @@ public:
 
      @return Pointer to the new created avp.
   */
-  Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
+  Avp * addAvp(AvpId id) noexcept(false) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
 
 
   /**
      Same as #addAvp but providing dictionary logical name for Avp searched
   */
-  Avp * addAvp(const char *name) throw(anna::RuntimeException);
+  Avp * addAvp(const char *name) noexcept(false);
 
 
   /**
@@ -472,7 +473,7 @@ public:
 
      @return Pointer to the added avp (again).
   */
-  Avp * addAvp(Avp * avp) throw();
+  Avp * addAvp(Avp * avp) ;
 
 
   /**
@@ -484,13 +485,13 @@ public:
 
      @return Returns true if something was removed. False in other cases (including i.e. when this message is empty).
   */
-  bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
+  bool removeAvp(AvpId id, int ocurrence = 1) noexcept(false) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
 
 
   /**
      Same as #removeAvp but providing dictionary logical name for Avp searched
   */
-  bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
+  bool removeAvp(const char *name, int ocurrence = 1) noexcept(false);
 
 
   /**
@@ -504,7 +505,7 @@ public:
   * you don't initialize the engine to NULL, the second use of the message will keep the same engine deduced from the first
   * decoding/loading operation, which could be wrong if the second message belongs to a different application identifier.
   */
-  virtual void clear(bool resetEngine = true) throw(anna::RuntimeException);
+  virtual void clear(bool resetEngine = true) noexcept(false);
 
   /**
      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
@@ -518,7 +519,7 @@ public:
      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
      NULL because no answer is built for answers. By default, automatic answer is not built.
   */
-  void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException);
+  void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) noexcept(false);
 
   /**
     Fix childrens content regarding dictionary avp positions.
@@ -526,7 +527,7 @@ public:
     This is useful to give flexibility to the application during message construction before encoding or representing the data.
     Is not recommended to fix a recently decoded message because possible validation problems will be hidden.
   */
-  void fix() throw();
+  void fix() ;
 
   /**
      Validates the message regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
@@ -535,14 +536,14 @@ public:
      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
      NULL because no answer is built for answers. By default, automatic answer is not built.
   */
-  bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
+  bool valid(Message *ptrAnswer = NULL) const noexcept(false);
 
   /**
      Interpret xml data in order to dump over the class content.
      You could apply this multiple times over the same object. A basic cleanup is done respecting the codec engine.
      \param messageNode Message root node obtained from @functions::xmlFileTo
   */
-  void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
+  void fromXML(const anna::xml::Node* messageNode) noexcept(false);
 
   /**
    * Interpret a xml file in order to create a diameter message
@@ -553,7 +554,18 @@ public:
    *
    * @param xmlPathFile Complete path file to the xml document which represents the diameter message
    */
-  void loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException);
+  void loadXMLFile(const std::string &xmlPathFile) noexcept(false);
+
+  /**
+   * Interpret a xml string in order to create a diameter message
+   * You could apply this multiple times over the same object. A basic cleanup is done respecting the codec engine.
+   *
+   * @see functions::messageXmlDocumentFromXmlString
+   * @see fromXML
+   *
+   * @param xmlString xml representation of the diameter message
+   */
+  void loadXMLString(const std::string &xmlString) noexcept(false);
 
 
   // getters
@@ -561,59 +573,59 @@ public:
   /**
      Gets Message identifier as pair (code, request indicator).
   */
-  const CommandId & getId() const throw() { return a_id; }
+  const CommandId & getId() const { return a_id; }
 
   /**
      Gets the command version. By default, messages initializes with value 1.
 
      @return version Message version
   */
-  U8 getVersion() const throw() { return a_version; }
+  U8 getVersion() const { return a_version; }
 
   /**
      Gets Message request indicator.
   */
-  bool isRequest() const throw() { return a_id.second; }
+  bool isRequest() const { return a_id.second; }
 
   /**
      Gets Message answer indicator.
   */
-  bool isAnswer() const throw() { return !isRequest(); }
+  bool isAnswer() const { return !isRequest(); }
 
   /**
      Gets the message application id
      @return aid Application-id.
   */
-  const U32 & getApplicationId() const throw() { return a_applicationId; }
+  const U32 & getApplicationId() const { return a_applicationId; }
 
   /**
      Gets the message hop-by-hop
      @return hbh Hop-by-hop identifier.
   */
-  const U32 & getHopByHop() const throw() { return a_hopByHop; }
+  const U32 & getHopByHop() const { return a_hopByHop; }
 
   /**
      Gets the message end-to-end
      @return ete End-to-end identifier.
   */
-  const U32 & getEndToEnd() const throw() { return a_endToEnd; }
+  const U32 & getEndToEnd() const { return a_endToEnd; }
 
   /**
      Gets stack command (dictionary command reference).
   */
-  const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); }
+  const anna::diameter::stack::Command *getStackCommand() const noexcept(false) { return getStackCommand(a_id); }
 
   /** Returns R bit activation state */
-  bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); }
+  bool requestBit() const { return ((a_flags & RBitMask) != 0x00); }
 
   /** Returns P bit activation state */
-  bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
+  bool proxiableBit() const { return ((a_flags & PBitMask) != 0x00); }
 
   /** Returns E bit activation state */
-  bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); }
+  bool errorBit() const { return ((a_flags & EBitMask) != 0x00); }
 
   /** Returns T bit activation state */
-  bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); }
+  bool potentiallyReTransmittedMessageBit() const { return ((a_flags & TBitMask) != 0x00); }
 
 
   /**
@@ -644,11 +656,11 @@ public:
      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
      @param emode Excepcion mode handling: Ignore (no action is taken), Throw (excepcion when missing avp), Trace (trace situation as warning).
   */
-  const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
+  const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const noexcept(false) {
     return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
   }
 
-  Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
+  Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false) {
     return const_cast<Avp*>(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode));
   }
 
@@ -656,11 +668,11 @@ public:
   /**
      Same as #getAvp but providing dictionary logical name for Avp searched
   */
-  const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
+  const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const noexcept(false) {
     return _getAvp(name, ocurrence, emode);
   }
 
-  Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
+  Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false) {
     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
   }
 
@@ -671,19 +683,19 @@ public:
 
      @param id Avp identifier (pair code + vendor-id).
   */
-  int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); }
+  int countAvp(AvpId id) const { return Avp::countAvp(a_avps, id); }
 
   /**
      Same as #countAvp but providing dictionary logical name for Avp searched
   */
-  int countAvp(const char *name) const throw(anna::RuntimeException);
+  int countAvp(const char *name) const noexcept(false);
 
   /**
      Counts the number of children
 
      @param id Avp identifier (pair code + vendor-id).
   */
-  int countChilds() const throw() { return Avp::countChilds(a_avps); }
+  int countChilds() const { return Avp::countChilds(a_avps); }
 
   /**
      Encodes datablock with the class content. In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
@@ -692,20 +704,23 @@ public:
 
      @return DataBlock encoded (internal memory used)
   */
-  const anna::DataBlock & code() throw(anna::RuntimeException);
+  const anna::DataBlock & code() noexcept(false);
 
   /**
      Class xml representation
      \param parent Parent XML node on which hold this instance information.
      \return XML document with relevant information for this instance.
   */
-  anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+  anna::xml::Node* asXML(anna::xml::Node* parent) const ;
 
   /**
      Class xml string representation
+     @param normalize Optional normalization which sorts attribute names and removes
+     newlines in the xml representation in order to ease regexp matching.
+
      \return XML string representation with relevant information for this instance.
   */
-  std::string asXMLString() const throw();
+  std::string asXMLString(bool normalize = false) const ;
 
   /**
      Comparison operator by mean serialization
@@ -715,75 +730,65 @@ public:
 
      @return Comparison result
   */
-  friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
+  friend bool operator == (const Message & m1, const Message & m2) { return (m1.asXMLString() == m2.asXMLString()); }
 
   /**
-     Match a regular expression (string pattern) regarding xml string serialization for this message.
-     Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before
-     using the method in order to perform a more controlled comparison. In the same way, flags could be
-     ignored to simplify message xml presentation.
-     This powerful tool could be used to program traffic analysis and decide future behaviour (routing,
-     traslation, etc.).
+     Matchs a regular expression (string pattern) regarding xml string serialization for this message.
+     The message xml representation is internally normalized (attribute names are sort and newlines
+     are removed) in order to ease regexp matching.
 
-     <pre>
-     Examples:
+     You could use simple regular expressions.
+     For example, the pattern '<avp data="(.)*32251@3gpp.org" name="Service-Context-Id"/>' detects
+     PS charging contexts because of data suffix specification '32251@3gpp.org' for that AVP.
+     The pattern '<message(.)* name="Capabilities-Exchange-Request"' detects a CER message. And so on.
 
-     The pattern '<avp name="Service-Context-Id" data="(.)*32251@3gpp.org"/>' detects PS charging contexts
-     because of data suffix specification '32251@3gpp.org' for that AVP.
+     It would seems strange or 'creative' to use regular expressions within an hex string representation,
+     but anyway you could also do such kind of things to check non-printable data parts within the message:
+     for example, the pattern '<avp hex-data="0a[A-Fa-f0-9]{2}0a0a" name="Framed-IP-Address"/>'
+     matchs IP addresses for '10.x.10.10' where x = [0..255].
 
-     The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
+     Normally only printable 'data' fields are used for matching issues.
 
-     The pattern (string including carriage returns):
+     Now imagine 'message.xml' containing this avp:
 
-     '<avp name="Subscription-Id">
-        <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
-        <avp name="Subscription-Id-Data" data="606000106"/>
+     <pre>
+     ...
+     <avp name="Subscription-Id">
+        <avp alias="END_USER_E164" data="0" name="Subscription-Id-Type"/>
+        <avp data="616[0-9]{6}" name="Subscription-Id-Data"/>
      </avp>'
+     ...
+     </pre>
 
-     detects MSISDN (not IMSI) equal to 606000106
+     You could also extract AVP xml normalized representation in this way:
 
-     It would seems strange or 'creative' to use regular expressions within an hex string representation,
-     but anyway you could also do such kind of things to check non-printable data parts within the message:
-     for example, the pattern '<avp name="Framed-IP-Address" hex-data="0a[A-Fa-f0-9][A-Fa-f0-9]0a0a"/>'
-     matchs IP addresses for '10.x.10.10' where x = [0..255].
+     <pre>
+     anna::diameter::codec::Message myMessage;
+     myMessage.loadXMLFile("message.xml");
+     std::string subscriptionId = myMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString(true);
+     // Former is '<avp data="616[0-9]{6}" name="Subscription-Id-Data"/>'
+     </pre>
+
+     And then use to match incoming messages:
 
-     Note that string pattern could also be generated via #loadXML and then #asXML, that is to say, you
-     could get patterns through xml files which act as conditional triggers over message. In that case,
-     it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
-     during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
-
-     For example, imagine a 'pattern.xml' file like:
-     <message version="1" name="Credit-Control-Request" application-id="16777236" hop-by-hop-id="0" end-to-end-id="0">
-        <avp name="Subscription-Id">
-           <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
-           <avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>
-        </avp>
-     </message>
-
-     Then you could do:
-
-     anna::diameter::codec::Message patternMessage;
-     patternMessage.loadXML("pattern.xml");
-     std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
-     // Former is '<avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>'
-     bool match = incomingMessage.isLike(pattern);
-
-     Then, messages having MSISDN numbers starting with '616' will match the pattern.
-     Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
-     You could also build that string manually:
-
-     Example 1:
-     std::string pattern = "<avp name=\"Subscription-Id\">\n";
-     pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Type\" data=\"0\" alias=\"END_USER_E164\"/>\n"
-     pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"/>"
-
-     Example 2:
-     std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
+     <pre>
+     bool match = incomingMessage.isLike(subscriptionId);
      </pre>
 
+     Using a complex pattern (many avps, grouped ones) is possible, indeed testing ADML engine supports 'waitfe/fc-xml'
+     operations which load entire diameter messages to be used as a whole regular expression (hop-by-hop, end-to-end and
+     Origin-State-Id avp is automatically replaced by '[0-9]+' to make possible the comparison).
+
+     Those operations makes all the work, but if you use the API, you may take into account:
+
+     - Respect indentation for inner Message xml representation (normally 3 spaces).
+     - Sort alphabetically the attribute names in every xml node.
+     - Remove all the newlines in the xml representation as normalization stage.
+     - Ignore flags and set the fix mode for the message.
+
      \return Returns the match result
   */
-  bool isLike(const std::string &pattern) const throw();
+  bool isLike(const std::string &pattern) const ;
 
 
 //friend class Engine;