diff --git a/AMPLSolver.cpp b/AMPLSolver.cpp
index 3e24d31..3865871 100644
--- a/AMPLSolver.cpp
+++ b/AMPLSolver.cpp
@@ -174,7 +174,11 @@ void AMPLSolver::DefineProblem(const Solver::OptimisationProblem & TheProblem,
   // The default values for the data will be loaded from the data file. This
   // operation is the same as the one done for data messages, and to avoid 
   // code duplication the handler is just invoked using the address of this
-  // solver Actor as the the sender is not important for this update.
+  // solver Actor as the the sender is not important for this update. However,
+  // if the information is missing from the message, no data file should be 
+  // loaded. It is necessary to convert the content to a string since the 
+  // JSON library only sees the string and not its length before it has been 
+  // unwrapped.
 
   if( TheProblem.contains( DataFileMessage::Keys::DataFile ) && 
       TheProblem.contains( DataFileMessage::Keys::NewData  )      )
@@ -255,7 +259,8 @@ void AMPLSolver::SolveProblem(
   // supported as values.
 
   for( const auto & [ TheName, MetricValue ] : 
-       Solver::MetricValueType( TheContext.at( Solver::ExecutionContext ) ) )
+       Solver::MetricValueType( TheContext.at( 
+       Solver::ApplicationExecutionContext::Keys::ExecutionContext ) ) )
     SetAMPLParameter( TheName, MetricValue );
 
   // Setting the given objective as the active objective and all other
@@ -264,8 +269,10 @@ void AMPLSolver::SolveProblem(
 
   std::string OptimisationGoal;
 
-  if( TheContext.contains( Solver::ObjectiveFunctionLabel ) )
-    OptimisationGoal = TheContext.at( Solver::ObjectiveFunctionLabel );
+  if( TheContext.contains( 
+      Solver::ApplicationExecutionContext::Keys::ObjectiveFunctionLabel ) )
+    OptimisationGoal = TheContext.at( 
+      Solver::ApplicationExecutionContext::Keys::ObjectiveFunctionLabel );
   else if( !DefaultObjectiveFunction.empty() )
     OptimisationGoal = DefaultObjectiveFunction;
   else
@@ -337,7 +344,8 @@ void AMPLSolver::SolveProblem(
   // application execution context has the deployment flag set.
 
   Solver::Solution::VariableValuesType VariableValues;
-  bool DeploymentFlagSet = TheContext.at( DeploymentFlag ).get<bool>();
+  bool DeploymentFlagSet 
+       = TheContext.at( Solver::Solution::Keys::DeploymentFlag ).get<bool>();
 
   for( auto Variable : ProblemDefinition.getVariables() )
   {
@@ -350,8 +358,9 @@ void AMPLSolver::SolveProblem(
 
   // The found solution can then be returned to the requesting actor or topic
 
-  Send( Solver::Solution(
-    TheContext.at( Solver::TimeStamp ).get< Solver::TimePointType >(),
+  Send( Solver::Solution( 
+    TheContext.at( 
+      Solver::Solution::Keys::TimeStamp ).get< Solver::TimePointType >(),
     OptimisationGoal, ObjectiveValues, VariableValues, 
     DeploymentFlagSet
   ), TheRequester ); 
diff --git a/MetricUpdater.cpp b/MetricUpdater.cpp
index 1607081..5b7c16b 100644
--- a/MetricUpdater.cpp
+++ b/MetricUpdater.cpp
@@ -40,7 +40,7 @@ namespace NebulOuS
 void MetricUpdater::AddMetricSubscription( 
      const MetricTopic & MetricDefinitions, const Address OptimiserController )
 {
-  JSON TheMetrics = MetricDefinitions.at( MetricList );
+  JSON TheMetrics = MetricDefinitions.at( MetricTopic::Keys::MetricList );
 
   if( TheMetrics.is_array() )
   {
@@ -57,18 +57,14 @@ void MetricUpdater::AddMetricSubscription(
       auto [ MetricRecordPointer, MetricAdded ] = MetricValues.try_emplace( 
              MetricRecord.get<std::string>(), JSON() );
 
-      TheMetricNames.insert( MetricRecordPointer->first );
-
-      // If a new metric was added, a subscription will be set up for this 
-      // new metric, and the flag indicating that values have been received 
-      // for all metrics will be reset since this new metric has yet to receive
-      // its first value
+        TheMetricNames.insert( MetricRecordPointer->first );
 
       if( MetricAdded )
       {
         Send( Theron::AMQ::NetworkLayer::TopicSubscription( 
           Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
-          std::string( MetricValueRootString ) + MetricRecordPointer->first ), 
+          std::string( MetricValueUpdate::MetricValueRootString ) 
+                       + MetricRecordPointer->first ), 
           GetSessionLayerAddress() );
 
         AllMetricValuesSet = false;
@@ -85,7 +81,7 @@ void MetricUpdater::AddMetricSubscription(
       {
         Send( Theron::AMQ::NetworkLayer::TopicSubscription( 
           Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
-          std::string( MetricValueRootString ) + TheMetric ), 
+          std::string( MetricValueUpdate::MetricValueRootString ) + TheMetric ), 
           GetSessionLayerAddress() );
 
         MetricValues.erase( TheMetric );
@@ -138,14 +134,16 @@ void MetricUpdater::UpdateMetricValue(
 {
   Theron::AMQ::TopicName TheTopic 
           = TheMetricTopic.AsString().erase( 0, 
-                                      NebulOuS::MetricValueRootString.size() );
+                           MetricValueUpdate::MetricValueRootString.size() );
 
   if( MetricValues.contains( TheTopic ) )
   {
-    MetricValues.at( TheTopic ) = TheMetricValue.at( NebulOuS::ValueLabel );
+    MetricValues.at( TheTopic ) 
+      = TheMetricValue.at( MetricValueUpdate::Keys::ValueLabel );
     
     ValidityTime = std::max( ValidityTime, 
-      TheMetricValue.at( NebulOuS::TimePoint ).get< Solver::TimePointType >() );
+      TheMetricValue.at( 
+        MetricValueUpdate::Keys::TimePoint ).get< Solver::TimePointType >() );
   }
 }
 
@@ -183,7 +181,8 @@ void MetricUpdater::SLOViolationHandler(
         [](const auto & MetricValue){ return MetricValue.is_null(); }  ))) )
   {
     Send( Solver::ApplicationExecutionContext(
-      SeverityMessage.at( NebulOuS::TimePoint ).get< Solver::TimePointType >(),
+      SeverityMessage.at( 
+        MetricValueUpdate::Keys::TimePoint ).get< Solver::TimePointType >(),
       MetricValues, true
     ), TheSolverManager );
 
@@ -250,17 +249,17 @@ MetricUpdater::MetricUpdater( const std::string UpdaterName,
 
   Send( Theron::AMQ::NetworkLayer::TopicSubscription(
     Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
-    NebulOuS::MetricSubscriptions ), 
+    MetricTopic::AMQTopic ), 
     GetSessionLayerAddress() );
 
   Send( Theron::AMQ::NetworkLayer::TopicSubscription(
     Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
-    NebulOuS::ReconfigurationTopic ), 
+    ReconfigurationMessage::AMQTopic ), 
     GetSessionLayerAddress() );
 
   Send( Theron::AMQ::NetworkLayer::TopicSubscription(
     Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
-    NebulOuS::SLOViolationTopic ), 
+    SLOViolation::AMQTopic ), 
     GetSessionLayerAddress() ); 
 }
 
@@ -275,24 +274,25 @@ MetricUpdater::~MetricUpdater()
   {
     Send( Theron::AMQ::NetworkLayer::TopicSubscription(
       Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
-      NebulOuS::MetricSubscriptions ), 
+      MetricTopic::AMQTopic ), 
       GetSessionLayerAddress() );
 
     Send( Theron::AMQ::NetworkLayer::TopicSubscription(
       Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
-      NebulOuS::ReconfigurationTopic ), 
+      ReconfigurationMessage::AMQTopic ), 
       GetSessionLayerAddress() );
 
     Send( Theron::AMQ::NetworkLayer::TopicSubscription(
       Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
-      NebulOuS::SLOViolationTopic ), 
+      SLOViolation::AMQTopic ), 
       GetSessionLayerAddress() );  
 
     std::ranges::for_each( std::views::keys( MetricValues ),
     [this]( const Theron::AMQ::TopicName & TheMetricTopic ){
       Send( Theron::AMQ::NetworkLayer::TopicSubscription(
         Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
-        std::string( MetricValueRootString ) + TheMetricTopic ), 
+        std::string( MetricValueUpdate::MetricValueRootString ) 
+                     + TheMetricTopic ), 
         GetSessionLayerAddress() );
     });
   }
diff --git a/MetricUpdater.hpp b/MetricUpdater.hpp
index 51257f6..281500b 100644
--- a/MetricUpdater.hpp
+++ b/MetricUpdater.hpp
@@ -68,74 +68,6 @@ using JSON = nlohmann::json;                    // Short form name space
 
 namespace NebulOuS 
 {
-/*==============================================================================
-
- Basic interface definitions
-
-==============================================================================*/
-//
-// Definitions for the terminology to facilitate changing the lables of the 
-// various message labels without changing the code. The definitions are 
-// compile time constants and as such should not lead to any run-time overhead.
-// The JSON attribute names may be found under the "Predicted monitoring 
-// metrics" section on the Wiki page [1].
-
-constexpr std::string_view ValueLabel = "metricValue";
-constexpr std::string_view TimePoint  = "predictionTime";
-
-// The topic used for receiving the message(s) defining the metrics of the 
-// application execution context as published by the Optimiser Controller is 
-// defined next.
-
-constexpr std::string_view MetricSubscriptions 
-          = "eu.nebulouscloud.optimiser.controller.metric_list";
-
-// The JSON message attribute for the list of metrics is another JSON object
-// stored under the following key, see the Event type III defined in 
-// https://158.39.75.54/projects/nebulous-collaboration-hub/wiki/slo-severity-based-violation-detector
-// where the name of the metric is defined under as sub-key.
-
-constexpr std::string_view MetricList = "metrics";
-
-// The metric value messages will be published on different topics and to 
-// check if an inbound message is from a metric value topic, it is necessary 
-// to test against the base string for the metric value topics according to 
-// the Wiki-page [1]
-
-constexpr std::string_view MetricValueRootString
-          = "eu.nebulouscloud.monitoring.predicted.";
-
-// The SLO violation detector will publish a message when a reconfiguration is 
-// deamed necessary for a future time point called "Event type V" on the wiki 
-// page [3]. The event contains a probability for at least one of the SLOs 
-// being violated at the predicted time point. It is not clear if the assessment
-// is being made by the SLO violation detector at every new metric prediction,
-// or if this event is only signalled when the probability is above some 
-// internal threshold of the SLO violation detector. 
-//
-// The current implementation assumes that the latter is the case, and hence 
-// just receiving the message indicates that a new application configuration 
-// should be found given the application execution context as predicted by the 
-// metric values recorded by the Metric Updater.  Should this assumption be 
-// wrong, the probability must be compared with some  user set threshold for 
-// each message, and to cater for this the probability field will always be 
-// compared to a threshold, currently set to zero to ensure that every event 
-// message will trigger a reconfiguration.
-//
-// The messages from the Optimizer Controller will be sent on a topic that 
-// should follow some standard topic convention.
-
-constexpr std::string_view SLOViolationTopic 
-          = "eu.nebulouscloud.monitoring.slo.severity_value";
-
-// When a reconfiguration has been enacted by the Optimiser Controller and 
-// a new configuration is confirmed to be running on the new platofrm, it will 
-// send a message to inform all other components that the reconfiguration 
-// has happened on the following topic.
-
-constexpr std::string_view ReconfigurationTopic
-          = "eu.nebulouscloud.optimiser.adaptations";
-
 /*==============================================================================
 
  Metric Updater
@@ -178,14 +110,12 @@ private:
 
   Solver::TimePointType ValidityTime;
 
-  // There is also a flag to indicate when all metric values have received 
-  // values since optimising for a application execution context defiend all 
-  // metrics requires that at least one value is received for each metric. This
-  // condition could be tested before sending the request to find a new 
-  // solution, but this means testing all metrics in a linear scan for a 
-  // condition that will only happen initially until all metrics have been seen
-  // and so it is better for the performance if there is a flag to check for 
-  // this condition.
+  // When an SLO violation message is received the current vector of metric 
+  // values should be sent as an application execution context (message) to the
+  // Solution Manager actor that will invoke a solver to find the optimal 
+  // configuration for this configuration. The Metric Updater must therefore 
+  // know the address of the Soler Manager, and this must be passed to 
+  // the constructor.
 
   bool AllMetricValuesSet;
 
@@ -204,18 +134,35 @@ private:
   {
   public:
 
+    // The topic used for receiving the message(s) defining the metrics of the 
+    // application execution context as published by the Optimiser Controller 
+    // is the following
+
+    static constexpr std::string_view AMQTopic 
+                     = "eu.nebulouscloud.optimiser.controller.metric_list";
+
+    // The EXN middleware sending the AMQP messages for the other component 
+    // of the NebulOuS project only sends JSON objects, meaning that the list 
+    // of metric names to subscribe is sent as a JSON array, but it must be 
+    // embedded in a map with a single key, see the message format described
+    // in the Wiki page at
+    // https://openproject.nebulouscloud.eu/projects/nebulous-collaboration-hub/wiki/1-optimiser-controller#controller-to-metric-updater-and-ems-metric-list
+
+    struct Keys
+    {
+      static constexpr std::string_view MetricList = "metrics";
+    };
+ 
+    // Constructors
+
     MetricTopic( void )
-    : JSONTopicMessage( std::string( MetricSubscriptions ) )
+    : JSONTopicMessage( AMQTopic )
     {}
 
     MetricTopic( const MetricTopic & Other )
     : JSONTopicMessage( Other )
     {}
 
-    // MetricTopic( const JSONTopicMessage & Other )
-    // : JSONTopicMessage( Other )
-    // {}
-
     virtual ~MetricTopic() = default;
   };
 
@@ -241,6 +188,25 @@ private:
   {
   public:
 
+    // The metric value messages will be published on different topics and to 
+    // check if an inbound message is from a metric value topic, it is 
+    // necessary to test against the base string for the metric value topics 
+    // according to the Wiki-page describing the Type II message:
+    // https://openproject.nebulouscloud.eu/projects/nebulous-collaboration-hub/wiki/monitoringdata-interface#type-ii-messages-predicted-monitoring-metrics
+
+    static constexpr std::string_view MetricValueRootString
+                      = "eu.nebulouscloud.monitoring.predicted.";
+
+    // Only two of the fields in this message will be looked up and stored
+    // in the current application context map.
+
+    struct Keys
+    {
+      static constexpr std::string_view 
+                ValueLabel = "metricValue",
+                TimePoint  = "predictionTime";
+    };
+
     MetricValueUpdate( void )
     : JSONWildcardMessage( std::string( MetricValueRootString ) )
     {}
@@ -263,21 +229,48 @@ private:
   // SLO violations
   // --------------------------------------------------------------------------
   //
-  // The SLO Violation detector publishes an event to indicate that at least 
-  // one of the constraints for the application deployment will be violated in 
-  // the predicted future, and that the search for a new solution should start.
-  // This will trigger the the publication of the Solver's Application Execution 
-  // context message. The context message will contain the current status of the
-  // metric values, and trigger a solver to find a new, optimal variable 
-  // assignment to be deployed to resolve the identified problem.
-
+  // The SLO violation detector will publish a message when a reconfiguration is 
+  // deamed necessary for a future time point called "Event type VI" on the wiki 
+  // page: https://openproject.nebulouscloud.eu/projects/nebulous-collaboration-hub/wiki/slo-severity-based-violation-detector#output-event-type-vi 
+  // The event contains a probability for at least one of the SLOs  being 
+  // violated at the predicted time point. It is not clear if the assessment
+  // is being made by the SLO violation detector at every new metric prediction,
+  // or if this event is only signalled when the probability is above some 
+  // internal threshold of the SLO violation detector. 
+  //
+  // The current implementation assumes that the latter is the case, and hence 
+  // just receiving the message indicates that a new application configuration 
+  // should be found given the application execution context as predicted by the 
+  // metric values recorded by the Metric Updater.  Should this assumption be 
+  // wrong, the probability must be compared with some  user set threshold for 
+  // each message, and to cater for this the probability field will always be 
+  // compared to a threshold, currently set to zero to ensure that every event 
+  // message will trigger a reconfiguration.
+  
   class SLOViolation
   : public Theron::AMQ::JSONTopicMessage
   {
   public:
 
+    // The messages from the SLO Violation Detector will be sent on a topic that 
+    // should follow some standard topic convention.
+
+    static constexpr std::string_view AMQTopic 
+                      = "eu.nebulouscloud.monitoring.slo.severity_value";
+
+    // The only information taken from this detction message is the prediction 
+    // time which will be used as the time for the application's execution 
+    // context when this is forwarded to the solvers for processing.
+
+    struct Keys
+    {
+      static constexpr std::string_view TimePoint  = "predictionTime";
+    };
+    
+    // Constructors
+
     SLOViolation( void )
-    : JSONTopicMessage( std::string( SLOViolationTopic ) )
+    : JSONTopicMessage( AMQTopic )
     {}
 
     SLOViolation( const SLOViolation & Other )
@@ -311,18 +304,28 @@ private:
 
   bool ReconfigurationInProgress;
 
-  // When the reconfiguration has been done and the Optimizer Controller 
-  // confirms that the application is running in a new configuration, it will 
-  // send a reconfiguration completed message. This message will just be a 
-  // JSON message.
+  // When a reconfiguration has been enacted by the Optimiser Controller and 
+  // a new configuration is confirmed to be running on the new platofrm, it 
+  // will send a message to inform all other components that the 
+  // reconfiguration has happened. The event is just the reception of the 
+  // message and its content will not be processed, so there are no keys for
+  // the JSON map received.
 
   class ReconfigurationMessage
   : public Theron::AMQ::JSONTopicMessage
   { 
   public:
 
+    // The topic for the reconfiguration finished messages is defined by the 
+    // optimiser as the sender.
+
+    static constexpr std::string_view AMQTopic
+                     = "eu.nebulouscloud.optimiser.controller.reconfiguration";
+
+    // Constructors
+
     ReconfigurationMessage( void )
-    : JSONTopicMessage( std::string( ReconfigurationTopic ) )
+    : JSONTopicMessage( AMQTopic )
     {}
 
     ReconfigurationMessage( const ReconfigurationMessage & Other )
diff --git a/Solver.hpp b/Solver.hpp
index c9228a3..befd603 100644
--- a/Solver.hpp
+++ b/Solver.hpp
@@ -79,52 +79,6 @@ public:
   // Application Execution Context
   // --------------------------------------------------------------------------
   //
-  // The message is defined as a JSON message representing an attribute-value 
-  // object. The attributes expected are defined as constant strings so that 
-  // the actual textual representation can be changed without changing the code
-  // 
-  // "Timestamp" : This is the field giving the implicit order of the 
-  // different application execution execution contexts waiting for being 
-  // solved when there are more requests than there are solvers available to 
-  // work on the different problems. 
-
-  static constexpr std::string_view TimeStamp = "Timestamp";
-
-  // There is also a definition for the objective function label since a multi-
-  // objective optimisation problem can have multiple objective functions and 
-  // the solution is found for only one of these functions at the time even 
-  // though all objective function values will be returned with the solution, 
-  // the solution will maximise only the objective function whose label is 
-  // given in the application execution context request message.
-  //
-  // The Application Execution Cntext message may contain the name of the 
-  // objective function to maximise. If so, this should be stored under the 
-  // key name indicated here. However, if the objective function name is not 
-  // given, the default objective function is used. The default objective 
-  // function will be named when defining the optimisation problem.
-
-  static constexpr std::string_view 
-  ObjectiveFunctionLabel = "ObjectiveFunction";
-
-  // Finally, there is another JSON object that defines all the metric name and
-  // value pairs that define the actual execution context. Note that there must
-  // be at least one metric-value pair for the request to be valid.
-
-  static constexpr std::string_view ExecutionContext = "ExecutionContext";
-
-  // Finally, the execution context can come from the Metric Collector actor
-  // as a consequence of an SLO Violation being detected. In this case the 
-  // optimised solution found by the solver should trigger a reconfiguration.
-  // However, various application execution context can also be tried for 
-  // simulating future events and to investigate which configuration would be
-  // the best for these situations. In this case the optimised solution should
-  // not reconfigure the running application. For this reason there is a flag
-  // in the message indicating whether the solution should be deployed, and 
-  // its default value is 'false' to prevent solutions form accidentially being
-  // deployed.
-
-  static constexpr std::string_view DeploymentFlag = "DeploySolution";
-
   // To ensure that the execution context is correctly provided by the senders
   // The expected metric value structure is defined as a type based on the 
   // standard unsorted map based on a JSON value object since this can hold 
@@ -161,6 +115,48 @@ public:
     static constexpr std::string_view AMQTopic 
                      = "eu.nebulouscloud.optimiser.solver.context";
 
+    // The keys used in the JSON message to send are defined first:
+    //
+    // "Timestamp" : This is the field giving the implicit order of the 
+    //    different application execution execution contexts waiting for being 
+    //    solved when there are more requests than there are solvers available
+    //    to work on the different problems. 
+    // "ObjectFunction" : There is also a definition for the objective function
+    //    label since a multi-objective optimisation problem can have multiple 
+    //    objective functions and the solution is found for only one of these
+    //    functions at the time even though all objective function values will
+    //    be returned with the solution, the solution will maximise only the 
+    //    objective function whose label is given in the application execution
+    //    context request message. The Application Execution Cntext message may
+    //    contain the name of the objective function to maximise. If so, this
+    //    should be stored under the key name indicated here. However, if the
+    //    objective function name is not given, the default objective function 
+    //    is used. The default objective function will be named when defining 
+    //    the optimisation problem.
+    // "ExecutionContext" : Defines all the metric name and value pairs that
+    //    define the actual execution context. Note that there must be at least
+    //    one metric-value pair for the request to be valid.
+    // "DeploySolution" : The execution context can come from the Metric 
+    //    Collector actor as a consequence of an SLO Violation being detected.
+    //    In this case the optimised solution found by the solver should trigger
+    //    a reconfiguration. However, various application execution context can
+    //    also be tried for simulating future events and to investigate which
+    //    configuration would be the best for these situations. In this case the
+    //    optimised solution should not reconfigure the running application. For
+    //    this reason there is a flag in the message indicating whether the 
+    //    solution should be deployed, and its default value is 'false' to 
+    //    prevent solutions form accidentially being deployed.
+
+
+    struct Keys
+    {
+      static constexpr std::string_view
+        TimeStamp               = "Timestamp",
+        ObjectiveFunctionLabel  = "ObjectiveFunction",
+        ExecutionContext        = "ExecutionContext",
+        DeploymentFlag          = "DeploySolution";
+    };
+
     // The full constructor takes the time point, the objective function to 
     // solve for, and the application's execution context as the metric map
 
@@ -169,10 +165,10 @@ public:
                                  const MetricValueType & TheContext,
                                  bool DeploySolution = false )
     : JSONTopicMessage( std::string( AMQTopic ),
-    { { std::string( TimeStamp ), MicroSecondTimePoint },
-      { std::string( ObjectiveFunctionLabel ), ObjectiveFunctionID },
-      { std::string( ExecutionContext ), TheContext },
-      { std::string( DeploymentFlag ), DeploySolution }
+    { { Keys::TimeStamp, MicroSecondTimePoint },
+      { Keys::ObjectiveFunctionLabel, ObjectiveFunctionID },
+      { Keys::ExecutionContext, TheContext },
+      { Keys::DeploymentFlag, DeploySolution }
     }) {}
 
     // The constructor omitting the objective function identifier is similar
@@ -183,9 +179,9 @@ public:
                                  const MetricValueType & TheContext,
                                  bool DeploySolution = false )
     : JSONTopicMessage( std::string( AMQTopic ),
-    { { std::string( TimeStamp ), MicroSecondTimePoint },
-      { std::string( ExecutionContext ), TheContext },
-      { std::string( DeploymentFlag ), DeploySolution }
+    { { Keys::TimeStamp, MicroSecondTimePoint },
+      { Keys::ExecutionContext, TheContext },
+      { Keys::DeploymentFlag, DeploySolution }
     }) {}
 
     // The copy constructor simply passes the job on to the JSON Topic
@@ -206,9 +202,9 @@ public:
     virtual ~ApplicationExecutionContext() = default;
   };
 
-  // The handler for this message is virtual as it where the real action will
-  // happen and the search for the optimal solution will hopefully lead to a
-  // feasible soltuion that can be returned to the sender of the applicaton 
+  // The handler for this message is virtual as it is where the real action
+  // will happen and the search for the optimal solution will hopefully lead
+  // to a feasible soltuion that can be returned to the sender of the applicaton
   // context.
 
 protected:
@@ -241,26 +237,47 @@ public:
   {
   public:
 
+    // There are some aliases that can be used in other Actors processing this
+    // message in order to ensure portability
+
     using ObjectiveValuesType = MetricValueType;
     using VariableValuesType  = MetricValueType;
 
-    static constexpr std::string_view ObjectiveValues = "ObjectiveValues";
-    static constexpr std::string_view VariableValues  = "VariableValues";
-
+    // The topic for which the message is published is defined first
+   
     static constexpr std::string_view AMQTopic 
                      = "eu.nebulouscloud.optimiser.solver.solution";
 
+    // Most of the message keys are the same as for the application execution 
+    // context, but there are two new:
+    //
+    // "ObjectiveValues" : This holds a map of objective function names and 
+    //    their values under the currently found solution which is optimised
+    //    for the given objective function or the default objective function.
+    //    The other objective values is useful if one is searching for the 
+    //    Pareto front of the problem.
+    // "VariableValues" : This key is a map holding the variable names and 
+    //    their values found by the solver for the optimal solution. This is
+    //    used to reconfigure the application.
+
+    struct Keys : public ApplicationExecutionContext::Keys
+    {
+      static constexpr std::string_view
+        ObjectiveValues = "ObjectiveValues",
+        VariableValues  = "VariableValues";
+    };
+    
     Solution( const TimePointType MicroSecondTimePoint,
               const std::string ObjectiveFunctionID,
               const ObjectiveValuesType & TheObjectiveValues,
               const VariableValuesType & TheVariables,
               bool DeploySolution )
     : JSONTopicMessage( std::string( AMQTopic ) ,
-      { { std::string( TimeStamp ), MicroSecondTimePoint   },
-        { std::string( ObjectiveFunctionLabel ), ObjectiveFunctionID },
-        { std::string( ObjectiveValues ) , TheObjectiveValues },
-        { std::string( VariableValues ), TheVariables },
-        { std::string( DeploymentFlag ), DeploySolution }
+      { { Keys::TimeStamp, MicroSecondTimePoint   },
+        { Keys::ObjectiveFunctionLabel, ObjectiveFunctionID },
+        { Keys::ObjectiveValues, TheObjectiveValues },
+        { Keys::VariableValues, TheVariables },
+        { Keys::DeploymentFlag, DeploySolution }
       } )
       {}
     
@@ -335,6 +352,11 @@ public:
       Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
       OptimisationProblem::AMQTopic
     ), GetSessionLayerAddress() );
+
+    Send( Theron::AMQ::NetworkLayer::TopicSubscription(
+      Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
+      ApplicationExecutionContext::AMQTopic
+    ), GetSessionLayerAddress() );
   }
   
   Solver() = delete;
@@ -342,10 +364,18 @@ public:
   virtual ~Solver()
   {
     if( HasNetwork() )
+    {
       Send( Theron::AMQ::NetworkLayer::TopicSubscription(
         Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
         OptimisationProblem::AMQTopic
       ), GetSessionLayerAddress() );
+
+      Send( Theron::AMQ::NetworkLayer::TopicSubscription(
+        Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
+        ApplicationExecutionContext::AMQTopic
+      ), GetSessionLayerAddress() );
+
+    }
   }
 };
 
diff --git a/SolverManager.hpp b/SolverManager.hpp
index 7e4c423..bb9570d 100644
--- a/SolverManager.hpp
+++ b/SolverManager.hpp
@@ -174,7 +174,8 @@ private:
     const Address TheRequester )
   {
     ContextQueue.emplace( 
-      TheContext.at( Solver::TimeStamp ).get< Solver::TimePointType >(), 
+      TheContext.at( Solver::ApplicationExecutionContext::Keys::TimeStamp 
+                   ).get< Solver::TimePointType >(), 
       TheContext );
 
     DispatchToSolvers();