Remove dynamic exceptions
[anna.git] / include / anna / diameter / codec / EngineImpl.hpp
index b79aeb1..22fb82f 100644 (file)
@@ -1,37 +1,9 @@
-// ANNA - Anna is Not Nothingness Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// http://redmine.teslayout.com/projects/anna-suite
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     *  Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: eduardo.ramos.testillano@gmail.com
-//          cisco.tierra@gmail.com
+// ANNA - Anna is Not Nothingness Anymore                                                         //
+//                                                                                                //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
+//                                                                                                //
+// See project site at http://redmine.teslayout.com/projects/anna-suite                           //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
 
 
 #ifndef anna_diameter_codec_EngineImpl_hpp
@@ -64,8 +36,6 @@ class Dictionary;
 
 namespace codec {
 
-extern const char *MessageDTD;
-
 class Message;
 class Avp;
 
@@ -78,23 +48,15 @@ class Avp;
  * A child implementation could manage complex Avp classes with new data-part formats. Grouped ones could
  *  allocate new complex Avps through such engine which knows how to allocate this special Avp's (also for
  *  complex Message classes with application-specific setters and getters as credit-control related avps,
- *  or some another context items). For example helpers for TME scope stands for a new engine component
- *  called tme::Engine, allocating tme::Avp and tme::Message classes which support three new Avp formats:
+ *  or some another context items). For example tme::Avp and tme::Message classes support three new Avp formats:
  *  ISDNNumber, ISDNAddress and Unsigned16. Anyway, main Message/Avp and Engine classes stand for all contexts
  *  included in anna::diameter, that is to say, whole contexts (at the time only TME) will be included in future
  *  when needed apart from the independent namespace version. Thank to this, single threaded applications could
  *  use whole engine in a easy way.
  *
- * Usually an engine component is associated to a single diameter stack, although single threaded processes could
- *  use a common engine alternating different stack dictionaries by mean #setDictionary, depending on which kind of
- *  messages are being analyzed. Although the application must ensure that a single dictionary is activated during
- *  the same context operations an Avp could be considered as Unknown if was created with another, and we could
- *  have validation problems (i.e. if mandatory Avp bit is enabled). In general, managing Unknown data-part format
- *  don't have to be a problem because it is interpreted as OctetString format. Depending on what setters/getters
- *  we use, it could reach a RuntimeException at our application.
- *
- * At multithread processes we must use one heir engine per stack and never switching stacks within same component.
- * We will use each engine for each context.
+ * An engine component is associated to a single diameter stack. It is application responsability to use message
+ * container initialized with the correct codec engine depending on the context. There are helpers to do this at
+ * anna::diameter::codec::functions::getApplicationId (from xml document or hexadecimal buffer).
  *
  * It is recommended to use Message class to create Avps (adding them through pair identification <code + vendor-id>
  *  prototype), but we could create Avps separately (other program section, i.e) and join them after:
@@ -103,7 +65,7 @@ class Avp;
  * 1. Recommended way:
  *
  *    // Message creation:
- *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
+ *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer, codecEngine);
  *    // Adding + creation:
  *    Avp * avp_sid = msg->addAvp(helpers::base::AVPID__Session_Id);
  *    Avp * avp_oh = msg->addAvp(helpers::base::AVPID__Origin_Host);
@@ -116,12 +78,12 @@ class Avp;
  * 2. External Avp creation:
  *
  *    // Message creation:
- *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
+ *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer, codecEngine);
  *    // Creation:
- *    Avp * avp_sid = new Avp(helpers::base::AVPID__Session_Id);
- *    Avp * avp_oh = new Avp(helpers::base::AVPID__Origin_Host);
- *    Avp * avp_or = new Avp(helpers::base::AVPID__Origin_Realm);
- *    Avp * avp_rc = new Avp(helpers::base::AVPID__Result_Code);
+ *    Avp * avp_sid = new Avp(helpers::base::AVPID__Session_Id, codecEngine);
+ *    Avp * avp_oh = new Avp(helpers::base::AVPID__Origin_Host, codecEngine);
+ *    Avp * avp_or = new Avp(helpers::base::AVPID__Origin_Realm, codecEngine);
+ *    Avp * avp_rc = new Avp(helpers::base::AVPID__Result_Code, codecEngine);
  *    // Adding:
  *    msg->addAvp(avp_sid);
  *    msg->addAvp(avp_oh);
