Remove dynamic exceptions
[anna.git] / include / anna / diameter / codec / Message.hpp
index fd44c42..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,27 +150,53 @@ 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:
 
   /**
   * Default constructor
+  * @param engine Codec engine used
   */
-  Message();
+  Message(Engine *engine = NULL);
 
   /**
   * Identified constructor
   * @param id Command identifier as pair (code,request-indicator).
+  * @param engine Codec engine used
   */
-  Message(CommandId id);
+  Message(CommandId id, Engine *engine = NULL);
+
+
+  /**
+  * Sets the codec engine.
+  *
+  * Once assigned (here or at constructor), this method SHALL NOT be used anymore.
+  * Also, the associated dictionary SHOULD NOT BE CHANGED through the engine,
+  * unless you know what are you doing.
+  * Setting a new different engine with different stack, even same engine where the
+  * stack has been dynamically changed, could cause a bad behaviour depending on the
+  * changes: in general, if the dictionary grows, nothing bad will happen, but if
+  * you remove or modified some elements which were processed with a certain format,
+  * will be interpreted as 'unknown' with the new dictionary, and then some problems
+  * may occur. If you add elements (vendors, avps, messages) is not a problem.
+  *
+  * IMPORTANT NOTES:
+  * 1) if you want to reuse the message, as a recommendation, you should #clear the
+  * message. In that way, next operation will adjust automatically the needed engine.
+  * 2) if you have dedicated message objects for each interface (application id), then
+  * you could set the corresponding engine on constructor (or setEngine), and forget
+  * 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) ;
 
 
   // Length references
@@ -197,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'
@@ -211,21 +238,20 @@ public:
      Sets the command identifier and clear the former content.
 
      @param id Command identifier as pair (code,request-indicator).
-     @param _clear Message will be cleared when updating the command identifier (default behaviour).
   */
-  void setId(CommandId id, bool _clear = true) 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.
@@ -233,29 +259,31 @@ 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.
      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
+     This flag MUST NOT be set in request messages (in this case, it will be ignored).
 
      @param activate Activates/deactivates the bit. True by default.
   */
