Hard refactoring. CodecEngine is associated to a unique stack.
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 27 Sep 2015 21:45:37 +0000 (23:45 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 27 Sep 2015 21:45:37 +0000 (23:45 +0200)
51 files changed:
.gitignore
example/diameter/batchConverter/main.cpp
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/Launcher.hpp
example/diameter/launcher/MyDiameterEntity.cpp
example/diameter/launcher/MyDiameterEntity.hpp
example/diameter/launcher/MyLocalServer.cpp
example/diameter/launcher/MyLocalServer.hpp
example/diameter/launcher/ProgrammedAnswers.cpp
example/diameter/launcher/ProgrammedAnswers.hpp
example/diameter/launcher/RealmNode.cpp
example/diameter/launcher/RealmNode.hpp
example/diameter/launcher/main.cpp
example/diameter/launcher/resources/scripts/operation_tps.sh
example/diameter/launcher/resources/services_examples/balancer.xml
example/diameter/launcher/resources/services_examples/client.xml
example/diameter/launcher/resources/services_examples/dummy.xml
example/diameter/launcher/resources/services_examples/multi-client.xml
example/diameter/launcher/resources/services_examples/server.xml
example/diameter/launcher/resources/services_examples/services.dtd
example/diameter/launcher/testing/TestCase.cpp
example/diameter/launcher/testing/TestCase.hpp
example/diameter/launcher/testing/TestCondition.cpp
example/diameter/launcher/testing/TestCondition.hpp
example/diameter/launcher/testing/TestManager.cpp
example/diameter/launcher/testing/TestManager.hpp
example/diameter/launcher/testing/TestStep.cpp
example/diameter/launcher/testing/TestStep.hpp
example/diameter/tme/main.cpp
include/anna/diameter/codec/Avp.hpp
include/anna/diameter/codec/Engine.hpp
include/anna/diameter/codec/EngineImpl.hpp
include/anna/diameter/codec/EngineManager.hpp [new file with mode: 0644]
include/anna/diameter/codec/Message.hpp
include/anna/diameter/codec/functions.hpp
include/anna/diameter/codec/tme/Avp.hpp
include/anna/diameter/codec/tme/Engine.hpp [deleted file]
include/anna/diameter/codec/tme/Engine.hpp__ [new file with mode: 0644]
include/anna/diameter/codec/tme/Message.hpp
include/anna/xml/DTDFile.hpp
include/anna/xml/DTDMemory.hpp
source/diameter.comm/Engine.cpp
source/diameter/codec/Avp.cpp
source/diameter/codec/EngineImpl.cpp
source/diameter/codec/EngineManager.cpp [new file with mode: 0644]
source/diameter/codec/Message.cpp
source/diameter/codec/functions.cpp
source/diameter/codec/tme/Avp.cpp
source/diameter/codec/tme/Message.cpp
source/xml/DTDFile.cpp
source/xml/DTDMemory.cpp

index 5f06328..5507480 100644 (file)
@@ -22,3 +22,4 @@ docs/doxygen/man
 *.old
 .cproject
 .project
+/Debug/
index 7232973..5ccf1c8 100644 (file)
@@ -23,6 +23,7 @@
 #include <anna/xml/xml.hpp>
 #include <anna/diameter/stack/Engine.hpp>
 #include <anna/diameter/codec/Engine.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
 #include <anna/diameter/codec/Message.hpp>
 //#include <anna/diameter/codec/functions.hpp> // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
 
@@ -30,8 +31,7 @@
 using namespace anna;
 using namespace anna::diameter;
 
-anna::diameter::codec::Message *G_codecMsg;
-anna::diameter::codec::Engine *G_codecEngine;
+anna::diameter::codec::Message G_codecMsg;
 
 bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) throw() {
   // Get hex string
@@ -70,9 +70,7 @@ void _exit(const std::string &message, int resultCode = 1) {
 // Decodes a diameter message coming from a datablock
 void decodeDataBlock(const anna::DataBlock &db/*, unsigned int & detectedApplicationId*/) throw() {
   try {
-    //detectedApplicationId = anna::diameter::codec::functions::getApplicationId(db);
-    //G_codecEngine->setDictionary(detectedApplicationId); we enabled this feature in the codec engine: selectStackWithApplicationId(true);
-    G_codecMsg->decode(db);
+    G_codecMsg.decode(db);
   } catch(RuntimeException &ex) {
     _exit(ex.asString());
   }
@@ -122,12 +120,13 @@ int main(int argc, char **argv) {
   bool processHex = xmlOnly ? false:true;
   Logger::setLevel(debug ? Logger::Debug:Logger::Warning);
   Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000));
-  G_codecEngine = new anna::diameter::codec::Engine("MyCodecEngine");
-  G_codecMsg = G_codecEngine->createMessage();
   anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  anna::diameter::codec::Engine *ce;
+  unsigned int appid = 0;
+
 
   // Register stacks:
-  bool multistack = false;
   try {
     anna::Tokenizer stacksTok;
     stacksTok.apply(stacks, "#");
@@ -141,26 +140,25 @@ int main(int argc, char **argv) {
       if(stackTok.size() == 1) {
         if(stacksTok.size() != 1)
           throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION);
-
-        anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary
-        G_codecEngine->setDictionary(d);
+        anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(appid, stack); // the stack is the dictionary
+        ce = new anna::diameter::codec::Engine("CodecEngineForUniqueStackId_0", d);
+        em.registerCodecEngine(0, ce);
         break;
       }
 
       if(stackTok.size() != 2)
         throw anna::RuntimeException("Each stack must be in the form '<application-id>,<xml dictionary pathfile>'", ANNA_FILE_LOCATION);
 
-      multistack = true;
       stack_it = stackTok.begin();
       unsigned int stackId = atoll(anna::Tokenizer::data(stack_it));
       stack_it++;
       std::string file = anna::Tokenizer::data(stack_it);
-      anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file);
+      anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(stackId, file);
+      std::string codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", stackId);
+      ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d);
+      em.registerCodecEngine(stackId, ce);
     }
 
-    // Auto stack selection based on Application-ID:
-    if (multistack) G_codecEngine->selectStackWithApplicationId(true);
-
     std::cout << "Stacks provided:          " << std::endl;
     std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
     std::cout << std::endl;
@@ -173,10 +171,13 @@ int main(int argc, char **argv) {
   }
 
   // Validation kindness
-  G_codecEngine->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire)
-  G_codecEngine->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports
-  if(no_validation) G_codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
-  if(ignore_flags) G_codecEngine->ignoreFlagsOnValidation(true);
+  for (anna::diameter::codec::appid_codec_engines_it it = em.begin(); it != em.end(); it++) {
+    ce = it->second;
+    ce->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire)
+    ce->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports
+    if(no_validation) ce->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
+    if(ignore_flags) ce->ignoreFlagsOnValidation(true);
+  }
 
   // Auxiliary variables:
   anna::DataBlock db_aux(true);
@@ -205,7 +206,7 @@ int main(int argc, char **argv) {
       // Write conversion:
       std::string outputFile = entry + ".as.xml";
       std::ofstream out(outputFile.c_str(), std::ifstream::out);
-      out << G_codecMsg->asXMLString();
+      out << G_codecMsg.asXMLString();
       out.close();
 
       anyHexConverted = true;
@@ -220,10 +221,10 @@ int main(int argc, char **argv) {
       LOGDEBUG(anna::Logger::debug(entry + " is being converted to hex", ANNA_FILE_LOCATION));
   
       // Load file:
-      G_codecMsg->loadXML(entry);  
+      G_codecMsg.loadXML(entry);  
       
       // Write conversion:
-      std::string hexString = anna::functions::asHexString(G_codecMsg->code());
+      std::string hexString = anna::functions::asHexString(G_codecMsg.code());
       std::string outputFile = entry + ".as.hex";
       std::ofstream out(outputFile.c_str(), std::ifstream::out);
       out.write(hexString.c_str(), hexString.size());
index 8f3cacd..f7921e7 100644 (file)
@@ -15,7 +15,9 @@
 // Project
 #include <anna/timex/Engine.hpp>
 #include <anna/statistics/Engine.hpp>
+#include <anna/diameter/codec/functions.hpp>
 #include <anna/diameter/codec/Engine.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
 #include <anna/http/Transport.hpp>
 #include <anna/diameter/stack/Engine.hpp>
 #include <anna/diameter/helpers/base/functions.hpp>
@@ -35,7 +37,6 @@
 #define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.out"
 
 
-
 const char *ServicesDTD = "\
 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
 <!-- Diameter services DTD -->\n\
@@ -43,22 +44,27 @@ const char *ServicesDTD = "\
 <!ELEMENT services (stack*, node*)>\n\
 \n\
 <!ELEMENT stack EMPTY>\n\
-<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>\n\
+<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED validationMode (BeforeEncoding | AfterDecoding | Always | Never) #IMPLIED validationDepth (Complete | FirstError) #IMPLIED fixMode (BeforeEncoding | AfterDecoding | Always | Never) #IMPLIED ignoreFlagsOnValidation (yes | no) #IMPLIED>\n\
 <!--\n\
    Stack record\n\
 \n\
-   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed\n\
-               (in multistack applications, it shall be mandatory respect such association to know the stack used\n\
-               for processed messages).\n\
-   dictionary: Path to the dictionary file\n\
+    id:                      Normally the id corresponds to the Application-Id for which the dictionary provided is designed\n\
+                             (in multistack applications, it shall be mandatory respect such association to know the stack used\n\
+                             for processed messages).\n\
+    dictionary:              Path to the dictionary file.\n\
+    validationMode:          Sets the validation mode. Default is 'AfterDecoding'.\n\
+    validationDepth:         Sets the validation depth. Default is 'FirstError'.\n\
+    fixMode:                 Sets the fix mode. Default is 'BeforeEncoding'.\n\
+    ignoreFlagsOnValidation: Ignore flags during message validation. Default is 'no'.\n\
 -->\n\
 \n\
 <!ELEMENT node EMPTY>\n\
-<!ATTLIST node originRealm CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
+<!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
 <!--\n\
    Node record\n\
 \n\
    originRealm:                             Node identifier (Origin-Realm name).\n\
+   applicationId:                           The Application-Id provided must exists as a registered 'stack id'.\n\
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname\n\
                                             Note that if you have two or more realms, the names must be different.\n\
    cer:                                     User defined CER path file to be encoded to establish diameter connections.\n\
@@ -110,8 +116,6 @@ const char *ServicesDTD = "\
 
 
 Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "1.1"), a_communicator(NULL) {
-  a_codecEngine = new anna::diameter::codec::Engine("MyCodecEngine");
-  a_baseProtocolDictionary = NULL;
   a_timeEngine = NULL;
   a_counterRecorder = NULL;
   a_admlMinResolution = 2 * anna::timex::Engine::minResolution; // 2*10 = 20 ms; 1000/20 = 50 ticks per second;
@@ -129,19 +133,25 @@ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "
 
 void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOperation) throw(anna::RuntimeException) {
   //<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
-  const anna::xml::Attribute  *id, *dictionary;
+  const anna::xml::Attribute *id, *dictionary;
 
-  // <!ATTLIST node originRealm CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
-  const anna::xml::Attribute  *originRealm, *originHost, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay,
-                              *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
-                              *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
-                              *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
+  // <!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
+  const anna::xml::Attribute *originRealm, *appId, *originHost, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay,
+  *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
+  *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
+  *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
 
   // Never clear services content from here (append new data from xml). At the moment no node removing is implemented in this process
 
   // Stacks
   anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
   anna::diameter::stack::Dictionary *d;
+  const anna::diameter::stack::Dictionary *bpd = NULL; // base protocol dictionary
+
+  // Codec engine manager:
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  anna::diameter::codec::Engine *ce;
+
   ///////////////////////////////////////////
   // APPLICATION MESSAGE OAM MODULE SCOPES //
   ///////////////////////////////////////////
@@ -151,6 +161,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
   static int scope_id = 3;
   bool id_0_registered = false;
   unsigned int id_value;
+  std::string codecEngineName;
 
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
@@ -163,7 +174,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
 
       try {
         d = stackEngine.createDictionary(id_value, dictionary->getValue());
-        getCodecEngine()->setDictionary(d);
+        LOGDEBUG(anna::Logger::debug(anna::functions::asString("Created dictionary (%p) for stack id %llu", d, id_value), ANNA_FILE_LOCATION));
 
         // OAM module for counters:
         appMsgOamModule.createStackCounterScope(scope_id, id_value /* application-id */);
@@ -174,9 +185,47 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
         throw ex;
       }
 
-      if (id_value == 0)
+      if (id_value == 0) {
         id_0_registered = true;
-        a_baseProtocolDictionary = d;
+        bpd = d;
+      }
+
+      // Create codec engine and register it in the codec engine manager:
+      codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", id_value);
+      ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d);
+      em.registerCodecEngine(id_value, ce);
+
+      // Codec engine configuration:
+      const anna::xml::Attribute *vm_attr = (*it)->getAttribute("validationMode", false /* no exception */);
+      const anna::xml::Attribute *vd_attr = (*it)->getAttribute("validationDepth", false /* no exception */);
+      const anna::xml::Attribute *fm_attr = (*it)->getAttribute("fixMode", false /* no exception */);
+      const anna::xml::Attribute *if_attr = (*it)->getAttribute("ignoreFlags", false /* no exception */);
+
+      std::string vm_value = vm_attr ? vm_attr->getValue() : "AfterDecoding";
+      std::string vd_value = vd_attr ? vd_attr->getValue() : "FirstError";
+      std::string fm_value = fm_attr ? fm_attr->getValue() : "BeforeEncoding";
+
+      anna::diameter::codec::Engine::ValidationMode::_v vm;
+      if (vm_value == "BeforeEncoding") vm = anna::diameter::codec::Engine::ValidationMode::BeforeEncoding;
+      else if (vm_value == "AfterDecoding") vm = anna::diameter::codec::Engine::ValidationMode::AfterDecoding;
+      else if (vm_value == "Always") vm = anna::diameter::codec::Engine::ValidationMode::Always;
+      else if (vm_value == "Never") vm = anna::diameter::codec::Engine::ValidationMode::Never;
+      ce->setValidationMode(vm);
+
+      anna::diameter::codec::Engine::ValidationDepth::_v vd;
+      if (vd_value == "Complete") vd = anna::diameter::codec::Engine::ValidationDepth::Complete;
+      else if (vd_value == "FirstError") vd = anna::diameter::codec::Engine::ValidationDepth::FirstError;
+      ce->setValidationDepth(vd);
+
+      anna::diameter::codec::Engine::FixMode::_v fm;
+      if (fm_value == "BeforeEncoding") fm = anna::diameter::codec::Engine::FixMode::BeforeEncoding;
+      else if (fm_value == "AfterDecoding") fm = anna::diameter::codec::Engine::FixMode::AfterDecoding;
+      else if (fm_value == "Always") fm = anna::diameter::codec::Engine::FixMode::Always;
+      else if (fm_value == "Never") fm = anna::diameter::codec::Engine::FixMode::Never;
+      ce->setFixMode(fm);
+
+      bool if_value = (if_attr ? (if_attr->getValue() == "yes") : false);
+      ce->ignoreFlagsOnValidation(if_value);
     }
   }
 
@@ -184,26 +233,26 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
   std::cout << "Stacks currently loaded:" << std::endl;
   std::cout << anna::functions::tab(stackEngine.asString(false /* light */)) << std::endl;
 
-
-  // Codec engine adjustments:
-  // Auto stack selection based on Application-ID:
+  // Basic checking for multistack:
   bool multistack = (stackEngine.stack_size() > 1);
   if (multistack) {
-    getCodecEngine()->selectStackWithApplicationId(true);
-    // In multistack, id = 0 MUST be registered:
-    if (!id_0_registered)
+    if(!id_0_registered)
       throw anna::RuntimeException("In multistack applications is mandatory register a stack id = 0 using a dictionary which contains the needed elements to build base protocol messages (CER/A, DWR/A, DPR/A, STR/A, etc.)", ANNA_FILE_LOCATION);
   }
-  else {
-    a_baseProtocolDictionary = d;
+  else { // monostack
+    if (!bpd)
+      bpd = ce->getDictionary(); // in mono-stack applications, we understand the existing stack as the used
+                                 // for base protocol, regardless if it is registered with stack id 0 or not
   }
 
+  // REALMS:
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
 
     if(nodeName == "node") {
       // Input data:
       originRealm = (*it)->getAttribute("originRealm");
+      appId = (*it)->getAttribute("applicationId");
       originHost = (*it)->getAttribute("originHost", false /* no exception */);
       cer = (*it)->getAttribute("cer", false /* no exception */);
       dwr = (*it)->getAttribute("dwr", false /* no exception */);
@@ -232,6 +281,12 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
         throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
       }
 
+      unsigned int applicationId = appId->getIntegerValue();
+      if (!stackEngine.getDictionary(applicationId)) {
+        std::string msg = "Cannot found a registered stack id with the value of applicationId provided: "; msg += appId->getValue();
+        throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+      }
+
       // Engine time measures checking & assignment:
       anna::Millisecond allowedInactivityTimeMs(90000);
       anna::Millisecond tcpConnectDelayMs(200);
@@ -260,7 +315,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       }
 
       // Create new Node instance /////////////////////////////////////////////////////////////////
-      a_workingNode = new RealmNode(originRealm->getValue(), a_codecEngine, a_baseProtocolDictionary);
+      a_workingNode = new RealmNode(originRealm->getValue(), applicationId, bpd);
       MyDiameterEngine *commEngine = a_workingNode->getMyDiameterEngine();
       /////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -313,12 +368,15 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       // Lazy initialization for comm engine:
       if (eventOperation) commEngine->lazyInitialize();
 
-      // New Node assignment //////////////////////////////////////////////////////////////////////
+      // Node and Codec Engine registration ///////////////////////////////////////////////////////
       a_nodes[originRealm->getValue()] = a_workingNode;
       /////////////////////////////////////////////////////////////////////////////////////////////
     }
   }
 
+  if (!uniqueRealm())
+    a_workingNode = NULL; // by default, mode auto
+
   // Diameter comm engines which are loaded after application start (via management operation 'services') are not really started,
   //  but this don't care because application startComponents() -> initialize() -> do_initialize() -> do nothing.
   // And when stopped, running state is not checked and it will be stopped anyway.
@@ -333,10 +391,10 @@ void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation
   }
 
   LOGDEBUG(
-    std::string trace = "Loading ADML services file '";
-    trace += xmlPathFile;
-    trace += "'";
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      std::string trace = "Loading ADML services 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)
   anna::xml::DTDMemory xmlDTD;
@@ -348,19 +406,19 @@ void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation
   }
   catch (anna::RuntimeException &ex) {
     LOGWARNING(
-      std::string msg = "Services DTD schema:\n\n";
-      msg += ServicesDTD;
-      anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+        std::string msg = "Services DTD schema:\n\n";
+    msg += ServicesDTD;
+    anna::Logger::warning(msg, ANNA_FILE_LOCATION);
     );
     throw ex;
   }
 
   LOGDEBUG(
-    std::string trace = "Loaded XML file (";
-    trace += xmlPathFile;
-    trace += "):\n";
-    trace += anna::xml::Compiler().apply(rootNode);
-    anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+      std::string trace = "Loaded XML file (";
+  trace += xmlPathFile;
+  trace += "):\n";
+  trace += anna::xml::Compiler().apply(rootNode);
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
   );
   servicesFromXML(rootNode, eventOperation);
 }
@@ -407,37 +465,63 @@ anna::Millisecond Launcher::checkTimeMeasure(const std::string &parameter, const
   throw RuntimeException(msg, ANNA_FILE_LOCATION);
 }
 
-RealmNode *Launcher::getWorkingNode() const throw(anna::RuntimeException) {
-
-  if (!a_workingNode)
-    throw RuntimeException("No services yet loaded. Try 'services' operation (via management interface), or restart process using command-line 'services' parameter", ANNA_FILE_LOCATION);
-
-  return a_workingNode;
-}
-
 bool Launcher::setWorkingNode(const std::string &name) throw() {
   bool result = false;
 
-  realm_nodes_nc_it nodeIt = a_nodes.find(name);
+  realm_nodes_it nodeIt = a_nodes.find(name);
   if (nodeIt == a_nodes.end()) {
     LOGWARNING(
-      std::string msg = "Unknown node with name '"; msg += name; msg += "'. Ignoring ...";
-      anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+        std::string msg = "Unknown node with name '"; msg += name; msg += "'. Ignoring ...";
+    anna::Logger::warning(msg, ANNA_FILE_LOCATION);
     );
   }
   else {
-    a_workingNode = nodeIt->second;
+    a_workingNode = const_cast<RealmNode*>(nodeIt->second);
     result = true;
   }
 
   return result;
 }
 
