platform/src/ReactionEngine.cpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #include <boost/asio.hpp>
00021 #include <pion/platform/CodecFactory.hpp>
00022 #include <pion/platform/ProtocolFactory.hpp>
00023 #include <pion/platform/DatabaseManager.hpp>
00024 #include <pion/platform/ReactionEngine.hpp>
00025 
00026 
00027 namespace pion {        // begin namespace pion
00028 namespace platform {    // begin namespace platform (Pion Platform Library)
00029 
00030 
00031 // static members of ReactionEngine
00032 
00033 const boost::uint32_t   ReactionEngine::DEFAULT_NUM_THREADS = 4;
00034 const std::string       ReactionEngine::DEFAULT_CONFIG_FILE = "reactors.xml";
00035 const std::string       ReactionEngine::CONNECTION_ELEMENT_NAME = "Connection";
00036 const std::string       ReactionEngine::TYPE_ELEMENT_NAME = "Type";
00037 const std::string       ReactionEngine::FROM_ELEMENT_NAME = "From";
00038 const std::string       ReactionEngine::TO_ELEMENT_NAME = "To";
00039 const std::string       ReactionEngine::TOTAL_OPS_ELEMENT_NAME = "TotalOps";
00040 const std::string       ReactionEngine::EVENTS_QUEUED_ELEMENT_NAME = "EventsQueued";
00041 const std::string       ReactionEngine::CONNECTION_TYPE_REACTOR = "reactor";
00042 const std::string       ReactionEngine::CONNECTION_TYPE_INPUT = "input";
00043 const std::string       ReactionEngine::CONNECTION_TYPE_OUTPUT = "output";
00044 const std::string       ReactionEngine::REACTORS_PERMISSION_TYPE = "Reactors";
00045 const std::string       ReactionEngine::UNRESTRICTED_ELEMENT_NAME = "Unrestricted";
00046 const std::string       ReactionEngine::WORKSPACE_QUALIFIER_ELEMENT_NAME = "Workspace";
00047 
00048 
00049 // ReactionEngine member functions
00050     
00051 ReactionEngine::ReactionEngine(VocabularyManager& vocab_mgr,
00052                                CodecFactory& codec_factory,
00053                                ProtocolFactory& protocol_factory,
00054                                DatabaseManager& database_mgr)
00055     : PluginConfig<Reactor>(vocab_mgr, DEFAULT_CONFIG_FILE, Reactor::REACTOR_ELEMENT_NAME),
00056     m_codec_factory(codec_factory),
00057     m_protocol_factory(protocol_factory),
00058     m_database_mgr(database_mgr),
00059     m_is_running(false),
00060     m_multithread_branches(false)
00061 {
00062     setLogger(PION_GET_LOGGER("pion.platform.ReactionEngine"));
00063     m_scheduler.setLogger(PION_GET_LOGGER("pion.platform.ReactionEngine"));
00064     m_scheduler.setNumThreads(DEFAULT_NUM_THREADS);
00065     m_codec_connection = m_codec_factory.registerForUpdates(boost::bind(&ReactionEngine::updateCodecs, this));
00066     m_db_connection = m_database_mgr.registerForUpdates(boost::bind(&ReactionEngine::updateDatabases, this));
00067     m_protocol_connection = m_protocol_factory.registerForUpdates(boost::bind(&ReactionEngine::updateProtocols, this));
00068 }
00069 
00070 void ReactionEngine::openConfigFile(void)
00071 {
00072     boost::mutex::scoped_lock engine_lock(m_mutex);
00073 
00074     // just return if it's already open
00075     if (ConfigManager::configIsOpen())
00076         return;
00077 
00078     // open the plug-in config file and load plug-ins
00079     ConfigManager::openPluginConfig(m_plugin_element);
00080     
00081     // Step through and process Reactor connections.
00082     // This must be done last & independently to ensure that all Reactors have
00083     // been loaded; otherwise, you would encounter references to Reactors that
00084     // have not yet been loaded.
00085     xmlNodePtr connection_node = m_config_node_ptr->children;
00086     while ( (connection_node = ConfigManager::findConfigNodeByName(CONNECTION_ELEMENT_NAME, connection_node)) != NULL)
00087     {
00088         // parse new plug-in definition
00089         std::string connection_id;
00090         if (! ConfigManager::getNodeId(connection_node, connection_id))
00091             throw EmptyConnectionIdException(ConfigManager::getConfigFile());
00092 
00093         // make sure that it is a reactor connection type
00094         std::string connection_type;
00095         if (! ConfigManager::getConfigOption(TYPE_ELEMENT_NAME, connection_type, connection_node->children)
00096             || connection_type != CONNECTION_TYPE_REACTOR)
00097         {
00098             throw BadConnectionTypeException(connection_id);
00099         }
00100         
00101         // get the ID for the Reactor where events come from
00102         std::string from_id;
00103         if (! ConfigManager::getConfigOption(FROM_ELEMENT_NAME, from_id, connection_node->children))
00104             throw EmptyFromException(connection_id);
00105         
00106         // get the ID for the Reactor where events go to
00107         std::string to_id;
00108         if (! ConfigManager::getConfigOption(TO_ELEMENT_NAME, to_id, connection_node->children))
00109             throw EmptyToException(connection_id);
00110 
00111         // add the connection w/o locking
00112         addConnectionNoLock(connection_id, from_id, to_id);
00113 
00114         // step to the next Reactor connection
00115         connection_node = connection_node->next;
00116     }
00117     
00118     PION_LOG_INFO(m_logger, "Loaded Reactor configuration file: " << ConfigManager::getConfigFile());
00119     
00120     // start the ReactionEngine
00121     engine_lock.unlock();
00122     start();
00123 }
00124     
00125 void ReactionEngine::clearReactorStats(const std::string& reactor_id)
00126 {
00127     // convert "plugin not found" exceptions into "reactor not found"
00128     try {
00129         m_plugins.run(reactor_id, boost::bind(&Reactor::clearStats, _1));
00130     } catch (PluginManager<Reactor>::PluginNotFoundException& /* e */) {
00131         throw ReactorNotFoundException(reactor_id);
00132     }
00133     PION_LOG_DEBUG(m_logger, "Cleared reactor statistics: " << reactor_id);
00134 }
00135 
00136 void ReactionEngine::start(void)
00137 {
00138     boost::mutex::scoped_lock engine_lock(m_mutex);
00139     if (! m_is_running) {
00140         PION_LOG_INFO(m_logger, "Starting the ReactionEngine");
00141 
00142         // notify the thread scheduler that we need it now
00143         m_scheduler.addActiveUser();
00144 
00145         m_is_running = true;
00146     }
00147 }
00148 
00149 void ReactionEngine::stop(void)
00150 {
00151     boost::mutex::scoped_lock engine_lock(m_mutex);
00152     stopNoLock();
00153 }
00154 
00155 void ReactionEngine::shutdown(void)
00156 {
00157     stop();
00158     m_scheduler.shutdown();
00159     m_temp_connections.clear();
00160     m_reactor_connections.clear();
00161     m_plugins.run(boost::bind(&Reactor::clearConnections, _1));
00162     this->releasePlugins();
00163 }
00164 
00165 void ReactionEngine::clearStats(void)
00166 {
00167     m_plugins.run(boost::bind(&Reactor::clearStats, _1));
00168     PION_LOG_DEBUG(m_logger, "Cleared all reactor statistics");
00169 }
00170     
00171 void ReactionEngine::updateCodecs(void)
00172 {
00173     m_plugins.run(boost::bind(&Reactor::updateCodecs, _1));
00174 }
00175 
00176 void ReactionEngine::updateDatabases(void)
00177 {
00178     m_plugins.run(boost::bind(&Reactor::updateDatabases, _1));
00179 }
00180 
00181 void ReactionEngine::updateProtocols(void)
00182 {
00183     m_plugins.run(boost::bind(&Reactor::updateProtocols, _1));
00184 }
00185 
00186 void ReactionEngine::restartReactorsThatShouldBeRunning(void)
00187 {
00188     try {
00189         // step through each reactor config node
00190         xmlNodePtr reactor_node = m_config_node_ptr->children;
00191         while ( (reactor_node = findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL)
00192         {
00193             // get the reactor identifier
00194             std::string reactor_id;
00195             if (getNodeId(reactor_node, reactor_id)) {
00196                 // attempt to restart the Reactor if necessary
00197                 m_plugins.run(reactor_id,
00198                     boost::bind(&Reactor::startOutRunning, _1, reactor_node->children, true));
00199             }
00200     
00201             // look for more reactor config nodes
00202             reactor_node = reactor_node->next;
00203         }
00204     } catch (std::exception& e) {
00205         // log but don't propagate exceptions
00206         PION_LOG_ERROR(m_logger, e.what());
00207     }
00208 }
00209     
00210 void ReactionEngine::setReactorConfig(const std::string& reactor_id,
00211                                       const xmlNodePtr config_ptr)
00212 {
00213     // convert PluginNotFound exceptions into ReactorNotFound exceptions
00214     try {
00215         PluginConfig<Reactor>::setPluginConfig(reactor_id, config_ptr);
00216     } catch (PluginManager<Reactor>::PluginNotFoundException&) {
00217         throw ReactorNotFoundException(reactor_id);
00218     }
00219 }
00220 
00221 void ReactionEngine::setReactorLocation(const std::string& reactor_id,
00222                                         const xmlNodePtr config_ptr)
00223 {
00224     // make sure that the plug-in configuration file is open
00225     if (! configIsOpen())
00226         throw ConfigNotOpenException(getConfigFile());
00227 
00228     // Find the Reactor node of the configuration with the specified ID.
00229     xmlNodePtr reactor_node = m_config_node_ptr->children;
00230     while ( (reactor_node = ConfigManager::findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
00231         std::string node_id;
00232         getNodeId(reactor_node, node_id);
00233         if (node_id == reactor_id)
00234             break;
00235         reactor_node = reactor_node->next;
00236     }
00237     if (reactor_node == NULL)
00238         throw ReactorNotFoundException(reactor_id);
00239 
00240     // Update the X and Y coordinates using the values in config_ptr (if found).
00241     std::string x_coord;
00242     if (ConfigManager::getConfigOption(Reactor::X_COORDINATE_ELEMENT_NAME, x_coord, config_ptr))
00243         if (! ConfigManager::updateConfigOption(Reactor::X_COORDINATE_ELEMENT_NAME, x_coord, reactor_node))
00244             throw UpdateConfigOptionException(reactor_id);
00245     std::string y_coord;
00246     if (ConfigManager::getConfigOption(Reactor::Y_COORDINATE_ELEMENT_NAME, y_coord, config_ptr))
00247         if (! ConfigManager::updateConfigOption(Reactor::Y_COORDINATE_ELEMENT_NAME, y_coord, reactor_node))
00248             throw UpdateConfigOptionException(reactor_id);
00249 
00250     // Update any proxy coordinates found in config_ptr.
00251     const std::string prefix_1 = "Proxy_X_";
00252     const std::string prefix_2 = "Proxy_Y_";
00253     const xmlChar* xmlchar_prefix_1_ptr = reinterpret_cast<const xmlChar*>(prefix_1.c_str());
00254     const xmlChar* xmlchar_prefix_2_ptr = reinterpret_cast<const xmlChar*>(prefix_2.c_str());
00255     for (xmlNodePtr cur_node = config_ptr; cur_node != NULL; cur_node = cur_node->next) {
00256         if (cur_node->type == XML_ELEMENT_NODE) {
00257             if (xmlStrncmp(cur_node->name, xmlchar_prefix_1_ptr, prefix_1.length()) == 0
00258                 || xmlStrncmp(cur_node->name, xmlchar_prefix_2_ptr, prefix_2.length()) == 0)
00259             {
00260                 // The current element tag starts with "Proxy_X_" or "Proxy_Y_", so update reactor_node using its content.
00261                 xmlChar* new_coord_ptr = xmlNodeGetContent(cur_node);
00262                 if (new_coord_ptr != NULL) {
00263                     if (! ConfigManager::updateConfigOption(reinterpret_cast<const char*>(cur_node->name),
00264                                                             reinterpret_cast<const char*>(new_coord_ptr),
00265                                                             reactor_node))
00266                         throw UpdateConfigOptionException(reactor_id);
00267                     xmlFree(new_coord_ptr);
00268                 }
00269             }
00270         }
00271     }
00272 
00273     saveConfigFile();
00274 }
00275 
00276 std::string ReactionEngine::addReactor(const xmlNodePtr config_ptr)
00277 {
00278     return PluginConfig<Reactor>::addPlugin(config_ptr);
00279 }
00280 
00281 void ReactionEngine::removeReactor(const std::string& reactor_id)
00282 {
00283     boost::mutex::scoped_lock engine_lock(m_mutex);
00284 
00285     Reactor *reactor_ptr = m_plugins.get(reactor_id);
00286     if (reactor_ptr == NULL)
00287         throw ReactorNotFoundException(reactor_id);
00288 
00289     // If the Reactor is still running, stop it.
00290     if (reactor_ptr->isRunning()) {
00291         stopReactor(reactor_id);
00292     }
00293 
00294     // disconnect any Reactor connections involving the Reactor being removed
00295     ReactorConnectionList::iterator reactor_i = m_reactor_connections.begin();
00296     while (reactor_i != m_reactor_connections.end()) {
00297         ReactorConnectionList::iterator current_i = reactor_i++;
00298         if (current_i->m_from_id == reactor_id || current_i->m_to_id == reactor_id) {
00299             // remove the connection
00300             removeConnectionNoLock(current_i->m_from_id, current_i->m_to_id);
00301             removeConnectionConfigNoLock(current_i->m_from_id, current_i->m_to_id);
00302             m_reactor_connections.erase(current_i);
00303         }
00304     }
00305     
00306     // disconnect any temporary output connections involving the Reactor being removed
00307     TempConnectionList::iterator connection_i = m_temp_connections.begin();
00308     while (connection_i != m_temp_connections.end()) {
00309         TempConnectionList::iterator current_i = connection_i++;
00310         if (current_i->m_reactor_id == reactor_id) {
00311             if (current_i->m_output_connection) {
00312                 // remove the output connection from the Reactor
00313                 removeConnectionNoLock(current_i->m_reactor_id, current_i->m_connection_id);
00314             }
00315             // send notification that the Reactor is being removed
00316             current_i->m_removed_handler();
00317             // remove the connection
00318             m_temp_connections.erase(current_i);
00319         }
00320     }
00321 
00322     // convert PluginNotFound exceptions into ReactorNotFound exceptions
00323     try {
00324         // remove the Reactor object
00325         engine_lock.unlock();
00326         PluginConfig<Reactor>::removePlugin(reactor_id);
00327     } catch (PluginManager<Reactor>::PluginNotFoundException&) {
00328         throw ReactorNotFoundException(reactor_id);
00329     }
00330 }
00331 
00332 Reactor *ReactionEngine::addTempConnectionIn(const std::string& reactor_id, 
00333                                              const std::string& connection_id,
00334                                              const std::string& connection_info,
00335                                              boost::function0<void> removed_handler)
00336 {
00337     // make sure that the plug-in configuration file is open
00338     if (! configIsOpen())
00339         throw ConfigNotOpenException(getConfigFile());
00340     
00341     // get a pointer to the Reactor to return to the caller
00342     boost::mutex::scoped_lock engine_lock(m_mutex);
00343     Reactor *reactor_ptr = m_plugins.get(reactor_id);
00344     if (reactor_ptr == NULL)
00345         throw ReactorNotFoundException(reactor_id);
00346 
00347     // keep track of the temporary connection
00348     m_temp_connections.push_back(TempConnection(false, reactor_id, connection_id,
00349                                                 connection_info, removed_handler));
00350     
00351     PION_LOG_DEBUG(m_logger, "Added temporary Reactor input connection: "
00352                    << reactor_id << " <- " << connection_info);
00353     
00354     return reactor_ptr;
00355 }
00356 
00357 void ReactionEngine::addTempConnectionOut(const std::string& reactor_id, 
00358                                           const std::string& connection_id,
00359                                           const std::string& connection_info,
00360                                           Reactor::EventHandler connection_handler)
00361 {
00362     // make sure that the plug-in configuration file is open
00363     if (! configIsOpen())
00364         throw ConfigNotOpenException(getConfigFile());
00365     
00366     // connect the Reactor to the connection handler
00367     boost::mutex::scoped_lock engine_lock(m_mutex);
00368     Reactor *reactor_ptr = m_plugins.get(reactor_id);
00369     if (reactor_ptr == NULL)
00370         throw ReactorNotFoundException(reactor_id);
00371     reactor_ptr->addConnection(connection_id, connection_handler);
00372 
00373     // if the Reactor is removed, send a null event to the connection
00374     EventPtr null_event_ptr;
00375     boost::function0<void>  removed_handler(boost::bind(connection_handler, null_event_ptr));
00376                                                     
00377     // keep track of the temporary connection
00378     m_temp_connections.push_back(TempConnection(true, reactor_id, connection_id,
00379                                                 connection_info, removed_handler));
00380     
00381     PION_LOG_DEBUG(m_logger, "Added temporary Reactor output connection: "
00382                    << reactor_id << " -> " << connection_info);
00383 }
00384     
00385 void ReactionEngine::removeTempConnection(const std::string& connection_id)
00386 { 
00387     // make sure that the plug-in configuration file is open
00388     if (! configIsOpen())
00389         throw ConfigNotOpenException(getConfigFile());
00390 
00391     // some variables to keep track of for later
00392     bool type_is_output = true;
00393     std::string reactor_id;
00394     std::string connection_info;
00395 
00396     // remove the connection from memory structures
00397     boost::mutex::scoped_lock engine_lock(m_mutex);
00398     for (TempConnectionList::iterator i = m_temp_connections.begin();
00399          i != m_temp_connections.end(); ++i)
00400     {
00401         if (i->m_connection_id == connection_id) {
00402             type_is_output = i->m_output_connection;
00403             reactor_id = i->m_reactor_id;
00404             connection_info = i->m_connection_info;
00405             m_temp_connections.erase(i);
00406             break;
00407         }
00408     }
00409     
00410     if (! reactor_id.empty()) {
00411         if (type_is_output) {
00412             // remove the output connection from the Reactor
00413             removeConnectionNoLock(reactor_id, connection_id);
00414 
00415             PION_LOG_DEBUG(m_logger, "Removed temporary Reactor output connection: "
00416                            << reactor_id << " -> " << connection_info);
00417         } else {
00418             PION_LOG_DEBUG(m_logger, "Removed temporary Reactor input connection: "
00419                            << reactor_id << " <- " << connection_info);
00420         }
00421     }
00422 }
00423 
00424 void ReactionEngine::startReactor(const std::string& reactor_id)
00425 {
00426     // make sure that the plug-in configuration file is open
00427     if (! configIsOpen())
00428         throw ConfigNotOpenException(getConfigFile());
00429 
00430     // Find the Reactor node of the configuration with the specified ID.
00431     xmlNodePtr reactor_node = m_config_node_ptr->children;
00432     while ( (reactor_node = ConfigManager::findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
00433         std::string node_id;
00434         getNodeId(reactor_node, node_id);
00435         if (node_id == reactor_id)
00436             break;
00437         reactor_node = reactor_node->next;
00438     }
00439     if (reactor_node == NULL)
00440         throw ReactorNotFoundException(reactor_id);
00441 
00442     // Start the reactor.
00443     m_plugins.run(reactor_id, boost::bind(&Reactor::start, _1));
00444 
00445     // Update the Reactor's run status and save the configuration file.
00446     if (! ConfigManager::updateConfigOption(Reactor::RUNNING_ELEMENT_NAME, "true", reactor_node))
00447         throw UpdateConfigOptionException(reactor_id);
00448     saveConfigFile();
00449 }
00450 
00451 void ReactionEngine::stopReactor(const std::string& reactor_id)
00452 {
00453     // make sure that the plug-in configuration file is open
00454     if (! configIsOpen())
00455         throw ConfigNotOpenException(getConfigFile());
00456 
00457     // Find the Reactor node of the configuration with the specified ID.
00458     xmlNodePtr reactor_node = m_config_node_ptr->children;
00459     while ( (reactor_node = ConfigManager::findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
00460         std::string node_id;
00461         getNodeId(reactor_node, node_id);
00462         if (node_id == reactor_id)
00463             break;
00464         reactor_node = reactor_node->next;
00465     }
00466     if (reactor_node == NULL)
00467         throw ReactorNotFoundException(reactor_id);
00468 
00469     // Stop the reactor.
00470     m_plugins.run(reactor_id, boost::bind(&Reactor::stop, _1));
00471 
00472     // Update the Reactor's run status and save the configuration file.
00473     if (! ConfigManager::updateConfigOption(Reactor::RUNNING_ELEMENT_NAME, "false", reactor_node))
00474         throw UpdateConfigOptionException(reactor_id);
00475     saveConfigFile();
00476 }
00477 
00478 std::string ReactionEngine::addReactorConnection(const std::string& from_id,
00479                                                  const std::string& to_id)
00480 {
00481     // make sure that the plug-in configuration file is open
00482     if (! configIsOpen())
00483         throw ConfigNotOpenException(getConfigFile());
00484     
00485     // generate a unique identifier to represent the connection
00486     const std::string connection_id(ConfigManager::createUUID());
00487     
00488     // add the connection to memory structures
00489     boost::mutex::scoped_lock engine_lock(m_mutex);
00490     addConnectionNoLock(connection_id, from_id, to_id);
00491     
00492     // add the connection to the config file
00493     
00494     // create a new node for the connection and add it to the XML config document
00495     xmlNodePtr connection_node = xmlNewNode(NULL, reinterpret_cast<const xmlChar*>(CONNECTION_ELEMENT_NAME.c_str()));
00496     if (connection_node == NULL)
00497         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00498     if ((connection_node=xmlAddChild(m_config_node_ptr, connection_node)) == NULL) {
00499         xmlFreeNode(connection_node);
00500         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00501     }
00502 
00503     // add the "id" attribute
00504     if (xmlNewProp(connection_node,
00505                    reinterpret_cast<const xmlChar*>(ID_ATTRIBUTE_NAME.c_str()),
00506                    reinterpret_cast<const xmlChar*>(connection_id.c_str())) == NULL)
00507         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00508     
00509     // add a "Type" child element to the connection
00510     if (xmlNewTextChild(connection_node, NULL,
00511                         reinterpret_cast<const xmlChar*>(TYPE_ELEMENT_NAME.c_str()),
00512                         reinterpret_cast<const xmlChar*>(CONNECTION_TYPE_REACTOR.c_str())) == NULL)
00513         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00514     
00515     // add a "From" child element to the connection
00516     if (xmlNewTextChild(connection_node, NULL,
00517                         reinterpret_cast<const xmlChar*>(FROM_ELEMENT_NAME.c_str()),
00518                         reinterpret_cast<const xmlChar*>(from_id.c_str())) == NULL)
00519         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00520     
00521     // add a "To" child element to the connection
00522     if (xmlNewTextChild(connection_node, NULL,
00523                         reinterpret_cast<const xmlChar*>(TO_ELEMENT_NAME.c_str()),
00524                         reinterpret_cast<const xmlChar*>(to_id.c_str())) == NULL)
00525         throw AddConnectionConfigException(getConnectionAsText(from_id, to_id));
00526     
00527     // save the new XML config file
00528     saveConfigFile();
00529     
00530     PION_LOG_DEBUG(m_logger, "Added reactor connection: " << from_id << " -> " << to_id);
00531     
00532     return connection_id;
00533 }
00534 
00535 std::string ReactionEngine::addReactorConnection(const xmlNodePtr config_ptr)
00536 {
00537     // get the "From" value
00538     std::string from_id;
00539     if (! ConfigManager::getConfigOption(FROM_ELEMENT_NAME, from_id, config_ptr))
00540         throw BadConnectionConfigException();
00541     
00542     // get the "To" value
00543     std::string to_id;
00544     if (! ConfigManager::getConfigOption(TO_ELEMENT_NAME, to_id, config_ptr))
00545         throw BadConnectionConfigException();
00546     
00547     // call addReactorConnection() to do the real work
00548     return addReactorConnection(from_id, to_id);
00549 }
00550 
00551 void ReactionEngine::removeReactorConnection(const std::string& from_id,
00552                                              const std::string& to_id)
00553 {
00554     // make sure that the plug-in configuration file is open
00555     if (! configIsOpen())
00556         throw ConfigNotOpenException(getConfigFile());
00557 
00558     // remove the connection from memory structures
00559     boost::mutex::scoped_lock engine_lock(m_mutex);
00560     removeConnectionNoLock(from_id, to_id);
00561     for (ReactorConnectionList::iterator i = m_reactor_connections.begin();
00562          i != m_reactor_connections.end(); ++i)
00563     {
00564         if (i->m_from_id == from_id && i->m_to_id == to_id) {
00565             m_reactor_connections.erase(i);
00566             break;
00567         }
00568     }
00569     
00570     // remove the connection from the config file
00571     removeConnectionConfigNoLock(from_id, to_id);
00572     
00573     PION_LOG_DEBUG(m_logger, "Removed reactor connection: " << from_id << " -> " << to_id);
00574 }
00575     
00576 void ReactionEngine::removeReactorConnection(const std::string& connection_id)
00577 {
00578     // make sure that the plug-in configuration file is open
00579     if (! configIsOpen())
00580         throw ConfigNotOpenException(getConfigFile());
00581     
00582     // find the connection in our memory structures
00583     boost::mutex::scoped_lock engine_lock(m_mutex);
00584     ReactorConnectionList::iterator i = m_reactor_connections.begin();
00585     while (i != m_reactor_connections.end()) {
00586         if (i->m_connection_id == connection_id)
00587             break;
00588         ++i;
00589     }
00590     if (i == m_reactor_connections.end())
00591         throw ConnectionNotFoundException(connection_id);
00592     
00593     // remove the connection between the reactors
00594     removeConnectionNoLock(i->m_from_id, i->m_to_id);
00595     
00596     // remove the connection from the config file
00597     removeConnectionConfigNoLock(i->m_from_id, i->m_to_id);
00598     
00599     PION_LOG_DEBUG(m_logger, "Removed reactor connection: "
00600                    << i->m_from_id << " -> " << i->m_to_id);
00601 
00602     // remove the connection from memory structures
00603     m_reactor_connections.erase(i);
00604 }
00605 
00606 void ReactionEngine::addConnectionNoLock(const std::string& connection_id,
00607                                          const std::string& from_id,
00608                                          const std::string& to_id)
00609 {
00610     // find the source Reactor
00611     Reactor *from_ptr = m_plugins.get(from_id);
00612     if (from_ptr == NULL)
00613         throw ReactorNotFoundException(from_id);
00614 
00615     // find the destination Reactor
00616     Reactor *to_ptr = m_plugins.get(to_id);
00617     if (to_ptr == NULL)
00618         throw ReactorNotFoundException(to_id);
00619     
00620     // connect them together
00621     from_ptr->addConnection(*to_ptr);
00622 
00623     // keep track of all Reactor connections
00624     m_reactor_connections.push_back(ReactorConnection(connection_id, from_id, to_id));
00625 }
00626 
00627 void ReactionEngine::removeConnectionNoLock(const std::string& reactor_id,
00628                                             const std::string& connection_id)
00629 {
00630     // find the source Reactor
00631     Reactor *from_ptr = m_plugins.get(reactor_id);
00632     if (from_ptr == NULL)
00633         throw ReactorNotFoundException(reactor_id);
00634 
00635     // remove the connection
00636     from_ptr->removeConnection(connection_id);
00637 }
00638 
00639 void ReactionEngine::removeConnectionConfigNoLock(const std::string& from_id,
00640                                                   const std::string& to_id)
00641 {
00642     // step through each connection to find the right one
00643     xmlNodePtr connection_node = m_config_node_ptr->children;
00644     while ( (connection_node = ConfigManager::findConfigNodeByName(CONNECTION_ELEMENT_NAME, connection_node)) != NULL)
00645     {
00646         // get the "From" and "To" connection identifiers
00647         std::string node_from_id;
00648         std::string node_to_id;
00649         ConfigManager::getConfigOption(FROM_ELEMENT_NAME, node_from_id, connection_node->children);
00650         ConfigManager::getConfigOption(TO_ELEMENT_NAME, node_to_id, connection_node->children);
00651         
00652         // check if this is the connection we want to remove
00653         if (from_id == node_from_id && to_id == node_to_id) {
00654             // found it!
00655             break;
00656         }
00657         
00658         // step to the next Reactor connection
00659         connection_node = connection_node->next;
00660     }
00661     
00662     // throw exception if connection was not found
00663     if (connection_node == NULL)
00664         throw RemoveConnectionConfigException(getConnectionAsText(from_id, to_id));
00665     
00666     // remove the connection from the XML tree
00667     xmlUnlinkNode(connection_node);
00668     xmlFreeNode(connection_node);
00669     
00670     // save the new XML config file
00671     saveConfigFile();
00672 }
00673 
00674 std::string ReactionEngine::addWorkspace(const char* content_buf, std::size_t content_length)
00675 {
00676     // make sure that the plug-in configuration file is open
00677     if (! configIsOpen())
00678         throw ConfigNotOpenException(getConfigFile());
00679 
00680     // generate a unique identifier to represent the Workspace
00681     const std::string workspace_id(ConfigManager::createUUID());
00682 
00683     boost::mutex::scoped_lock engine_lock(m_mutex);
00684 
00685     // create a new node for the Workspace and add it to the XML config document
00686     xmlNodePtr workspace_node = xmlNewNode(NULL, reinterpret_cast<const xmlChar*>(Reactor::WORKSPACE_ELEMENT_NAME.c_str()));
00687     if (workspace_node == NULL)
00688         throw AddWorkspaceConfigException();
00689     if ((workspace_node = xmlAddChild(m_config_node_ptr, workspace_node)) == NULL) {
00690         xmlFreeNode(workspace_node);
00691         throw AddWorkspaceConfigException();
00692     }
00693 
00694     // add the "id" attribute
00695     if (xmlNewProp(workspace_node,
00696                    reinterpret_cast<const xmlChar*>(ID_ATTRIBUTE_NAME.c_str()),
00697                    reinterpret_cast<const xmlChar*>(workspace_id.c_str())) == NULL)
00698         throw AddWorkspaceConfigException();
00699 
00700     setWorkspaceConfig(workspace_node, content_buf, content_length);
00701 
00702     // save the new XML config file
00703     saveConfigFile();
00704 
00705     PION_LOG_DEBUG(m_logger, "Added Reactor Workspace: " << workspace_id);
00706 
00707     return workspace_id;
00708 }
00709 
00710 void ReactionEngine::removeReactorsFromWorkspace(const std::string& workspace_id)
00711 {
00712     // make sure that the plug-in configuration file is open
00713     if (! configIsOpen())
00714         throw ConfigNotOpenException(getConfigFile());
00715 
00716     if (! hasWorkspace(workspace_id))
00717         throw WorkspaceNotFoundException(workspace_id);
00718 
00719     boost::mutex::scoped_lock engine_lock(m_mutex);
00720 
00721     // Make a list of IDs of all the Reactors in the Workspace.
00722     std::vector<std::string> reactors_in_workspace;
00723 
00724     // Step through each Reactor config node.
00725     xmlNodePtr reactor_node = m_config_node_ptr->children;
00726     while ( (reactor_node = findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
00727         std::string workspace_str;
00728         if (ConfigManager::getConfigOption(Reactor::WORKSPACE_ELEMENT_NAME, workspace_str, reactor_node->children)) {
00729             if (workspace_str == workspace_id) {
00730                 std::string reactor_id;
00731                 if (! getNodeId(reactor_node, reactor_id))
00732                     throw EmptyPluginIdException(getConfigFile());
00733                 reactors_in_workspace.push_back(reactor_id);
00734             }
00735         }
00736 
00737         // look for more reactor config nodes
00738         reactor_node = reactor_node->next;
00739     }
00740 
00741     // Remove all the Reactors that were found.
00742     engine_lock.unlock();
00743     std::for_each(reactors_in_workspace.begin(), reactors_in_workspace.end(), boost::bind(&ReactionEngine::removeReactor, this, _1));
00744 }
00745 
00746 void ReactionEngine::removeWorkspace(const std::string& workspace_id)
00747 {
00748     // make sure that the plug-in configuration file is open
00749     if (! configIsOpen())
00750         throw ConfigNotOpenException(getConfigFile());
00751 
00752     // Find existing Workspace configuration.
00753     boost::mutex::scoped_lock engine_lock(m_mutex);
00754     xmlNodePtr workspace_node = findConfigNodeByAttr(Reactor::WORKSPACE_ELEMENT_NAME,
00755                                                      ID_ATTRIBUTE_NAME,
00756                                                      workspace_id,
00757                                                      m_config_node_ptr->children);
00758 
00759     if (workspace_node == NULL)
00760         throw WorkspaceNotFoundException(workspace_id);
00761 
00762     // Determine whether the Workspace is empty by stepping through the Reactor config nodes and checking the Workspace IDs.
00763     bool empty = true;
00764     xmlNodePtr reactor_node = m_config_node_ptr->children;
00765     while ( (reactor_node = findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
00766         std::string workspace_str;
00767         if (ConfigManager::getConfigOption(Reactor::WORKSPACE_ELEMENT_NAME, workspace_str, reactor_node->children)) {
00768             if (workspace_str == workspace_id) {
00769                 empty = false;
00770                 break;
00771             }
00772         }
00773 
00774         // look for more reactor config nodes
00775         reactor_node = reactor_node->next;
00776     }
00777 
00778     if (! empty)
00779         throw RemoveNonEmptyWorkspaceException(workspace_id);
00780 
00781     // remove the connection from the XML tree
00782     xmlUnlinkNode(workspace_node);
00783     xmlFreeNode(workspace_node);
00784 
00785     // save the new XML config file
00786     saveConfigFile();
00787 
00788     PION_LOG_DEBUG(m_logger, "Removed Reactor Workspace: " << workspace_id);
00789 }
00790 
00791 void ReactionEngine::setWorkspaceConfig(const std::string& workspace_id, const char* content_buf, std::size_t content_length)
00792 {
00793     // Find existing Workspace configuration.
00794     boost::mutex::scoped_lock engine_lock(m_mutex);
00795     xmlNodePtr workspace_node = findConfigNodeByAttr(Reactor::WORKSPACE_ELEMENT_NAME,
00796                                                      ID_ATTRIBUTE_NAME,
00797                                                      workspace_id,
00798                                                      m_config_node_ptr->children);
00799 
00800     if (workspace_node == NULL)
00801         throw WorkspaceNotFoundException(workspace_id);
00802 
00803     // update the configuration in the XML tree
00804     setWorkspaceConfig(workspace_node, content_buf, content_length);
00805 
00806     // save the new XML config file
00807     saveConfigFile();
00808 }
00809 
00810 void ReactionEngine::setWorkspaceConfig(xmlNodePtr workspace_node, const char* content_buf, std::size_t content_length)
00811 {
00812     // extract the XML config info from the content buffer
00813     xmlNodePtr config_ptr = ConfigManager::createResourceConfig(Reactor::WORKSPACE_ELEMENT_NAME,
00814                                                                 content_buf,
00815                                                                 content_length);
00816     if (config_ptr == NULL)
00817         throw BadWorkspaceConfigException();
00818 
00819     // try to get the "Name" value, and if found, update the "Name" element in the Workspace node
00820     std::string name;
00821     if (ConfigManager::getConfigOption(ConfigManager::NAME_ELEMENT_NAME, name, config_ptr)) {
00822         if (! ConfigManager::updateConfigOption(ConfigManager::NAME_ELEMENT_NAME, name, workspace_node)) {
00823             xmlFreeNodeList(config_ptr);
00824             throw SetWorkspaceConfigException();
00825         }
00826     }
00827 
00828     // try to get the "Comment" value, and if found, update the "Comment" element in the Workspace node
00829     std::string comment;
00830     if (ConfigManager::getConfigOption(ConfigManager::COMMENT_ELEMENT_NAME, comment, config_ptr)) {
00831         if (! ConfigManager::updateConfigOption(ConfigManager::COMMENT_ELEMENT_NAME, comment, workspace_node)) {
00832             xmlFreeNodeList(config_ptr);
00833             throw SetWorkspaceConfigException();
00834         }
00835     }
00836     
00837     xmlFreeNodeList(config_ptr);
00838 }
00839 
00840 void ReactionEngine::stopNoLock(void)
00841 {
00842     if (m_is_running) {
00843         PION_LOG_INFO(m_logger, "Stopping the ReactionEngine");
00844 
00845         // terminate all temporary connections
00846         for (TempConnectionList::iterator i = m_temp_connections.begin();
00847              i != m_temp_connections.end(); ++i)
00848         {
00849             if (i->m_output_connection) {
00850                 // remove the output connection from the Reactor
00851                 removeConnectionNoLock(i->m_reactor_id, i->m_connection_id);
00852             }
00853             // send notification that the Reactor is being removed
00854             i->m_removed_handler();
00855         }
00856         m_temp_connections.clear();
00857         
00858         // stop all reactors
00859         PION_LOG_INFO(m_logger, "Stopping all reactors");
00860         m_plugins.run(boost::bind(&Reactor::stop, _1));
00861 
00862         // notify the thread scheduler that we no longer need it
00863         m_scheduler.removeActiveUser();
00864 
00865         m_is_running = false;
00866     }
00867 }
00868 
00869 void ReactionEngine::writeStatsXML(std::ostream& out, const std::string& only_id, const bool details)
00870 {
00871     writeBeginPionStatsXML(out);
00872 
00873     const Reactor::QueryBranches branches;
00874     const Reactor::QueryParams qp;
00875     boost::mutex::scoped_lock engine_lock(m_mutex);
00876 
00877     if (only_id.empty()) {
00878         // step through each reactor configured
00879         std::string reactor_id;
00880         Reactor *reactor_ptr;
00881         xmlNodePtr reactor_node = m_config_node_ptr->children;
00882         while ( (reactor_node = ConfigManager::findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL)
00883         {
00884             // get a pointer to the reactor
00885             if (getNodeId(reactor_node, reactor_id)
00886                 && (reactor_ptr = m_plugins.get(reactor_id)) != NULL)
00887             {
00888                 // write reactor statistics
00889                 if (details) {
00890                     reactor_ptr->query(out, branches, qp);
00891                 } else {
00892                     reactor_ptr->writeStatsXML(out);
00893                 }
00894             }
00895             // step to the next Reactor
00896             reactor_node = reactor_node->next;
00897         }
00898 
00899         // write total operations
00900         out << "\t<" << TOTAL_OPS_ELEMENT_NAME << '>' << getTotalOperations()
00901             << "</" << TOTAL_OPS_ELEMENT_NAME << '>' << std::endl;
00902 
00903         // write events queued
00904         out << "\t<" << EVENTS_QUEUED_ELEMENT_NAME << '>' << getEventsQueued()
00905             << "</" << EVENTS_QUEUED_ELEMENT_NAME << '>' << std::endl;
00906             
00907     } else {
00908         // get a pointer to the reactor
00909         Reactor *reactor_ptr = m_plugins.get(only_id);
00910 
00911         // write reactor statistics
00912         if (details) {
00913             reactor_ptr->query(out, branches, qp);
00914         } else {
00915             reactor_ptr->writeStatsXML(out);
00916         }
00917     }
00918     
00919     writeEndPionStatsXML(out);
00920 }
00921 
00922 void ReactionEngine::writeConnectionsXML(std::ostream& out,
00923                                          const std::string& only_id) const
00924 {
00925     ConfigManager::writeBeginPionConfigXML(out);
00926     
00927     bool found_one = false;
00928     boost::mutex::scoped_lock engine_lock(m_mutex);
00929 
00930     // iterate through Reactor connections
00931     for (ReactorConnectionList::const_iterator reactor_i = m_reactor_connections.begin();
00932          reactor_i != m_reactor_connections.end(); ++reactor_i)
00933     {
00934         if (only_id.empty() || reactor_i->m_connection_id == only_id
00935             || reactor_i->m_from_id == only_id || reactor_i->m_to_id == only_id)
00936         {
00937             found_one = true;
00938             out << "\t<" << CONNECTION_ELEMENT_NAME << ' ' << ID_ATTRIBUTE_NAME
00939                 << "=\"" << reactor_i->m_connection_id << "\">" << std::endl
00940                 << "\t\t<" << TYPE_ELEMENT_NAME << '>' << CONNECTION_TYPE_REACTOR
00941                 << "</" << TYPE_ELEMENT_NAME << '>' << std::endl
00942                 << "\t\t<" << FROM_ELEMENT_NAME << '>' << reactor_i->m_from_id << "</"
00943                 << FROM_ELEMENT_NAME << '>' << std::endl
00944                 << "\t\t<" << TO_ELEMENT_NAME << '>' << reactor_i->m_to_id << "</"
00945                 << TO_ELEMENT_NAME << '>' << std::endl
00946                 << "\t</" << CONNECTION_ELEMENT_NAME << '>' << std::endl;
00947         }
00948     }
00949 
00950     // iterate through temporary connections
00951     for (TempConnectionList::const_iterator temp_i = m_temp_connections.begin();
00952          temp_i != m_temp_connections.end(); ++temp_i)
00953     {
00954         if (only_id.empty() || temp_i->m_connection_id == only_id
00955             || temp_i->m_reactor_id == only_id)
00956         {
00957             found_one = true;
00958             out << "\t<" << CONNECTION_ELEMENT_NAME << ' ' << ID_ATTRIBUTE_NAME
00959                 << "=\"" << temp_i->m_connection_id << "\">" << std::endl
00960                 << "\t\t<" << TYPE_ELEMENT_NAME << '>';
00961             if (temp_i->m_output_connection) {
00962                 out << CONNECTION_TYPE_OUTPUT << "</" << TYPE_ELEMENT_NAME << '>' << std::endl
00963                     << "\t\t<" << FROM_ELEMENT_NAME << '>' << temp_i->m_reactor_id
00964                     << "</" << FROM_ELEMENT_NAME << '>' << std::endl
00965                     << "\t\t<" << TO_ELEMENT_NAME << '>' << temp_i->m_connection_info;
00966             } else {
00967                 out << CONNECTION_TYPE_INPUT << "</" << TYPE_ELEMENT_NAME << '>' << std::endl
00968                     << "\t\t<" << FROM_ELEMENT_NAME << '>' << temp_i->m_connection_info
00969                     << "</" << FROM_ELEMENT_NAME << '>' << std::endl
00970                     << "\t\t<" << TO_ELEMENT_NAME << '>' << temp_i->m_reactor_id;
00971             }
00972             out << "</" << TO_ELEMENT_NAME << '>' << std::endl
00973                 << "\t</" << CONNECTION_ELEMENT_NAME << '>' << std::endl;
00974         }
00975     }
00976 
00977     if (! found_one && ! only_id.empty())
00978         throw ConnectionNotFoundException(only_id);
00979     
00980     ConfigManager::writeEndPionConfigXML(out);
00981 }
00982 
00983 bool ReactionEngine::writeWorkspaceXML(std::ostream& out,
00984                                        const std::string& workspace_id) const
00985 {
00986     // find the Workspace element with the specified ID in the XML config document
00987     boost::mutex::scoped_lock engine_lock(m_mutex);
00988     xmlNodePtr workspace_node = findConfigNodeByAttr(Reactor::WORKSPACE_ELEMENT_NAME,
00989                                                      ID_ATTRIBUTE_NAME,
00990                                                      workspace_id,
00991                                                      m_config_node_ptr->children);
00992     if (workspace_node == NULL)
00993         return false;
00994 
00995     // found it
00996     ConfigManager::writeBeginPionConfigXML(out);
00997     ConfigManager::writeConfigXML(out, workspace_node, false);
00998     ConfigManager::writeEndPionConfigXML(out);
00999 
01000     return true;
01001 }
01002 
01003 void ReactionEngine::writeWorkspacesXML(std::ostream& out) const
01004 {
01005     boost::mutex::scoped_lock engine_lock(m_mutex);
01006     ConfigManager::writeBeginPionConfigXML(out);
01007 
01008     // step through Workspace configurations
01009     xmlNodePtr workspace_node = m_config_node_ptr->children;
01010     while ( (workspace_node = ConfigManager::findConfigNodeByName(Reactor::WORKSPACE_ELEMENT_NAME, workspace_node)) != NULL) {
01011         ConfigManager::writeConfigXML(out, workspace_node, false);
01012         workspace_node = workspace_node->next;
01013     }
01014 
01015     ConfigManager::writeEndPionConfigXML(out);
01016 }
01017 
01018 bool ReactionEngine::hasWorkspace(const std::string& workspace_id) const
01019 {
01020     xmlNodePtr workspace_node = findConfigNodeByAttr(Reactor::WORKSPACE_ELEMENT_NAME,
01021                                                      ID_ATTRIBUTE_NAME,
01022                                                      workspace_id,
01023                                                      m_config_node_ptr->children);
01024     return workspace_node != NULL;
01025 }
01026 
01027 bool ReactionEngine::writeWorkspaceLimitedConfigXML(std::ostream& out, const std::string& workspace_id) const {
01028     // find the Workspace element with the specified ID in the XML config document
01029     boost::mutex::scoped_lock engine_lock(m_mutex);
01030     xmlNodePtr workspace_node = findConfigNodeByAttr(Reactor::WORKSPACE_ELEMENT_NAME,
01031                                                      ID_ATTRIBUTE_NAME,
01032                                                      workspace_id,
01033                                                      m_config_node_ptr->children);
01034     if (workspace_node == NULL)
01035         return false;
01036 
01037     ConfigManager::writeBeginPionConfigXML(out);
01038 
01039     // step through each Reactor config node
01040     xmlNodePtr reactor_node = m_config_node_ptr->children;
01041     while ( (reactor_node = findConfigNodeByName(Reactor::REACTOR_ELEMENT_NAME, reactor_node)) != NULL) {
01042         std::string workspace_str;
01043         if (ConfigManager::getConfigOption(Reactor::WORKSPACE_ELEMENT_NAME, workspace_str, reactor_node->children)) {
01044             if (workspace_str == workspace_id)
01045                 ConfigManager::writeConfigXML(out, reactor_node);
01046         }
01047 
01048         // look for more reactor config nodes
01049         reactor_node = reactor_node->next;
01050     }
01051 
01052     // Step through each Connection config node, and if it has either a source Reactor or sink Reactor
01053     // in the specified Workspace, output the configuration.
01054     xmlNodePtr connection_node = m_config_node_ptr->children;
01055     while ( (connection_node = findConfigNodeByName(CONNECTION_ELEMENT_NAME, connection_node)) != NULL) {
01056         std::string source_reactor_id;
01057         if (ConfigManager::getConfigOption(FROM_ELEMENT_NAME, source_reactor_id, connection_node->children)) {
01058             const Reactor* source_reactor_ptr = m_plugins.get(source_reactor_id);
01059             if (source_reactor_ptr == NULL)
01060                 throw ReactorNotFoundException(source_reactor_id);
01061 
01062             if (source_reactor_ptr->getWorkspace() == workspace_id) {
01063                 ConfigManager::writeConfigXML(out, connection_node);
01064             } else {
01065                 std::string sink_reactor_id;
01066                 if (ConfigManager::getConfigOption(TO_ELEMENT_NAME, sink_reactor_id, connection_node->children)) {
01067                     const Reactor* sink_reactor_ptr = m_plugins.get(sink_reactor_id);
01068                     if (sink_reactor_ptr == NULL)
01069                         throw ReactorNotFoundException(sink_reactor_id);
01070 
01071                     if (sink_reactor_ptr->getWorkspace() == workspace_id)
01072                         ConfigManager::writeConfigXML(out, connection_node);
01073                 }
01074             }
01075         }
01076 
01077         // look for more Connection config nodes
01078         connection_node = connection_node->next;
01079     }
01080 
01081     ConfigManager::writeEndPionConfigXML(out);
01082 
01083     return true;
01084 }
01085 
01086 bool ReactionEngine::creationAllowed(xmlNodePtr permission_config_ptr, xmlNodePtr config_ptr) const
01087 {
01088     if (permission_config_ptr == NULL)
01089         return false;
01090 
01091     if (ConfigManager::findConfigNodeByContent(UNRESTRICTED_ELEMENT_NAME, "true", permission_config_ptr->children))
01092         return true;    // The User has full privileges for Reactors.
01093 
01094     if (config_ptr == NULL)
01095         return false;   // Since the User is restricted, the actual configuration is needed to determine permission.
01096 
01097     // Handle according to whether config_ptr is for a Reactor, Connection or Workspace.
01098     // Since we only have the children of the configuration node, we'll check for distinguishing child nodes.
01099     if (findConfigNodeByName(PLUGIN_ELEMENT_NAME, config_ptr) != NULL) {
01100         // config_ptr is for a Reactor
01101 
01102         std::string workspace_id;
01103         if (! ConfigManager::getConfigOption(Reactor::WORKSPACE_ELEMENT_NAME, workspace_id, config_ptr))
01104             throw Reactor::MissingWorkspaceException();
01105         if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME, workspace_id, permission_config_ptr->children))
01106             return true;    // The User has permission to create Reactors in the specified Workspace.
01107     } else if (findConfigNodeByName(FROM_ELEMENT_NAME, config_ptr) != NULL) {
01108         // config_ptr is for a Connection
01109 
01110         std::string source_reactor_id;
01111         if (! ConfigManager::getConfigOption(FROM_ELEMENT_NAME, source_reactor_id, config_ptr))
01112             throw BadConnectionConfigException();
01113         std::string sink_reactor_id;
01114         if (! ConfigManager::getConfigOption(TO_ELEMENT_NAME, sink_reactor_id, config_ptr))
01115             throw BadConnectionConfigException();
01116 
01117         const Reactor* source_reactor_ptr = m_plugins.get(source_reactor_id);
01118         if (source_reactor_ptr == NULL)
01119             throw ReactorNotFoundException(source_reactor_id);
01120         const Reactor* sink_reactor_ptr = m_plugins.get(sink_reactor_id);
01121         if (sink_reactor_ptr == NULL)
01122             throw ReactorNotFoundException(sink_reactor_id);
01123 
01124         if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME,
01125                                                    source_reactor_ptr->getWorkspace(),
01126                                                    permission_config_ptr->children) 
01127             && ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME,
01128                                                       sink_reactor_ptr->getWorkspace(),
01129                                                       permission_config_ptr->children)) {
01130             return true;    // The User has permission to modify both Reactors, so a Connection between them is allowed.
01131         }
01132 
01133     } else {
01134         // config_ptr is for a Workspace
01135 
01136         return false;   // Creating a new Workspace requires full privileges for Reactors.
01137     }
01138 
01139     return false;
01140 }
01141 
01142 bool ReactionEngine::updateAllowed(xmlNodePtr permission_config_ptr, const std::string& id, xmlNodePtr config_ptr) const
01143 {
01144     if (permission_config_ptr == NULL)
01145         return false;
01146 
01147     if (ConfigManager::findConfigNodeByContent(UNRESTRICTED_ELEMENT_NAME, "true", permission_config_ptr->children))
01148         return true;    // The User has full privileges for Reactors.
01149 
01150     if (hasPlugin(id)) {
01151         // id is a Reactor ID, so we need to check the Workspace IDs of both the current and requested configurations.
01152 
01153         if (config_ptr == NULL)
01154             return false;   // Since the User is restricted, the actual configuration is needed to determine permission.
01155 
01156         const Reactor* reactor_ptr = m_plugins.get(id);
01157         if (reactor_ptr == NULL)
01158             throw ReactorNotFoundException(id);
01159 
01160         // Does the User have permission for the Workspace that the specified Reactor is currently in?
01161         if (ConfigManager::findConfigNodeByContent(ReactionEngine::WORKSPACE_QUALIFIER_ELEMENT_NAME, reactor_ptr->getWorkspace(), permission_config_ptr->children)) {
01162             // Does the User have permission for the Workspace specified in the new Reactor configuration?
01163             std::string workspace_id;
01164             if (! ConfigManager::getConfigOption(Reactor::WORKSPACE_ELEMENT_NAME, workspace_id, config_ptr))
01165                 throw Reactor::MissingWorkspaceException();
01166             if (ConfigManager::findConfigNodeByContent(ReactionEngine::WORKSPACE_QUALIFIER_ELEMENT_NAME, workspace_id, permission_config_ptr->children))
01167                 return true;
01168         }
01169     } else if (hasWorkspace(id)) {
01170         // id is a Workspace ID, so we just need to check whether the user has permission for this Workspace
01171 
01172         if (ConfigManager::findConfigNodeByContent(ReactionEngine::WORKSPACE_QUALIFIER_ELEMENT_NAME, id, permission_config_ptr->children))
01173             return true;
01174     }
01175 
01176     return false;
01177 }
01178 
01179 bool ReactionEngine::removalAllowed(xmlNodePtr permission_config_ptr, const std::string& id) const
01180 {
01181     if (permission_config_ptr == NULL)
01182         return false;
01183 
01184     if (ConfigManager::findConfigNodeByContent(UNRESTRICTED_ELEMENT_NAME, "true", permission_config_ptr->children))
01185         return true;    // The User has full privileges for Reactors.
01186 
01187     // Handle according to whether id is for a Reactor, Connection or Workspace.
01188     if (hasPlugin(id)) {
01189         // id is for a Reactor.
01190 
01191         std::string workspace_id = m_plugins.get(id)->getWorkspace();
01192         if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME, workspace_id, permission_config_ptr->children))
01193             return true;    // The User has permission for the Workspace of the specified Reactor.
01194     } else if (hasWorkspace(id)) {
01195         // id is for a Workspace.
01196 
01197         if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME, id, permission_config_ptr->children))
01198             return true;    // The User has permission for the specified Workspace.
01199     } else {
01200         // Check if id is for a Connection.
01201 
01202         ReactorConnectionList::const_iterator i = m_reactor_connections.begin();
01203         while (i != m_reactor_connections.end()) {
01204             if (i->m_connection_id == id)
01205                 break;
01206             ++i;
01207         }
01208         if (i == m_reactor_connections.end())
01209             return false;   // The id is not for a Reactor, Connection or Workspace, so don't grant permission.
01210 
01211         // id is for a Connection.
01212 
01213         const Reactor* source_reactor_ptr = m_plugins.get(i->m_from_id);
01214         if (source_reactor_ptr == NULL)
01215             throw ReactorNotFoundException(i->m_from_id);
01216         const Reactor* sink_reactor_ptr = m_plugins.get(i->m_to_id);
01217         if (sink_reactor_ptr == NULL)
01218             throw ReactorNotFoundException(i->m_to_id);
01219 
01220         if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME,
01221                                                    source_reactor_ptr->getWorkspace(),
01222                                                    permission_config_ptr->children) 
01223             && ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME,
01224                                                       sink_reactor_ptr->getWorkspace(),
01225                                                       permission_config_ptr->children)) {
01226             return true;    // The User has permission to modify both Reactors, so removing a Connection between them is allowed.
01227         }
01228     }
01229 
01230     return false;
01231 }
01232 
01233 bool ReactionEngine::accessAllowed(xmlNodePtr permission_config_ptr, const std::string& reactor_id) const
01234 {
01235     if (permission_config_ptr == NULL)
01236         return false;
01237 
01238     if (reactor_id.empty())
01239         return true;
01240 
01241     if (ConfigManager::findConfigNodeByContent(UNRESTRICTED_ELEMENT_NAME, "true", permission_config_ptr->children))
01242         return true;    // The User has full privileges for Reactors.
01243 
01244     // Get the Workspace of the specified Reactor.
01245     const Reactor* reactor_ptr = m_plugins.get(reactor_id);
01246     if (reactor_ptr == NULL)
01247         throw ReactorNotFoundException(reactor_id);
01248     std::string workspace_id = reactor_ptr->getWorkspace();
01249 
01250     // Does the User have permission for the Workspace?
01251     if (ConfigManager::findConfigNodeByContent(WORKSPACE_QUALIFIER_ELEMENT_NAME, workspace_id, permission_config_ptr->children))
01252         return true;
01253 
01254     return false;
01255 }
01256 
01257 
01258 }   // end namespace platform
01259 }   // end namespace pion

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7