FesaDeviceServer.cpp

Go to the documentation of this file.
00001 // Copyright CERN 2012 - Developed in collaboration with GSI
00002 
00003 #include <fesa-core/RDADeviceServer/FesaDeviceServer.h>
00004 
00005 #include <fesa-core/RDADeviceServer/SubscriptionTreeManager.h>
00006 #include <fesa-core/Core/AbstractEquipment.h>
00007 #include <fesa-core/Core/FesaDefs.h>
00008 #include <fesa-core/Core/ThreadPriorityConfiguration.h>
00009 #include <fesa-core/DataStore/AbstractDevice.h>
00010 #include <fesa-core/DataStore/AbstractDeviceFactory.h>
00011 #include <fesa-core/DataStore/EquipmentData.h>
00012 #include <fesa-core/DataStore/GlobalDevice.h>
00013 #include <fesa-core/Diagnostic/Diagnostics.h>
00014 #include <fesa-core/Exception/FesaException.h>
00015 #include <fesa-core/Server/AbstractServerDeviceClass.h>
00016 #include <fesa-core/Server/AbstractServerEquipment.h>
00017 #include <fesa-core/Server/Property.h>
00018 #include <fesa-core/Utilities/Lock.h>
00019 #include <fesa-core/Utilities/ProcessConfiguration.h>
00020 #include <fesa-core/Utilities/XMLParser.h>
00021 
00022 #include <cmw-rda/Config.h>
00023 #include <cmw-rda/Data.h>
00024 #include <cmw-rda/Exception.h>
00025 #include <cmw-log/Logger.h>
00026 
00027 
00028 namespace
00029 {
00030 
00031 CMW::Log::Logger& logger = CMW::Log::LoggerFactory::getLogger("FESA.FWK.fesa-core.RDADeviceServer.FesaDeviceServer");
00032 const std::string diagTopic = fesa::DiagnosticUtils::rdaTrackingStr;
00033 
00034 } // namespace
00035 
00036 
00037 namespace fesa
00038 {
00039 
00040 const std::string ERROR_CATEGORY = "FESA";
00041 
00042 FesaDeviceServer::FesaDeviceServer(const std::string& name, const ProcessConfiguration* processConfiguration, SubscriptionTreeManager* pSubscriptionTreeManager) :
00043     rdaDeviceServerBase(name.c_str()),
00044     pTreeManager_(pSubscriptionTreeManager)
00045 {
00046     firstUpdateAcquisitionEnabled_ = processConfiguration->getBoolValue(PropertyTag::FIRST_UPDATE_ACQUISITION);
00047     firstUpdateSettingEnabled_ = processConfiguration->getBoolValue(PropertyTag::FIRST_UPDATE_SETTING);
00048     try
00049     {
00050         rdaConfig::useConfigFile(processConfiguration->getCMWConfigFile().c_str());
00051     }
00052     catch (rdaInternalError& ex)
00053     {
00054         std::ostringstream msg;
00055         msg << "rdaConfig::useConfigFile failed: " << ex.getMessage();
00056         LOG_ERROR_IF(logger, msg.str());
00057     }
00058 }
00059 
00060 FesaDeviceServer::~FesaDeviceServer()
00061 {
00062     shutDown();//stops the RDA Server ( this makes the runServer() method return)
00063     mutex_.lock();
00064 }
00065 
00066 void FesaDeviceServer::runDeviceServer()
00067 {
00068     const boost::shared_ptr<Diagnostics>& diagnostics = AbstractEquipment::getInstance()->getDiagnostics();
00069     DiagnosticUtils::DiagnosticMessage diagMsg;
00070     diagMsg.side = DiagnosticUtils::framework;
00071     diagMsg.source = DiagnosticUtils::server;
00072     std::ostringstream traceStrStream;
00073     traceStrStream << "Starting FESA device server with name '" << getName() << "' - Server side startup should be finished here";
00074     diagMsg.msg = traceStrStream.str();
00075     diagnostics->log(diagTopic, diagMsg);
00076     try
00077     {
00078         //starts the RDA Server ... this method will only return if the shutDown(); method is called
00079         Lock lock(mutex_);
00080         runServer();
00081     }
00082     catch (const rdaInternalError& ex)
00083     {
00084         std::ostringstream errorStrStream;
00085         errorStrStream << "RDA server failure. RDA internal error:" << ex.getFile() << " : " << ex.getLine() << " : " << ex.getMessage();
00086         LOG_ERROR_IF(logger, errorStrStream.str());
00087         throw;
00088     }
00089     // all calls below throw FesaExceptions instead of returning NULL
00090     // but only RDAException can be propagate to the caller
00091     catch (const rdaException& ex)
00092     {
00093         std::ostringstream errorStrStream;
00094         errorStrStream << "RDA server failure. RDA internal error: " << ex.getType() << "  " << ex.getMessage();
00095         LOG_ERROR_IF(logger, errorStrStream.str());
00096         throw;
00097     }
00098     catch (...)
00099     {
00100         LOG_ERROR_IF(logger, "RDA Server failure. Unknown exception in 'runRDADeviceServer'");
00101         throw;
00102     }
00103 }
00104 
00105 rdaData* FesaDeviceServer::get(const rdaIOPoint& iop, const rdaData& ctx)
00106 {
00107     const std::string threadName = "GetSetLayer";
00108     Thread::registerThreadIdName(pthread_self(), threadName);
00109     const boost::shared_ptr<Diagnostics>& diagnostics = AbstractEquipment::getInstance()->getDiagnostics();
00110     DiagnosticUtils::DiagnosticMessage diagMsg;
00111     diagMsg.side = DiagnosticUtils::framework;
00112     diagMsg.source = DiagnosticUtils::server;
00113     std::auto_ptr<rdaData> value;
00114     // All calls below throw FesaExceptions instead of returning NULL
00115     // but only RDAException can be propagated to the caller
00116     try
00117     {
00118         if (isRTProcessDown())
00119         {
00120             throw FesaException(__FILE__, __LINE__, FesaErrorRTProcessDown.c_str());
00121         }
00122         std::ostringstream traceStrStream;
00123         traceStrStream << "Device: " << iop.getDeviceName() << ". Property: " << iop.getPropertyName()
00124                        << ". Client: " << getClientInfo()->getUserName() << " from " << getClientInfo()->getHostName();
00125         diagMsg.msg = traceStrStream.str();
00126         diagnostics->log(diagTopic, diagMsg);
00127         //get pointers to all needed parameters
00128         Property* property;
00129         AbstractDevice* device;
00130         AbstractServerDeviceClass* srvDeviceClass;
00131         std::string cycleSelector("");
00132         decodeIOPoint(iop, srvDeviceClass, property, device, cycleSelector);
00133         value.reset(new rdaData());
00134         property->get(*device, cycleSelector, ctx, *value, GET);//perform the get
00135     }
00136     catch (FesaException& ex)
00137     {
00138         throw rdaIOError(ERROR_CATEGORY.c_str(), ex.getErrorCodeAsLong(), ex.getMessage().c_str());
00139     }
00140     catch (rdaException& ex)
00141     {
00142         throw rdaIOError("RDA", 0, ex.getMessage());
00143     }
00144     catch (...)// in case of any other exceptions, just throw them to the next level (the subscriber)
00145     {
00146         throw rdaIOError(ERROR_CATEGORY.c_str(), 0, "failure performing 'Get': Unknown Error");
00147     }
00148     rdaData* pRDAData = value.get();
00149     value.release();
00150     return pRDAData;
00151 }
00152 
00153 void FesaDeviceServer::set(const rdaIOPoint& iop, const rdaData& ctx, const rdaData& value)
00154 {
00155     const std::string threadName = "GetSetLayer";
00156     Thread::registerThreadIdName(pthread_self(), threadName);
00157     const boost::shared_ptr<Diagnostics>& diagnostics = AbstractEquipment::getInstance()->getDiagnostics();
00158     DiagnosticUtils::DiagnosticMessage diagMsg;
00159     diagMsg.side = DiagnosticUtils::framework;
00160     diagMsg.source = DiagnosticUtils::server;
00161     // All calls below throw FesaExceptions instead of returning NULL
00162     // but only RDAException can be propagated to the caller
00163     try
00164     {
00165         if (isRTProcessDown())
00166         {
00167             throw FesaException(__FILE__, __LINE__, FesaErrorRTProcessDown.c_str());
00168         }
00169         std::ostringstream traceStrStream;
00170         traceStrStream << "Device: " << iop.getDeviceName() << ". Property: " << iop.getPropertyName()
00171                        << ". Client: " << getClientInfo()->getUserName() << " from " << getClientInfo()->getHostName();
00172         diagMsg.msg = traceStrStream.str();
00173         diagnostics->log(diagTopic, diagMsg);
00174         // Get pointers to all needed parameters
00175         Property* property;
00176         AbstractDevice* device;
00177         AbstractServerDeviceClass* srvDeviceClass;
00178         std::string cycleSelector("");
00179         decodeIOPoint(iop, srvDeviceClass, property, device, cycleSelector);
00180         property->set(*device, cycleSelector, ctx, value); // Perform set
00181     }
00182     catch (rdaException& ex)
00183     {
00184         throw rdaIOError("RDA", 0, ex.getMessage());
00185     }
00186     catch (FesaException& ex)
00187     {
00188         throw rdaIOError(ERROR_CATEGORY.c_str(), ex.getErrorCodeAsLong(), ex.getMessage().c_str());
00189     }
00190     catch (...)// in case of any other exceptions, just throw them to the next level (the subscriber)
00191     {
00192         throw rdaIOError(ERROR_CATEGORY.c_str(), 0, "failure performing 'Set': Unknown Error");
00193     }
00194 }
00195 
00196 void FesaDeviceServer::monitorOn(const rdaIOPoint& iop, const rdaData& ctx, rdaValueChangeListener* listener)
00197 {
00198     const boost::shared_ptr<Diagnostics>& diagnostics = AbstractEquipment::getInstance()->getDiagnostics();
00199     DiagnosticUtils::DiagnosticMessage diagMsg;
00200     diagMsg.side = DiagnosticUtils::framework;
00201     diagMsg.source = DiagnosticUtils::server;
00202     Property* property;
00203     AbstractDevice* device;
00204     std::string cycleSelector("");
00205     AbstractServerDeviceClass* srvDeviceClass;
00206     // all calls below throw FesaExceptions instead of returning NULL
00207     // but only RDAException can be propagated to the caller
00208     try
00209     {
00210         if (isRTProcessDown())
00211         {
00212             throw FesaException(__FILE__, __LINE__, FesaErrorRTProcessDown.c_str());
00213         }
00214         std::ostringstream traceStrStream;
00215         traceStrStream << "Device: " << iop.getDeviceName() << ". Property: " << iop.getPropertyName()
00216                        << ". Client: " << getClientInfo()->getUserName() << " from " << getClientInfo()->getHostName();
00217         diagMsg.msg = traceStrStream.str();
00218         diagnostics->log(diagTopic, diagMsg);
00219         decodeIOPoint(iop, srvDeviceClass, property, device, cycleSelector);
00220         property->validateParameters(*device, cycleSelector, (ctx.isEmpty() ? false : true), SUBSCRIBE);
00221         // Checking if the subscription is disabled due to notification failure
00222         if (*(EquipmentData::getInstance()->notificationFailure_) == true)
00223         {
00224             throw FesaException(__FILE__, __LINE__, FesaErrorPropertySubscriptionDisabled.c_str());
00225         }
00226         pTreeManager_->addSubscriber(srvDeviceClass->getName(), *device, *property, cycleSelector, ctx, listener);  //This builds the subscription tree, and adds the enties in the notification objects
00227     }
00228     catch (rdaException& ex)
00229     {
00230         throw rdaIOError("RDA", 0, ex.getMessage());
00231     }
00232     catch (FesaException& ex)
00233     {
00234         throw rdaIOError(ERROR_CATEGORY.c_str(), ex.getErrorCodeAsLong(), ex.getMessage().c_str());
00235     }
00236     catch (...)// in case of any other exceptions, just throw them to the next level (the subscriber)
00237     {
00238         throw rdaIOError(ERROR_CATEGORY.c_str(), 0, "failure adding new Subscriber: Unknown Error");
00239     }
00240 }
00241 
00242 void FesaDeviceServer::monitorOff(const rdaIOPoint& iop, rdaValueChangeListener* listener)
00243 {
00244     const boost::shared_ptr<Diagnostics>& diagnostics = AbstractEquipment::getInstance()->getDiagnostics();
00245     DiagnosticUtils::DiagnosticMessage diagMsg;
00246     diagMsg.side = DiagnosticUtils::framework;
00247     diagMsg.source = DiagnosticUtils::server;
00248     AbstractServerDeviceClass* srvDeviceClass;
00249     Property* property;
00250     AbstractDevice* device;
00251     std::string cycleSelector;
00252 
00253     std::ostringstream traceStrStream;
00254     traceStrStream << "Device: " << iop.getDeviceName() << ". Property: " << iop.getPropertyName()
00255                    << ". Client: " << getClientInfo()->getUserName() << " from " << getClientInfo()->getHostName();
00256     diagMsg.msg = traceStrStream.str();
00257     diagnostics->log(diagTopic, diagMsg);
00258     try //try+catch is needed here in order to unlock the tree on an exception
00259     {
00260         //get pointers to all needed parameters
00261         decodeIOPoint(iop, srvDeviceClass, property, device, cycleSelector);
00262         pTreeManager_->removeSubscriber(*device, *property, cycleSelector, listener);//this will remove the subscriber from the subscription tree AND from the Notifications
00263 
00264     }
00265     catch (rdaException& ex)
00266     {
00267         throw rdaIOError("RDA", 0, ex.getMessage());
00268     }
00269     catch (FesaException& ex)
00270     {
00271         throw rdaIOError(ERROR_CATEGORY.c_str(), ex.getErrorCodeAsLong(), ex.getMessage().c_str());
00272     }
00273     catch (...)// in case of any other exceptions, just throw them to the next level (the subscriber)
00274     {
00275         throw rdaIOError(ERROR_CATEGORY.c_str(), 0, "failure removing Subscriber: Unknown Error");
00276     }
00277 }
00278 
00279 void FesaDeviceServer::decodeIOPoint(const rdaIOPoint& iop, AbstractServerDeviceClass*& srvDeviceClass, Property*& prop, AbstractDevice*& device,
00280                                      std::string& cycleSelector)
00281 {
00282     const std::string propertyName(iop.getPropertyName());
00283     const std::string deviceName(iop.getDeviceName());
00284 
00285     //TODO check if IOPoint return a null pointer
00286     // this is necessary, to be able to handle empty strings
00287     const char* cs = const_cast<char*> (iop.getCycleSelector());
00288     if (!cs)
00289         cs = "";
00290     cycleSelector = cs;
00291 
00292     //get pointers to all needed parameters
00293     AbstractServerEquipment* equipment = AbstractServerEquipment::getInstance();
00294     srvDeviceClass = equipment->getDeviceClassFromDeviceName(deviceName);
00295     prop = srvDeviceClass->getProperty(propertyName);
00296     if (prop == NULL)
00297     {
00298         throw FesaException(__FILE__, __LINE__, FesaErrorPropertyNotFound.c_str(), propertyName.c_str());
00299     }
00300 
00301     if (prop->isGlobal())
00302     {
00303         device = srvDeviceClass->getDeviceFactory()->getGlobalDevice();
00304         if (device == NULL)
00305         {
00306             device = srvDeviceClass->getDeviceFactory()->getDevice(deviceName);
00307             if (device != NULL)
00308                 // Global property cannot be accessed using a deviceInstance
00309                 throw FesaException(__FILE__, __LINE__, FesaErrorGlobalPropertyDeviceInstance.c_str(), propertyName.c_str());
00310             // unknown device
00311             throw FesaException(__FILE__, __LINE__, FesaErrorUnknownDevice.c_str(), deviceName.c_str());
00312         }
00313     }
00314     else
00315     {
00316         device = srvDeviceClass->getDeviceFactory()->getDevice(deviceName);
00317         if (device == NULL) {
00318             device = srvDeviceClass->getDeviceFactory()->getGlobalDevice();
00319             if (device != NULL)
00320                 // Device property cannot be accessed using teh global device
00321                 throw FesaException(__FILE__, __LINE__, FesaErrorDevicePropertyGlobalDevice.c_str(), propertyName.c_str());
00322             // unknown device
00323             throw FesaException(__FILE__, __LINE__, FesaErrorUnknownDevice.c_str(), deviceName.c_str());
00324         }
00325     }
00326 }
00327 
00328 
00329 bool FesaDeviceServer::isRTProcessDown()
00330 {
00331     EquipmentData* eqData = EquipmentData::getInstance();
00332     if (*(eqData->hasRt_) && !(*(eqData->rtUp_)))
00333     {
00334         return true;
00335     }
00336     return false;
00337 }
00338 
00339 void FesaDeviceServer::start()
00340 {
00341     {
00342         AbstractEquipment* eqp = AbstractEquipment::getInstance();
00343         std::string instanceFile = eqp->getDeviceDataFileName();
00344         XMLParser xmlParser(instanceFile, false);
00345         ThreadPriorityConfigurationFromFile conf(xmlParser, eqp->getProcessConfiguration());
00346         int32_t prio =  conf.getPrioCMW();
00347         setPriority(prio);
00348     }
00349     Thread::start(false, "DeviceServer");
00350 }
00351 
00352 void FesaDeviceServer::run()
00353 {
00354     try
00355     {
00356         runDeviceServer();
00357     }
00358     catch(const rdaInternalError& ex)
00359     {
00360         std::ostringstream errorStrStream;
00361         errorStrStream << "Fatal error in RDA runtime:" << ex.getFile() << " : " << ex.getLine() << " : " << ex.getMessage() << std::endl;
00362         LOG_ERROR_IF(logger, errorStrStream.str());
00363         throw FesaException(__FILE__, __LINE__, FesaErrorIRunningDeviceServer.c_str(), ex.getMessage());
00364     }
00365     catch(const rdaInternalException& ex)
00366     {
00367         std::ostringstream errorStrStream;
00368         errorStrStream << "Recoverable error in the RDA runtime:" << ex.getMessage() << std::endl;
00369         LOG_ERROR_IF(logger, errorStrStream.str());
00370         throw FesaException(__FILE__, __LINE__, FesaErrorIRunningDeviceServer.c_str(), ex.getMessage());
00371     }
00372 }
00373 
00374 void FesaDeviceServer::initCMW()
00375 {
00376     const int argc = 0;
00377     char** argv = NULL;
00378     try
00379     {
00380         rdaDeviceServerBase::init(argc, argv); // argc and argv are not used in RDA except in some restart procedure, which is obsolete according to CMW team
00381         std::ostringstream infoStringStream;
00382         infoStringStream << "CMW initialized from " << AbstractEquipment::getInstance()->getProcessConfiguration()->getCMWConfigFile();
00383         LOG_INFO_IF(logger, infoStringStream.str());
00384     }
00385     catch (const rdaInternalError& ex)
00386     {
00387         throw FesaException(__FILE__, __LINE__, FesaErrorInitializingRdaDeviceServerBase.c_str(), ex.getMessage());
00388     }
00389 }
00390 
00391 } // fesa

Generated on 18 Jan 2013 for Fesa by  doxygen 1.6.1