-RealmNode *Launcher::getRealmNode(const std::string &realmName) const throw() {
+RealmNode *Launcher::getRealmNode(const std::string &realmName) const throw(anna::RuntimeException) {
   realm_nodes_it it = a_nodes.find(realmName);
   if (it != a_nodes.end()) return it->second;
+  throw anna::RuntimeException(anna::functions::asString("There is no realm node registered as '%s' (set Origin-Realm avp correctly or force a specific realm with 'node' operation)", realmName.c_str()), ANNA_FILE_LOCATION);
+}
+
+RealmNode *Launcher::getRealmNode(const anna::diameter::codec::Message &message) const throw(anna::RuntimeException) {
+  std::string originRealm = message.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
+  return (getRealmNode(originRealm));
+}
 
-  return NULL; // this never happens
+void Launcher::updateOperatedRealmNodeWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException) {
+  if (!a_operatedRealm) // priority for working node by mean 'node' operation
+    a_operatedRealm = getRealmNode(message);
+}
+
+RealmNode *Launcher::getOperatedRealm() const throw(anna::RuntimeException) {
+  if(!a_operatedRealm)
+    throw anna::RuntimeException("Realm Node not identified (try to force a specific realm with 'node' operation)", ANNA_FILE_LOCATION);
+
+  return a_operatedRealm;
+}
+
+MyDiameterEntity *Launcher::getOperatedEntity() const throw(anna::RuntimeException) {
+  MyDiameterEntity *result = getOperatedRealm()->getEntity();
+  if (!result)
+    throw anna::RuntimeException("No entity configured for the operated Realm Node", ANNA_FILE_LOCATION);
+  return result;
+}
+
+MyLocalServer *Launcher::getOperatedServer() const throw(anna::RuntimeException) {
+  MyLocalServer *result = getOperatedRealm()->getDiameterServer();
+  if (!result)
+    throw anna::RuntimeException("No local server configured for the operated Realm Node", ANNA_FILE_LOCATION);
+  return result;
+}
+
+MyDiameterEngine *Launcher::getOperatedEngine() const throw(anna::RuntimeException) {
+  return getOperatedRealm()->getMyDiameterEngine(); // never will be NULL
 }
 
 void Launcher::initialize()
