summaryrefslogtreecommitdiffstats
path: root/mcop/trader_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mcop/trader_impl.cpp')
-rw-r--r--mcop/trader_impl.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/mcop/trader_impl.cpp b/mcop/trader_impl.cpp
new file mode 100644
index 0000000..fe954f0
--- /dev/null
+++ b/mcop/trader_impl.cpp
@@ -0,0 +1,345 @@
+ /*
+
+ 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 <iostream>
+#include <fstream>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <cstring>
+
+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<class TraderOffer_impl *> allOffers;
+ static TraderHelper *_instance;
+
+protected:
+ TraderHelper();
+ ~TraderHelper();
+ void addDirectory(const string& directory, const string& iface = "",
+ map< pair<dev_t,ino_t>, bool > *dirsDone = 0);
+
+public:
+ vector<TraderOffer> *doQuery(const vector<TraderRestriction>& query);
+ void load();
+ void unload();
+ static TraderHelper *the();
+ static void shutdown();
+};
+
+// TraderQuery
+class TraderQuery_impl : virtual public TraderQuery_skel {
+private:
+ vector<TraderRestriction> restrictions;
+public:
+ void supports(const string& property, const string& value);
+ vector<TraderOffer> *query();
+};
+
+REGISTER_IMPLEMENTATION(TraderQuery_impl);
+
+// TraderOffer
+class TraderOffer_impl : virtual public TraderOffer_skel {
+private:
+ string _interfaceName;
+ map<string, vector<string> > property;
+
+public:
+ TraderOffer_impl(const string& interfaceName, const string& filename);
+
+ bool match(const vector<TraderRestriction>& restrictions);
+
+ // IDL
+ string interfaceName();
+ vector<string>* getProperty(const string& name);
+};
+
+}
+
+// TraderQuery
+//----------------------------------------------------------------------------
+void TraderQuery_impl::supports(const string& property, const string& value)
+{
+ restrictions.push_back(TraderRestriction(property,value));
+}
+
+vector<TraderOffer> *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<string> values;
+
+ if(MCOPUtils::tokenize(line,key,values))
+ property[key] = values;
+ }
+
+ vector<string>& iname = property["InterfaceName"];
+ if(iname.empty())
+ iname.push_back(interfaceName);
+}
+
+bool TraderOffer_impl::match(const vector<TraderRestriction>& restrictions)
+{
+ vector<TraderRestriction>::const_iterator i;
+
+ for(i = restrictions.begin(); i != restrictions.end();i++)
+ {
+ const TraderRestriction& res = *i;
+ const vector<string>& myvalues = property[res.key];
+ bool okay = false;
+
+ vector<string>::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<string>* TraderOffer_impl::getProperty(const string& name)
+{
+ return new vector<string>(property[name]);
+}
+
+// TraderHelper
+//----------------------------------------------------------------------------
+
+TraderHelper::TraderHelper()
+{
+ load();
+}
+
+TraderHelper::~TraderHelper()
+{
+ unload();
+}
+
+void TraderHelper::load()
+{
+ const vector<string> *path = MCOPUtils::traderPath();
+
+ vector<string>::const_iterator pi;
+ for(pi = path->begin(); pi != path->end(); pi++) addDirectory(*pi);
+}
+
+void TraderHelper::unload()
+{
+ vector<TraderOffer_impl *>::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<dev_t,ino_t>, 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<dev_t,ino_t>, 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<string> *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<TraderOffer> *TraderHelper::doQuery(const
+ vector<TraderRestriction>& query)
+{
+ vector<TraderOffer> *result = new vector<TraderOffer>;
+
+ vector<TraderOffer_impl *>::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();
+}