#include #include #include "../../shared/SimpleLogFile.h" #include "../../shared/GlobalConfigFile.h" #include "CsvFileDataNodes.h" ///////////////////////////////////////////////////////////////////// // FileOwnerDataNode ///////////////////////////////////////////////////////////////////// #define RELOAD_ALL_CHANNEL "FileOwnerDataNode.reload" std::string FileOwnerDataNode::findDataFile(std::string const &fileName) { assert(!fileName.empty()); /* This wouldn't make any sense and would make * the logic below more complicated. */ if (fileName[0] == '/') // Absolute path. Leave it alone. return fileName; // Relative path. Add our preferred directory. return getConfigItem("data_directory", "data") + '/' + fileName; } FileOwnerDataNode::FileOwnerDataNode(DataNodeArgument const &args) : _fileName(findDataFile(args.getStringValue())), _recentlyUsed(false), _linkToSelf(createLink()) { TclList msg; msg<<"CsvFileDataNodes.C" <<"constructor" <<_fileName; sendToLogFile(msg); loadData(); registerForBroadcast(idleCallbackChannel(), bmIdleCallback); registerForBroadcast(reloadCallbackChannel(), bmReloadNow); registerForBroadcast(RELOAD_ALL_CHANNEL, bmReloadNow); sendIdleRequest(); } FileOwnerDataNode::~FileOwnerDataNode() { // Ideally these things should only be created occasionally. If they are // created a lot, that's a bug. TclList msg; msg<<"CsvFileDataNodes.C" <<"destructor" <<_fileName; sendToLogFile(msg); } void FileOwnerDataNode::loadData() { _values.loadFromCSV(_fileName); } void FileOwnerDataNode::onBroadcast(BroadcastMessage &message, int msgId) { switch (msgId) { case bmIdleCallback: if (_recentlyUsed) { _recentlyUsed = false; sendIdleRequest(); } else { DataNodeLink *temp = _linkToSelf; _linkToSelf = NULL; temp->release(); // This object might have deleted itself here. } break; case bmReloadNow: loadData(); notifyListeners(); break; } } void FileOwnerDataNode::sendIdleRequest() { BroadcastMessage *m = new BroadcastMessage(idleCallbackChannel()); m->send(getManager()); } void FileOwnerDataNode::releadAllSoon(DataNodeManager *manager) { BroadcastMessage *m = new BroadcastMessage(RELOAD_ALL_CHANNEL); m->send(manager); } void FileOwnerDataNode::reloadSoon() { BroadcastMessage *m = new BroadcastMessage(reloadCallbackChannel()); m->send(getManager()); } std::string FileOwnerDataNode::idleCallbackChannel() { return getOwnerChannel() + ".idle"; } std::string FileOwnerDataNode::reloadCallbackChannel() { return getOwnerChannel() + ".reload"; } std::string FileOwnerDataNode::get(std::string const &colHeader, std::string const &rowHeader) const { _recentlyUsed = true; return _values.get(colHeader, rowHeader); } bool FileOwnerDataNode::containsRow(std::string const &rowHeader) const { _recentlyUsed = true; return _values.containsRow(rowHeader); } DataNodeLink *FileOwnerDataNode::find(DataNodeListener *listener, int msgId, FileOwnerDataNode *&node, std::string const &fileName) { return findHelper(listener, msgId, node, fileName); } std::string FileOwnerDataNode::getStringValue(std::string const &fileName, std::string const &colKey, std::string const &rowKey) { FileOwnerDataNode *node; DataNodeLink *link = FileOwnerDataNode::find(NULL, 0, node, fileName); std::string result = node->get(colKey, rowKey); link->release(); return result; } ///////////////////////////////////////////////////////////////////// // GenericCsvFileDataNode ///////////////////////////////////////////////////////////////////// class GenericCsvFileDataNode : public GenericDataNode { private: std::string _colHeader; std::string _rowHeader; FileOwnerDataNode *_values; GenericCsvFileDataNode(DataNodeArgument const &args); friend class GenericDataNodeFactory; public: void getInteger(bool &valid, Integer &value) const; void getDouble(bool &valid, double &value) const; void getString(bool &valid, std::string &value) const; }; GenericCsvFileDataNode::GenericCsvFileDataNode(DataNodeArgument const &args) { DataNodeArgumentVector const &list = args.getListValue(); assert(list.size() == 3); std::string const &fileName = list[0].getStringValue(); _colHeader = list[1].getStringValue(); _rowHeader = list[2].getStringValue(); addAutoLink(FileOwnerDataNode::find(this, 0, _values, fileName)); } void GenericCsvFileDataNode::getInteger(bool &valid, Integer &value) const { std::string asString; getString(valid, asString); if (valid) { const Integer unlikely = std::numeric_limits< Integer >::min(); value = strtollDefault(asString, unlikely); if (value == unlikely) { valid = strtollDefault(asString, 0); } } } void GenericCsvFileDataNode::getDouble(bool &valid, double &value) const { std::string asString; getString(valid, asString); if (valid) { value = strtodDefault(asString, NAN); valid = !isnan(value); } } void GenericCsvFileDataNode::getString(bool &valid, std::string &value) const { value = _values->get(_colHeader, _rowHeader); valid = !value.empty(); } DataNodeArgument makeCsvFactory(DataNodeArgument const &fileName, DataNodeArgument const &colKey, DataNodeArgument const &rowKey) { DataNodeArgumentVector v; v.push_back(fileName); v.push_back(colKey); v.push_back(rowKey); return GenericDataNodeFactory::create< GenericCsvFileDataNode >(v); }