00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define FREPPLE_CORE
00028 #include "frepple/utils.h"
00029 #include <sys/stat.h>
00030
00031
00032 namespace frepple
00033 {
00034 namespace utils
00035 {
00036
00037
00038 DECLARE_EXPORT const MetaCategory* MetaCategory::firstCategory = NULL;
00039 DECLARE_EXPORT MetaCategory::CategoryMap MetaCategory::categoriesByTag;
00040 DECLARE_EXPORT MetaCategory::CategoryMap MetaCategory::categoriesByGroupTag;
00041
00042
00043 set<string> CommandLoadLibrary::registry;
00044
00045
00046 DECLARE_EXPORT const MetaCategory* Command::metadataInstruction;
00047
00048
00049
00050 DECLARE_EXPORT int Environment::processors = 1;
00051
00052
00053
00054 DECLARE_EXPORT ostream logger(cout.rdbuf());
00055
00056
00057 DECLARE_EXPORT ofstream Environment::logfile;
00058
00059
00060 DECLARE_EXPORT string Environment::logfilename;
00061
00062
00063 DECLARE_EXPORT const hashtype MetaCategory::defaultHash(Keyword::hash("default"));
00064
00065 DECLARE_EXPORT vector<PythonType*> PythonExtensionBase::table;
00066
00067
00068 DECLARE_EXPORT string Environment::searchFile(const string filename)
00069 {
00070 #ifdef _MSC_VER
00071 static char pathseperator = '\\';
00072 #else
00073 static char pathseperator = '/';
00074 #endif
00075
00076
00077 struct stat stat_p;
00078 int result = stat(filename.c_str(), &stat_p);
00079 if (!result && stat_p.st_mode & S_IREAD)
00080 return filename;
00081
00082
00083 string fullname;
00084 char * envvar = getenv("FREPPLE_HOME");
00085 if (envvar)
00086 {
00087 fullname = envvar;
00088 if (*fullname.rbegin() != pathseperator)
00089 fullname += pathseperator;
00090 fullname += filename;
00091 result = stat(fullname.c_str(), &stat_p);
00092 if (!result && stat_p.st_mode & S_IREAD)
00093 return fullname;
00094 }
00095
00096 #ifdef DATADIRECTORY
00097
00098 fullname = DATADIRECTORY;
00099 if (*fullname.rbegin() != pathseperator)
00100 fullname += pathseperator;
00101 fullname.append(filename);
00102 result = stat(fullname.c_str(), &stat_p);
00103 if (!result && stat_p.st_mode & S_IREAD)
00104 return fullname;
00105 #endif
00106
00107 #ifdef LIBDIRECTORY
00108
00109 fullname = LIBDIRECTORY;
00110 if (*fullname.rbegin() != pathseperator)
00111 fullname += pathseperator;
00112 fullname += "frepple/";
00113 fullname += filename;
00114 result = stat(fullname.c_str(), &stat_p);
00115 if (!result && stat_p.st_mode & S_IREAD)
00116 return fullname;
00117 #endif
00118
00119
00120 return "";
00121 }
00122
00123
00124 DECLARE_EXPORT void Environment::setLogFile(const string& x)
00125 {
00126
00127 if (!logfilename.empty())
00128 logger << "Stop logging at " << Date::now() << endl;
00129
00130
00131 if (logfile.is_open()) logfile.close();
00132
00133
00134 if (x.empty() || x == "+")
00135 {
00136 logfilename = x;
00137 logger.rdbuf(cout.rdbuf());
00138 return;
00139 }
00140
00141
00142 if (x[0] != '+') logfile.open(x.c_str(), ios::out);
00143 else logfile.open(x.c_str()+1, ios::app);
00144 if (!logfile.good())
00145 {
00146
00147 if (logfile.is_open()) logfile.close();
00148 logfile.open(logfilename.c_str(), ios::app);
00149 logger.rdbuf(logfile.is_open() ? logfile.rdbuf() : cout.rdbuf());
00150
00151 throw RuntimeException("Could not open log file '" + x + "'");
00152 }
00153
00154
00155 logfilename = x;
00156
00157
00158 logger.rdbuf(logfile.rdbuf());
00159
00160
00161 logger << "Start logging frePPLe " << PACKAGE_VERSION << " ("
00162 << __DATE__ << ") at " << Date::now() << endl;
00163 }
00164
00165
00166 void LibraryUtils::initialize()
00167 {
00168
00169 static bool init = false;
00170 if (init)
00171 {
00172 logger << "Warning: Calling frepple::LibraryUtils::initialize() more "
00173 << "than once." << endl;
00174 return;
00175 }
00176 init = true;
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 #if defined(HAVE_SETLOCALE) || defined(_MSC_VER)
00188 setlocale(LC_ALL, "" );
00189 #endif
00190
00191
00192 xercesc::XMLPlatformUtils::Initialize();
00193
00194
00195 Command::metadataInstruction = new MetaCategory
00196 ("instruction", "");
00197
00198
00199 CommandPython::metadata2 = new MetaClass(
00200 "instruction", "python", CommandPython::processorXMLInstruction);
00201
00202
00203 PythonInterpreter::initialize();
00204
00205
00206
00207
00208
00209
00210 const char *c = getenv("NUMBER_OF_PROCESSORS");
00211 if (c)
00212 {
00213 int p = atoi(c);
00214 Environment::setProcessors(p);
00215 }
00216 }
00217
00218
00219 DECLARE_EXPORT void MetaClass::registerClass (const string& a, const string& b,
00220 bool def, creatorDefault f)
00221 {
00222
00223 MetaCategory* cat
00224 = const_cast<MetaCategory*>(MetaCategory::findCategoryByTag(a.c_str()));
00225
00226
00227 if (!cat)
00228 throw LogicException("Category " + a
00229 + " not found when registering class " + b);
00230
00231
00232 type = b.empty() ? "unspecified" : b;
00233 typetag = &Keyword::find(type.c_str());
00234 category = cat;
00235
00236
00237 cat->classes[Keyword::hash(b)] = this;
00238
00239
00240 if (def) cat->classes[Keyword::hash("default")] = this;
00241
00242
00243 factoryMethodDefault = f;
00244 factoryPythonProxy = NULL;
00245 }
00246
00247
00248 DECLARE_EXPORT MetaCategory::MetaCategory (const string& a, const string& gr,
00249 readController f, writeController w)
00250 {
00251
00252 if (!a.empty()) categoriesByTag[Keyword::hash(a)] = this;
00253 if (!gr.empty()) categoriesByGroupTag[Keyword::hash(gr)] = this;
00254
00255
00256 readFunction = f;
00257 writeFunction = w;
00258 type = a.empty() ? "unspecified" : a;
00259 typetag = &Keyword::find(type.c_str());
00260 group = gr.empty() ? "unspecified" : gr;
00261 grouptag = &Keyword::find(group.c_str());
00262
00263
00264 nextCategory = NULL;
00265 if (!firstCategory)
00266 firstCategory = this;
00267 else
00268 {
00269 const MetaCategory *i = firstCategory;
00270 while (i->nextCategory) i = i->nextCategory;
00271 const_cast<MetaCategory*>(i)->nextCategory = this;
00272 }
00273 }
00274
00275
00276 DECLARE_EXPORT const MetaCategory* MetaCategory::findCategoryByTag(const char* c)
00277 {
00278
00279 CategoryMap::const_iterator i = categoriesByTag.find(Keyword::hash(c));
00280 return (i!=categoriesByTag.end()) ? i->second : NULL;
00281 }
00282
00283
00284 DECLARE_EXPORT const MetaCategory* MetaCategory::findCategoryByTag(const hashtype h)
00285 {
00286
00287 CategoryMap::const_iterator i = categoriesByTag.find(h);
00288 return (i!=categoriesByTag.end()) ? i->second : NULL;
00289 }
00290
00291
00292 DECLARE_EXPORT const MetaCategory* MetaCategory::findCategoryByGroupTag(const char* c)
00293 {
00294
00295 CategoryMap::const_iterator i = categoriesByGroupTag.find(Keyword::hash(c));
00296 return (i!=categoriesByGroupTag.end()) ? i->second : NULL;
00297 }
00298
00299
00300 DECLARE_EXPORT const MetaCategory* MetaCategory::findCategoryByGroupTag(const hashtype h)
00301 {
00302
00303 CategoryMap::const_iterator i = categoriesByGroupTag.find(h);
00304 return (i!=categoriesByGroupTag.end()) ? i->second : NULL;
00305 }
00306
00307
00308 DECLARE_EXPORT const MetaClass* MetaCategory::findClass(const char* c) const
00309 {
00310
00311 MetaCategory::ClassMap::const_iterator j = classes.find(Keyword::hash(c));
00312 return (j == classes.end()) ? NULL : j->second;
00313 }
00314
00315
00316 DECLARE_EXPORT const MetaClass* MetaCategory::findClass(const hashtype h) const
00317 {
00318
00319 MetaCategory::ClassMap::const_iterator j = classes.find(h);
00320 return (j == classes.end()) ? NULL : j->second;
00321 }
00322
00323
00324 DECLARE_EXPORT void MetaCategory::persist(XMLOutput *o)
00325 {
00326 for (const MetaCategory *i = firstCategory; i; i = i->nextCategory)
00327 if (i->writeFunction) i->writeFunction(i, o);
00328 }
00329
00330
00331 DECLARE_EXPORT const MetaClass* MetaClass::findClass(const char* c)
00332 {
00333
00334 for (MetaCategory::CategoryMap::const_iterator i = MetaCategory::categoriesByTag.begin();
00335 i != MetaCategory::categoriesByTag.end(); ++i)
00336 {
00337
00338 MetaCategory::ClassMap::const_iterator j
00339 = i->second->classes.find(Keyword::hash(c));
00340 if (j != i->second->classes.end()) return j->second;
00341 }
00342
00343 return NULL;
00344 }
00345
00346
00347 DECLARE_EXPORT void MetaClass::printClasses()
00348 {
00349 logger << "Registered classes:" << endl;
00350
00351 for (MetaCategory::CategoryMap::const_iterator i = MetaCategory::categoriesByTag.begin();
00352 i != MetaCategory::categoriesByTag.end(); ++i)
00353 {
00354 logger << " " << i->second->type << endl;
00355
00356 for (MetaCategory::ClassMap::const_iterator
00357 j = i->second->classes.begin();
00358 j != i->second->classes.end();
00359 ++j)
00360 if (j->first == Keyword::hash("default"))
00361 logger << " default ( = " << j->second->type << " )" << j->second << endl;
00362 else
00363 logger << " " << j->second->type << j->second << endl;
00364 }
00365 }
00366
00367
00368 DECLARE_EXPORT Action MetaClass::decodeAction(const char *x)
00369 {
00370
00371 if (!x) throw LogicException("Invalid action NULL");
00372 else if (!strcmp(x,"AC")) return ADD_CHANGE;
00373 else if (!strcmp(x,"A")) return ADD;
00374 else if (!strcmp(x,"C")) return CHANGE;
00375 else if (!strcmp(x,"R")) return REMOVE;
00376 else throw LogicException("Invalid action '" + string(x) + "'");
00377 }
00378
00379
00380 DECLARE_EXPORT Action MetaClass::decodeAction(const AttributeList& atts)
00381 {
00382
00383 const DataElement* c = atts.get(Tags::tag_action);
00384 return *c ? decodeAction(c->getString().c_str()) : ADD_CHANGE;
00385 }
00386
00387
00388 DECLARE_EXPORT bool MetaClass::raiseEvent(Object* v, Signal a) const
00389 {
00390 bool result(true);
00391 for (list<Functor*>::const_iterator i = subscribers[a].begin();
00392 i != subscribers[a].end(); ++i)
00393
00394
00395
00396 if (!(*i)->callback(v,a)) result = false;
00397
00398
00399 return (category && category!=this) ?
00400 (result && category->raiseEvent(v,a)) :
00401 result;
00402 }
00403
00404
00405 Object* MetaCategory::ControllerDefault (const MetaClass* cat, const AttributeList& in)
00406 {
00407 Action act = ADD;
00408 switch (act)
00409 {
00410 case REMOVE:
00411 throw DataException
00412 ("Entity " + cat->type + " doesn't support REMOVE action");
00413 case CHANGE:
00414 throw DataException
00415 ("Entity " + cat->type + " doesn't support CHANGE action");
00416 default:
00417
00418 const MetaClass* j;
00419 if (cat->category)
00420
00421 j = cat;
00422 else
00423 {
00424
00425 const DataElement* type = in.get(Tags::tag_type);
00426 j = static_cast<const MetaCategory&>(*cat).findClass(*type ? Keyword::hash(type->getString()) : MetaCategory::defaultHash);
00427 if (!j)
00428 {
00429 string t(*type ? type->getString() : "default");
00430 throw LogicException("No type " + t + " registered for category " + cat->type);
00431 }
00432 }
00433
00434
00435 Object* result = j->factoryMethodDefault();
00436
00437
00438 if (!result->getType().raiseEvent(result, SIG_ADD))
00439 {
00440
00441 delete result;
00442 throw DataException("Can't create object");
00443 }
00444
00445
00446 return result;
00447 }
00448 throw LogicException("Unreachable code reached");
00449 return NULL;
00450 }
00451
00452
00453 void HasDescription::writeElement(XMLOutput *o, const Keyword &t, mode m) const
00454 {
00455
00456
00457
00458 o->writeElement(Tags::tag_category, cat);
00459 o->writeElement(Tags::tag_subcategory, subcat);
00460 o->writeElement(Tags::tag_description, descr);
00461 }
00462
00463
00464 void HasDescription::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00465 {
00466 if (pAttr.isA(Tags::tag_category))
00467 setCategory(pElement.getString());
00468 else if (pAttr.isA(Tags::tag_subcategory))
00469 setSubCategory(pElement.getString());
00470 else if (pAttr.isA(Tags::tag_description))
00471 setDescription(pElement.getString());
00472 }
00473
00474 }
00475 }
00476