#ifndef __CsvFileDataNodes_h_ #define __CsvFileDataNodes_h_ #include "GenericDataNodes.h" #include "../../shared/TwoDLookup.h" // FileOwnerDataNode is a simple wrapper around a TwoDArray to make it a data // node. This data node reads a file, and makes it's contents available to // users. // // The file is read once, on creation. The data is immediately available. As // long as the file is present when the data node is created, it is safe to // read the data node immediately. This differs from data nodes which talk // to a remote server. With those data nodes you cannot rely on the data // being immediately available. // // The file can be re-read at other times, and this data node will send out // standard notifications. Currently the file will only be reread on request. // Presumably someone could send a specific command through the tcp/ip control // interface to request this. // // This data node could watch for changes in the file and automatically // reread the file when required. The Delphi code did that. It was helpful // sometimes in development, but never in production use. That feature could // be added in the future if required, but I don't expect to ever to that. // // This data node has a way of sticking around for a short time after it is // released. Sometimes a series of seperate routines will each ask for single // field from a csv file, then release the data node. TwoDArray is not // optimized for that, and will spend a lot of time parsing a big file each // time it is read. This optimization allows us to reuse the same TwoDArray, // without rereading the data for each request. // // In this unit the file name is always relative to the data directory. By // default if you say "Overnight.csv", that gets translated to // "data/Overnight.csv". Absolute file names are allowed and these will be // used as is. The "data/" prefix can be changed from the command line using // the "data_directory" option. class FileOwnerDataNode : public DataNode { private: const std::string _fileName; TwoDArray _values; mutable bool _recentlyUsed; DataNodeLink *_linkToSelf; FileOwnerDataNode(DataNodeArgument const &args); friend class DataNode; ~FileOwnerDataNode(); void loadData(); void sendIdleRequest(); std::string idleCallbackChannel(); std::string reloadCallbackChannel(); enum { bmIdleCallback, bmReloadNow }; void onBroadcast(BroadcastMessage &message, int msgId); public: // These are thread safe. If they are called in the same thread, they are // still posted to the message queue, the update will not happen immediately. static void releadAllSoon(DataNodeManager *manager); void reloadSoon(); std::string get(std::string const &colHeader, std::string const &rowHeader) const; bool containsRow(std::string const &rowHeader) const; static DataNodeLink *find(DataNodeListener *listener, int msgId, FileOwnerDataNode *&node, std::string const &fileName); // This will find a data node, in an attempt to maximize reuse. If you are // not in a thread with a data node manager, use TwoDLookup.h directly, // instead. static std::string getStringValue(std::string const &fileName, std::string const &colKey, std::string const &rowKey); // This data node automatically calls this funtion. (And makeCsvFactory() // indirectly calls this.) Other files can call this directly if they want // consistant results but they read the file through other means. static std::string findDataFile(std::string const &fileName); }; // This will create a new factory object. The resulting data node will look // in the row and column of the given file for a value. This can be retrieved // as a string, an integer, or a double. The string will be considered valid // if it is not the empty string. The number will be considered valid if we // can successfully convert the underlying string value into the given data // type. fileName, colKey, and rowKey should all be strings or placeholders // which eventually are filled in with strings. DataNodeArgument makeCsvFactory(DataNodeArgument const &fileName, DataNodeArgument const &colKey, DataNodeArgument const &rowKey); // This is the most common case. inline DataNodeArgument makeCsvFactory(std::string const &fileName, std::string const &colKey) { return makeCsvFactory(fileName, colKey, symbolPlaceholderObject); } #endif