@@ -484,12 +568,12 @@ throw(anna::RuntimeException) {
   anna::statistics::Engine::instantiate().enable();
 
   LOGINFORMATION(
-    // Help on startup traces:
-    anna::Logger::information(help(), ANNA_FILE_LOCATION);
-    // Test messages dtd:
-    std::string msg = "\n                     ------------- TESTMESSAGES DTD -------------\n";
-    msg += anna::diameter::codec::MessageDTD;
-    anna::Logger::information(msg, ANNA_FILE_LOCATION);
+      // Help on startup traces:
+      anna::Logger::information(help(), ANNA_FILE_LOCATION);
+  // Test messages dtd:
+  std::string msg = "\n                     ------------- TESTMESSAGES DTD -------------\n";
+  msg += anna::diameter::codec::MessageDTD;
+  anna::Logger::information(msg, ANNA_FILE_LOCATION);
   );
 
   // HTTP Server:
@@ -626,29 +710,6 @@ throw(anna::RuntimeException) {
     a_timeEngine->activate(a_counterRecorderClock); // start clock
   }
 
-
-  // Integration (validation 'Complete' for receiving messages) and debugging (validation also before encoding: 'Always').
-  // If missing 'integrationAndDebugging', default behaviour at engine is: mode 'AfterDecoding', depth 'FirstError':
-  if(cl.exists("integrationAndDebugging")) {
-    getCodecEngine()->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always);
-    getCodecEngine()->setValidationDepth(anna::diameter::codec::Engine::ValidationDepth::Complete);
-  }
-
-  // Fix mode
-  if(cl.exists("fixMode")) { // BeforeEncoding(default), AfterDecoding, Always, Never
-    std::string fixMode = cl.getValue("fixMode");
-    anna::diameter::codec::Engine::FixMode::_v fm;
-    if (fixMode == "BeforeEncoding") fm = anna::diameter::codec::Engine::FixMode::BeforeEncoding;
-    else if (fixMode == "AfterDecoding") fm = anna::diameter::codec::Engine::FixMode::AfterDecoding;
-    else if (fixMode == "Always") fm = anna::diameter::codec::Engine::FixMode::Always;
-    else if (fixMode == "Never") fm = anna::diameter::codec::Engine::FixMode::Never;
-    else LOGINFORMATION(anna::Logger::information("Unreconized command-line fix mode. Assumed default 'BeforeEncoding'", ANNA_FILE_LOCATION));
-    getCodecEngine()->setFixMode(fm);
-  }
-
-  getCodecEngine()->ignoreFlagsOnValidation(cl.exists("ignoreFlags"));
-
-
   // Log statistics concepts
   if(cl.exists("logStatisticSamples")) {
     std::string list = cl.getValue("logStatisticSamples");
@@ -707,9 +768,9 @@ bool Launcher::getDataBlockFromHexFile(const std::string &pathfile, anna::DataBl
     // Allow colon separator in hex string: we have to remove them before processing with 'fromHexString':
     hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
     LOGDEBUG(
-      std::string msg = "Hex string (remove colons if exists): ";
-      msg += hexString;
-      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+        std::string msg = "Hex string (remove colons if exists): ";
+    msg += hexString;
+    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
     );
     anna::functions::fromHexString(hexString, db);
     // Close file
@@ -721,7 +782,14 @@ bool Launcher::getDataBlockFromHexFile(const std::string &pathfile, anna::DataBl
 }
 
 void Launcher::resetStatistics() throw() {
-  getWorkingNode()->getMyDiameterEngine()->resetStatistics();
+  if (a_workingNode) {
+    a_workingNode->getMyDiameterEngine()->resetStatistics();
+  }
+  else {
+    for (realm_nodes_it it = a_nodes.begin(); it != a_nodes.end(); it++) {
+      it->second->getMyDiameterEngine()->resetStatistics();
+    }
+  }
 }
 
 void Launcher::resetCounters() throw() {
@@ -732,12 +800,12 @@ void Launcher::resetCounters() throw() {
 
 void Launcher::signalUSR2() throw(anna::RuntimeException) {
   LOGNOTICE(
-    std::string msg = "Captured signal SIGUSR2. Reading tasks at '";
-    msg += SIGUSR2_TASKS_INPUT_FILENAME;
-    msg += "' (results will be written at '";
-    msg += SIGUSR2_TASKS_OUTPUT_FILENAME;
-    msg += "')";
-    anna::Logger::notice(msg, ANNA_FILE_LOCATION);
+      std::string msg = "Captured signal SIGUSR2. Reading tasks at '";
+  msg += SIGUSR2_TASKS_INPUT_FILENAME;
+  msg += "' (results will be written at '";
+  msg += SIGUSR2_TASKS_OUTPUT_FILENAME;
+  msg += "')";
+  anna::Logger::notice(msg, ANNA_FILE_LOCATION);
   );
 
   // Operation:
@@ -752,9 +820,9 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) {
 
   while(getline(in_file, line)) {
     LOGDEBUG(
-      std::string msg = "Processing line: ";
-      msg += line;
-      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+        std::string msg = "Processing line: ";
+    msg += line;
+    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
     );
 
     try {
@@ -827,7 +895,7 @@ std::string Launcher::help() const throw() {
   result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
   result += "\n";
   result += "\n  <!-- Nodes -->";
-  result += "\n  <node originRealm=\"ADML-client\" entity=\"localhost:3868\"/>";
+  result += "\n  <node originRealm=\"ADML-client\" applicationId=\"0\" entity=\"localhost:3868\"/>";
   result += "\n</services>";
   result += "\n";
   result += "\nServer configuration:";
@@ -837,7 +905,7 @@ std::string Launcher::help() const throw() {
   result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
   result += "\n";
   result += "\n  <!-- Nodes -->";
-  result += "\n  <node originRealm=\"ADML-server\" diameterServer=\"localhost:3868\"/>";
+  result += "\n  <node originRealm=\"ADML-server\" applicationId=\"0\" diameterServer=\"localhost:3868\"/>";
   result += "\n</services>";
   result += "\n";
   result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably";
@@ -854,8 +922,8 @@ std::string Launcher::help() const throw() {
   result += "\n  <stack id=\"0\" dictionary=\"dictionary_base.xml\"/>";
   result += "\n";
   result += "\n  <!-- Nodes -->";
-  result += "\n  <node originRealm=\"ADML-Rx-client\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>";
-  result += "\n  <node originRealm=\"ADML-Gx-client\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>";
+  result += "\n  <node originRealm=\"ADML-Rx-client\" applicationId=\"16777236\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>";
+  result += "\n  <node originRealm=\"ADML-Gx-client\" applicationId=\"16777238\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>";
   result += "\n</services>";
   result += "\n";
   result += "\n";
@@ -875,11 +943,24 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nhelp                                 This help.";
   result += "\n";
-  result += "\n---------------------------------------------------------------------------------------- Node selection";
-  result += "\n";
-  result += "\nnode[|<name>]                         Select current working node by mean the registered name.";
-  result += "\n                                      All the subsequent operations will be referred to this node.";
-  result += "\n                                      Without argument, the current node information is retrieved.";
+  result += "\n--------------------------------------------------------------------------------------- Node management";
+  result += "\n";
+  result += "\nnode[|<name>]                         Selects a context working node by mean a registered name.";
+  result += "\n                                      All the subsequent operations will be forced to work with";
+  result += "\n                                      this node, which makes possible some rare scenarios like";
+  result += "\n                                      sending unexpected messages on remote peers. This is also";
+  result += "\n                                      useful for some operations in order to restrict the scope";
+  result += "\n                                      of action (statistics, communication visibility, etc.).";
+  result += "\n                                      Empty parameter will show the current configuration.";
+  result += "\n";
+  result += "\nnode_auto                             Returns to the default behaviour (smart node selection).";
+  result += "\n                                      Depending on the operation, this could imply a global";
+  result += "\n                                      action scope, affecting to all the registered realms.";
+  result += "\n                                      This should be the normal configuration. Take into";
+  result += "\n                                      account that if you fix the working node, this could";
+  result += "\n                                      affect to things like test programming: communication";
+  result += "\n                                      resources will override those which would be inferred";
+  result += "\n                                      from programmed messages Origin-Realm avps.";
   result += "\n";
   result += "\n------------------------------------------------------------------------------------ Parsing operations";
   result += "\n";
@@ -904,8 +985,10 @@ std::string Launcher::help() const throw() {
   result += "\n                                      default '/var/tmp/anna.context.<pid>' will be used.";
   result += "\ncollect                              Reset statistics and counters to start a new test stage of";
   result += "\n                                      performance measurement. Context data can be written at";
-  result += "\n                                      '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>'";
+  result += "\n                                      '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>'.";
   result += "\n                                      or sending operation 'context|[target file]'.";
+  result += "\n                                     This operation applies over all the registered realm nodes";
+  result += "\n                                      except if one specific working node has been set.";
   result += "\nforceCountersRecord                  Forces dump to file the current counters of the process.";
   result += "\n";
   result += "\n<visibility action>[|<address>:<port>][|socket id]";
@@ -924,20 +1007,18 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nsendxml2e|<source_file>    Sends xml source file (pathfile) through configured entity.";
   result += "\nsendxml2c|<source_file>    Sends xml source file (pathfile) to client.";
-  result += "\nsendxml|<source_file>      Same as 'sendxml2e'.";
   result += "\nanswerxml2e[|source_file]  Answer xml source file (pathfile) for incoming request with same code from entity.";
   result += "\n                           The answer is stored in a FIFO queue for a specific message code, then there are";
   result += "\n                           as many queues as different message codes have been programmed.";
   result += "\nanswerxml2c[|source_file]  Answer xml source file (pathfile) for incoming request with same code from client.";
   result += "\n                           The answer is stored in a FIFO queue for a specific message code, then there are";
   result += "\n                           as many queues as different message codes have been programmed.";
-  result += "\nanswerxml[|source_file]    Same as 'answerxml2c'.";
-  result += "\nanswerxml(2e/2c)           List programmed answers (to entity/client) if no parameter provided.";
-  result += "\nanswerxml(2e/2c)|dump      Write programmed answers (to entity/client) to file 'programmed_answer.<message code>.<sequence>',";
+  result += "\nanswerxml<2e/2c>           List programmed answers (to entity/client) if no parameter provided.";
+  result += "\nanswerxml<2e/2c>|dump      Write programmed answers (to entity/client) to file 'programmed_answer.<message code>.<sequence>',";
   result += "\n                           where 'sequence' is the order of the answer in each FIFO code-queue of programmed answers.";
-  result += "\nanswerxml(2e/2c)|clear     Clear programmed answers (to entity/client).";
-  result += "\nanswerxml(2e/2c)|exhaust   Disable the corresponding queue rotation, which is the default behaviour.";
-  result += "\nanswerxml(2e/2c)|rotate    Enable the corresponding queue rotation, useful in performance tests.";
+  result += "\nanswerxml<2e/2c>|clear     Clear programmed answers (to entity/client).";
+  result += "\nanswerxml<2e/2c>|exhaust   Disable the corresponding queue rotation, which is the default behaviour.";
+  result += "\nanswerxml<2e/2c>|rotate    Enable the corresponding queue rotation, useful in performance tests.";
   result += "\n                           Rotation consists in add again to the queue, each element retrieved for answering.";
   result += "\n";
   result += "\nSend operations are available using hexadecimal content (hex formatted files) which also allow to test";
@@ -945,13 +1026,12 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nsendhex2e|<source_file>    Sends hex source file (pathfile) through configured entity.";
   result += "\nsendhex2c|<source_file>    Sends hex source file (pathfile) to client.";
-  result += "\nsendhex|<source_file>      Same as 'sendhex2e'.";
   result += "\n";
   result += "\nAnswer programming in hexadecimal is not really neccessary (you could use send primitives) and also";
   result += "\n is intended to be used with decoded messages in order to replace things like hop by hop, end to end,";
   result += "\n subscriber id, session id, etc. Anyway you could use 'decode' operation and then program the xml created.";
   result += "\n";
-  result += "\nIf a request is received, answer map (built with 'answerxml<[2c] or 2e>' operations) will be";
+  result += "\nIf a request is received, answer map (built with 'answerxml<2e/2c>' operations) will be";
   result += "\n checked to find a corresponding programmed answer to be replied(*). If no ocurrence is found,";
   result += "\n or answer message was received, the message is forwarded to the other side (entity or client),";
   result += "\n or nothing but trace when no peer at that side is configured. Answer to client have sense when";
@@ -964,7 +1044,7 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored";
   result += "\n    to the peer which sent the request. If user wants to test a specific answer without changing it,";
-  result += "\n    use sendxml/sendhex operations better than programming.";
+  result += "\n    use sendxml<2e/2c>/sendhex<2e/2c> operations better than programming.";
   result += "\n";
   result += "\nBalance ('--balance' command line parameter) could be used to forward server socket receptions through";
   result += "\n entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should";
@@ -992,6 +1072,12 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n------------------------------------------------------------------------------------------- Burst tests";
   result += "\n";
+  result += "\nIn order to simplify user experience, burst category operations are only allowed in single realm node";
+  result += "\n configuration. Indeed, you could send messages with incorrect Origin-Realm, and no warning is shown.";
+  result += "\nAll the operations are performed through the unique realm: if you need to use more interfaces, you may";
+  result += "\n launch different ADML instances. Is nonsense to allow burst in a multi-realm configured ADML, because";
+  result += "\n this feature is not able to coordinate the messages.";
+  result += "\n";
   result += "\nburst|<action>[|parameter]     Used for performance testing, we first program diameter requests";
   result += "\n                                messages in order to launch them from client side to the configured";
   result += "\n                                diameter entity. We could start the burst with an initial load";
@@ -1030,7 +1116,9 @@ std::string Launcher::help() const throw() {
   result += "\n                           Adds a new step to the test case with provided identifier. If provided identifier";
   result += "\n                            is not registered yet, a new test case will be created with that value and the";
   result += "\n                            step will be added as the first. For a specific 'id', the steps are stored in";
-  result += "\n                            order as they are programmed";
+  result += "\n                            order as they are programmed. Check possible runtime exceptions when adding a";
+  result += "\n                            new step because those which fail, will be ignored/skipped during test case";
+  result += "\n                            programming giving an incomplete sequence invalid for the testing purpose.";
   result += "\n";
   result += "\n                           <id>: integer number, normally monotonically increased for each test case. Some external";
   result += "\n                                 script/procedure shall clone a test case template in order to build a collection";
@@ -1104,14 +1192,14 @@ std::string Launcher::help() const throw() {
   result += "\n                                         a real unexpected message).";
 
   // TODO(***)
-//  result += "\n                                        The way to identify the test case, is through registered Session-Id values for";
-//  result += "\n                                         programmed requests. But this depends on the type of node. Acting as clients,";
-//  result += "\n                                         requests received have Session-Id values which are already registered with";
-//  result += "\n                                         one test case, causing an error if not found. Acting as servers, requests are";
-//  result += "\n                                         received over a diameter local server from a client which are generating that";
-//  result += "\n                                         Session-Id values. Then we know nothing about such values. The procedure in";
-//  result += "\n                                         this case is find out a test case not-started containing a condition which";
-//  result += "\n                                         comply with the incoming message, and reactivates it.";
+  //  result += "\n                                        The way to identify the test case, is through registered Session-Id values for";
+  //  result += "\n                                         programmed requests. But this depends on the type of node. Acting as clients,";
+  //  result += "\n                                         requests received have Session-Id values which are already registered with";
+  //  result += "\n                                         one test case, causing an error if not found. Acting as servers, requests are";
+  //  result += "\n                                         received over a diameter local server from a client which are generating that";
+  //  result += "\n                                         Session-Id values. Then we know nothing about such values. The procedure in";
+  //  result += "\n                                         this case is find out a test case not-started containing a condition which";
+  //  result += "\n                                         comply with the incoming message, and reactivates it.";
   // The other solution: register Session-Id values for answers send to client from a local diameter server.
 
   result += "\n                                        How to answer: a wait condition for a request will store the incoming message";
@@ -1126,12 +1214,10 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n                                        Condition format:";
   result += "\n";
-  result += "\n                                           [code]|[bitR]|[ResultCode]|[sessionId]|[hopByHop]|[msisdn]|[imsi]|[serviceContextId]";
+  result += "\n                                           [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]";
   result += "\n";
   result += "\n                                             code: integer number";
   result += "\n                                             bitR: 1 (request), 0 (answer)";
-  result += "\n                                             ResultCode: integer number";
-  result += "\n                                             sessionId: string";
   result += "\n                                             hopByHop: integer number or request send step reference: #<step number>";
   result += "\n";
   result += "\n                                                       Using the hash reference, you would indicate a specific wait condition";
@@ -1140,6 +1226,9 @@ std::string Launcher::help() const throw() {
   result += "\n                                                       This 'hop-by-hop' variant eases the wait condition for answers in the";
   result += "\n                                                        safest way.";
   result += "\n";
+  result += "\n                                             applicationId: integer number";
+  result += "\n                                             sessionId: string";
+  result += "\n                                             resultCode: integer number";
   result += "\n                                             msisdn: string";
   result += "\n                                             imsi: string";
   result += "\n                                             serviceContextId: string";
@@ -1167,14 +1256,14 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n                              test|1|timeout|5000                  (step 1: whole time requirement is 5 seconds)";
   result += "\n                              test|1|sendxml2e|CCR-I.xml           (step 2: imagine this xml uses the Session-Id 'SGx')";
-  result += "\n                              test|1|waitfe|272|0|2001|SGx         (step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS)";
+  result += "\n                              test|1|waitfe|272|0|||SGx|2001       (step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS)";
   result += "\n                              test|1|sendxml2e|AAR-flows.xml       (step 4: imagine this xml uses the Session-Id 'SRx')";
-  result += "\n                              test|1|waitfe|265|0|2001|SRx         (step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS)";
-  result += "\n                              test|1|waitfe|258|1||SGx             (step 6: waits the RAR (install policies) from the PCRF server)";
+  result += "\n                              test|1|waitfe|265|0|||SRx|2001       (step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS)";
+  result += "\n                              test|1|waitfe|258|1|||SGx            (step 6: waits the RAR (install policies) from the PCRF server)";
   result += "\n                              test|1|sendxml2e|RAA-install.xml|6   (step 7: sends the response for the RAR)";
   result += "\n                              test|1|sendxml2e|CCR-T.xml           (step 8: termination of the Gx session, imagine this xml puts hop-by-hop 'H1')";
-  result += "\n                              test|1|waitfe|272|0|2001|SGx|H1      (step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1')";
-  result += "\n                              test|1|waitfe|258|1||SGx             (step 10: waits the RAR (remove policies) from the PCRF server)";
+  result += "\n                              test|1|waitfe|272|0|H1||SGx|2001     (step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1')";
+  result += "\n                              test|1|waitfe|258|1|||SGx            (step 10: waits the RAR (remove policies) from the PCRF server)";
   result += "\n                              test|1|sendxml2e|RAA-remove.xml|10   (step 11: sends the response for the RAR)";
   result += "\n";
   result += "\n                              Notes: We added an additional condition in step 9: the hop-by-hop. When we program the corresponding";
@@ -1196,9 +1285,9 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n                                     Other simplifications: the steps 3, 5 and 9 can be replaced by";
   result += "\n";
-  result += "\n                                        test|1|waitfe||0|||#2";
-  result += "\n                                        test|1|waitfe||0|||#4";
-  result += "\n                                        test|1|waitfe||0|||#8";
+  result += "\n                                        test|1|waitfe||0|#2";
+  result += "\n                                        test|1|waitfe||0|#4";
+  result += "\n                                        test|1|waitfe||0|#8";
   result += "\n";
   result += "\n                                        which means that hop-by-hop must be retrieved from steps 2, 4 and 8 respectively,";
   result += "\n                                        and the expected message shall be an answer. Normally you will add other conditions,";
@@ -1304,18 +1393,19 @@ std::string Launcher::help() const throw() {
 void Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tm("Launcher", "eventOperation", ANNA_FILE_LOCATION));
   if (operation == "") return; // ignore
-
-  CommandLine& cl(anna::CommandLine::instantiate());
-  TestManager &testManager = TestManager::instantiate();
   LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION));
 
   // Default response:
   response_content = "Operation processed with exception (see traces): ";
   response_content += operation;
-
-
   std::string opt_response_content = ""; // aditional response content
   anna::DataBlock db_aux(true);
+  anna::diameter::codec::Message codecMsg; // auxiliary codec message
+
+  // Singletons:
+  CommandLine& cl(anna::CommandLine::instantiate());
+  TestManager &testManager = TestManager::instantiate();
+
 
   ///////////////////////////////////////////////////////////////////
   // Simple operations without arguments:
@@ -1350,7 +1440,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   // Get the operation type and parameters:
   Tokenizer::const_iterator tok_iter = params.begin();
   std::string opType = Tokenizer::data(tok_iter);
-  std::string param1, param2, param3, param4, param5, param6, param7, param8, param9, param10;
+  std::string param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11;
   if(numParams >= 1) { tok_iter++; param1 = Tokenizer::data(tok_iter); }
   if(numParams >= 2) { tok_iter++; param2 = Tokenizer::data(tok_iter); }
   if(numParams >= 3) { tok_iter++; param3 = Tokenizer::data(tok_iter); }
@@ -1362,6 +1452,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   if(numParams >= 8) { tok_iter++; param8 = Tokenizer::data(tok_iter); }
   if(numParams >= 9) { tok_iter++; param9 = Tokenizer::data(tok_iter); }
   if(numParams >= 10) { tok_iter++; param10 = Tokenizer::data(tok_iter); }
+  if(numParams >= 11) { tok_iter++; param11 = Tokenizer::data(tok_iter); }
   // Remove '<null>' artificial token to ease further checkings:
   if (param1 == "<null>") param1 = "";
   if (param2 == "<null>") param2 = "";
@@ -1373,6 +1464,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   if (param8 == "<null>") param8 = "";
   if (param9 == "<null>") param9 = "";
   if (param10 == "<null>") param10 = "";
+  if (param11 == "<null>") param11 = "";
 
   // No operation has more than 2 arguments except 'test' ...
   if(opType != "test" && numParams > 2)
@@ -1383,10 +1475,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   bool wrongBody = false;
 
   if((opType == "node") && (numParams > 1)) wrongBody = true;
+  if((opType == "node_auto") && (numParams > 0)) wrongBody = true;
 
   if(((opType == "code") || (opType == "decode")) && (numParams != 2)) wrongBody = true;
 
-  if(((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) && (numParams != 1)) wrongBody = true;
+  if(((opType == "sendxml2e") || (opType == "sendhex2e")) && (numParams != 1)) wrongBody = true;
 
   if((opType == "burst") && (numParams < 1)) wrongBody = true;
 
@@ -1427,19 +1520,31 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   // Realm switch:
   if(opType == "node") {
     if (param1 != "") {
-      if (setWorkingNode(param1)) response_content = anna::functions::asString("Current node is now '%s'", param1.c_str());
+      if (setWorkingNode(param1)) response_content = anna::functions::asString("Forced node is now '%s'", param1.c_str());
     }
     else {
-      response_content = getWorkingNode()->asXMLString();
+      if (a_workingNode) {
+        response_content = "Working node is forced to be: \n\n";
+        response_content += a_workingNode->asXMLString();
+      }
+      else {
+        response_content = "Working node is automatic";
+      }
     }
     return;
   }
+  if(opType == "node_auto") {
+    a_workingNode = NULL;
+    response_content = "Working node has been set to automatic";
+    return;
+  }
 
-  // Diameter endpoints:
-  MyDiameterEntity *entity = getWorkingNode()->getEntity();
-  MyDiameterEngine *commEngine = getWorkingNode()->getMyDiameterEngine();
-  MyLocalServer *localServer = getWorkingNode()->getDiameterServer();
-  anna::diameter::codec::Message codecMsg(getCodecEngine());
+  // Operated realm from possible forced-working node:
+  a_operatedRealm = a_workingNode ? a_workingNode /* priority */: NULL /* auto */;
+  // Use later:
+  //    If any message is managed: updateOperatedRealmNodeWithMessage(codecMessage)
+  //    To operate, use the exception-protected methods which never will return NULL:
+  //         getOperatedRealm(), getOperatedEntity(), getOperatedServer(), getOperatedEngine()
 
 
   if(opType == "code") {
@@ -1463,7 +1568,6 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     outfile.write(xmlString.c_str(), xmlString.size());
     outfile.close();
   } else if((opType == "hide") || (opType == "show") || (opType == "hidden") || (opType == "shown")) {
-    if(!entity) throw anna::RuntimeException("No entity configured to send messages", ANNA_FILE_LOCATION);
 
     if(param1 != "") {
       if(param2 != "") {
@@ -1471,65 +1575,68 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         key += "|";
         key += param2;
 
-        if(opType == "hide") commEngine->findClientSession(key)->hide();
+        if(opType == "hide") getOperatedEngine()->findClientSession(key)->hide();
 
-        if(opType == "show") commEngine->findClientSession(key)->show();
+        if(opType == "show") getOperatedEngine()->findClientSession(key)->show();
 
-        if(opType == "hidden") opt_response_content = commEngine->findClientSession(key)->hidden() ? "true" : "false";
+        if(opType == "hidden") opt_response_content = getOperatedEngine()->findClientSession(key)->hidden() ? "true" : "false";
 
-        if(opType == "shown") opt_response_content = commEngine->findClientSession(key)->shown() ? "true" : "false";
+        if(opType == "shown") opt_response_content = getOperatedEngine()->findClientSession(key)->shown() ? "true" : "false";
       } else {
         std::string address;
         int port;
         anna::functions::getAddressAndPortFromSocketLiteral(param1, address, port);
 
-        if(opType == "hide") commEngine->findServer(address, port)->hide();
+        if(opType == "hide") getOperatedEngine()->findServer(address, port)->hide();
 
-        if(opType == "show") commEngine->findServer(address, port)->show();
+        if(opType == "show") getOperatedEngine()->findServer(address, port)->show();
 
-        if(opType == "hidden") opt_response_content = commEngine->findServer(address, port)->hidden() ? "true" : "false";
+        if(opType == "hidden") opt_response_content = getOperatedEngine()->findServer(address, port)->hidden() ? "true" : "false";
 
-        if(opType == "shown") opt_response_content = commEngine->findServer(address, port)->shown() ? "true" : "false";
+        if(opType == "shown") opt_response_content = getOperatedEngine()->findServer(address, port)->shown() ? "true" : "false";
       }
     } else {
-      if(opType == "hide") entity->hide();
+      if(opType == "hide") getOperatedEntity()->hide();
 
-      if(opType == "show") entity->show();
+      if(opType == "show") getOperatedEntity()->show();
 
-      if(opType == "hidden") opt_response_content = entity->hidden() ? "true" : "false";
+      if(opType == "hidden") opt_response_content = getOperatedEntity()->hidden() ? "true" : "false";
 
-      if(opType == "shown") opt_response_content = entity->shown() ? "true" : "false";
+      if(opType == "shown") opt_response_content = getOperatedEntity()->shown() ? "true" : "false";
     }
-  } else if((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) {
-    if(!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION);
-    anna::diameter::comm::Message *msg = getWorkingNode()->createCommMessage();
+  } else if((opType == "sendxml2e") || (opType == "sendhex2e")) {
+    anna::diameter::comm::Message *msg;
 
-    if((opType == "sendxml") || (opType == "sendxml2e")) {
+    if(opType == "sendxml2e") {
       codecMsg.loadXML(param1);
+      updateOperatedRealmNodeWithMessage(codecMsg);
+      msg = getOperatedRealm()->createCommMessage();
       msg->clearBody();
       try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
-
       msg->setBody(codecMsg.code());
     } else {
       // Get DataBlock from file with hex content:
       if(!getDataBlockFromHexFile(param1, db_aux))
         throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION);
-
+      msg = getOperatedRealm()->createCommMessage();
       msg->setBody(db_aux);
+      try { if(getOperatedRealm()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); }
     }
 
-    bool success = entity->send(msg, cl.exists("balance"));
-    getWorkingNode()->releaseCommMessage(msg);
+    bool success = getOperatedEntity()->send(msg, cl.exists("balance"));
+    getOperatedRealm()->releaseCommMessage(msg);
 
     // Detailed log:
-    if(getWorkingNode()->logEnabled()) {
-      anna::diameter::comm::Server *usedServer = entity->getLastUsedResource();
+    if(getOperatedRealm()->logEnabled()) {
+      anna::diameter::comm::Server *usedServer = getOperatedEntity()->getLastUsedResource();
       anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL;
       std::string detail = usedClientSession ? usedClientSession->asString() : "<null client session>"; // shouldn't happen
-      getWorkingNode()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail);
+      getOperatedRealm()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail);
     }
   } else if((opType == "burst")) {
-    if(!entity) throw anna::RuntimeException("No entity configured to use burst feature", ANNA_FILE_LOCATION);
+
+    if (!uniqueRealm())
+      throw anna::RuntimeException("Burst category operations are only allowed in single realm node configuration. This is only to simplify user experience.", ANNA_FILE_LOCATION);
 
     // burst|clear                     clears all loaded burst messages.
     // burst|load|<source_file>        loads the next diameter message into launcher burst.
@@ -1546,17 +1653,16 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
     if(param1 == "clear") {
       opt_response_content = "removed ";
-      opt_response_content += anna::functions::asString(getWorkingNode()->clearBurst());
+      opt_response_content += anna::functions::asString(getOperatedRealm()->clearBurst());
       opt_response_content += " elements";
     } else if(param1 == "load") {
       if(param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION);
 
       codecMsg.loadXML(param2);
-
       if(codecMsg.isAnswer()) throw anna::RuntimeException("Cannot load diameter answers for burst feature", ANNA_FILE_LOCATION);
       try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue loading (see validation mode configured in launcher)
 
-      int position = getWorkingNode()->loadBurstMessage(codecMsg.code());
+      int position = getOperatedRealm()->loadBurstMessage(codecMsg.code());
       opt_response_content = "loaded '";
       opt_response_content += param2;
       opt_response_content += "' file into burst list position ";
@@ -1565,7 +1671,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if(param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION);
 
       int initialLoad = atoi(param2.c_str());
-      int processed = getWorkingNode()->startBurst(initialLoad);
+      int processed = getOperatedRealm()->startBurst(initialLoad);
 
       if(processed > 0) {
         opt_response_content = "initial load completed for ";
@@ -1574,7 +1680,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     } else if(param1 == "push") {
       if(param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION);
 
-      int pushed = getWorkingNode()->pushBurst(atoi(param2.c_str()));
+      int pushed = getOperatedRealm()->pushBurst(atoi(param2.c_str()));
 
       if(pushed > 0) {
         opt_response_content = "pushed ";
@@ -1584,14 +1690,14 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if(param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION);
 
       int releaseLoad = atoi(param2.c_str());
-      int popped = getWorkingNode()->popBurst(releaseLoad);
+      int popped = getOperatedRealm()->popBurst(releaseLoad);
 
       if(popped > 0) {
         opt_response_content = "burst popped for ";
         opt_response_content += anna::functions::entriesAsString(popped, "message");
       }
     } else if(param1 == "stop") {
-      int left = getWorkingNode()->stopBurst();
+      int left = getOperatedRealm()->stopBurst();
 
       if(left != -1) {
         opt_response_content += anna::functions::entriesAsString(left, "message");
@@ -1601,12 +1707,12 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if(param2 == "") param2 = "yes";
 
       bool repeat = (param2 == "yes");
-      getWorkingNode()->repeatBurst(repeat);
+      getOperatedRealm()->repeatBurst(repeat);
       opt_response_content += (repeat ? "repeat enabled" : "repeat disabled");
     } else if(param1 == "send") {
       if(param2 == "") throw anna::RuntimeException("Missing amount for burst send operation", ANNA_FILE_LOCATION);
 
-      int sent = getWorkingNode()->sendBurst(atoi(param2.c_str()));
+      int sent = getOperatedRealm()->sendBurst(atoi(param2.c_str()));
 
       if(sent > 0) {
         opt_response_content = "sent ";
@@ -1615,11 +1721,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     } else if(param1 == "goto") {
       if(param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION);
 
-      opt_response_content = getWorkingNode()->gotoBurst(atoi(param2.c_str()));
+      opt_response_content = getOperatedRealm()->gotoBurst(atoi(param2.c_str()));
     } else if(param1 == "look") {
       int order = ((param2 != "") ? atoi(param2.c_str()) : -1);
       opt_response_content = "\n\n";
-      opt_response_content += getWorkingNode()->lookBurst(order);
+      opt_response_content += getOperatedRealm()->lookBurst(order);
     } else {
       throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION);
     }
@@ -1778,13 +1884,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if(id < 0)
         throw anna::RuntimeException("Invalid test case identifier: must be a non-negative number", ANNA_FILE_LOCATION);
 
-      // PARAM: 1     2            3      4          5           6          7         8       9           10
+      // PARAM: 1     2            3      4          5           6             7           8          9       10         11
       // test|<id>|<command>
       //             timeout|    <msecs>
       //             sendxml2e|  <file>[|<step number>]
       //             sendxml2c|  <file>[|<step number>]
       //             delay|      [msecs]
-      //             wait<fe/fc>|[code]|[bitR]|[ResultCode]|[sessionId]|[hopByHop]|[msisdn]|[imsi]|[serviceContextId]
+      //             wait<fe/fc>|[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
       //      wait<fe/fc>-answer|<step number>
       //      wait<fe/fc>-regexp|<regexp>
       if(param2 == "") throw anna::RuntimeException("Missing command for test id operation", ANNA_FILE_LOCATION);
@@ -1809,16 +1915,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         else {
           if (param4 == "") LOGWARNING(anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION));
         }
+        updateOperatedRealmNodeWithMessage(codecMsg);
         int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1);
-        std::string originRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
-        RealmNode *realm = getRealmNode(originRealm);
-        if (!realm)
-          throw anna::RuntimeException("Cannot identify the realm node for the manager message. Check the Origin-Realm avp value (use the realm node name)", ANNA_FILE_LOCATION);
 
         if (param2 == "sendxml2e")
-          testManager.getTestCase(id)->addSendxml2e(codecMsg.code(), realm, stepNumber); // creates / reuses
+          testManager.getTestCase(id)->addSendxml2e(codecMsg.code(), getOperatedRealm(), stepNumber); // creates / reuses
         else
-          testManager.getTestCase(id)->addSendxml2c(codecMsg.code(), realm, stepNumber); // creates / reuses
+          testManager.getTestCase(id)->addSendxml2c(codecMsg.code(), getOperatedRealm(), stepNumber); // creates / reuses
       }
       else if (param2 == "delay") {
         if (numParams > 3)
@@ -1828,11 +1931,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         testManager.getTestCase(id)->addDelay(delay); // creates / reuses
       }
       else if ((param2 == "waitfe")||(param2 == "waitfc")) {
-        if (numParams > 10)
+        if (numParams > 11)
           throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
-        if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "") {
+        if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "" || param11 != "") {
           bool fromEntity = (param2.substr(4,2) == "fe");
-          testManager.getTestCase(id)->addWait(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10);
+          testManager.getTestCase(id)->addWait(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10, param11);
         }
         else {
           throw anna::RuntimeException(anna::functions::asString("Missing condition for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
@@ -1861,11 +1964,12 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     }
 
   } else if((opType == "sendxml2c") || (opType == "sendhex2c")) {
-    if(!localServer) throw anna::RuntimeException("No local server configured to send the message", ANNA_FILE_LOCATION);
-    anna::diameter::comm::Message *msg = getWorkingNode()->createCommMessage();
+    anna::diameter::comm::Message *msg;
 
     if(opType == "sendxml2c") {
       codecMsg.loadXML(param1);
+      updateOperatedRealmNodeWithMessage(codecMsg);
+      msg = getOperatedRealm()->createCommMessage();
       msg->clearBody();
       try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
 
@@ -1874,18 +1978,18 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       // Get DataBlock from file with hex content:
       if(!getDataBlockFromHexFile(param1, db_aux))
         throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION);
-
+      msg = getOperatedRealm()->createCommMessage();
       msg->setBody(db_aux);
     }
 
-    bool success = localServer->send(msg);
-    getWorkingNode()->releaseCommMessage(msg);
+    bool success = getOperatedServer()->send(msg);
+    getOperatedRealm()->releaseCommMessage(msg);
 
     // Detailed log:
-    if(getWorkingNode()->logEnabled()) {
-      anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource();
+    if(getOperatedRealm()->logEnabled()) {
+      anna::diameter::comm::ServerSession *usedServerSession = getOperatedServer()->getLastUsedResource();
       std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // shouldn't happen
-      getWorkingNode()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail);
+      getOperatedRealm()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail);
     }
   } else if(opType == "loadxml") {
     codecMsg.loadXML(param1);
@@ -1893,69 +1997,58 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     return;
   } else if(opType == "diameterServerSessions") {
     int diameterServerSessions = atoi(param1.c_str());
+    getOperatedServer()->setMaxConnections(diameterServerSessions);
 
-    if(localServer)
-      localServer->setMaxConnections(diameterServerSessions);
-    else
-      LOGWARNING(anna::Logger::warning("To update the number of sessions, you must configure the process diameter local server: you could also launch it with no sessions (disabled)", ANNA_FILE_LOCATION));
-
-  } else if((opType == "answerxml") || (opType == "answerxml2c")) {
-    if(!localServer)
-      throw anna::RuntimeException("Operation not applicable (no own diameter server has been configured)", ANNA_FILE_LOCATION);
-
+  } else if(opType == "answerxml2c") {
     if(param1 == "") { // programmed answers FIFO's to stdout
-      response_content = localServer->getReactingAnswers()->asString("ANSWERS TO CLIENT");
+      response_content = getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT");
       return;
     } else if (param1 == "rotate") {
-      localServer->getReactingAnswers()->rotate(true);
+      getOperatedServer()->getReactingAnswers()->rotate(true);
     } else if (param1 == "exhaust") {
-      localServer->getReactingAnswers()->rotate(false);
+      getOperatedServer()->getReactingAnswers()->rotate(false);
     } else if (param1 == "clear") {
-      localServer->getReactingAnswers()->clear();
+      getOperatedServer()->getReactingAnswers()->clear();
     } else if (param1 == "dump") {
-      localServer->getReactingAnswers()->dump();
+      getOperatedServer()->getReactingAnswers()->dump();
     } else {
-      anna::diameter::codec::Message *message = getCodecEngine()->createMessage(param1);
-      LOGDEBUG
-      (
-        anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION);
-      );
+      codecMsg.loadXML(param1);
+      updateOperatedRealmNodeWithMessage(codecMsg);
+      anna::diameter::codec::Message *message = getOperatedRealm()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils
+      LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
 
       if(message->isRequest())
         throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION);
 
       int code = message->getId().first;
       LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
-      localServer->getReactingAnswers()->addMessage(code, message);
+      getOperatedServer()->getReactingAnswers()->addMessage(code, message);
     }
   } else if(opType == "answerxml2e") {
-    if(!entity)
-      throw anna::RuntimeException("Operation not applicable (no diameter entity has been configured)", ANNA_FILE_LOCATION);
 
     if(param1 == "") { // programmed answers FIFO's to stdout
-      response_content = entity->getReactingAnswers()->asString("ANSWERS TO ENTITY");
+      response_content = getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY");
       return;
     } else if (param1 == "rotate") {
-      entity->getReactingAnswers()->rotate(true);
+      getOperatedEntity()->getReactingAnswers()->rotate(true);
     } else if (param1 == "exhaust") {
-      entity->getReactingAnswers()->rotate(false);
+      getOperatedEntity()->getReactingAnswers()->rotate(false);
     } else if (param1 == "clear") {
-      entity->getReactingAnswers()->clear();
+      getOperatedEntity()->getReactingAnswers()->clear();
     } else if (param1 == "dump") {
-      entity->getReactingAnswers()->dump();
+      getOperatedEntity()->getReactingAnswers()->dump();
     } else {
-      anna::diameter::codec::Message *message = getCodecEngine()->createMessage(param1);
-      LOGDEBUG
-      (
-        anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION);
-      );
+      codecMsg.loadXML(param1);
+      updateOperatedRealmNodeWithMessage(codecMsg);
+      anna::diameter::codec::Message *message = getOperatedRealm()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils
+      LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
 
       if(message->isRequest())
         throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION);
 
       int code = message->getId().first;
       LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
-      entity->getReactingAnswers()->addMessage(code, message);
+      getOperatedEntity()->getReactingAnswers()->addMessage(code, message);
     }
   } else {
     throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
@@ -1977,7 +2070,6 @@ throw() {
   result->createAttribute("StartTime", a_start_time.asString());
   result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000);
   // Diameter:
-  getCodecEngine()->asXML(result);
   for (realm_nodes_it it = a_nodes.begin(); it != a_nodes.end(); it++) {
     it->second->asXML(result);
   }
index 9ac09af..3ce4a20 100644 (file)
@@ -18,6 +18,7 @@
 #include <anna/core/core.hpp>
 #include <anna/comm/comm.hpp>
 #include <anna/time/Date.hpp>
+#include <anna/diameter/codec/Message.hpp>
 
 // Process
 #include <MyCommunicator.hpp>
@@ -42,6 +43,10 @@ namespace anna {
 }
 
 class TestManager;
+class RealmNode;
+class MyDiameterEntity;
+class MyLocalServer;
+class MyDiameterEngine;
 
 // RealmNode resources
 class RealmNode;
@@ -57,8 +62,6 @@ class Launcher : public anna::comm::Application {
 
   // Core engines:
   MyCommunicator *a_communicator;
-  anna::diameter::codec::Engine *a_codecEngine;
-  anna::diameter::stack::Dictionary *a_baseProtocolDictionary;
   anna::timex::Engine* a_timeEngine;
   MyCounterRecorder *a_counterRecorder;
   anna::Millisecond a_admlMinResolution;
@@ -67,6 +70,7 @@ class Launcher : public anna::comm::Application {
   // Nodes deployment:
   realm_nodes_t a_nodes;
   RealmNode *a_workingNode;
+  RealmNode *a_operatedRealm; // auxiliary for eventOperation
 
   // comm resources:
   anna::comm::ServerSocket* a_httpServerSocket; // HTTP
@@ -80,17 +84,23 @@ class Launcher : public anna::comm::Application {
 
 public:
   Launcher();
+  //~Launcher(); TODO
 
   void loadServices(const std::string & xmlPathFile, bool eventOperation = false) throw(anna::RuntimeException);
   void startServices() throw(anna::RuntimeException);
 
-  anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
-  //anna::diameter::stack::Dictionary *getBaseProtocolDictionary() const throw() { return a_baseProtocolDictionary; }
-  RealmNode *getWorkingNode() const throw(anna::RuntimeException); // management operations working node
-  bool setWorkingNode(const std::string &name) throw(); // we could update ignoreFlagsOnValidation/integrationAndDebugging over the global codec engine
-                                                        //  but finally, that configuration issues will be global to the process.
-
-  RealmNode *getRealmNode(const std::string &realmName) const throw();
+  bool setWorkingNode(const std::string &name) throw();
+  RealmNode *getRealmNode(const std::string &realmName) const throw(anna::RuntimeException);
+  RealmNode *getRealmNode(const anna::diameter::codec::Message &message) const throw(anna::RuntimeException);
+  bool uniqueRealm() const throw() { return (a_nodes.size() == 1); }
+
+  // Operated realm for communication resources smart assignment ////////////////////////////////////////////////////////////
+  void updateOperatedRealmNodeWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException);
+  RealmNode *getOperatedRealm() const throw(anna::RuntimeException);
+  MyDiameterEntity *getOperatedEntity() const throw(anna::RuntimeException);
+  MyLocalServer *getOperatedServer() const throw(anna::RuntimeException);
+  MyDiameterEngine *getOperatedEngine() const throw(anna::RuntimeException);
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
   MyCommunicator *getCommunicator() throw() { return a_communicator; }
index 50a9663..6c1244b 100644 (file)
@@ -101,9 +101,6 @@ throw(anna::RuntimeException) {
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
   RealmNode * my_node = my_app.getRealmNode(getEngine()->getRealm());
 
-  // Testing:
-  TestManager::instantiate().receiveMessage(message, clientSession);
-
   // CommandId:
   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
   LOGDEBUG
@@ -177,6 +174,9 @@ throw(anna::RuntimeException) {
       ex.trace();
     }
   }
+
+  // Testing:
+  TestManager::instantiate().receiveMessage(message, my_node, clientSession);
 }
 
 void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response)
@@ -195,9 +195,6 @@ throw(anna::RuntimeException) {
   bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable);
   bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success);
 
-  // Testing:
-  TestManager::instantiate().receiveMessage(*message, clientSession);
-
   // CommandId:
   anna::diameter::CommandId request_cid = request->getCommandId();
   LOGDEBUG
@@ -272,6 +269,9 @@ throw(anna::RuntimeException) {
 
   // Triggering burst:
   if(isOK || contextExpired) my_node->sendBurstMessage();
+
+  // Testing:
+  TestManager::instantiate().receiveMessage(*message, my_node, clientSession);
 }
 
 void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
index 9476883..73494b5 100644 (file)
@@ -25,7 +25,6 @@ namespace anna {
 
 class MyDiameterEntity : public anna::diameter::comm::Entity {
 
-  anna::diameter::codec::Engine * a_codecEngine; // for automatic answers (failed-avp), write logs, etc.
   bool a_balance; // Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.). Default: false.
   std::string a_sessionBasedModelsType;
 
@@ -41,13 +40,11 @@ class MyDiameterEntity : public anna::diameter::comm::Entity {
 public:
 
   MyDiameterEntity() {
-    a_codecEngine = NULL;
     a_balance = false;
     a_sessionBasedModelsType = "SessionIdLowPart";
   }
 
   ProgrammedAnswers a_reactingAnswers;
-  void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; a_reactingAnswers.setCodecEngine(codecEngine); }
   ProgrammedAnswers *getReactingAnswers() throw() { return (ProgrammedAnswers *)&a_reactingAnswers; }
 
   // Additional configuration parameters:
index 8127d84..110efdc 100644 (file)
@@ -30,9 +30,7 @@ throw(anna::RuntimeException) {
   // Performance stats:
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
   RealmNode * my_node = my_app.getRealmNode(getEngine()->getRealm());
-
-  // Testing:
-  TestManager::instantiate().receiveMessage(message, serverSession);
+  anna::diameter::codec::Engine *codecEngine = my_node->getCodecEngine();
 
   // CommandId:
   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
@@ -71,14 +69,18 @@ throw(anna::RuntimeException) {
       my_node->writeLogFile(message, (success ? "fwd2e" : "fwd2eError"), detail); // forwarded
     }
 
+
+    // Testing:
+    TestManager::instantiate().receiveMessage(message, my_node, serverSession);
+
     return;
   }
 
   // Error analisys:
   bool analysisOK = true; // by default
   anna::diameter::codec::Message *answer_message = NULL;
-  anna::diameter::codec::Message codecMsg(a_codecEngine);
-  anna::diameter::codec::Message codecAnsMsg(a_codecEngine);
+  anna::diameter::codec::Message codecMsg;
+  anna::diameter::codec::Message codecAnsMsg;
 
   CommandLine& cl(anna::CommandLine::instantiate());
   if(!cl.exists("ignoreErrors")) {  // Error analysis
@@ -98,13 +100,19 @@ throw(anna::RuntimeException) {
       answer_message = programmed_answer;
       // Prepare answer:
       my_app.getCommunicator()->prepareAnswer(answer_message, message);
-    } else return; // nothing done
+    } else {
+
+      // Testing:
+      TestManager::instantiate().receiveMessage(message, my_node, serverSession);
+
+      return; // nothing done
+    }
   }
 
-  anna::diameter::codec::Engine::ValidationMode::_v backupVM = a_codecEngine->getValidationMode();
+  anna::diameter::codec::Engine::ValidationMode::_v backupVM = codecEngine->getValidationMode();
 
   if(!analysisOK)
-    a_codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Never);
+    codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Never);
 
   anna::diameter::comm::Message *msg;
   try {
@@ -122,10 +130,13 @@ throw(anna::RuntimeException) {
   my_node->releaseCommMessage(msg);
 
   // Restore validation mode
-  a_codecEngine->setValidationMode(backupVM);
+  codecEngine->setValidationMode(backupVM);
 
   // Pop front the reacting answer:
   if(analysisOK && programmed) a_reactingAnswers.nextMessage(code);
+
+  // Testing:
+  TestManager::instantiate().receiveMessage(message, my_node, serverSession);
 }
 
 void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response)
@@ -144,9 +155,6 @@ throw(anna::RuntimeException) {
   bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable);
   bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success);
 
-  // Testing:
-  TestManager::instantiate().receiveMessage(*message, serverSession);
-
   // CommandId:
   anna::diameter::CommandId request_cid = request->getCommandId();
   LOGDEBUG
@@ -219,6 +227,9 @@ throw(anna::RuntimeException) {
       my_node->releaseCommMessage(request);
     }
   }
+
+  // Testing:
+  TestManager::instantiate().receiveMessage(*message, my_node, serverSession);
 }
 
 void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message)
index da4ed97..831e15b 100644 (file)
@@ -25,8 +25,6 @@ namespace anna {
 
 class MyLocalServer : public anna::diameter::comm::LocalServer {
 
-  anna::diameter::codec::Engine * a_codecEngine; // for automatic answers (failed-avp), write logs, etc.
-
   void eventResponse(const anna::diameter::comm::Response&) throw(anna::RuntimeException);
   void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException);
   void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException);
@@ -35,7 +33,6 @@ class MyLocalServer : public anna::diameter::comm::LocalServer {
 public:
 
   ProgrammedAnswers a_reactingAnswers;
-  void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; a_reactingAnswers.setCodecEngine(codecEngine); }
   ProgrammedAnswers *getReactingAnswers() throw() { return (ProgrammedAnswers *)&a_reactingAnswers; }
 };
 
index 9356dac..3f64a35 100644 (file)
 // 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 //
 
-
 // Standard
 #include <string>
 #include <fstream>
 
 // Project
+#include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/codec/Engine.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
 
 // Process
 #include <ProgrammedAnswers.hpp>
 
 
-void ProgrammedAnswers::clear () throw() {
-  for (reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
-       a_codecEngine->releaseMessage(*(it->second->begin()));
-       delete(it->second);
+void ProgrammedAnswers::clear() throw () {
+  try {
+    anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+    for (reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
+      anna::diameter::codec::Message *message = *(it->second->begin());
+      em.getCodecEngine(message->getApplicationId())->releaseMessage(message);
+      delete (it->second);
+    }
+    a_deques.clear();
+  }
+  catch (anna::RuntimeException &ex) {
+    ex.trace();
   }
-  a_deques.clear();
 }
 
-void ProgrammedAnswers::dump () throw() {
+void ProgrammedAnswers::dump() throw () {
   std::string outfilename, xmlString;
-  for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
-       int sequence = 1;
-       for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) {
-         // programmed_answer.<code>.<sequence>
-         outfilename = "programmed_answer.";
-         outfilename += anna::functions::asString(it->first);
-         outfilename += ".";
-         outfilename += anna::functions::asString(sequence++);
-         outfilename += ".xml";
-         std::ofstream outfile(outfilename.c_str(), std::ifstream::out);
-         xmlString =  (*itm)->asXMLString();
-         outfile.write(xmlString.c_str(), xmlString.size());
-         outfile.close();
-       }
+  for (reacting_answers_const_iterator it = a_deques.begin();
+      it != a_deques.end(); it++) {
+    int sequence = 1;
+    for (codec_messages_deque_const_iterator itm = it->second->begin();
+        itm != it->second->end(); itm++) {
+      // programmed_answer.<code>.<sequence>
+      outfilename = "programmed_answer.";
+      outfilename += anna::functions::asString(it->first);
+      outfilename += ".";
+      outfilename += anna::functions::asString(sequence++);
+      outfilename += ".xml";
+      std::ofstream outfile(outfilename.c_str(), std::ifstream::out);
+      xmlString = (*itm)->asXMLString();
+      outfile.write(xmlString.c_str(), xmlString.size());
+      outfile.close();
+    }
   }
 }
 
-void ProgrammedAnswers::addMessage(int code, anna::diameter::codec::Message *message) throw() {
-  if (!message) return; // just in case
-  message->setEngine(a_codecEngine); // just in case
+void ProgrammedAnswers::addMessage(int code, anna::diameter::codec::Message *message) throw () {
+  if (!message)
+    return; // just in case
 
   reacting_answers_const_iterator it = a_deques.find(code);
   if (it != a_deques.end()) {
-       it->second->push_back(message);
-  }
-  else {
-       codec_messages_deque *deque = new codec_messages_deque;
-       a_deques[code] = deque;
-       deque->push_back(message);
+    it->second->push_back(message);
+  } else {
+    codec_messages_deque *deque = new codec_messages_deque;
+    a_deques[code] = deque;
+    deque->push_back(message);
   }
 }
 
-anna::diameter::codec::Message* ProgrammedAnswers::getMessage(int code) const throw() { //get the front message (begin()), returns NULL if deque is empty
+anna::diameter::codec::Message* ProgrammedAnswers::getMessage(int code) const throw () { //get the front message (begin()), returns NULL if deque is empty
   anna::diameter::codec::Message *result = NULL;
   reacting_answers_const_iterator it = a_deques.find(code);
   if (it != a_deques.end()) {
-       if (!it->second->empty()) result = *(it->second->begin());
+    if (!it->second->empty())
+      result = *(it->second->begin());
   }
   return result;
 }
 
-void ProgrammedAnswers::nextMessage(int code) throw() { //pops the deque and release the message (when deque is not empty: deque::empty)
-  reacting_answers_const_iterator it = a_deques.find(code);
-  if (it != a_deques.end()) {
-       if (!it->second->empty()) {
-         if (a_rotate) {
-               addMessage(code, *(it->second->begin()));
-         }
-         else {
-               a_codecEngine->releaseMessage(*(it->second->begin()));
-         }
-         it->second->pop_front();
-       }
+void ProgrammedAnswers::nextMessage(int code) throw () { //pops the deque and release the message (when deque is not empty: deque::empty)
+  try {
+    reacting_answers_const_iterator it = a_deques.find(code);
+    if (it != a_deques.end()) {
+      if (!it->second->empty()) {
+        if (a_rotate) {
+          addMessage(code, *(it->second->begin()));
+        } else {
+          anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+          anna::diameter::codec::Message *message = *(it->second->begin());
+          em.getCodecEngine(message->getApplicationId())->releaseMessage(message);
+        }
+        it->second->pop_front();
+      }
+    }
+  }
+  catch (anna::RuntimeException &ex) {
+    ex.trace();
   }
 }
 
-std::string ProgrammedAnswers::asString(const char *queueName) const throw() {
+std::string ProgrammedAnswers::asString(const char *queueName) const throw () {
   std::string result = "";
   std::string aux = "FIFO QUEUE '";
   aux += queueName;
   aux += "', Rotation ";
-  aux += a_rotate ? "enabled":"disabled";
+  aux += a_rotate ? "enabled" : "disabled";
   result += anna::functions::highlightJustify(aux);
-  result += "Codec engine: ";
-  result += a_codecEngine->getClassName();
-  if(a_deques.size() != 0) {
-       for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
-         if (it->second->size() != 0) {
-               aux = "Answer code ";
-               aux += anna::functions::asString(it->first);
-               result += anna::functions::highlightJustify(aux, anna::functions::TextHighlightMode::OverAndUnderline,
-                                                                                                                anna::functions::TextJustifyMode::Left, '-');
-               for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) {
-                 result += (*itm)->asXMLString();
-                 result += "\n";
-               }
-               result += "\n";
-         }
-       }
-  }
-  else {
-       result = "No ocurrences found\n\n";
+  if (a_deques.size() != 0) {
+    for (reacting_answers_const_iterator it = a_deques.begin();
+        it != a_deques.end(); it++) {
+      if (it->second->size() != 0) {
+        aux = "Answer code ";
+        aux += anna::functions::asString(it->first);
+        result += anna::functions::highlightJustify(aux,
+            anna::functions::TextHighlightMode::OverAndUnderline,
+            anna::functions::TextJustifyMode::Left, '-');
+        for (codec_messages_deque_const_iterator itm = it->second->begin();
+            itm != it->second->end(); itm++) {
+          result += (*itm)->asXMLString();
+          result += "\n";
+        }
+        result += "\n";
+      }
+    }
+  else {
+    result = "No ocurrences found\n\n";
   }
   return result;
 }
index a7cd897..00b9d4d 100644 (file)
@@ -18,7 +18,6 @@ namespace anna {
   namespace diameter {
     namespace codec {
       class Message;
-      class Engine;
     }
   }
 }
@@ -35,13 +34,11 @@ typedef std::map < int /* message code */, codec_messages_deque* >::const_iterat
 
   reacting_answers_container a_deques;
   bool a_rotate;
-  anna::diameter::codec::Engine *a_codecEngine;
 
   public:
     ProgrammedAnswers() { a_rotate = false; }
     ~ProgrammedAnswers() { clear(); }
 
-    void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; }
     bool rotate() const throw() { return a_rotate; }
     void rotate(bool r) throw() { a_rotate = r; }
 
index d3a2b89..d227650 100644 (file)
@@ -11,6 +11,8 @@
 
 // Project
 #include <anna/diameter.comm/Message.hpp>
+#include <anna/diameter/stack/Dictionary.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
 #include <anna/core/core.hpp>
 #include <anna/time/Date.hpp>
 #include <anna/xml/Compiler.hpp>
@@ -19,6 +21,7 @@
 #include <RealmNode.hpp>
 #include <MyDiameterEngine.hpp>
 
+
 namespace anna {
   namespace diameter {
     namespace stack {
@@ -27,12 +30,13 @@ namespace anna {
   }
 }
 
-RealmNode::RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary) :
-  a_originRealm(originRealm), a_codecEngine(codecEngine) {
+RealmNode::RealmNode(const std::string &originRealm, unsigned int applicationId, const anna::diameter::stack::Dictionary *baseProtocolDictionary) :
+  a_originRealm(originRealm), a_applicationId(applicationId) {
 
   std::string commEngineName = a_originRealm + "_DiameterCommEngine";
   a_commEngine = new MyDiameterEngine(commEngineName.c_str(), baseProtocolDictionary);
   a_commEngine->setAutoBind(false);  // allow to create client-sessions without binding them, in order to set timeouts.
+  a_codecEngine = anna::diameter::codec::EngineManager::instantiate().getCodecEngine(applicationId);
 
   a_logFile = "";
   a_burstLogFile = "";
@@ -68,9 +72,6 @@ void RealmNode::createEntity(const std::string &entityRepresentation, const anna
   a_entity = (MyDiameterEntity*)(a_commEngine->createEntity(servers, entityDescription));
   a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::Bind, bindTimeout);
   a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::ApplicationMessage, applicationTimeout);
-
-  // Codec engine for reacting answers (failed-avp):
-  a_entity->setCodecEngine(getCodecEngine());
 }
 
 void RealmNode::startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException) {
@@ -86,9 +87,6 @@ void RealmNode::startDiameterServer(const std::string &serverRepresentation, int
 
   a_diameterServer->setDescription(serverDescription);
   a_diameterServer->setAllowedInactivityTime(inactivityTimeout);
-
-  // Codec engine for reacting answers (failed-avp):
-  a_diameterServer->setCodecEngine(getCodecEngine());
 }
 
 anna::diameter::comm::Message *RealmNode::createCommMessage() throw(anna::RuntimeException) {
@@ -105,16 +103,13 @@ void RealmNode::releaseCommMessage(anna::diameter::comm::Message *msg) throw() {
 
 
 void RealmNode::writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail) const throw() {
-//   if (!logEnabled()) return;
-  anna::diameter::codec::Message codecMsg(getCodecEngine());
+  anna::diameter::codec::Message codecMsg;
   try { codecMsg.decode(db); } catch(anna::RuntimeException &ex) { ex.trace(); }
   writeLogFile(codecMsg, logExtension, detail);
-
 }
 
-// Si ya lo tengo decodificado:
-void RealmNode::writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw() {
-//   if (!logEnabled()) return;
+// Already decoded:
+void RealmNode::writeLogFile(const anna::diameter::codec::Message &decodedMessage, const std::string &logExtension, const std::string &detail) const throw() {
   // Open target file:
   std::string targetFile = a_logFile;
 
@@ -379,10 +374,8 @@ std::string RealmNode::lookBurst(int order) const throw() {
   std::map<int, anna::diameter::comm::Message*>::const_iterator it = a_burstMessages.find(order - 1);
 
   if(it != a_burstMessages.end()) {
-    // Decode
-    anna::diameter::codec::Message codecMsg(getCodecEngine());
-    try { codecMsg.decode((*it).second->getBody()); } catch(anna::RuntimeException &ex) { ex.trace(); }
-    result = codecMsg.asXMLString();
+    anna::diameter::codec::Message codecMsg;
+    try { codecMsg.decode((*it).second->getBody()); result = codecMsg.asXMLString(); } catch(anna::RuntimeException &ex) { ex.trace(); }
   }
 
   return result;
@@ -407,6 +400,7 @@ throw() {
   anna::xml::Node* result = parent->createChild("RealmNode");
 
   result->createAttribute("OriginRealm", a_originRealm);
+  result->createAttribute("ApplicationId", a_applicationId);
   result->createAttribute("LogFile", a_logFile);
   result->createAttribute("SplitLog", a_splitLog ? "yes" : "no");
   result->createAttribute("DetailedLog", a_detailedLog ? "yes" : "no");
index 774e858..7f239ca 100644 (file)
@@ -53,6 +53,7 @@ class RealmNode {
 
   // main
   std::string a_originRealm;
+  unsigned int a_applicationId;
 
   // Timming
   anna::Millisecond a_allowedInactivityTime;
@@ -76,12 +77,16 @@ class RealmNode {
   int a_burstPopCounter;
 
 public:
-  RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary);
+  RealmNode(const std::string &originRealm, unsigned int applicationId, const anna::diameter::stack::Dictionary *baseProtocolDictionary);
   ~RealmNode() {;}
 
+  const std::string &getName() const throw() { return a_originRealm; }
+
   // Core resources:
   MyDiameterEngine* getMyDiameterEngine() const throw() { return a_commEngine; }
+  unsigned int getApplicationId() const throw() { return a_applicationId; }
   anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
+
   void createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw(anna::RuntimeException);
   MyDiameterEntity *getEntity() const throw() { return a_entity; }
   void startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException);
index 309a7ef..a0f4fb6 100644 (file)
@@ -41,11 +41,8 @@ int main(int argc, const char** argv) {
     commandLine.add("httpServer", anna::CommandLine::Argument::Optional, "HTTP Management interface address (using i.e. curl tool) in '<address>:<port>' format. For example: 10.20.30.40:8080");
     commandLine.add("httpServerShared", anna::CommandLine::Argument::Optional, "Enables shared bind for HTTP Management interface address. It would be useful i.e. to allow a great amount of curl operations per second", false);
 
-    // Codec engine
+    // Automatic error answer
     commandLine.add("ignoreErrors", anna::CommandLine::Argument::Optional, "Local server skips requests errors analysis which would prepare automatic answers for them when a problem is found. If no answer is programmed and entity is configured, a failed request would be forwarded (delegates at the end point) even if this parameter is missing", false);
-    commandLine.add("ignoreFlags", anna::CommandLine::Argument::Optional, "Ignore flags on validation (at the moment only bits M & P from AVPs, because V bit is too important; no operation flags could be checked). Also force compact xml presentation ignoring flags during dictionary elements identification", false);
-    commandLine.add("integrationAndDebugging", anna::CommandLine::Argument::Optional, "Sets validation mode to 'Always' (default validates only after decoding), and validation depth to 'Complete' (default validates until 'FirstError')", false);
-    commandLine.add("fixMode", anna::CommandLine::Argument::Optional, "Sets message fix mode (unreconized values will assume default 'BeforeEncoding'). Allowed: 'BeforeEncoding', 'AfterDecoding', 'Always', 'Never'");
 
     commandLine.initialize(argv, argc);
     commandLine.verify();
index 29f41eb..3c5d7ff 100755 (executable)
@@ -59,7 +59,7 @@ echo
 [[ "$1" = "" ]] && use
 [[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; }
 echo
-operation="sendxml|$1"
+operation="sendxml2e|$1"
 [[ "$2" = "2c" ]] && operation="sendxml2c|$1"
 
 curl -m 1 --data "$operation" $TRACE ${SERVER}
index a7d3f30..d7bfbc6 100644 (file)
@@ -3,7 +3,7 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-balancer" entity="192.168.12.11:3868,192.168.12.21:3868" diameterServer="localhost:3868" balance="yes"/>
-  <!-- <node originRealm="ADML-proxy" entity="localhost:3868" diameterServer="localhost:3870"/> -->
+  <node originRealm="ADML-balancer" applicationId="0" entity="192.168.12.11:3868,192.168.12.21:3868" diameterServer="localhost:3868" balance="yes"/>
+  <!-- <node originRealm="ADML-proxy" applicationId="0" entity="localhost:3868" diameterServer="localhost:3870"/> -->
 </services>
 
index 4c5e019..dfbb943 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-client" entity="localhost:3868"/>
+  <node originRealm="ADML-client" applicationId="0" entity="localhost:3868"/>
 </services>
 
index c09c529..f1602be 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-dummy"/>
+  <node originRealm="ADML-dummy" applicationId="0"/>
 </services>
 
index a47db65..aa884eb 100644 (file)
@@ -6,9 +6,9 @@
   <stack id="0" dictionary="dictionaryBase.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="afNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ggsnNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ggsn2Node" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ocsNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="afNode" applicationId="16777236" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ggsnNode" applicationId="16777238" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ggsn2Node" applicationId="16777238" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ocsNode" applicationId="16777302" entity="192.168.12.11:3868,192.168.12.21:3868"/>
 </services>
 
index e615c4a..c257afc 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-server" diameterServer="localhost:3868"/>
+  <node originRealm="ADML-server" applicationId="0" diameterServer="localhost:3868"/>
 </services>
 
index 6dd31ed..1e40d28 100755 (executable)
@@ -4,22 +4,27 @@
 <!ELEMENT services (stack*, node*)>
 
 <!ELEMENT stack EMPTY>
-<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
+<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED validationMode (BeforeEncoding | AfterDecoding | Always | Never) #IMPLIED validationDepth (Complete | FirstError) #IMPLIED fixMode (BeforeEncoding | AfterDecoding | Always | Never) #IMPLIED ignoreFlagsOnValidation (yes | no) #IMPLIED>
 <!--
    Stack record
 
-   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed
-               (in multistack applications, it shall be mandatory respect such association to know the stack used
-               for processed messages).
-   dictionary: Path to the dictionary file
+   id:                      Normally the id corresponds to the Application-Id for which the dictionary provided is designed
+                            (in multistack applications, it shall be mandatory respect such association to know the stack used
+                            for processed messages).
+   dictionary:              Path to the dictionary file.
+   validationMode:          Sets the validation mode. Default is 'AfterDecoding'.
+   validationDepth:         Sets the validation depth. Default is 'FirstError'.
+   fixMode:                 Sets the fix mode. Default is 'BeforeEncoding'.
+   ignoreFlagsOnValidation: Ignore flags during message validation. Default is 'no'.
 -->
 
 <!ELEMENT node EMPTY>
-<!ATTLIST node originRealm CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
+<!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
 <!--
    Node record
 
    originRealm:                             Node identifier (Origin-Realm name).
+   applicationId:                           The Application-Id provided must exists as a registered 'stack id'.
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname
                                             Note that if you have two or more realms, the names must be different.
    cer:                                     User defined CER path file to be encoded to establish diameter connections.
index a8b9643..32ecba1 100644 (file)
@@ -248,15 +248,15 @@ void TestCase::addSendxml2e(const anna::DataBlock &db, RealmNode *realm, int ste
     int steps = a_steps.size();
     int stepIndx = stepNumber - 1;
     if ((stepIndx < 0) || (stepIndx > (a_steps.size()-1)))
-      throw anna::RuntimeException(anna::functions::asString("Step number out of range (test case %llu)", a_id), ANNA_FILE_LOCATION);
+      throw anna::RuntimeException(anna::functions::asString("Step number (%d) out of range (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
 
     TestStep *stepReferred = a_steps[stepIndx];
     if (stepReferred->getType() != TestStep::Type::Wait)
-      throw anna::RuntimeException(anna::functions::asString("Step number must refer to a 'wait' step (test case %llu)", a_id), ANNA_FILE_LOCATION);
+      throw anna::RuntimeException(anna::functions::asString("Step number (%d) must refer to a 'wait' step (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
 
     const TestCondition &tc = (static_cast<TestStepWait*>(stepReferred))->getCondition();
     if (tc.getCode() == "0") { // if regexp used, is not possible to detect this kind of errors
-      throw anna::RuntimeException(anna::functions::asString("Step number must refer to a 'wait for request' step (test case %llu)", a_id), ANNA_FILE_LOCATION);
+      throw anna::RuntimeException(anna::functions::asString("Step number (%d) must refer to a 'wait for request' step (test case %llu)", stepNumber, a_id), ANNA_FILE_LOCATION);
     }
   }
 
@@ -285,8 +285,9 @@ void TestCase::addDelay(const anna::Millisecond &delay) throw(anna::RuntimeExcep
 }
 
 void TestCase::addWait(bool fromEntity,
-                        const std::string &code, const std::string &bitR, const std::string &resultCode, const std::string &sessionId,
-                        const std::string &hopByHop, const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw(anna::RuntimeException) {
+              const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId,
+              const std::string &sessionId, const std::string &resultCode,
+              const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw(anna::RuntimeException) {
   assertInitialized();
   std::string usedHopByHop = hopByHop;
   TestStepWait *step = NULL;
@@ -329,7 +330,7 @@ void TestCase::addWait(bool fromEntity,
   }
 
   if (!step) step = new TestStepWait(this);
-  step->setCondition(fromEntity, code, bitR, resultCode, sessionId, usedHopByHop, msisdn, imsi, serviceContextId);
+  step->setCondition(fromEntity, code, bitR, usedHopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId);
 
   LOGWARNING(
     if (hasSameCondition(step->getCondition()))
index ea8dd1b..0a2c93b 100644 (file)
@@ -75,8 +75,9 @@ public:
   void addSendxml2c(const anna::DataBlock &db, RealmNode *realm, int stepNumber) throw(anna::RuntimeException);
   void addDelay(const anna::Millisecond &delay) throw(anna::RuntimeException);
   void addWait(bool fromEntity,
-                const std::string &code, const std::string &bitR, const std::string &resultCode, const std::string &sessionId,
-                const std::string &hopByHop, const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw(anna::RuntimeException);
+                const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId,
+                const std::string &sessionId, const std::string &resultCode,
+                const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw(anna::RuntimeException);
   void addWaitAnswer(bool fromEntity, int stepNumber) throw(anna::RuntimeException);
   void addWaitRegexp(bool fromEntity, const std::string &regexp) throw(anna::RuntimeException);
   void addCmd(const std::string &script, const std::string &parameters) throw(anna::RuntimeException);
index 7f535d5..ced5db6 100644 (file)
@@ -13,6 +13,7 @@
 #include <anna/xml/Compiler.hpp>
 #include <anna/diameter/defines.hpp>
 #include <anna/diameter/codec/functions.hpp>
+#include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/helpers/base/functions.hpp>
 
 #include <anna/diameter/helpers/dcca/defines.hpp>
@@ -21,7 +22,6 @@
 
 // Process
 #include <TestCondition.hpp>
-#include <Launcher.hpp>
 
 
 const char* TestCondition::asText(const Type::_v type)
@@ -34,7 +34,7 @@ bool TestCondition::exists() const throw() {
   if (a_type == Type::Generic)
     return (a_regexp != "");
   else
-    return (a_code != "" || a_bitR != "" || a_resultCode != "" || a_sessionId != "" || a_hopByHop != "" || a_msisdn != "" || a_imsi != "" || a_serviceContextId != "");
+    return (a_code != "" || a_bitR != "" || a_hopByHop != "" || a_applicationId != "" || a_sessionId != "" || a_resultCode != "" || a_msisdn != "" || a_imsi != "" || a_serviceContextId != "");
 }
 
 bool operator==(const TestCondition &c1, const TestCondition &c2) throw() {
@@ -47,9 +47,10 @@ bool operator==(const TestCondition &c1, const TestCondition &c2) throw() {
   else {
     if (c1.a_code != c2.a_code) return false;
     if (c1.a_bitR != c2.a_bitR) return false;
-    if (c1.a_resultCode != c2.a_resultCode) return false;
-    if (c1.a_sessionId != c2.a_sessionId) return false;
     if (c1.a_hopByHop != c2.a_hopByHop) return false;
+    if (c1.a_applicationId != c2.a_applicationId) return false;
+    if (c1.a_sessionId != c2.a_sessionId) return false;
+    if (c1.a_resultCode != c2.a_resultCode) return false;
     if (c1.a_msisdn != c2.a_msisdn) return false;
     if (c1.a_imsi != c2.a_imsi) return false;
     if (c1.a_serviceContextId != c2.a_serviceContextId) return false;
@@ -61,15 +62,8 @@ bool operator==(const TestCondition &c1, const TestCondition &c2) throw() {
 bool TestCondition::comply(const anna::DataBlock &message/*, bool matchSessionId*/) const throw() {
 
   if (a_type == Type::Generic) {
-    Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-    static anna::diameter::codec::Message codecMsg(my_app.getCodecEngine());
-    try {
-      codecMsg.decode(message);
-    }
-    catch (anna::RuntimeException &ex) {
-      ex.trace();
-    }
-
+    anna::diameter::codec::Message codecMsg;
+    try { codecMsg.decode(message); } catch (anna::RuntimeException &ex) { ex.trace(); }
     return codecMsg.isLike(a_regexp);
   }
 
@@ -94,32 +88,41 @@ bool TestCondition::comply(const anna::DataBlock &message/*, bool matchSessionId
     if (a_bitR != compare) return false;
   }
 
-  if (a_resultCode != "") {
+  if (a_hopByHop != "") {
     try {
-      anna::U32 rc = anna::diameter::helpers::base::functions::getResultCode(message);
-      compare = anna::functions::asString(rc);
+      anna::diameter::HopByHop h = anna::diameter::codec::functions::getHopByHop(message);
+      compare = anna::functions::asString(h);
     }
     catch (anna::RuntimeException &) { return false; }
-    if (a_resultCode != compare) return false;
+    if (a_hopByHop != compare) return false;
+  }
+
+  if (a_applicationId != "") {
+    try {
+      anna::diameter::ApplicationId a = anna::diameter::codec::functions::getApplicationId(message);
+      compare = anna::functions::asString(a);
+    }
+    catch (anna::RuntimeException &) { return false; }
+    if (a_applicationId != compare) return false;
   }
 
   //if (matchSessionId) {
-    if (a_sessionId != "") {
-      try {
-        compare = anna::diameter::helpers::base::functions::getSessionId(message);
-      }
-      catch (anna::RuntimeException &) { return false; }
-      if (a_sessionId != compare) return false;
+  if (a_sessionId != "") {
+    try {
+      compare = anna::diameter::helpers::base::functions::getSessionId(message);
     }
+    catch (anna::RuntimeException &) { return false; }
+    if (a_sessionId != compare) return false;
+  }
   //}
 
-  if (a_hopByHop != "") {
+  if (a_resultCode != "") {
     try {
-      anna::diameter::HopByHop h = anna::diameter::codec::functions::getHopByHop(message);
-      compare = anna::functions::asString(h);
+      anna::U32 rc = anna::diameter::helpers::base::functions::getResultCode(message);
+      compare = anna::functions::asString(rc);
     }
     catch (anna::RuntimeException &) { return false; }
-    if (a_hopByHop != compare) return false;
+    if (a_resultCode != compare) return false;
   }
 
   if (a_msisdn != "") {
@@ -160,9 +163,10 @@ throw() {
   else {
     if (a_code != "") result->createAttribute("Code", atoi(a_code.c_str()));
     if (a_bitR != "") result->createAttribute("BitR", ((a_bitR == "1") ? "yes":"no"));
+    if (a_hopByHop != "") result->createAttribute("HopByHop", atoll(a_hopByHop.c_str()));
+    if (a_applicationId != "") result->createAttribute("ApplicationId", atoll(a_applicationId.c_str()));
     if (a_sessionId != "") result->createAttribute("SessionId", a_sessionId);
     if (a_resultCode != "") result->createAttribute("ResultCode", atoi(a_resultCode.c_str()));
-    if (a_hopByHop != "") result->createAttribute("HopByHop", atoll(a_hopByHop.c_str()));
     if (a_msisdn != "") result->createAttribute("Msisdn", a_msisdn);
     if (a_imsi != "") result->createAttribute("Imsi", a_imsi);
     if (a_serviceContextId != "") result->createAttribute("ServiceContextId", a_serviceContextId);
index 7ff58d9..57cba63 100644 (file)
@@ -32,8 +32,9 @@ class TestCondition {
 
     TestCondition() : a_rcvFromEntity(true),
                       a_regexp(""),
-                      a_code(""), a_bitR(""), a_resultCode(""), a_sessionId(""),
-                      a_hopByHop(""), a_msisdn(""), a_imsi(""), a_serviceContextId("") { a_type = Type::Basic; }
+                      a_code(""), a_bitR(""), a_hopByHop(""), a_applicationId(""),
+                      a_sessionId(""), a_resultCode(""),
+                      a_msisdn(""), a_imsi(""), a_serviceContextId("") { a_type = Type::Basic; }
 
 
     // Source of the received message
@@ -45,9 +46,10 @@ class TestCondition {
     // Basic
     void setCode(const std::string &value) throw() { a_code = value; }
     void setBitR(const std::string &value) throw() { a_bitR = value; }
-    void setResultCode(const std::string &value) throw() { a_resultCode = value; }
-    void setSessionId(const std::string &value) throw() { a_sessionId = value; }
     void setHopByHop(const std::string &value) throw() { a_hopByHop = value; }
+    void setApplicationId(const std::string &value) throw() { a_applicationId = value; }
+    void setSessionId(const std::string &value) throw() { a_sessionId = value; }
+    void setResultCode(const std::string &value) throw() { a_resultCode = value; }
     void setMsisdn(const std::string &value) throw() { a_msisdn = value; }
     void setImsi(const std::string &value) throw() { a_imsi = value; }
     void setServiceContextId(const std::string &value) throw() { a_serviceContextId = value; }
@@ -60,9 +62,10 @@ class TestCondition {
     // Basic
     const std::string & getCode() const throw() { return a_code; }
     const std::string & getBitR() const throw() { return a_bitR; }
-    const std::string & getResultCode() const throw() { return a_resultCode; }
-    const std::string & getSessionId() const throw() { return a_sessionId; }
     const std::string & getHopByHop() const throw() { return a_hopByHop; }
+    const std::string & getApplicationId() const throw() { return a_applicationId; }
+    const std::string & getSessionId() const throw() { return a_sessionId; }
+    const std::string & getResultCode() const throw() { return a_resultCode; }
     const std::string & getMsisdn() const throw() { return a_msisdn; }
     const std::string & getImsi() const throw() { return a_imsi; }
     const std::string & getServiceContextId() const throw() { return a_serviceContextId; }
@@ -88,9 +91,10 @@ class TestCondition {
     // Basic:
     std::string a_code;
     std::string a_bitR;
-    std::string a_resultCode;
-    std::string a_sessionId;
     std::string a_hopByHop;
+    std::string a_applicationId;
+    std::string a_sessionId;
+    std::string a_resultCode;
     std::string a_msisdn;
     std::string a_imsi;
     std::string a_serviceContextId;
index c01b89e..38916d0 100644 (file)
@@ -24,6 +24,7 @@
 #include <TestCase.hpp>
 #include <TestClock.hpp>
 #include <Launcher.hpp>
+#include <RealmNode.hpp>
 
 
 class TestTimer;
@@ -311,7 +312,7 @@ TestCase *TestManager::getTestCaseFromSessionId(const anna::DataBlock &message,
   return NULL;
 }
 
-void TestManager::receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException) {
+void TestManager::receiveMessage(const anna::DataBlock &message, RealmNode *realm, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException) {
 
   // Testing disabled:
   if (!tests()) return;
@@ -327,10 +328,15 @@ void TestManager::receiveMessage(const anna::DataBlock &message, const anna::dia
     std::string hint = "Uncovered condition for received message from entity over Session-Id '"; hint += sessionId; hint += "':";
 
     try {
-      Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-      static anna::diameter::codec::Message codecMsg(my_app.getCodecEngine());
+      static anna::diameter::codec::Message codecMsg;
       codecMsg.decode(message);
       hint += "\n"; hint += codecMsg.asXMLString();
+
+      //      // Realm checking:
+      //      std::string messageOR = message.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
+      //      if (messageOR != realm->getName()) {
+      //        LOGWARNING(anna::Logger::warning(anna::functions::asString("Received message from realm '%s', with different Origin-Realm: %s", realm->getName().c_str(), messageOR.c_str()), ANNA_FILE_LOCATION));
+      //      }
     }
     catch (anna::RuntimeException &ex) {
       ex.trace();
@@ -346,7 +352,7 @@ void TestManager::receiveMessage(const anna::DataBlock &message, const anna::dia
   }
 }
 
-void TestManager::receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException) {
+void TestManager::receiveMessage(const anna::DataBlock &message, RealmNode *realm, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException) {
 
   // Testing disabled:
   if (!tests()) return;
@@ -362,10 +368,15 @@ void TestManager::receiveMessage(const anna::DataBlock &message, const anna::dia
     std::string hint = "Uncovered condition for received message from client over Session-Id '"; hint += sessionId; hint += "':";
 
     try {
-      Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-      static anna::diameter::codec::Message codecMsg(my_app.getCodecEngine());
+      static anna::diameter::codec::Message codecMsg;
       codecMsg.decode(message);
       hint += "\n"; hint += codecMsg.asXMLString();
+
+      //      // Realm checking:
+      //      std::string messageOR = message.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
+      //      if (messageOR != realm->getName()) {
+      //        LOGWARNING(anna::Logger::warning(anna::functions::asString("Received message from realm '%s', with different Origin-Realm: %s", realm->getName().c_str(), messageOR.c_str()), ANNA_FILE_LOCATION));
+      //      }
     }
     catch (anna::RuntimeException &ex) {
       ex.trace();
index 1719faf..6a292e4 100644 (file)
@@ -39,6 +39,8 @@ namespace anna {
 class TestClock;
 class TestCase;
 class TestCaseStep;
+class RealmNode;
+
 
 typedef std::map<unsigned int /* test case id */, TestCase*> test_pool_t;
 typedef std::map<unsigned int /* test case id */, TestCase*>::const_iterator test_pool_it;
@@ -124,8 +126,8 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
 
     // Main logic
     TestCase *getTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw();
-    void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException);
-    void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException);
+    void receiveMessage(const anna::DataBlock &message, RealmNode *realm, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException);
+    void receiveMessage(const anna::DataBlock &message, RealmNode *realm, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException);
 
     anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
     std::string asXMLString() const throw();
index d08d482..8a5e2b0 100644 (file)
@@ -24,7 +24,6 @@
 #include <anna/diameter.comm/ServerSession.hpp>
 #include <anna/diameter.comm/Server.hpp>
 #include <anna/core/tracing/Logger.hpp>
-#include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/codec/functions.hpp>
 #include <anna/diameter/helpers/base/functions.hpp>
 
 #include <MyDiameterEntity.hpp>
 #include <MyLocalServer.hpp>
 #include <TestStep.hpp>
-#include <Launcher.hpp>
 #include <TestCase.hpp>
 #include <TestManager.hpp>
 #include <TestTimer.hpp>
+#include <Launcher.hpp>
 
 
 namespace {
@@ -93,19 +92,14 @@ namespace {
     // TODO: mutex the step while setting data here !!
   }
 
-  bool decodeMessage(const anna::DataBlock &message, anna::diameter::codec::Message *messageCodec) throw() {
+  bool decodeMessage(const anna::DataBlock &message, anna::diameter::codec::Message &messageCodec) throw() {
 
     if (message.isEmpty())
       return false;
 
     bool result = true;
     try {
-      if (!messageCodec) {
-        Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-        messageCodec = new anna::diameter::codec::Message(my_app.getCodecEngine());
-      }
-
-      messageCodec->decode(message);
+      messageCodec.decode(message);
     }
     catch (anna::RuntimeException &ex) {
       ex.trace();
@@ -114,7 +108,6 @@ namespace {
 
     return result;
   }
-
 }
 
 
@@ -130,13 +123,23 @@ void TestStep::initialize(TestCase *testCase) {
   a_number = testCase->steps() + 1; // testCase is not NULL
 }
 
+bool TestStep::decodeMessage() throw() {
+  if (a_messageCodec) return true;
+  a_messageCodec = new anna::diameter::codec::Message;
+  if (::decodeMessage(a_message, *a_messageCodec)) return true;
+
+  delete a_messageCodec;
+  a_messageCodec = NULL;
+  return false;
+}
+
 const char* TestStep::asText(const Type::_v type)
 throw() {
   static const char* text [] = { "Unconfigured", "Timeout", "Sendxml2e", "Sendxml2c", "Delay", "Wait", "Cmd" };
   return text [type];
 }
 
-anna::xml::Node* TestStep::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStep::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = parent->createChild("TestStep");
 
@@ -159,7 +162,7 @@ throw() {
   return result;
 }
 
-std::string TestStep::asXMLString() const throw() {
+std::string TestStep::asXMLString() throw() {
   anna::xml::Node root("root");
   return anna::xml::Compiler().apply(asXML(&root));
 }
@@ -195,7 +198,7 @@ void TestStep::next() throw() {
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 // TestStepTimeout
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
-anna::xml::Node* TestStepTimeout::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStepTimeout::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = TestStep::asXML(parent); // end timestamp will be 0 if test finished OK
   //parent->createChild("TestStepTimeout");
@@ -247,12 +250,7 @@ void TestStepTimeout::do_reset() throw() {
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 // TestStepSendxml
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
-TestStepSendxml::~TestStepSendxml() {
-  delete a_messageCodec;
-  a_messageCodec = NULL;
-}
-
-anna::xml::Node* TestStepSendxml::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStepSendxml::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = TestStep::asXML(parent);
   //parent->createChild("TestStepSendxml");
@@ -268,7 +266,7 @@ throw() {
     }
   }
 
-  if (decodeMessage(a_message, a_messageCodec)) {
+  if (decodeMessage()) {
     xmlmsg = "\n";
     xmlmsg += a_messageCodec->asXMLString();
     xmlmsg += "\n";
@@ -346,10 +344,7 @@ bool TestStepSendxml::do_execute() throw() {
 
       // Detailed log:
       if(a_realmNode->logEnabled()) {
-        if (!a_messageCodec)
-          decodeMessage(a_message, a_messageCodec);
-
-        if (a_messageCodec) {
+        if (decodeMessage()) {
           std::string detail = usedClientSession ? usedClientSession->asString() : "<null client session>"; // shouldn't happen
           a_realmNode->writeLogFile(*a_messageCodec, (success ? "sent2e" : "send2eError"), detail);
         }
@@ -383,10 +378,7 @@ bool TestStepSendxml::do_execute() throw() {
 
       // Detailed log:
       if(a_realmNode->logEnabled()) {
-        if (!a_messageCodec)
-          decodeMessage(a_message, a_messageCodec);
-
-        if (a_messageCodec) {
+        if (decodeMessage()) {
           std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // shouldn't happen
           a_realmNode->writeLogFile(*a_messageCodec, (success ? "sent2c" : "send2cError"), detail);
         }
@@ -414,12 +406,13 @@ bool TestStepSendxml::do_execute() throw() {
 void TestStepSendxml::do_reset() throw() {
   a_expired = false;
   //a_message.clear();
+  //a_messageAlreadyDecoded = false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 // TestStepDelay
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
-anna::xml::Node* TestStepDelay::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStepDelay::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = TestStep::asXML(parent);
   //parent->createChild("TestStepDelay");
@@ -461,14 +454,10 @@ void TestStepDelay::do_reset() throw() {
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 // TestStepWait
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
-TestStepWait::~TestStepWait() {
-  delete a_messageCodec;
-  a_messageCodec = NULL;
-}
-
 void TestStepWait::setCondition(bool fromEntity,
-                                  const std::string &code, const std::string &bitR, const std::string &resultCode, const std::string &sessionId,
-                                  const std::string &hopByHop, const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw() {
+    const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId,
+    const std::string &sessionId, const std::string &resultCode,
+    const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw() {
 
   a_condition.setReceivedFromEntity(fromEntity);
   a_condition.setCode(code);
@@ -487,7 +476,7 @@ void TestStepWait::setCondition(bool fromEntity, const std::string &regexp) thro
   a_condition.setRegexp(regexp);
 }
 
-anna::xml::Node* TestStepWait::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStepWait::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = TestStep::asXML(parent);
   //parent->createChild("TestStepWait");
@@ -506,7 +495,7 @@ throw() {
     }
   }
 
-  if (decodeMessage(a_message, a_messageCodec)) {
+  if (decodeMessage()) {
     xmlmsg = "\n";
     xmlmsg += a_messageCodec->asXMLString();
     xmlmsg += "\n";
@@ -546,7 +535,7 @@ void TestStepWait::do_reset() throw() {
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 // TestStepCmd
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
-anna::xml::Node* TestStepCmd::asXML(anna::xml::Node* parent) const
+anna::xml::Node* TestStepCmd::asXML(anna::xml::Node* parent)
 throw() {
   anna::xml::Node* result = TestStep::asXML(parent);
   //parent->createChild("TestStepCmd");
index e4574c1..9b69579 100644 (file)
@@ -17,6 +17,7 @@
 // Project
 #include <anna/core/DataBlock.hpp>
 #include <anna/xml/Node.hpp>
+#include <anna/diameter/codec/Message.hpp>
 
 // Process
 #include <TestCondition.hpp>
@@ -62,7 +63,7 @@ class TestStep {
     struct Type { enum _v { Unconfigured, Timeout, Sendxml2e, Sendxml2c, Delay, Wait, Cmd }; };
     static const char* asText(const Type::_v type) throw();
 
-    TestStep(TestCase *testCase) { initialize(testCase); }
+    TestStep(TestCase *testCase) : a_message(true), a_messageCodec(NULL) { initialize(testCase); }
     virtual ~TestStep() {;}
 
     // setter & getters
@@ -74,14 +75,19 @@ class TestStep {
     void complete() throw();
     void reset() throw();
     void next() throw();
-    virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
-    std::string asXMLString() const throw();
+    virtual anna::xml::Node* asXML(anna::xml::Node* parent) throw();
+    std::string asXMLString() throw();
 
   protected:
     TestCase *a_testCase;
     bool a_completed;
     Type::_v a_type;
 
+    // Message (not for all step types)
+    anna::DataBlock a_message;
+    anna::diameter::codec::Message *a_messageCodec; // used as helper and for traffic logs
+    bool decodeMessage() throw();
+
     virtual bool do_execute() throw() = 0; // returns true if next step must be executed
     virtual void do_complete() throw() = 0; // end of transaction (delay/timeout expired, wait condition fulfilled, sending done)
                                             // In all cases, the next step will be executed except 'timeout' which is asynchronous
@@ -106,7 +112,7 @@ class TestStepTimeout : public TestStep {
     bool do_execute() throw();
     void do_complete() throw(); // timeout reached, test case failed
     void do_reset() throw();
-    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+    anna::xml::Node* asXML(anna::xml::Node* parent) throw();
 };
 
 
@@ -119,16 +125,15 @@ class TestStepSendxml : public TestStep {
     // Step number reference ('wait for request' step)
     int a_waitForRequestStepNumber;
 
-    // Message
-    anna::DataBlock a_message;
-    anna::diameter::codec::Message *a_messageCodec; // used as helper and for traffic logs
-
     // Expired ?
     bool a_expired; // a_endTimestamp will be the expiration reception timestamp
 
   public:
-    TestStepSendxml(TestCase *testCase) : TestStep(testCase), a_message(true), a_messageCodec(NULL), a_expired(false), a_realmNode(NULL), a_waitForRequestStepNumber(-1) {;}
-    ~TestStepSendxml();
+    TestStepSendxml(TestCase *testCase) : TestStep(testCase),
+      a_expired(false),
+      a_realmNode(NULL),
+      a_waitForRequestStepNumber(-1) {;}
+    ~TestStepSendxml() {;}
 
     // setter & getters
     void setRealmNode(RealmNode *realm) throw() { a_realmNode = realm; }
@@ -142,7 +147,7 @@ class TestStepSendxml : public TestStep {
     bool do_execute() throw();
     void do_complete() throw() {;}
     void do_reset() throw();
-    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+    anna::xml::Node* asXML(anna::xml::Node* parent) throw();
 };
 
 class TestStepSendxml2e : public TestStepSendxml {
@@ -171,26 +176,29 @@ class TestStepDelay : public TestStep {
     bool do_execute() throw();
     void do_complete() throw(); // delay reached
     void do_reset() throw();
-    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+    anna::xml::Node* asXML(anna::xml::Node* parent) throw();
 };
 
 
 class TestStepWait : public TestStep {
 
     TestCondition a_condition;
-    anna::DataBlock a_message; // message which complies with condition
-    anna::diameter::codec::Message *a_messageCodec; // used as helper and for traffic logs
     anna::diameter::comm::ClientSession *a_clientSession;
     anna::diameter::comm::ServerSession *a_serverSession;
 
   public:
-    TestStepWait(TestCase *testCase) : TestStep(testCase), a_message(true), a_messageCodec(NULL) { a_type = Type::Wait; a_clientSession = NULL; a_serverSession = NULL; }
-    ~TestStepWait();
+    TestStepWait(TestCase *testCase) : TestStep(testCase) {
+      a_type = Type::Wait;
+      a_clientSession = NULL;
+      a_serverSession = NULL;
+    }
+    ~TestStepWait() {;}
 
     // setter & getters
     void setCondition(bool fromEntity,
-                        const std::string &code, const std::string &bitR, const std::string &resultCode, const std::string &sessionId,
-                        const std::string &hopByHop, const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw();
+                        const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId,
+                        const std::string &sessionId, const std::string &resultCode,
+                        const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) throw();
     void setCondition(bool fromEntity, const std::string &regexp) throw();
 
     void setClientSession(anna::diameter::comm::ClientSession *cs) throw() { a_clientSession = cs; }
@@ -208,7 +216,7 @@ class TestStepWait : public TestStep {
     bool do_execute() throw(); // this will be executed when test case starts (at least we could measure the time until condition is fulfilled)
     void do_complete() throw(); // condition fulfilled
     void do_reset() throw();
-    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+    anna::xml::Node* asXML(anna::xml::Node* parent) throw();
 };
 
 
@@ -248,7 +256,7 @@ class TestStepCmd : public TestStep {
     bool do_execute() throw();
     void do_complete() throw();
     void do_reset() throw();
-    anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+    anna::xml::Node* asXML(anna::xml::Node* parent) throw();
 };
 
 
index 3bd2df5..fdfe996 100644 (file)
@@ -19,7 +19,7 @@
 #include <anna/time/functions.hpp>
 #include <anna/time/Date.hpp>
 
-#include <anna/diameter/codec/tme/Engine.hpp>
+#include <anna/diameter/codec/Engine.hpp>
 #include <anna/diameter/codec/tme/Message.hpp>
 
 
@@ -57,7 +57,6 @@ int main(int argc, char** argv) {
   anna::time::functions::setControlPoint(); // start control point (application lifetime)
   anna::diameter::stack::Engine & stackEngine = anna::diameter::stack::Engine::instantiate();
   anna::diameter::stack::Dictionary *dictionary;
-  anna::diameter::codec::tme::Engine *codecEngine = new anna::diameter::codec::tme::Engine();
   std::string exec = argv[0];
   std::string param = argv[1] ? argv[1] : "";
 
@@ -93,18 +92,18 @@ int main(int argc, char** argv) {
     dictionary->load(param + "/avps_tgpp.xml");
     dictionary->load(param + "/avps_tme.xml");
     dictionary->load(param + "/commands_dccaOCS-CS_HuaweiNGIN_de-es.xml");
-    codecEngine->setDictionary(dictionary);
     // Trace:
     LOGINFORMATION(Logger::information(stackEngine.asString(), ANNA_FILE_LOCATION));
     LOGDEBUG(Logger::debug(dictionary->asString(), ANNA_FILE_LOCATION));
-    LOGDEBUG(Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
   } catch(anna::RuntimeException &ex) {
     ex.trace();
     std::cout << ex.getText() << std::endl;
   }
 
   // Build CCA
-  tmeMessage cca;
+  anna::diameter::codec::Engine *codecEngine = new anna::diameter::codec::Engine("TME Engine", dictionary);
+  LOGDEBUG(Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
+  tmeMessage cca(codecEngine);
   cca.setId("Credit-Control-Answer");
   tmeAvp *sid = (tmeAvp*)cca.addAvp("Session-Id");
   tmeAvp *ohst = (tmeAvp*)cca.addAvp("Origin-Host");
index cce2a48..0057ac8 100644 (file)
@@ -373,20 +373,35 @@ public:
 
   /**
   * Default constructor
-    @param engine Codec engine used
+  * @param engine Codec engine used
   */
   Avp(Engine *engine = NULL);
 
   /**
   * Identified constructor
   * @param id Avp identifier as pair (code,vendor-id).
-    @param engine Codec engine used
+  * @param engine Codec engine used
   */
   Avp(AvpId id, Engine *engine = NULL);
 
 
-  /** Sets the codec engine */
-  void setEngine(Engine *engine) throw() { a_engine = engine; }
+  /**
+  * 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. If you want to reconfigure the engine,
+  * first #clear the avp and then you could reuse the same object with
+  * different configurations (execution contexts).
+  *
+  * 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.
+  */
+  void setEngine(Engine *engine) throw();
 
 
   // Length references
@@ -462,7 +477,7 @@ public:
 
   /**
      Adds an avp child providing its identifier and reserve internal memory it.
-     An exception is launched is the Avp is not a grouped avp.
+     An exception is launched is the Avp over which we add the new avp, is not a grouped avp.
 
      @param id Avp identifier as pair (code,vendor-id).
 
@@ -476,16 +491,19 @@ public:
   */
   Avp * addAvp(const char *name) throw(anna::RuntimeException);
 
-
   /**
      Adds an avp child providing a persistent pointer (must be maintained by application).
-     An exception is launched is the Avp is not a grouped avp.
+     An exception is launched is the Avp over which we add the new avp, is not a grouped avp.
+     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(anna::RuntimeException) { if(!avp) return NULL; addChild(avp); return avp; }
+  Avp * addAvp(Avp * avp) throw(anna::RuntimeException);
+
 
   // Data part access
   /** Access content for OctetString Avp in order to set data part */
index 1f106c6..907bcd4 100644 (file)
@@ -47,7 +47,7 @@ public:
      Constructor
      @param className Logical name for the class.
   */
-  Engine(const char *className) : EngineImpl(className) {;}
+  Engine(const char *className, const stack::Dictionary * dictionary) : EngineImpl(className, dictionary) {;}
 
   void releaseAvp(Avp* avp) throw() {
     if(avp == NULL) return;
index b973e8d..0305727 100644 (file)
@@ -36,8 +36,6 @@ class Dictionary;
 
 namespace codec {
 
-extern const char *MessageDTD;
-
 class Message;
 class Avp;
 
@@ -50,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:
@@ -75,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);
@@ -88,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);
@@ -175,14 +165,11 @@ public:
 
 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;
@@ -196,8 +183,14 @@ 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
@@ -205,56 +198,6 @@ 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.
-  * @warning must register the base protocol stack (with id = 0 = application-id) to manage base protocol messages.
-  * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header.
-  *               False by default on engine construction.
-  */
-  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 (default) 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).
 
@@ -339,11 +282,6 @@ public:
    */
   bool getSingleFailedAVP() const throw() { return a_singleFailedAVP; }
 
-  /**
-     DTD document for xml message parsing
-  */
-  const anna::xml::DTDMemory & getDTD() const throw() { return a_dtd; }
-
   /**
   * Creates a new diameter avp assigning its identifier, using engine resources to allocate memory (recommended
   *  recycler allocation at engine component re-implementation of allocator methods). Obviously, normal objects
diff --git a/include/anna/diameter/codec/EngineManager.hpp b/include/anna/diameter/codec/EngineManager.hpp
new file mode 100644 (file)
index 0000000..268e318
--- /dev/null
@@ -0,0 +1,131 @@
+// 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_EngineManager_hpp
+#define anna_diameter_codec_EngineManager_hpp
+
+
+// Project
+#include <anna/core/Singleton.hpp>
+#include <anna/diameter/defines.hpp>
+
+// Standard
+#include <map>
+
+
+namespace anna {
+
+namespace diameter {
+
+namespace codec {
+
+class Engine;
+
+typedef std::map<anna::diameter::ApplicationId, Engine*> appid_codec_engines_t;
+typedef std::map<anna::diameter::ApplicationId, Engine*>::const_iterator appid_codec_engines_it;
+typedef std::map<anna::diameter::ApplicationId, Engine*>::iterator appid_codec_engines_nc_it;
+
+/**
+ * Helper class to centralize application codec engines and ease the automatic codec engine selection from
+ * codec resources (mainly Message class, but also Avp).
+ *
+ * This is useful if you enable the auto selection from messages application id, avoiding to pre-initialize
+ * such codec messages with a specific engine before interpreting the data sources or building.
+ * At multithread application, it is recommended to specialize the message codec for each stack without using
+ * this engine manager.
+ */
+class EngineManager : public anna::Singleton <EngineManager> {
+
+private:
+
+  bool a_autoSelectFromApplicationId;
+  appid_codec_engines_t a_appid_codec_engines;
+
+  // private constructor
+  EngineManager() : a_autoSelectFromApplicationId(true) {};
+
+public:
+
+  /**
+   * First element iterator
+   */
+  appid_codec_engines_it begin() const throw() { return a_appid_codec_engines.begin(); }
+
+  /**
+   * Last element iterator
+   */
+  appid_codec_engines_it end() const throw() { return a_appid_codec_engines.end(); }
+
+  /**
+   * Number of registered engines
+   */
+  int size() const throw() { return a_appid_codec_engines.size(); }
+
+  /**
+   * Registers a new codec engine (externally allocated) associated to an application id.
+   * If the application id exists, the new engine pointer will replace the existing one.
+   *
+   * @param appid Application-Id
+   * @param engine Associated codec engine
+   */
+  void registerCodecEngine(const ApplicationId &appid, Engine* engine) throw();
+
+  /**
+   * Get the associated codec engine for a provided Application-Id.
+   *
+   * @param appid Application-Id
+   *
+   * @return Found codec engine, NULL if not found
+   */
+  Engine *getCodecEngine(const ApplicationId &appid) const throw();
+
+  /**
+   * If only one codec engine is registered (mono-stack application), it will be returned
+   * (NULL in other case). This is because mono-stack applications could merge compatible
+   * stacks into one unique dictionary, using a global value for stack id with no relation
+   * regarding application-id concept.
+   *
+   * @return Unique codec engine, NULL if not unique (empty manager or more than one)
+   */
+  Engine *getMonoStackCodecEngine() const throw() {
+    return ((size() != 1) ? NULL : begin()->second);
+  }
+
+  /**
+   * The user could select the appropriate codec engine depending on the context, but some applications could
+   * consider interesting automatic codec engine selection from managed messages (decoded from any source,
+   * or built from scratch). Then, this engine manager will be used registering all the supported stacks
+   * with their corresponding codec engines, and automatic selection will be done during decoding of any
+   * supported source of data (hexadecimal buffers, xml documents) or build operations.
+   *
+   * If the user pre-initializes the codec engine for a #Message or #Avp element, this selection is ignored
+   * even if enabled: the codec engine only can be established one time, for security reasons.
+   *
+   * @param enable Activates/deactivates the codec engine selection from the Application-Id value. True by default
+   * and applicable when this manager store is not empty.
+   */
+  void selectFromApplicationId (bool enable) throw() { a_autoSelectFromApplicationId = enable; }
+
+  /**
+    Gets the currently configured behaviour regarding codec engine selection.
+
+    @return True if selection is done with the Application-Id (default behaviour). False to disable (the manager
+    could be used for some other things which could be also interesting).
+   */
+  bool selectFromApplicationId (void) throw() { return a_autoSelectFromApplicationId; }
+
+
+  friend class anna::Singleton <EngineManager>;
+};
+
+}
+}
+}
+
+#endif
+
index 48d2b84..69aecf2 100644 (file)
@@ -175,8 +175,23 @@ public:
   Message(CommandId id, Engine *engine = NULL);
 
 
-  /** Sets the codec engine */
-  void setEngine(Engine *engine) throw() { a_engine = engine; }
+  /**
+  * 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. If you want to reconfigure the engine,
+  * first #clear the message and then you could reuse the same object with
+  * different configurations (execution contexts).
+  *
+  * 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.
+  */
+  void setEngine(Engine *engine) throw();
 
 
   // Length references
@@ -297,9 +312,11 @@ 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) throw(anna::RuntimeException) {
     if(!request.getId().second) return;
 
+    a_engine = request.getEngine(); // we know this will be
+
     setId(CommandId(request.getId().first, !request.getId().second), false /* don't clear */);
     setVersion(request.getVersion());
     setApplicationId(request.getApplicationId());
@@ -375,7 +392,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) throw(anna::RuntimeException);
 
 
   /**
@@ -443,12 +460,15 @@ public:
 
   /**
      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) throw();
 
 
   /**
@@ -471,7 +491,7 @@ public:
 
   /**
   * 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.
   */
@@ -506,87 +526,21 @@ public:
   */
   bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
 
-
   /**
      Interpret xml data in order to dump over the class content.
-     \param messageNode Message root node
+     \param messageNode Message root node obtained from @functions::xmlFileTo
   */
   void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
 
   /**
-     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);
-
-  /**
-     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 file in order to create a diameter message
+   *
+   * @see functions::messageXmlDocumentFromXmlFile
+   * @see fromXML
+   *
+   * @param xmlPathFile Complete path file to the xml document which represents the diameter message
+   */
+  void loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException);
 
 
   // getters
index 44a8f15..9c4c5a8 100644 (file)
 #define anna_diameter_codec_functions_hpp
 
 
-// Local
+// Project
 #include <anna/diameter/defines.hpp>
-
 #include <anna/core/RuntimeException.hpp>
+#include <anna/xml/xml.hpp>
 
 // STL
 #include <string>
@@ -41,6 +41,81 @@ namespace diameter {
 namespace codec {
 
 
+static const char *MessageDTD = "\
+<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<!-- Diameter message DTD -->\n\
+\n\
+<!ELEMENT message (avp*)>\n\
+<!ELEMENT avp (avp*)>\n\
+\n\
+<!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED p-bit (yes | no) #IMPLIED e-bit (yes | no) #IMPLIED t-bit (yes | no) #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>\n\
+<!--\n\
+   version: Diameter version. Sets '1' by default\n\
+   name:    Command name within working stack (dictionary identifier)\n\
+   p-bit:   (P)roxiable bit flag (yes, no). By default is 'no'\n\
+   e-bit:   (E)rror bit flag (yes, no). By default is 'no'\n\
+   t-bit:   Potentially re-(T)ransmitted bit flag (yes, no). By default is 'no'\n\
+\n\
+   In order to get more coding capabilities, command code and flags could be established instead of former fields,\n\
+    but neither of them are allowed if the other are present (and vice versa):\n\
+\n\
+   code:    Command code\n\
+   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\n\
+\n\
+\n\
+   application-id:   Message application id\n\
+   hop-by-hop-id:    Message hop by hop id. Sets '0' by default\n\
+   end-by-end-id:    Message end by end id. Sets '0' by default\n\
+-->\n\
+\n\
+<!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED alias CDATA #IMPLIED>\n\
+<!--\n\
+   name:   Avp name within working stack (dictionary identifier)\n\
+\n\
+   In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,\n\
+    but neither of them are allowed if 'name' is provided (and vice versa):\n\
+\n\
+   code:          Avp code\n\
+   vendor-code:   Avp vendor code\n\
+   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)\n\
+   alias:         Descriptive/helper field for certain numeric data values. Aliases are defined at diameter dictionary, but are ignored (not checked) at xml message parsing\n\
+                  The reason to include it in dtd definition, is because xml messages traced by the diameter codec could add alias field for some Avps\n\
+\n\
+\n\
+   data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also\n\
+                   useful for certain formats which could be easily understandable in such friendly/smart representation. We will\n\
+                   achieve different human-readable strings depending on data format:\n\
+\n\
+                     [ OctetString ] (if printable, but not recommended)\n\
+                     [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)\n\
+                     [ Time ] (NTP timestamp, normal number representation)\n\
+                     [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.\n\
+                                 Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for\n\
+                                 IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.\n\
+                                 Currently, only IPv4, IPv6 and E164 address types have a known printable presentation, anyway using printable format\n\
+                                 for another types will encode the address value directly as E164 does)\n\
+                     [ UTF8String, DiameterIdentity, DiameterURI ] (printable)\n\
+                     [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)\n\
+\n\
+                     New application formats must define specific natural representation for internal raw data\n\
+\n\
+   hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind\n\
+                   of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable\n\
+                   data and should better be encoded within this field although being printable. Unknown avps (which fails identifying\n\
+                   provided name or code/vendor-code) must always use this representation.\n\
+\n\
+   Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,\n\
+    OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport\n\
+    readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).\n\
+   Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,\n\
+    because xml is read by humans with testing and monitoring purposes.\n\
+-->\n\
+\n\
+";
+
+
+
+
 // Used for alarms, tracing and Failed-AVP construction:
 typedef struct parent {
 
@@ -82,75 +157,75 @@ struct functions {
 
 
   /**
-  * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context.
-  *
-  * @param start Must be a valid command start (point to the command version byte).
-  * @param version Diameter version.
-  * @param length Message length.
-  * @param flags Command flags.
-  * @param id Command identification (code, request<true,false>).
-  * @param appId Application-ID.
-  * @param hbh Hop-by-Hop Identifier.
-  * @param ete End-to-End Identifier.
-  */
+   * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context.
+   *
+   * @param start Must be a valid command start (point to the command version byte).
+   * @param version Diameter version.
+   * @param length Message length.
+   * @param flags Command flags.
+   * @param id Command identification (code, request<true,false>).
+   * @param appId Application-ID.
+   * @param hbh Hop-by-Hop Identifier.
+   * @param ete End-to-End Identifier.
+   */
   static void decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException);
 
   /**
-  * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context.
-  *
-  * @param start Must be a valid avp start (point to the 32-bits avp code word).
-  * @param id Avp identification (code, vendorId).
-  * @param flags Avp flags byte.
-  * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length).
-  * @param data Avp data part.
-  */
+   * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context.
+   *
+   * @param start Must be a valid avp start (point to the 32-bits avp code word).
+   * @param id Avp identification (code, vendorId).
+   * @param flags Avp flags byte.
+   * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length).
+   * @param data Avp data part.
+   */
   static void decodeAVP(const char *start, AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException);
 
   /**
-  * Gets the next AVP pointer reference starting from a first-avp data block. It could be the first avp within
-  * a command, or within an grouped avp.
-  *
-  * @param avpsDB AVP data block buffer pointer
-  * @param avpsLen AVP data block buffer length
-  * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
-  *
-  * @return Pointer to the next AVP found. NULL if no more.
-  */
+   * Gets the next AVP pointer reference starting from a first-avp data block. It could be the first avp within
+   * a command, or within an grouped avp.
+   *
+   * @param avpsDB AVP data block buffer pointer
+   * @param avpsLen AVP data block buffer length
+   * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
+   *
+   * @return Pointer to the next AVP found. NULL if no more.
+   */
   static const char * nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException);
 
-//  /**
-//  * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within
-//  * a command, or within an grouped avp.
-//  *
-//  * @param avpsDB AVPs set as datablock
-//  * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
-//  *
-//  * @return Pointer to the next AVP found. NULL if no more.
-//  */
-//  static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException);
+  //  /**
+  //  * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within
+  //  * a command, or within an grouped avp.
+  //  *
+  //  * @param avpsDB AVPs set as datablock
+  //  * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
+  //  *
+  //  * @return Pointer to the next AVP found. NULL if no more.
+  //  */
+  //  static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException);
 
   /**
-  * Gets the next AVP pointer reference within an AVPs set data block with a certain AVP identification.
-  *
-  * @param avpsDB AVP data block buffer pointer
-  * @param avpsLen AVP data block buffer length
-  * @param id Avp identification (code, vendorId).
-  * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
-  *
-  * @return Pointer to first AVP found with identification provided. NULL if not found.
-  */
+   * Gets the next AVP pointer reference within an AVPs set data block with a certain AVP identification.
+   *
+   * @param avpsDB AVP data block buffer pointer
+   * @param avpsLen AVP data block buffer length
+   * @param id Avp identification (code, vendorId).
+   * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
+   *
+   * @return Pointer to first AVP found with identification provided. NULL if not found.
+   */
   static const char *findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n = 1) throw(anna::RuntimeException);
 
-//  /**
-//  * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification.
-//  *
-//  * @param avpsDB AVPs set as datablock
-//  * @param id Avp identification (code, vendorId).
-//  * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
-//  *
-//  * @return Pointer to first AVP found with identification provided. NULL if not found.
-//  */
-//  static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException);
+  //  /**
+  //  * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification.
+  //  *
+  //  * @param avpsDB AVPs set as datablock
+  //  * @param id Avp identification (code, vendorId).
+  //  * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
+  //  *
+  //  * @return Pointer to first AVP found with identification provided. NULL if not found.
+  //  */
+  //  static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException);
 
 
 
@@ -158,6 +233,94 @@ struct functions {
   static void setHopByHop(anna::DataBlock &, HopByHop) throw(anna::RuntimeException);
   static void setEndToEnd(anna::DataBlock &, EndToEnd) throw(anna::RuntimeException);
   static void setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate = true) throw(anna::RuntimeException);
+
+
+  /**
+     Interpret a xml file in order to create a memory xml document.
+     The xml file is based on this message DTD:
+
+     <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 xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument)
+     @param xmlPathFile Complete path file to the xml document which represents the diameter message
+     @see messageXmlDocumentFromXmlString
+
+     @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document.
+     For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using
+     the xml document #getRootNode) during document lifetime. After that, it could be destroyed.
+   */
+  static void messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) throw(anna::RuntimeException);
+
+  /**
+     Interpret xml string representation in order to create a memory xml document.
+     DTD validation is used in the same way that #messageXmlDocumentFromXmlFile does.
+
+     @param xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument)
+     @param xmlString XML string representation of the diameter message
+     @see messageXmlDocumentFromXmlFile
+
+     @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document.
+     For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using
+     the xml document #getRootNode) during document lifetime. After that, it could be destroyed.
+   */
+  static void messageXmlDocumentFromXmlString(anna::xml::DocumentFile &xmlDocument, const std::string &xmlString) throw(anna::RuntimeException);
 };
 
 
index b4a1917..0b25df7 100644 (file)
@@ -41,11 +41,13 @@ class ISDNAddress;
 
 namespace codec {
 
+class Engine;
+
 namespace tme {
 
 class Avp;
 class Message;
-class Engine;
+//class Engine;
 
 
 using namespace helpers::tme::codectypes;
@@ -70,24 +72,27 @@ class Avp : public anna::diameter::codec::Avp {
   virtual void allocationByFormat(const anna::diameter::stack::Format *stackFormat) throw();
   virtual void clearByFormat() throw();
 
-protected:
+//protected:
 
-  /** Codec Engine getter: avoids have to create base engine when using its child */
-  virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException);
+//  /** Codec Engine getter: avoids have to create base engine when using its child */
+//  virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException);
 
 
 public:
 
   /**
   * Default constructor
+  * @param engine Codec engine used
   */
-  Avp();
+  Avp(Engine *engine = NULL) : anna::diameter::codec::Avp(engine) {;}
 
   /**
   * Identified constructor
-  * @param id Avp identifier as pair (code,vendorID).
+  * @param id Avp identifier as pair (code,vendor-id).
+  * @param engine Codec engine used
   */
-  Avp(AvpId id);
+  Avp(AvpId id, Engine *engine = NULL) : anna::diameter::codec::Avp(id, engine) {;}
+
 
   /**
   * Destructor
@@ -114,7 +119,7 @@ public:
 
 
   friend class Message;
-  friend class Engine;
+  friend class anna::diameter::codec::Engine;
 };
 
 }
diff --git a/include/anna/diameter/codec/tme/Engine.hpp b/include/anna/diameter/codec/tme/Engine.hpp
deleted file mode 100644 (file)
index 92fbc31..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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_tme_Engine_hpp
-#define anna_diameter_codec_tme_Engine_hpp
-
-
-// STL
-#include <string>
-
-#include <anna/core/util/Recycler.hpp>
-
-#include <anna/diameter/codec/tme/Message.hpp>
-#include <anna/diameter/codec/tme/Avp.hpp>
-#include <anna/diameter/codec/EngineImpl.hpp>
-
-
-using namespace anna::diameter::codec::tme;
-
-
-//------------------------------------------------------------------------------
-//---------------------------------------------------------------------- #define
-//------------------------------------------------------------------------------
-
-
-namespace anna {
-
-namespace diameter {
-
-namespace codec {
-
-namespace tme {
-
-
-
-/**
- * Standard inheritance for engine component implementation, allocating basic Avp and Message classes.
- */
-class Engine : public EngineImpl {
-
-public:
-
-  /**
-     Constructor
-     @param className Logical name for the class.
-  */
-  Engine(const char *className = "anna::diameter::codec::tme::Engine") : EngineImpl(className) {;}
-
-  void releaseAvp(anna::diameter::codec::Avp* avp) throw() {
-    if(avp == NULL) return;
-
-    Avp* aux = static_cast <Avp*>(avp);
-    aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens
-    a_avps.release(aux);
-  }
-
-  void releaseMessage(anna::diameter::codec::Message* message) throw() {
-    if(message == NULL) return;
-
-    Message* aux = static_cast <Message*>(message);
-    aux->clear(); // free internal data-part storage specially for childrens releasing
-    a_messages.release(aux);
-  }
-
-protected:
-
-  anna::Recycler<Avp> a_avps;
-  anna::Recycler<Message> a_messages;
-
-  anna::diameter::codec::Avp* allocateAvp() throw() { return a_avps.create(); }
-  anna::diameter::codec::Message* allocateMessage() throw() { return a_messages.create(); }
-
-  friend class Message;
-  friend class Avp;
-};
-
-}
-}
-}
-}
-
-#endif
-
diff --git a/include/anna/diameter/codec/tme/Engine.hpp__ b/include/anna/diameter/codec/tme/Engine.hpp__
new file mode 100644 (file)
index 0000000..92fbc31
--- /dev/null
@@ -0,0 +1,88 @@
+// 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_tme_Engine_hpp
+#define anna_diameter_codec_tme_Engine_hpp
+
+
+// STL
+#include <string>
+
+#include <anna/core/util/Recycler.hpp>
+
+#include <anna/diameter/codec/tme/Message.hpp>
+#include <anna/diameter/codec/tme/Avp.hpp>
+#include <anna/diameter/codec/EngineImpl.hpp>
+
+
+using namespace anna::diameter::codec::tme;
+
+
+//------------------------------------------------------------------------------
+//---------------------------------------------------------------------- #define
+//------------------------------------------------------------------------------
+
+
+namespace anna {
+
+namespace diameter {
+
+namespace codec {
+
+namespace tme {
+
+
+
+/**
+ * Standard inheritance for engine component implementation, allocating basic Avp and Message classes.
+ */
+class Engine : public EngineImpl {
+
+public:
+
+  /**
+     Constructor
+     @param className Logical name for the class.
+  */
+  Engine(const char *className = "anna::diameter::codec::tme::Engine") : EngineImpl(className) {;}
+
+  void releaseAvp(anna::diameter::codec::Avp* avp) throw() {
+    if(avp == NULL) return;
+
+    Avp* aux = static_cast <Avp*>(avp);
+    aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens
+    a_avps.release(aux);
+  }
+
+  void releaseMessage(anna::diameter::codec::Message* message) throw() {
+    if(message == NULL) return;
+
+    Message* aux = static_cast <Message*>(message);
+    aux->clear(); // free internal data-part storage specially for childrens releasing
+    a_messages.release(aux);
+  }
+
+protected:
+
+  anna::Recycler<Avp> a_avps;
+  anna::Recycler<Message> a_messages;
+
+  anna::diameter::codec::Avp* allocateAvp() throw() { return a_avps.create(); }
+  anna::diameter::codec::Message* allocateMessage() throw() { return a_messages.create(); }
+
+  friend class Message;
+  friend class Avp;
+};
+
+}
+}
+}
+}
+
+#endif
+
index 76524ee..500b252 100644 (file)
@@ -28,7 +28,7 @@ namespace codec {
 namespace tme {
 
 class Avp;
-class Engine;
+//class Engine;
 
 /**
 * Diameter TME message generic container
@@ -39,14 +39,32 @@ class Message : public anna::diameter::codec::Message {
 
 protected:
 
-  /** Codec Engine getter: avoids have to create base engine when using its child */
-  virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException);
+//  /** Codec Engine getter: avoids have to create base engine when using its child */
+//  virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException);
 
   /**
   * Initializes Message class information.
   * Any reimplementation must first invoke base class method.
   */
   virtual void initialize() throw();
+
+public:
+
+  /**
+  * Default constructor
+  * @param engine Codec engine used
+  */
+  Message(Engine *engine = NULL) : anna::diameter::codec::Message(engine) {;}
+
+  /**
+  * Identified constructor
+  * @param id Command identifier as pair (code,request-indicator).
+  * @param engine Codec engine used
+  */
+  Message(CommandId id, Engine *engine = NULL) : anna::diameter::codec::Message(id, engine) {;}
+
+
+
 };
 
 }
index 0068ced..da1e5fd 100644 (file)
@@ -20,10 +20,12 @@ namespace xml {
 */
 class DTDFile : public DTD {
 public:
+
   /**
-     Constructor.
+     Constructor
+     \param file File name
   */
-  DTDFile() {;}
+  DTDFile(const char *file = NULL) { if (file) initialize(file); }
 
 private:
   _xmlDtd* parse(const char* fileName) const throw(RuntimeException);
index b1c4b93..0a33ac5 100644 (file)
@@ -23,10 +23,12 @@ namespace xml {
 */
 class DTDMemory : public DTD {
 public:
+
   /**
-     Constructor.
+     Constructor
+     \param dtd Dtd representation
   */
-  DTDMemory();
+  DTDMemory(const char *dtd = NULL);
 
 private:
   std::string a_filename;
index 9bfaf60..489a093 100644 (file)
@@ -60,14 +60,13 @@ comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtoco
   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
   a_numberOfClientSessionsPerServer(1),
-  a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str())
+  a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary)
 {
   anna::diameter::sccs::activate();
   a_realm = anna::functions::getDomainname();
   a_host = anna::functions::getHostname();
 
   // Internal base protocol codec engine:
-  a_baseProtocolCodecEngine.setDictionary(baseProtocolDictionary);
   a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
 }
 
index 79b04b0..89884be 100644 (file)
@@ -59,7 +59,6 @@ Avp::Avp(Engine *engine) : a_engine(engine) {
   initialize();
 }
 
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------- Avp::Avp()
 //------------------------------------------------------------------------------
@@ -68,7 +67,6 @@ Avp::Avp(AvpId id, Engine *engine) : a_engine(engine) {
   setId(id);
 }
 
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------ Avp::~Avp()
 //------------------------------------------------------------------------------
@@ -76,13 +74,24 @@ Avp::~Avp() {
   clear();
 }
 
+//------------------------------------------------------------------------------
+//------------------------------------------------------------- Avp::setEngine()
+//------------------------------------------------------------------------------
+void Avp::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 avp first to set the engine again.", ANNA_FILE_LOCATION));
+    return;
+  }
+
+  a_engine = engine;
+}
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------- Avp::getEngine()
 //------------------------------------------------------------------------------
 Engine * Avp::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;
 }
@@ -187,6 +196,17 @@ Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id
 }
 
 
+//------------------------------------------------------------------------------
+//---------------------------------------------------------------- Avp::addAvp()
+//------------------------------------------------------------------------------
+Avp * Avp::addAvp(Avp * avp) throw(anna::RuntimeException) {
+  if(!avp) return NULL;
+  if (avp->getEngine() != getEngine()) return NULL;
+  addChild(avp);
+  return avp;
+}
+
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------- Avp::removeAvp()
 //------------------------------------------------------------------------------
@@ -1227,7 +1247,17 @@ std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) cons
 
   if(!stackFormat) {
     isHex = true;
-    return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad
+    // Tricky situation: if you change the dictionary dynamically, and a previous formatted avp
+    //  becomes unknown (the change consists in remove Avps basically), then this would get a core
+    //  dump: a_Unknown = NULL. We are not going to protect that situation because it represents a
+    //  implementation fault, and there are many points which could have similar bad behaviour
+    //  (those where we access directly the a_Unknown pointer).
+    // The best way to afford this is ... TODO:
+    // Freeze dictionary after use from any resource (avp, message), setting a flag which deny
+    //  any modification in such dictionary. The best way to do this is on engine configuration
+    //  for Avp o Message, where we could  invoke something like getEngine()->getDictionary()->freeze()
+
+    return a_Unknown->asHexString(); // asHexString for OctetString cannot launch exception
   }
 
   // Special case for Address: could launch exception if not printable
index c25bec0..5fff449 100644 (file)
 #include <anna/core/mt/Guard.hpp>
 
 
-
-namespace anna {
-namespace diameter {
-namespace codec {
-
-const char *MessageDTD = "\
-<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<!-- Diameter message DTD -->\n\
-\n\
-<!ELEMENT message (avp*)>\n\
-<!ELEMENT avp (avp*)>\n\
-\n\
-<!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED p-bit (yes | no) #IMPLIED e-bit (yes | no) #IMPLIED t-bit (yes | no) #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>\n\
-<!--\n\
-   version: Diameter version. Sets '1' by default\n\
-   name:    Command name within working stack (dictionary identifier)\n\
-   p-bit:   (P)roxiable bit flag (yes, no). By default is 'no'\n\
-   e-bit:   (E)rror bit flag (yes, no). By default is 'no'\n\
-   t-bit:   Potentially re-(T)ransmitted bit flag (yes, no). By default is 'no'\n\
-\n\
-   In order to get more coding capabilities, command code and flags could be established instead of former fields,\n\
-    but neither of them are allowed if the other are present (and vice versa):\n\
-\n\
-   code:    Command code\n\
-   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\n\
-\n\
-\n\
-   application-id:   Message application id\n\
-   hop-by-hop-id:    Message hop by hop id. Sets '0' by default\n\
-   end-by-end-id:    Message end by end id. Sets '0' by default\n\
--->\n\
-\n\
-<!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED alias CDATA #IMPLIED>\n\
-<!--\n\
-   name:   Avp name within working stack (dictionary identifier)\n\
-\n\
-   In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,\n\
-    but neither of them are allowed if 'name' is provided (and vice versa):\n\
-\n\
-   code:          Avp code\n\
-   vendor-code:   Avp vendor code\n\
-   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)\n\
-   alias:         Descriptive/helper field for certain numeric data values. Aliases are defined at diameter dictionary, but are ignored (not checked) at xml message parsing\n\
-                  The reason to include it in dtd definition, is because xml messages traced by the diameter codec could add alias field for some Avps\n\
-\n\
-\n\
-   data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also\n\
-                   useful for certain formats which could be easily understandable in such friendly/smart representation. We will\n\
-                   achieve different human-readable strings depending on data format:\n\
-\n\
-                     [ OctetString ] (if printable, but not recommended)\n\
-                     [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)\n\
-                     [ Time ] (NTP timestamp, normal number representation)\n\
-                     [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.\n\
-                                 Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for\n\
-                                 IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.\n\
-                                 Currently, only IPv4, IPv6 and E164 address types have a known printable presentation, anyway using printable format\n\
-                                 for another types will encode the address value directly as E164 does)\n\
-                     [ UTF8String, DiameterIdentity, DiameterURI ] (printable)\n\
-                     [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)\n\
-\n\
-                     New application formats must define specific natural representation for internal raw data\n\
-\n\
-   hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind\n\
-                   of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable\n\
-                   data and should better be encoded within this field although being printable. Unknown avps (which fails identifying\n\
-                   provided name or code/vendor-code) must always use this representation.\n\
-\n\
-   Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,\n\
-    OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport\n\
-    readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).\n\
-   Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,\n\
-    because xml is read by humans with testing and monitoring purposes.\n\
--->\n\
-\n\
-";
-
-
-}
-}
-}
-
 using namespace anna::diameter::codec;
 
 
 //------------------------------------------------------------------------------
 //----------------------------------------------------- EngineImpl::EngineImpl()
 //------------------------------------------------------------------------------
-EngineImpl::EngineImpl(const char* className) :
+EngineImpl::EngineImpl(const char* className, const stack::Dictionary * dictionary) :
   anna::Component(className),
-  a_dictionary(NULL),
+  a_dictionary(dictionary),
   a_validationDepth(ValidationDepth::FirstError),
   a_validationMode(ValidationMode::AfterDecoding),
   a_singleFailedAVP(true),
   a_ignoreFlags(false),
-  a_selectStackWithApplicationId(false),
   a_fixMode(FixMode::BeforeEncoding) {
   anna::diameter::sccs::activate();
   anna::xml::functions::initialize();
-  a_dtd.initialize(MessageDTD);
-}
-
-
-//------------------------------------------------------------------------------
-//-------------------------------------------------- EngineImpl::setDictionary()
-//------------------------------------------------------------------------------
-const anna::diameter::stack::Dictionary *EngineImpl::setDictionary(unsigned int stackId) throw() {
-  a_dictionary = (stack::Engine::instantiate()).getDictionary(stackId);
-  return a_dictionary;
 }
 
 
diff --git a/source/diameter/codec/EngineManager.cpp b/source/diameter/codec/EngineManager.cpp
new file mode 100644 (file)
index 0000000..68add2b
--- /dev/null
@@ -0,0 +1,28 @@
+// 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 //
+
+
+// Project
+#include <anna/diameter/codec/EngineManager.hpp>
+#include <anna/diameter/stack/Engine.hpp>
+#include <anna/diameter/stack/Dictionary.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+using namespace anna::diameter::codec;
+
+Engine *EngineManager::getCodecEngine(const ApplicationId &appid) const throw() {
+  appid_codec_engines_it it = a_appid_codec_engines.find(appid);
+  if (it != a_appid_codec_engines.end())
+    return it->second;
+
+  return NULL;
+}
+
+void EngineManager::registerCodecEngine(const ApplicationId &appid, Engine* engine) throw() {
+  if (!engine) return; // nothing done
+  a_appid_codec_engines[appid] = engine;
+}
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()
 //------------------------------------------------------------------------------
index 8c5d350..93ee8e3 100644 (file)
 #include <string>
 
 
-using namespace anna::diameter::codec;
-
 
+namespace anna {
+namespace diameter {
+namespace codec {
+// Preloaded MemoryDTD for function helpers:
+anna::xml::DTDMemory MessageDTDMemory(MessageDTD);
+}
+}
+}
 
 
 // Parent struct helper /////////////////////////////////////////////////////////////////////////////
-void parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) throw() {
+void anna::diameter::codec::parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) throw() {
   MessageId = mid;
   if (mname) {
     MessageName = mname;
   }
   else {
-       MessageName = "Message";
+    MessageName = "Message";
     MessageName += anna::diameter::functions::commandIdAsPairString(mid);
   }
 }
 
-void parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) throw() {
+void anna::diameter::codec::parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) throw() {
   AvpsId.push_back(aid);
   std::string name;
   if (aname) {
-       name = aname;
+    name = aname;
   }
   else {
     name = "Avp";
-       name += anna::diameter::functions::avpIdAsPairString(aid);
+    name += anna::diameter::functions::avpIdAsPairString(aid);
   }
   AvpsName.push_back(name);
 }
 
-std::string parent::asString() const throw() { // "<command><avp 1>-><avp 2>->...-><avp N>"
+std::string anna::diameter::codec::parent::asString() const throw() { // "<command><avp 1>-><avp 2>->...-><avp N>"
   std::string result = MessageName;
   for (std::vector<std::string>::const_iterator it = AvpsName.begin(); it != AvpsName.end(); it++) {
-       result += "->";
-       result += (*it);
+    result += "->";
+    result += (*it);
   }
 
   return result;
@@ -64,90 +70,88 @@ std::string parent::asString() const throw() { // "<command><avp 1>-><avp 2>->..
 /////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
-
-
 // getters
-anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) {
+anna::diameter::CommandId anna::diameter::codec::functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   const char * data = db.getData();
   U8 flags =  data[4];
   U24 code = DECODE3BYTES_INDX_VALUETYPE(data, 5, U24);
-//   U24 code = (((U24)data[5] << 16) & 0xFF0000) +
-//              (((U24)data[6] << 8)  & 0x00FF00) +
-//              (((U24)data[7]) & 0x0000FF);
+  //   U24 code = (((U24)data[5] << 16) & 0xFF0000) +
+  //              (((U24)data[6] << 8)  & 0x00FF00) +
+  //              (((U24)data[7]) & 0x0000FF);
   return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00));
 }
 
-bool functions::requestBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
+bool anna::diameter::codec::functions::requestBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   return (((db.getData())[4] & Message::RBitMask) != 0x00);
 }
 
-bool functions::proxiableBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
+bool anna::diameter::codec::functions::proxiableBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   return (((db.getData())[4] & Message::PBitMask) != 0x00);
 }
 
-bool functions::errorBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
+bool anna::diameter::codec::functions::errorBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   return (((db.getData())[4] & Message::EBitMask) != 0x00);
 }
 
-bool functions::potentiallyReTransmittedMessageBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
+bool anna::diameter::codec::functions::potentiallyReTransmittedMessageBit(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   return (((db.getData())[4] & Message::TBitMask) != 0x00);
 }
 
-anna::diameter::ApplicationId functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) {
+anna::diameter::ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   const char * appidPtr = db.getData() + 8;
   anna::diameter::ApplicationId result = DECODE4BYTES_INDX_VALUETYPE(appidPtr, 0, U32);
-//   anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) +
-//                               (((U32)appidPtr[1] << 16) & 0x00FF0000) +
-//                               (((U32)appidPtr[2] << 8) & 0x0000FF00) +
-//                               (((U32)appidPtr[3]) & 0x000000FF);
+  //   anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) +
+  //                               (((U32)appidPtr[1] << 16) & 0x00FF0000) +
+  //                               (((U32)appidPtr[2] << 8) & 0x0000FF00) +
+  //                               (((U32)appidPtr[3]) & 0x000000FF);
   return result;
 }
 
-anna::diameter::HopByHop functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) {
+anna::diameter::HopByHop anna::diameter::codec::functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   const char * hbhPtr = db.getData() + 12;
   anna::diameter::HopByHop result = DECODE4BYTES_INDX_VALUETYPE(hbhPtr, 0, U32);
-//   anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) +
-//                               (((U32)hbhPtr[1] << 16) & 0x00FF0000) +
-//                               (((U32)hbhPtr[2] << 8) & 0x0000FF00) +
-//                               (((U32)hbhPtr[3]) & 0x000000FF);
+  //   anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) +
+  //                               (((U32)hbhPtr[1] << 16) & 0x00FF0000) +
+  //                               (((U32)hbhPtr[2] << 8) & 0x0000FF00) +
+  //                               (((U32)hbhPtr[3]) & 0x000000FF);
   return result;
 }
 
-anna::diameter::EndToEnd functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) {
+anna::diameter::EndToEnd anna::diameter::codec::functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength)
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
 
   const char * etePtr = db.getData() + 16;
   anna::diameter::EndToEnd result = DECODE4BYTES_INDX_VALUETYPE(etePtr, 0, U32);
-//   anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) +
-//                               (((U32)etePtr[1] << 16) & 0x00FF0000) +
-//                               (((U32)etePtr[2] << 8) & 0x0000FF00) +
-//                               (((U32)etePtr[3]) & 0x000000FF);
+  //   anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) +
+  //                               (((U32)etePtr[1] << 16) & 0x00FF0000) +
+  //                               (((U32)etePtr[2] << 8) & 0x0000FF00) +
+  //                               (((U32)etePtr[3]) & 0x000000FF);
   return result;
 }
 
-void functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) {
+void anna::diameter::codec::functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) {
   if(start == NULL)
     throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION);
 
@@ -181,7 +185,7 @@ void functions::decodeCommandHeader(const char *start, char & version, U24 & len
   ete = DECODE4BYTES_INDX_VALUETYPE(start, 16, U32);
 }
 
-void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) {
+void anna::diameter::codec::functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) {
   if(start == NULL)
     throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION);
 
@@ -208,24 +212,24 @@ void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags,
   const char *dataPointer = (vendorSpecific ? (start + 12) : (start + 8)); // pointer to data part
   data.assign(dataPointer, dataLength);
   LOGLOCAL3(
-    std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s",
-                      id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str());
-    anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION);
+      std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s",
+          id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str());
+  anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION);
   );
 }
 
-const char * functions::nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException) {
+const char * anna::diameter::codec::functions::nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException) {
   if(start == NULL)
     throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION);
   if(avpsDB == NULL)
     throw anna::RuntimeException("NULL provided avpsDB pointer", ANNA_FILE_LOCATION);
 
   const char *result;
-//   LOGDEBUG(
-//      std::string msg("DataBlock provided to 'nextAVP'");
-//      msg += avpsDB.asString();
-//      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
-//   );
+  //   LOGDEBUG(
+  //      std::string msg("DataBlock provided to 'nextAVP'");
+  //      msg += avpsDB.asString();
+  //      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+  //   );
   //int avpLength = (start[5] << 16) + (start[6] << 8) + start[7]; // AVP Length
   int avpLength = DECODE3BYTES_INDX_VALUETYPE(start, 5, int);
   result = start + 4 * REQUIRED_WORDS(avpLength);
@@ -242,7 +246,7 @@ const char * functions::nextAVP(const char *avpsDB, int avpsLen, const char *sta
 //  return nextAVP(avpsDB.getData(), avpsDB.getSize(), start);
 //}
 
-const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n) throw(anna::RuntimeException) {
+const char * anna::diameter::codec::functions::findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n) throw(anna::RuntimeException) {
   const char *result = avpsDB; // first avp
   int positives = 0;
   // Decoded avp information:
@@ -259,10 +263,10 @@ const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter:
 
     if(result == NULL) {  // (*)
       LOGDEBUG(
-        std::string msg = "AVP ";
-        msg += anna::diameter::functions::avpIdAsPairString(id);
-        msg += " not found at DataBlock";
-        anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+          std::string msg = "AVP ";
+      msg += anna::diameter::functions::avpIdAsPairString(id);
+      msg += " not found at DataBlock";
+      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
       );
       return NULL;
     }
@@ -280,7 +284,7 @@ const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter:
 //}
 
 // modifiers
-void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) {
+void anna::diameter::codec::functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength) {
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
   }
@@ -294,7 +298,7 @@ void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(
 }
 
 
-void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) {
+void anna::diameter::codec::functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength) {
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
   }
@@ -307,7 +311,7 @@ void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(
   memcpy((char *)(db.getData() + 16), source, 4);
 }
 
-void functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate) throw(anna::RuntimeException) {
+void anna::diameter::codec::functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate) throw(anna::RuntimeException) {
   if(db.getSize() < Message::HeaderLength) {
     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
   }
@@ -318,4 +322,23 @@ void functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db
   memcpy((char *)(db.getData() + 4), flags, 1);
 }
 
+// XML parsers for diameter messages ///////////////////////////////////////////////////////////////////////////
+void anna::diameter::codec::functions::messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) throw(anna::RuntimeException) {
+  LOGDEBUG(anna::Logger::debug(anna::functions::asString("Parsing diameter message from xml file '%s' into xml document", xmlPathFile.c_str()), ANNA_FILE_LOCATION));
+  xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error
+  const anna::xml::Node *rootNode = xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd
+  LOGDEBUG(
+      std::string trace = "Parsing OK from XML file '";
+  trace += xmlPathFile;
+  trace += "':\n";
+  trace += anna::xml::Compiler().apply(rootNode);
+  anna::Logger::debug(trace, ANNA_FILE_LOCATION);
+  );
+}
 
+void anna::diameter::codec::functions::messageXmlDocumentFromXmlString(anna::xml::DocumentFile &xmlDocument, const std::string &xmlString) throw(anna::RuntimeException) {
+  LOGDEBUG(anna::Logger::debug("Parsing diameter message from xml string representation into xml document", ANNA_FILE_LOCATION));
+  xmlDocument.initialize(xmlString.c_str());
+  xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd
+  LOGDEBUG(anna::Logger::debug("Parsing OK from XML string representation", ANNA_FILE_LOCATION));
+}
index f105670..6875c87 100644 (file)
@@ -8,7 +8,7 @@
 
 // Local
 #include <anna/diameter/codec/tme/Avp.hpp>
-#include <anna/diameter/codec/tme/Engine.hpp>
+//#include <anna/diameter/codec/tme/Engine.hpp>
 
 #include <anna/diameter/helpers/defines.hpp>
 #include <anna/diameter/stack/Format.hpp>
@@ -21,22 +21,20 @@ using namespace anna::diameter::codec::tme;
 
 
 
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------- Avp::Avp()
-//------------------------------------------------------------------------------
-Avp::Avp() {
-  initialize();
-}
-
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------- Avp::Avp()
-//------------------------------------------------------------------------------
-Avp::Avp(AvpId id) {
-  initialize();
-  setId(id);
-}
-
+////------------------------------------------------------------------------------
+////------------------------------------------------------------------- Avp::Avp()
+////------------------------------------------------------------------------------
+//Avp::Avp(Engine *engine) : anna::diameter::codec::Avp(engine) {
+//  initialize();
+//}
+//
+////------------------------------------------------------------------------------
+////------------------------------------------------------------------- Avp::Avp()
+////------------------------------------------------------------------------------
+//Avp::Avp(AvpId id, Engine *engine)/* : anna::diameter::codec::Avp(id, engine)*/ {
+//  initialize();
+//  setId(id);
+//}
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------ Avp::~Avp()
@@ -46,15 +44,15 @@ Avp::~Avp() {
 }
 
 
-//------------------------------------------------------------------------------
-//------------------------------------------------------------- Avp::getEngine()
-//------------------------------------------------------------------------------
-anna::diameter::codec::Engine * Avp::getEngine() const throw(anna::RuntimeException) {
-  if(!a_engine)
-    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
-
-  return a_engine;
-}
+////------------------------------------------------------------------------------
+////------------------------------------------------------------- Avp::getEngine()
+////------------------------------------------------------------------------------
+//anna::diameter::codec::Engine * Avp::getEngine() const throw(anna::RuntimeException) {
+//  if(!a_engine)
+//    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
+//
+//  return a_engine;
+//}
 
 
 //------------------------------------------------------------------------------
index 190a281..69872cd 100644 (file)
@@ -8,22 +8,22 @@
 
 // Local
 #include <anna/diameter/codec/tme/Message.hpp>
-#include <anna/diameter/codec/tme/Engine.hpp>
+//#include <anna/diameter/codec/tme/Engine.hpp>
 #include <anna/core/functions.hpp>
 
 
 using namespace anna::diameter::codec::tme;
 
 
-//------------------------------------------------------------------------------
-//--------------------------------------------------------- Message::getEngine()
-//------------------------------------------------------------------------------
-anna::diameter::codec::Engine * Message::getEngine() const throw(anna::RuntimeException) {
-  if(!a_engine)
-    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
-
-  return a_engine;
-}
+////------------------------------------------------------------------------------
+////--------------------------------------------------------- Message::getEngine()
+////------------------------------------------------------------------------------
+//anna::diameter::codec::Engine * Message::getEngine() const throw(anna::RuntimeException) {
+//  if(!a_engine)
+//    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
+//
+//  return a_engine;
+//}
 
 
 //------------------------------------------------------------------------------
index 6cc20c3..cdddb0a 100644 (file)
@@ -23,7 +23,7 @@ using namespace std;
 using namespace anna;
 using namespace anna::xml;
 
-_xmlDtd* DTDFile::parse(const charfilename) const
+_xmlDtd* DTDFile::parse(const char *filename) const
 throw(RuntimeException) {
   LOGMETHOD(TraceMethod tf("anna::xml::DTDFile", "parse", ANNA_FILE_LOCATION));
   _xmlDtd* result;
index 3721681..e685ada 100644 (file)
@@ -24,16 +24,17 @@ using namespace std;
 using namespace anna;
 using namespace anna::xml;
 
-DTDMemory::DTDMemory() {
+DTDMemory::DTDMemory(const char *dtd) {
   a_filename = "/tmp/anna.xml.";
   a_filename += functions::asString((int) getpid());
   a_filename += ".dtd";
+  if (dtd) initialize(dtd);
 }
 
 //---------------------------------------------------------------------------------------------
 // Aunque la libXML ofrece funciones para analizar una DTD a partir de un buffer de memoria
-// hemos sido incapaces de hacerla funcionar correctamente. Así que nos vemos obligados
-// a volcar el buffer en un archivo .. y una vez allí analizarlo con la función que analiza
+// hemos sido incapaces de hacerla funcionar correctamente. As que nos vemos obligados
+// a volcar el buffer en un archivo .. y una vez all� analizarlo con la funci�n que analiza
 // la DTD a partir de un archivo.
 //---------------------------------------------------------------------------------------------
 _xmlDtd* DTDMemory::parse(const char* content) const