Hard refactoring. CodecEngine is associated to a unique stack.
[anna.git] / source / diameter / codec / Message.cpp
index 35db129..b5d87f6 100644 (file)
@@ -16,6 +16,7 @@
 #include <anna/diameter/codec/functions.hpp> // REQUIRED_WORDS
 #include <anna/diameter/codec/OamModule.hpp>
 #include <anna/diameter/codec/Engine.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
 #include <anna/diameter/stack/Avp.hpp>
 #include <anna/diameter/stack/Format.hpp>
 #include <anna/diameter/stack/Dictionary.hpp>
@@ -78,12 +79,26 @@ Message::~Message() {
 }
 
 
+//------------------------------------------------------------------------------
+//--------------------------------------------------------- Message::setEngine()
+//------------------------------------------------------------------------------
+void Message::setEngine(Engine *engine) throw() {
+
+  if (a_engine && engine != a_engine) {
+    LOGWARNING(anna::Logger::warning("Ignored: it is not a good practice to change the codec engine once assigned. Clear the message first to set the engine again.", ANNA_FILE_LOCATION));
+    return;
+  }
+
+  a_engine = engine;
+}
+
+
 //------------------------------------------------------------------------------
 //--------------------------------------------------------- Message::getEngine()
 //------------------------------------------------------------------------------
 Engine * Message::getEngine() const throw(anna::RuntimeException) {
   if(!a_engine)
-    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
+    throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION);
 
   return a_engine;
 
@@ -208,11 +223,17 @@ void Message::setId(const char *name) throw(anna::RuntimeException) {
 void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) {
   a_applicationId = aid;
 
-  // Default behaviour:
-  if (!getEngine()->hasSelectStackWithApplicationId()) return;
+  // Automatic engine configuration:
+  if (a_engine) return;
 
-  // Adapts for Application-ID stack identifier:
-  getEngine()->setDictionary(aid);
+  // Codec engine manager (a multithreaded application, normally does not achieve this point, because
+  // messages are prepared for each interface with the corresponding codec engine)
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  if (em.selectFromApplicationId()) {
+    Engine *monostackEngine = em.getMonoStackCodecEngine();
+    if (monostackEngine) { a_engine = monostackEngine; return; }
+    a_engine = em.getCodecEngine(aid);
+  }
 }
 
 
@@ -224,6 +245,17 @@ Avp * Message::addAvp(const char *name) throw(anna::RuntimeException) {
 }
 
 
+//------------------------------------------------------------------------------
+//------------------------------------------------------------ Message::addAvp()
+//------------------------------------------------------------------------------
+Avp * Message::addAvp(Avp * avp) throw() {
+  if(!avp) return NULL;
+  if (avp->getEngine() != getEngine()) return NULL;
+  addChild(avp);
+  return avp;
+}
+
+
 //------------------------------------------------------------------------------
 //--------------------------------------------------------- Message::removeAvp()
 //------------------------------------------------------------------------------
@@ -268,10 +300,10 @@ U24 Message::getLength() const throw() {
 void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::RuntimeException) {
   // Trace
   LOGDEBUG(
-    anna::xml::Node root("Message::decode");
-    std::string trace = "DataBlock to decode:\n";
-    trace += db.asString();
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      anna::xml::Node root("Message::decode");
+  std::string trace = "DataBlock to decode:\n";
+  trace += db.asString();
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
   );
   clear();
   // EXCEPTION MANAGEMENT IN THIS METHOD
@@ -372,8 +404,8 @@ void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::
     } catch(anna::RuntimeException &ex) {
       getEngine()->releaseAvp(avp);
       LOGWARNING(
-        anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION);
-        anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION);
+          anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION);
+      anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION);
       );
       break;
     }
@@ -389,9 +421,9 @@ void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::
 
   // Trace
   LOGDEBUG(
-    std::string trace = "Message decoded:\n";
-    trace += asXMLString();
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      std::string trace = "Message decoded:\n";
+  trace += asXMLString();
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
   );
   // Post-Validation
   Engine::ValidationMode::_v vmode = getEngine()->getValidationMode();
@@ -453,19 +485,19 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron
 
   if(isRequest()) return;
 
-// RFC 6733:
-//
-//  7.5.  Failed-AVP AVP
-//
-//     The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides
-//     debugging information in cases where a request is rejected or not
-//     fully processed due to erroneous information in a specific AVP.  The
-//     value of the Result-Code AVP will provide information on the reason
-//     for the Failed-AVP AVP.  A Diameter answer message SHOULD contain an
-//     instance of the Failed-AVP AVP that corresponds to the error
-//     indicated by the Result-Code AVP.  For practical purposes, this
-//     Failed-AVP would typically refer to the first AVP processing error
-//     that a Diameter node encounters.
+  // RFC 6733:
+  //
+  //  7.5.  Failed-AVP AVP
+  //
+  //     The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides
+  //     debugging information in cases where a request is rejected or not
+  //     fully processed due to erroneous information in a specific AVP.  The
+  //     value of the Result-Code AVP will provide information on the reason
+  //     for the Failed-AVP AVP.  A Diameter answer message SHOULD contain an
+  //     instance of the Failed-AVP AVP that corresponds to the error
+  //     indicated by the Result-Code AVP.  For practical purposes, this
+  //     Failed-AVP would typically refer to the first AVP processing error
+  //     that a Diameter node encounters.
 
   // Although the Failed-AVP definition has cardinality 1* and Failed-AVP itself is defined in
   // most of the command codes as *[Failed-AVP], i think this is not a deliberate ambiguity.