-  void setErrorBit(bool activate = true) throw() { 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.
      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
+     This flag MUST NOT be set in answer messages (in this case, it will be ignored).
 
      @param activate Activates/deactivates the bit. True by default.
   */
-  void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { 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.
 
      The codec engine could be configured to force a stack selection based in this field value: see #selectStackWithApplicationId.
-     In multistack applications (which also shall be monothreaded), you only have to take care about how to apply this method: the thing
+     In multistack applications (in case of being monothread), you only have to take care about how to apply this method: the thing
      is that you must not interleave message builds which belongs to different stacks. For example, you could think about setting the
      message header for message A using stack A. Then, start to add the message header fields for a second message B using another stack B.
      Following you would add the message A avps, but then, the stack is not going to be automatically changed (this is only done through this
@@ -266,19 +294,19 @@ public:
 
      @param aid Application-id.
   */
-  void setApplicationId(U32 aid) throw();
+  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; }
 
 
   /**
@@ -289,10 +317,12 @@ public:
 
      @warning Request provided must be a request, in other case method do nothing.
   */
-  void setHeaderToAnswer(const Message &request) throw() {
+  void setHeaderToAnswer(const Message &request) noexcept(false) {
     if(!request.getId().second) return;
 
-    setId(CommandId(request.getId().first, !request.getId().second), false /* don't clear */);
+    a_engine = request.getEngine(); // we know this will be
+
+    setId(CommandId(request.getId().first, !request.getId().second));
     setVersion(request.getVersion());
     setApplicationId(request.getApplicationId());
     setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2).
@@ -367,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();
+  void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) noexcept(false);
 
 
   /**
@@ -405,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);
 
 
   /**
@@ -414,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 ;
 
 
   /**
@@ -424,23 +454,26 @@ 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);
 
 
   /**
      Adds an avp child providing a persistent pointer (must be maintained by application).
+     It is not allowed to add an avp with no codec engine configured, neither if the engine
+     is not the same.
 
      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
+     Also NULL returned for bad engine configuration.
 
      @return Pointer to the added avp (again).
   */
-  Avp * addAvp(Avp * avp) throw() { if(!avp) return NULL; addChild(avp); return avp; }
+  Avp * addAvp(Avp * avp) ;
 
 
   /**
@@ -452,34 +485,41 @@ 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);
 
 
   /**
   * Clears and initializes Message class information.
-  * Application must clear auxiliary message objects before adding Avps in a new context.
+  * Application must clear auxiliary message objects before adding Avps in a new context if the same object is reused.
   * Application don't need to clear a message object before decode operation (decode invokes #clear before any other task).
   * Any reimplementation must first invoke base class method.
+  *
+  * @param resetEngine Sets to NULL the codec engine (true, default) or respect its current value (false). If you are going
+  * to reuse the message instance it is better to clear all the information (default) to manage different stacks, because if
+  * 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() 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
      message is valid against all odds then validation will go on). In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
      in a moment which depends on validation depth (codec::Engine::ValidationDepth).
 
+     You could decode multiple times over the same object. A basic cleanup is done respecting the codec engine.
+
      @param db buffer data block processed. Before decoding, the whole message instance will be cleared (no need to invoke #clear before #decode).
      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
      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.
@@ -487,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.
@@ -496,89 +536,36 @@ 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.
-     \param messageNode Message root node
+     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 xml string representation in order to dump over the class content.
-     DTD validation is used in the same way that #loadXML does.
-     \param xmlString XML string representation with relevant information for this instance
-  */
-  void fromXMLString(const std::string &xmlString) throw(anna::RuntimeException);
+   * Interpret a xml file 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::messageXmlDocumentFromXmlFile
+   * @see fromXML
+   *
+   * @param xmlPathFile Complete path file to the xml document which represents the diameter message
+   */
+  void loadXMLFile(const std::string &xmlPathFile) noexcept(false);
 
   /**
-     Loads an xml file based on this message DTD (could be accumulative, no initialization will be performed by this method).
-
-     <pre>
-     <!ELEMENT message (avp*)>
-     <!ELEMENT avp (avp*)>
-
-     <!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>
-     <!--
-        version: Diameter version. Sets '1' by default
-        name:    Command name within working stack (dictionary identifier)
-
-        In order to get more coding capabilities, command code and flags could be established instead of former command name,
-         but neither of them are allowed if 'name' is provided (and vice versa):
-
-        code:    Command code
-        flags:   Command flags byte value (0-255) where standard bit set for flags is 'RPET rrrr': (R)equest, (P)roxiable, (E)rror, Potentially re-(T)ransmitted message and (r)eserved
-
-
-        application-id:   Message application id
-        hop-by-hop-id:    Message hop by hop id. Sets '0' by default
-        end-by-end-id:    Message end by end id. Sets '0' by default
-     -->
-
-     <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
-     <!--
-        name:   Avp name within working stack (dictionary identifier)
-
-        In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,
-         but neither of them are allowed if 'name' is provided (and vice versa):
-
-        code:          Avp code
-        vendor-code:   Avp vendor code
-        flags:         Avp flags byte value (0-255) where standard bit set for flags is 'VMPr rrrr': (V)endor-specific, (M)andatory, end to end encry(P)tion and r(eserved)
-
-
-        data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also
-                        useful for certain formats which could be easily understandable in such friendly/smart representation. We will
-                        achieve different human-readable strings depending on data format:
-
-                          [ OctetString ] (if printable, but not recommended)
-                          [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)
-                          [ Time ] (NTP timestamp, normal number representation)
-                          [ Address ] (auto detects IPv4 or IPv6 address version, then only ip address is specified: IPv4 with dots, IPv6 with colons)
-                          [ UTF8String, DiameterIdentity, DiameterURI ] (printable)
-                          [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)
-
-                          New application formats must define specific natural representation for internal raw data
-
-        hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind
-                        of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable
-                        data and should better be encoded within this field although being printable. Unknown avps (which fails identifying
-                        provided name or code/vendor-code) must always use this representation.
-
-        Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,
-         OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport
-         readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).
-        Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,
-         because xml is read by humans with testing and monitoring purposes.
-     -->
-     </pre>
-
-     @param xmlPathFile Complete path file to the xml document which represents the diameter message
-     @see fromXMLString
-  */
-  void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException);
-
+   * 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
@@ -586,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); }
 
 
   /**
@@ -669,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));
   }
 
@@ -681,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));
   }
 
@@ -696,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
@@ -717,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
@@ -740,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-by-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;
@@ -821,3 +801,4 @@ public:
 
 
 #endif
+