@@ -142,25 +104,24 @@ class Avp;
  *
  *     class MyEngine : public EngineImpl {
  *     public:
- *        Engine (getClassName()) {;}
- *        static const char* getClassName() throw() { return "<full-naming path>::MyEngine"; }
+ *        MyEngine (const char *className = "MyEngine") : Engine(className) {;}
  *
  *     private:
  *        anna::Recycler<MyAvp> a_avps;
  *        anna::Recycler<MyMessage> a_messages;
  *
- *        anna::diameter::codec::Avp* allocateAvp () throw () { return a_avps.create (); }
+ *        anna::diameter::codec::Avp* allocateAvp () { return a_avps.create (); }
  *
- *        void releaseAvp (anna::diameter::codec::Avp* avp) throw () {
+ *        void releaseAvp (anna::diameter::codec::Avp* avp) {
  *             if (avp == NULL) return;
  *             MyAvp* aux = static_cast <MyAvp*> (avp);
  *             aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens
  *             a_avps.release (aux);
  *        }
  *
- *        anna::diameter::codec::Message* allocateMessage () throw () { return a_messages.create (); }
+ *        anna::diameter::codec::Message* allocateMessage () { return a_messages.create (); }
  *
- *        void releaseMessage (anna::diameter::codec::Message* message) throw () {
+ *        void releaseMessage (anna::diameter::codec::Message* message) {
  *             if (message == NULL) return;
  *             MyMessage* aux = static_cast <MyMessage*> (message);
  *             aux->clear(); // free internal data-part storage specially for childrens releasing
@@ -198,34 +159,38 @@ public:
 
 
   // Creators
-  Avp* createAvp(const AvpId *id) throw(anna::RuntimeException);
-  Message* createMessage(const CommandId *id) throw(anna::RuntimeException);
+  Avp* createAvp(const AvpId *id) noexcept(false);
+  Message* createMessage(const CommandId *id) noexcept(false);
 
 
 private:
 
-  anna::xml::DTDMemory a_dtd;
   ValidationDepth::_v a_validationDepth;
   ValidationMode::_v a_validationMode;
+  bool a_singleFailedAVP;
   bool a_ignoreFlags;
   FixMode::_v a_fixMode;
-  bool a_selectStackWithApplicationId; // default behaviour: let the user switch the stack (false for this boolean)
-
 
   // Auxiliary
   const stack::Dictionary * a_dictionary;
 
   // helpers
-  static const char* asText(const ValidationDepth::_v) throw();
-  static const char* asText(const ValidationMode::_v) throw();
-  static const char* asText(const FixMode::_v) throw();
+  static const char* asText(const ValidationDepth::_v) ;
+  static const char* asText(const ValidationMode::_v) ;
+  static const char* asText(const FixMode::_v) ;
 
 public:
 
   /** Constructor
       @param className Logical name for the class.
+      @param dictionary Diameter dictionary. At single threaded processes, the same codec engine could be used with
+      different diameter dictionaries (multi-stack applications). In that case the process must switch the stack for
+      the whole decoding or enconding operation over a Message depending on the context (normally the message header
+      Application-Id is used as stack identifier). But the smart way implies inherit from this engine creating a
+      component for each diameter stack managed in the application. Inheritance is mandatory in multi-threaded processes:
+      one engine, a unique stack.
    */
-  EngineImpl(const char* className);
+  EngineImpl(const char* className, const stack::Dictionary * dictionary);
 
   /**
    * Destructor
@@ -233,67 +198,19 @@ public:
   virtual ~EngineImpl() {;}
 
 
-  // setters
-  /**
-     Sets diameter dictionary loaded at stack engine. It's recommended to configure a valid dictionary
-     (if not, or NULL provided at #setDictionary, all avps will be managed as 'Unknown' format and all
-     items will need to be manually updated, i.e. message and avp flags).
-
-     @param dictionary Diameter dictionary. At single threaded processes, the same codec engine could be used with
-     different diameter dictionaries (multi-stack applications). In that case the process must switch the stack for
-     the whole decoding or enconding operation over a Message depending on the context (normally the message header
-     Application-Id is used as stack identifier). But the smart way implies inherit from this engine creating a
-     component for each diameter stack managed in the application. Inheritance is mandatory in multi-threaded processes:
-     one engine, a unique stack.
-  */
-  void setDictionary(const stack::Dictionary * dictionary) throw() { a_dictionary = dictionary; }
-
-  /**
-  * Sets diameter dictionary loaded at stack engine with the provided identifier.
-  *
-  * @param stackId Stack identifier. When missing, NULL will be returned
-  * @return Returns configured dictionary (NULL if stack id was not found)
-  */
-  const stack::Dictionary *setDictionary(unsigned int stackId) throw();
-
-
-  /**
-  * By default, the user will select the appropiate stack id depending on the context (see #setDictionary), but
-  * some applications could consider interesting automatic stack selection based on managed messages (incoming
-  * decoded ones, or built messages to be encoded). By default, on engine construction, no changes are done.
-  * Multithreaded processes should have a unique codec engine for each managed stack (then you don't have to
-  * worry about), but mono processes with multistack implementation over the same-unique engine, should activate
-  * this to have the commonly recommended way to choose the stack: using the Application-Id value.
-  *
-  * @warning do not activate in case of multithreaded applications.
-  * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header.
-  */
-  void selectStackWithApplicationId (bool enable) throw() { a_selectStackWithApplicationId = enable; }
-
-  // getters
-
-  /**
-    Gets the currently configured behaviour regarding stack selection for multistack codec engines in mono thread
-    applications.
-
-    @return True if selection is done with the Application-Id. False if no selection is performed (user responsibility).
-  */
-  bool hasSelectStackWithApplicationId (void) throw() { return a_selectStackWithApplicationId; }
-
-
   /**
      Gets currently configured dictionary. NULL if not configured (manual encode/decode operations).
 
      @return Returns currently configured engine dictionary
   */
-  const stack::Dictionary *getDictionary() const throw() { return a_dictionary; }
+  const stack::Dictionary *getDictionary() const { return a_dictionary; }
 
 
   /**
    * Sets behaviour on validation procedure.
    * \param validationDepth Behaviour on validation procedure: complete analysis or stop at first validation error over the message.
    */
-  void setValidationDepth(const ValidationDepth::_v validationDepth)  throw() { a_validationDepth = validationDepth; }
+  void setValidationDepth(const ValidationDepth::_v validationDepth)  { a_validationDepth = validationDepth; }
 
   /**
    * Returns behaviour on on validation procedure.
@@ -303,7 +220,7 @@ public:
    *
    * \return Behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default).
    */
-  ValidationDepth::_v getValidationDepth() const throw() { return a_validationDepth; }
+  ValidationDepth::_v getValidationDepth() const { return a_validationDepth; }
 
   /**
    * Sets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is
@@ -312,7 +229,7 @@ public:
    * \param ignoreFlags Validation will ignore flags.
    */
 
-  void ignoreFlagsOnValidation(bool ignoreFlags) throw() { a_ignoreFlags = ignoreFlags; }
+  void ignoreFlagsOnValidation(bool ignoreFlags) { a_ignoreFlags = ignoreFlags; }
 
   /**
    * Gets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is
@@ -320,13 +237,13 @@ public:
    * By default (at engine start), flags are verified.
    * \return Validation ignore flags indicator.
    */
-  bool ignoreFlagsOnValidation() const throw() { return a_ignoreFlags; }
+  bool ignoreFlagsOnValidation() const { return a_ignoreFlags; }
 
   /**
    * Sets validation mode.
    * \param validationMode Validation mode: before encoding, after decoding, always or never.
    */
-  void setValidationMode(const ValidationMode::_v validationMode)  throw() { a_validationMode = validationMode; }
+  void setValidationMode(const ValidationMode::_v validationMode)  { a_validationMode = validationMode; }
 
   /**
    * Returns validation mode.
@@ -334,7 +251,7 @@ public:
    * during development phase.
    * \return Validation mode: before encoding, after decoding (by default), always or never.
    */
-  ValidationMode::_v getValidationMode() const throw() { return a_validationMode; }
+  ValidationMode::_v getValidationMode() const { return a_validationMode; }
 
 
 
@@ -342,20 +259,28 @@ public:
    * Sets fix mode.
    * \param fixMode Fix mode: before encoding, after decoding, always or never.
    */
-  void setFixMode(const FixMode::_v fixMode)  throw() { a_fixMode = fixMode; }
+  void setFixMode(const FixMode::_v fixMode)  { a_fixMode = fixMode; }
 
   /**
    * Returns fix mode.
    * \return Fix mode: before encoding (by default), after decoding, always or never.
    */
-  FixMode::_v getFixMode() const throw() { return a_fixMode; }
-
+  FixMode::_v getFixMode() const { return a_fixMode; }
 
+  /**
+   * Sets single FailedAVP. True by default. If false, and more than one wrong avp are found during message
+   * decoding and or validation, a new Failed-AVP will be added to the dynamic answer provided. The standard
+   * talks about only one but it is open to do this.
+   *
+   * \param single Single Failed-AVP boolean.
+   */
+  void setSingleFailedAVP(bool single = true)  { a_singleFailedAVP = single; }
 
   /**
-     DTD document for xml message parsing
-  */
-  const anna::xml::DTDMemory & getDTD() const throw() { return a_dtd; }
+   * Returns single Failed-AVP boolean.
+   * \return Failed-AVP could be one (true) or more (false) in answer message.
+   */
+  bool getSingleFailedAVP() const { return a_singleFailedAVP; }
 
   /**
   * Creates a new diameter avp assigning its identifier, using engine resources to allocate memory (recommended
@@ -367,7 +292,7 @@ public:
   *
   * @return Created avp ready to be used
   */
-  Avp* createAvp(AvpId id) throw(anna::RuntimeException) { return createAvp(&id); }
+  Avp* createAvp(AvpId id) noexcept(false) { return createAvp(&id); }
 
   /**
   * Creates a new diameter avp, using engine resources to allocate memory (recommended recycler allocation at
@@ -375,7 +300,7 @@ public:
   *
   * @return Created avp ready to be used
   */
-  Avp* createAvp() throw(anna::RuntimeException) { return createAvp(NULL); }
+  Avp* createAvp() noexcept(false) { return createAvp(NULL); }
 
   /**
   * Creates a new diameter Message assigning its identifier, using engine resources to allocate memory (recommended
@@ -387,7 +312,7 @@ public:
   *
   * @return Created message ready to be used
   */
-  Message* createMessage(CommandId id) throw(anna::RuntimeException) { return createMessage(&id); }
+  Message* createMessage(CommandId id) noexcept(false) { return createMessage(&id); }
 
   /**
   * Creates a new diameter message, using engine resources to allocate memory (recommended recycler allocation
@@ -395,28 +320,29 @@ public:
   *
   * @return Created message ready to be used
   */
-  Message* createMessage() throw(anna::RuntimeException) { return createMessage(NULL); }
+  Message* createMessage() noexcept(false) { return createMessage(NULL); }
 
 
   /**
-     Loads an xml file representing a diameter message base in a DTD document (#getDTD)
+     Loads an xml file/string representing a diameter message base in a DTD document (#getDTD)
 
-     @param xmlPathFile Complete path file to the xml document which represents the diameter message
+     @param xmlPathFile_or_string Complete path file or string representation for the xml document which represents the diameter message
+     @param pathfile_or_string boolean about the interpretation of the previous argument
   */
-  Message *createMessage(const std::string & xmlPathFile) throw(anna::RuntimeException);
+  Message *createMessage(const std::string & xmlPathFile_or_string, bool pathfile_or_string = true) noexcept(false);
 
 
   /**
      Invoked to free Avps.
      \see anna::Recycler
   */
-  virtual void releaseAvp(Avp*) throw() = 0;
+  virtual void releaseAvp(Avp*)  = 0;
 
   /**
      Invoked to free Messages.
      \see anna::Recycler
   */
-  virtual void releaseMessage(Message*) throw() = 0;
+  virtual void releaseMessage(Message*)  = 0;
 
 
   /**
@@ -424,14 +350,14 @@ public:
   *
   * @return String with class content
   */
-  virtual std::string asString(void) const throw();
+  virtual std::string asString(void) const ;
 
   /**
      Class XML representation.
      \param parent XML node over which we will put instance information.
      \return XML documentcon with class content.
   */
-  virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+  virtual anna::xml::Node* asXML(anna::xml::Node* parent) const ;
 
 
   /**
@@ -441,7 +367,7 @@ public:
 
      @return Avp identifier as pair (code,vendor-id)
   */
-  AvpId avpIdForName(const char * name) throw(anna::RuntimeException);
+  AvpId avpIdForName(const char * name) noexcept(false);
 
 
   /**
@@ -451,7 +377,7 @@ public:
 
      @return Command identifier as pair (code,request-indicator)
   */
-  CommandId commandIdForName(const char * name) throw(anna::RuntimeException);
+  CommandId commandIdForName(const char * name) noexcept(false);
 
 
 protected:
@@ -463,7 +389,7 @@ protected:
 
      \see anna::Recycler
   */
-  virtual Avp* allocateAvp() throw() = 0;
+  virtual Avp* allocateAvp()  = 0;
 
 
   /**
@@ -473,7 +399,7 @@ protected:
 
      \see anna::Recycler
   */
-  virtual Message* allocateMessage() throw() = 0;
+  virtual Message* allocateMessage()  = 0;
 
 
   /**
@@ -485,7 +411,7 @@ protected:
      @see setValidationDepth
      @see getValidationDepth
   */
-  void validationAnomaly(const std::string & description) const throw(anna::RuntimeException);
+  void validationAnomaly(const std::string & description) const noexcept(false);
 };
 
 }