/* Copyright (C) 2000-2002 Stefan Westerfeld stefan@space.twc.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "common.h" #include "debug.h" #include #include #include #include #include #include #include #include using namespace Arts; using namespace std; namespace Arts { // TraderRestriction struct TraderRestriction { TraderRestriction(const string& key, const string& value) :key(key), value(value) { } string key; string value; }; // TraderHelper (internal, no public interface) class TraderHelper { private: vector allOffers; static TraderHelper *_instance; protected: TraderHelper(); ~TraderHelper(); void addDirectory(const string& directory, const string& iface = "", map< pair, bool > *dirsDone = 0); public: vector *doQuery(const vector& query); void load(); void unload(); static TraderHelper *the(); static void shutdown(); }; // TraderQuery class TraderQuery_impl : virtual public TraderQuery_skel { private: vector restrictions; public: void supports(const string& property, const string& value); vector *query(); }; REGISTER_IMPLEMENTATION(TraderQuery_impl); // TraderOffer class TraderOffer_impl : virtual public TraderOffer_skel { private: string _interfaceName; map > property; public: TraderOffer_impl(const string& interfaceName, const string& filename); bool match(const vector& restrictions); // IDL string interfaceName(); vector* getProperty(const string& name); }; } // TraderQuery //---------------------------------------------------------------------------- void TraderQuery_impl::supports(const string& property, const string& value) { restrictions.push_back(TraderRestriction(property,value)); } vector *TraderQuery_impl::query() { return TraderHelper::the()->doQuery(restrictions); } // TraderOffer //---------------------------------------------------------------------------- TraderOffer_impl::TraderOffer_impl(const string& interfaceName, const string& filename) :_interfaceName(interfaceName) { ifstream file(filename.c_str()); string line; while(getline(file,line)) { string key; vector values; if(MCOPUtils::tokenize(line,key,values)) property[key] = values; } vector& iname = property["InterfaceName"]; if(iname.empty()) iname.push_back(interfaceName); } bool TraderOffer_impl::match(const vector& restrictions) { vector::const_iterator i; for(i = restrictions.begin(); i != restrictions.end();i++) { const TraderRestriction& res = *i; const vector& myvalues = property[res.key]; bool okay = false; vector::const_iterator offerIt = myvalues.begin(); while(!okay && offerIt != myvalues.end()) { if(res.value == *offerIt) okay = true; else offerIt++; } if(!okay) return false; } return true; } string TraderOffer_impl::interfaceName() { return _interfaceName; } vector* TraderOffer_impl::getProperty(const string& name) { return new vector(property[name]); } // TraderHelper //---------------------------------------------------------------------------- TraderHelper::TraderHelper() { load(); } TraderHelper::~TraderHelper() { unload(); } void TraderHelper::load() { const vector *path = MCOPUtils::traderPath(); vector::const_iterator pi; for(pi = path->begin(); pi != path->end(); pi++) addDirectory(*pi); } void TraderHelper::unload() { vector::iterator i; for(i = allOffers.begin(); i != allOffers.end(); i++) { TraderOffer_impl *offer = *i; offer->_release(); } allOffers.clear(); } void TraderHelper::addDirectory(const string& directory, const string& iface, map< pair, bool > *dirsDone) { bool created_dirs_done = false; arts_debug("addDirectory(%s,%s)", directory.c_str(), iface.c_str()); if(!dirsDone) { /* map to prevent doing directories again due to symlinks */ dirsDone = new map< pair, bool >; struct stat st; stat(directory.c_str(), &st); (*dirsDone)[make_pair(st.st_dev, st.st_ino)] = true; created_dirs_done = true; } DIR *dir = opendir(directory.c_str()); if(!dir) return; struct dirent *de; while((de = readdir(dir)) != 0) { string currentEntry = directory + "/" + de->d_name; string currentIface = iface; if(!iface.empty()) currentIface += "::"; currentIface += de->d_name; struct stat st; stat(currentEntry.c_str(),&st); // recurse into subdirectories if(S_ISDIR(st.st_mode)) { bool& done = (*dirsDone)[make_pair(st.st_dev, st.st_ino)]; if(strcmp(de->d_name,".") && strcmp(de->d_name,"..") && !done) { done = true; addDirectory(currentEntry,currentIface,dirsDone); } } else if(S_ISREG(st.st_mode)) { if(strlen(de->d_name) > 10 && strncmp(&de->d_name[strlen(de->d_name)-10],".mcopclass",10) == 0) { // cut .mcopclass for currentIface; currentIface = currentIface.substr(0, currentIface.size()-10); allOffers.push_back( new TraderOffer_impl(currentIface,currentEntry) ); } } } if (created_dirs_done) delete dirsDone; closedir(dir); } static inline int getOfferPreference(TraderOffer offer) { int result = 0; vector *p = offer.getProperty("Preference"); if(!p->empty()) result = atoi(p->front().c_str()); delete p; return result; } static bool traderOfferCmp(TraderOffer offer1, TraderOffer offer2) { int p1 = getOfferPreference(offer1); int p2 = getOfferPreference(offer2); if(p1 > p2) return true; if(p1 < p2) return false; /* if the Preference= entry doesn't indicate which offer is better, * sort the offers by name to make the trader results at least * independant from the order they are read from the file system */ return offer1.interfaceName() < offer2.interfaceName(); } vector *TraderHelper::doQuery(const vector& query) { vector *result = new vector; vector::iterator i; for(i = allOffers.begin(); i != allOffers.end(); i++) { TraderOffer_impl *offer = *i; if(offer->match(query)) { result->push_back(TraderOffer::_from_base(offer->_copy())); } } /* sort trader query result by Preference= line for more than one result */ if(result->size() > 1) sort(result->begin(), result->end(), traderOfferCmp); return result; } TraderHelper *TraderHelper::_instance = 0; TraderHelper *TraderHelper::the() { if(!_instance) _instance = new TraderHelper(); return _instance; } void TraderHelper::shutdown() { if(_instance) { delete _instance; _instance = 0; } } namespace Arts { // trader shutdown class TraderShutdown :public StartupClass { public: void startup() { }; void shutdown() { TraderHelper::shutdown(); }; }; static TraderShutdown traderShutdown; } // Dispatcher function for reloading the trader data: void Dispatcher::reloadTraderData() { TraderHelper::the()->unload(); TraderHelper::the()->load(); }