@@ -485,17 +517,17 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron
   Avp *leaf = theFailedAvp;
 
   LOGDEBUG(
-    std::string msg = "Adding to Failed-AVP, the wrong avp ";
-    msg += wrongName ? wrongName : (anna::diameter::functions::avpIdAsPairString(wrong));
-    msg += " found inside ";
-    msg += parent.asString();
+      std::string msg = "Adding to Failed-AVP, the wrong avp ";
+  msg += wrongName ? wrongName : (anna::diameter::functions::avpIdAsPairString(wrong));
+  msg += " found inside ";
+  msg += parent.asString();
 
-    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+  anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
 
   std::vector<AvpId>::const_iterator it;
   for(it = parent.AvpsId.begin(); it != parent.AvpsId.end(); it++)
-       leaf = leaf->addAvp(*it);
+    leaf = leaf->addAvp(*it);
 
   leaf->addAvp(wrong);
 }
@@ -504,7 +536,7 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron
 //------------------------------------------------------------------------------
 //----------------------------------------------- Message::setStandardToAnswer()
 //------------------------------------------------------------------------------
-void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw() {
+void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw(anna::RuntimeException) {
   if(!request.getId().second) return;
 
   // Message header:
@@ -513,7 +545,7 @@ void Message::setStandardToAnswer(const Message &request, const std::string &ori
   const Avp *reqSessionId = request.getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore);
 
   if(reqSessionId)
-       if(!getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore))
+    if(!getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore))
       addAvp(helpers::base::AVPID__Session_Id)->getUTF8String()->setValue(reqSessionId->getUTF8String()->getValue());
 
   // Origin-Host & Realm
@@ -533,9 +565,9 @@ void Message::setStandardToAnswer(const Message &request, const std::string &ori
   // Fix:
   fix();
   LOGDEBUG(
-    std::string msg = "Completed answer:\n";
-    msg += asXMLString();
-    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+      std::string msg = "Completed answer:\n";
+  msg += asXMLString();
+  anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
 }
 
@@ -648,9 +680,9 @@ const anna::DataBlock & Message::code() throw(anna::RuntimeException) {
 
   // Trace
   LOGDEBUG(
-    std::string trace = "Message to code:\n";
-    trace += asXMLString();
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      std::string trace = "Message to code:\n";
+  trace += asXMLString();
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
   );
   // Memory allocation
   U24 length = getLength();
@@ -704,29 +736,24 @@ const anna::DataBlock & Message::code() throw(anna::RuntimeException) {
 
   // Trace
   LOGDEBUG(
-    std::string trace = "DataBlock encoded:\n";
-    trace += a_forCode.asString();
-//      trace += "\nAs continuous hexadecimal string:\n";
-//      trace += anna::functions::asHexString(a_forCode);
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      std::string trace = "DataBlock encoded:\n";
+  trace += a_forCode.asString();
+  //      trace += "\nAs continuous hexadecimal string:\n";
+  //      trace += anna::functions::asHexString(a_forCode);
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
   );
   return a_forCode;
 }
 
-
 //------------------------------------------------------------------------------
-//----------------------------------------------------- Message::fromXMLString()
+//----------------------------------------------------------- Message::loadXML()
 //------------------------------------------------------------------------------
-void Message::fromXMLString(const std::string &xmlString) throw(anna::RuntimeException) {
-  LOGDEBUG(anna::Logger::debug("Reading diameter message from xml string representation", ANNA_FILE_LOCATION));
-  anna::xml::DocumentMemory xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
-  const anna::xml::Node *rootNode;
-  xmlDocument.initialize(xmlString.c_str());
-  rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd
-  LOGDEBUG(anna::Logger::debug("Read OK from XML string representation", ANNA_FILE_LOCATION));
-  fromXML(rootNode);
-}
+void Message::loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException) {
 
+  anna::xml::DocumentFile xmlDocument;
+  anna::diameter::codec::functions::messageXmlDocumentFromXmlFile(xmlDocument, xmlPathFile);
+  fromXML(xmlDocument.getRootNode());
+}
 
 //------------------------------------------------------------------------------
 //----------------------------------------------------------- Message::fromXML()
@@ -861,7 +888,7 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc
       msg += "': negative values are not allowed";
       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
     }
-    */
+     */
   } else u_aux = 0;
 
   setHopByHop(u_aux);
@@ -876,7 +903,7 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc
       msg += "': negative values are not allowed";
       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
     }
-    */
+     */
   } else u_aux = 0;
 
   setEndToEnd(u_aux);
@@ -905,31 +932,6 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc
 }
 
 
-//------------------------------------------------------------------------------
-//----------------------------------------------------------- Message::loadXML()
-//------------------------------------------------------------------------------
-void Message::loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException) {
-  LOGDEBUG(
-    std::string trace = "Loading diameter message from file '";
-    trace += xmlPathFile;
-    trace += "'";
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
-  );
-  anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
-  const anna::xml::Node *rootNode;
-  xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error
-  rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd
-  LOGDEBUG(
-    std::string trace = "Loaded XML file (";
-    trace += xmlPathFile;
-    trace += "):\n";
-    trace += anna::xml::Compiler().apply(rootNode);
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
-  );
-  fromXML(rootNode);
-}
-
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------- Message::asXML()
 //------------------------------------------------------------------------------