Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * interfaceimporter.cpp - Fawkes Lua Interface Importer 00004 * 00005 * Created: Thu Jan 01 14:32:11 2009 00006 * Copyright 2006-2009 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include <lua/interface_importer.h> 00024 #include <lua/context.h> 00025 00026 #include <config/config.h> 00027 #include <interface/interface.h> 00028 #include <blackboard/blackboard.h> 00029 #include <logging/logger.h> 00030 00031 #include <cstring> 00032 00033 namespace fawkes { 00034 #if 0 /* just to make Emacs auto-indent happy */ 00035 } 00036 #endif 00037 00038 /** @class LuaInterfaceImporter <lua/interface_importer.h> 00039 * Lua interface importer. 00040 * The Lua interface importer reads a list from the configuration for a given 00041 * prefix and exports them to the Lua environment. The configuration entries have 00042 * the form "/this/is/the/prefix/variablename" -> Interface UID. The interfaces 00043 * are exported as a table assigned to the global variable named "interfaces". 00044 * This table has four entries, reading and writing to tables with variablename 00045 * to interface mappings and reading_by_uid and writing_by_uid with mappings from 00046 * the interface UID to the interface. 00047 * @author Tim Niemueller 00048 */ 00049 00050 /** Constructor. 00051 * @param context Lua context 00052 * @param blackboard BlackBoard 00053 * @param config configuration 00054 * @param logger Logger 00055 */ 00056 LuaInterfaceImporter::LuaInterfaceImporter(LuaContext *context, 00057 BlackBoard *blackboard, 00058 Configuration *config, 00059 Logger *logger) 00060 { 00061 __context = context; 00062 __blackboard = blackboard; 00063 __config = config; 00064 __logger = logger; 00065 __two_stage = false; 00066 __context->add_watcher(this); 00067 00068 __interfaces_pushed = false; 00069 } 00070 00071 00072 /** Destructor. */ 00073 LuaInterfaceImporter::~LuaInterfaceImporter() 00074 { 00075 __context->remove_watcher(this); 00076 close_writing_interfaces(); 00077 close_reading_interfaces(); 00078 __ext_rifs.clear(); 00079 __ext_wifs.clear(); 00080 } 00081 00082 00083 /** Open interfaces (internal). 00084 * @param prefix configuration prefix for the interface list 00085 * @param imap interface map to fill with interfaces 00086 * @param write if true interfaces are opened for writing, false to open for reading 00087 */ 00088 void 00089 LuaInterfaceImporter::open_interfaces(std::string &prefix, InterfaceMap &imap, bool write) 00090 { 00091 if (! __config) throw NullPointerException("Config has not been set"); 00092 00093 Configuration::ValueIterator *vi = __config->search(prefix.c_str()); 00094 while (vi->next()) { 00095 if (strcmp(vi->type(), "string") != 0) { 00096 TypeMismatchException e("Only values of type string may occur in %s, " 00097 "but found value of type %s", 00098 prefix.c_str(), vi->type()); 00099 delete vi; 00100 throw e; 00101 } 00102 std::string uid = vi->get_string(); 00103 00104 if (uid.find("::") == std::string::npos) { 00105 delete vi; 00106 throw Exception("Interface UID '%s' at %s is not valid, missing double colon", 00107 uid.c_str(), vi->path()); 00108 } 00109 std::string varname = std::string(vi->path()).substr(prefix.length()); 00110 std::string iftype = uid.substr(0, uid.find("::")); 00111 std::string ifname = uid.substr(uid.find("::") + 2); 00112 00113 if ( __reading_ifs.find(varname) != __reading_ifs.end() ) { 00114 delete vi; 00115 throw Exception("Reading interface with varname %s already opened", varname.c_str()); 00116 } 00117 if ( __reading_multi_ifs.find(varname) != __reading_multi_ifs.end() ) { 00118 delete vi; 00119 throw Exception("Reading multi interface with varname %s already opened", varname.c_str()); 00120 } 00121 if ( __writing_ifs.find(varname) != __writing_ifs.end() ) { 00122 delete vi; 00123 throw Exception("Writing interface with varname %s already opened", varname.c_str()); 00124 } 00125 00126 00127 if (ifname.find_first_of("*?[") == std::string::npos) { 00128 __logger->log_info("LuaInterfaceImporter", "Adding %s interface %s::%s with name %s", 00129 write ? "writing" : "reading", 00130 iftype.c_str(), ifname.c_str(), varname.c_str()); 00131 try { 00132 Interface *iface; 00133 if (write) { 00134 iface = __blackboard->open_for_writing(iftype.c_str(), ifname.c_str()); 00135 } else { 00136 iface = __blackboard->open_for_reading(iftype.c_str(), ifname.c_str()); 00137 } 00138 if (__two_stage) { 00139 iface->resize_buffers(1); 00140 } 00141 imap[varname] = iface; 00142 } catch (Exception &e) { 00143 delete vi; 00144 throw; 00145 } 00146 } else { 00147 if (write) { 00148 delete vi; 00149 throw Exception("Illegal config entry %s=%s, multiple interfaces can " 00150 "only be opened for reading", vi->path(), uid.c_str()); 00151 } 00152 __logger->log_info("LuaInterfaceImporter", "Adding multiple %s interfaces %s::%s with in table %s", 00153 write ? "writing" : "reading", 00154 iftype.c_str(), ifname.c_str(), varname.c_str()); 00155 00156 std::list<Interface *> interfaces = __blackboard->open_multiple_for_reading(iftype.c_str(), ifname.c_str()); 00157 __reading_multi_ifs[varname] = interfaces; 00158 InterfaceObserver *observer = 00159 new InterfaceObserver(this, varname, iftype.c_str(), ifname.c_str()); 00160 __observers[varname] = observer; 00161 __blackboard->register_observer(observer); 00162 } 00163 } 00164 delete vi; 00165 } 00166 00167 00168 /** Open interfaces for reading. 00169 * @param prefix configuration prefix for the interface list 00170 */ 00171 void 00172 LuaInterfaceImporter::open_reading_interfaces(std::string &prefix) 00173 { 00174 open_interfaces(prefix, __reading_ifs, /* write */ false); 00175 } 00176 00177 /** Open interfaces for writing. 00178 * @param prefix configuration prefix for the interface list 00179 */ 00180 void 00181 LuaInterfaceImporter::open_writing_interfaces(std::string &prefix) 00182 { 00183 open_interfaces(prefix, __writing_ifs, /* write */ true); 00184 } 00185 00186 00187 /** Add a single interface to be pushed to the context. 00188 * The given interface is pushed with the given variable name to the context, 00189 * on explicit push_interfaces() and on the next LuaContext restart. However, the 00190 * interface is not owned by the importer and thus neither is the interface read 00191 * during read() nor is it written during write(). It is also not automatically 00192 * closed in the destructor. 00193 * @param varname the variable name of the interface 00194 * @param interface the interface to push 00195 */ 00196 void 00197 LuaInterfaceImporter::add_interface(std::string varname, Interface *interface) 00198 { 00199 if ( interface->is_writer() ) { 00200 __ext_wifs[varname] = interface; 00201 } else { 00202 __ext_rifs[varname] = interface; 00203 } 00204 } 00205 00206 00207 void 00208 LuaInterfaceImporter::add_observed_interface(std::string varname, 00209 const char *type, const char *id) 00210 { 00211 try { 00212 if (__reading_multi_ifs.find(varname) == __reading_multi_ifs.end() ) { 00213 throw Exception("Notified about unknown interface varname %s", varname.c_str()); 00214 } 00215 Interface *iface = __blackboard->open_for_reading(type, id); 00216 __context->add_package((std::string("interfaces.") + iface->type()).c_str()); 00217 __reading_multi_ifs[varname].push_back(iface); 00218 __context->get_global("interfaces"); // it 00219 __context->get_field(-1, "reading"); // it rt 00220 __context->get_field(-1, varname.c_str()); // it rt vt 00221 __context->push_usertype(iface, iface->type(), "fawkes"); // it rt vt iface 00222 __context->raw_seti(-2, __reading_multi_ifs[varname].size()); // it rt vt 00223 __context->push_usertype(iface, iface->type(), "fawkes"); // it rt vt iface 00224 __context->set_field(iface->uid(), -2); // it rt vt 00225 __context->pop(3); // --- 00226 } catch (Exception &e) { 00227 __logger->log_warn("LuaInterfaceImporter", "Failed to add observed interface " 00228 "%s:%s, exception follows", type, id); 00229 __logger->log_warn("LuaInterfaceImporter", e); 00230 } 00231 } 00232 00233 00234 /** Close interfaces for reading. */ 00235 void 00236 LuaInterfaceImporter::close_reading_interfaces() 00237 { 00238 for (InterfaceMap::iterator i = __reading_ifs.begin(); i != __reading_ifs.end(); ++i) { 00239 __blackboard->close(i->second); 00240 } 00241 __reading_ifs.clear(); 00242 00243 for (ObserverMap::iterator o = __observers.begin(); o != __observers.end(); ++o) { 00244 __blackboard->unregister_observer(o->second); 00245 delete o->second; 00246 } 00247 __observers.clear(); 00248 00249 for (InterfaceListMap::iterator i = __reading_multi_ifs.begin(); i != __reading_multi_ifs.end(); ++i) { 00250 for (std::list<Interface *>::iterator j = i->second.begin(); j != i->second.end(); ++j) { 00251 __blackboard->close(*j); 00252 } 00253 } 00254 __reading_multi_ifs.clear(); 00255 } 00256 00257 00258 /** Close interfaces for writing. */ 00259 void 00260 LuaInterfaceImporter::close_writing_interfaces() 00261 { 00262 for (InterfaceMap::iterator i = __writing_ifs.begin(); i != __writing_ifs.end(); ++i) { 00263 __blackboard->close(i->second); 00264 } 00265 __writing_ifs.clear(); 00266 } 00267 00268 /** Get interface map of reading interfaces. 00269 * @return interface map of reading interfaces 00270 */ 00271 LuaInterfaceImporter::InterfaceMap & 00272 LuaInterfaceImporter::reading_interfaces() 00273 { 00274 return __reading_ifs; 00275 } 00276 00277 00278 /** Get interface map of writing interfaces. 00279 * @return interface map of writing interfaces 00280 */ 00281 LuaInterfaceImporter::InterfaceMap & 00282 LuaInterfaceImporter::writing_interfaces() 00283 { 00284 return __writing_ifs; 00285 } 00286 00287 00288 /** Read from all reading interfaces. */ 00289 void 00290 LuaInterfaceImporter::read() 00291 { 00292 for (InterfaceMap::iterator i = __reading_ifs.begin(); i != __reading_ifs.end(); ++i) { 00293 i->second->read(); 00294 } 00295 } 00296 00297 00298 /** Read from all reading interfaces into a buffer. 00299 */ 00300 void 00301 LuaInterfaceImporter::read_to_buffer() 00302 { 00303 InterfaceMap::iterator i; 00304 if (! __two_stage) { 00305 for (i = __reading_ifs.begin(); i != __reading_ifs.end(); ++i) { 00306 i->second->resize_buffers(1); 00307 } 00308 __two_stage = true; 00309 } 00310 for (i = __reading_ifs.begin(); i != __reading_ifs.end(); ++i) { 00311 i->second->copy_shared_to_buffer(0); 00312 } 00313 } 00314 00315 /** Update interfaces from internal buffers. 00316 * @exception Exception thrown if read_to_buffer() was not called 00317 * before. 00318 */ 00319 void 00320 LuaInterfaceImporter::read_from_buffer() 00321 { 00322 if (! __two_stage) { 00323 throw Exception("LuaInterfaceImporter: trying to read buffer witout " 00324 "previous read_to_buffer()"); 00325 } 00326 InterfaceMap::iterator i; 00327 for (i = __reading_ifs.begin(); i != __reading_ifs.end(); ++i) { 00328 i->second->read_from_buffer(0); 00329 } 00330 } 00331 00332 /** Write all writing interfaces. */ 00333 void 00334 LuaInterfaceImporter::write() 00335 { 00336 for (InterfaceMap::iterator i = __writing_ifs.begin(); i != __writing_ifs.end(); ++i) { 00337 try { 00338 i->second->write(); 00339 } catch (Exception &e) { 00340 e.append("Failed to write interface %s, ignoring.", i->second->uid()); 00341 e.print_trace(); 00342 } 00343 } 00344 } 00345 00346 void 00347 LuaInterfaceImporter::push_interfaces_varname(LuaContext *context, InterfaceMap &imap) 00348 { 00349 InterfaceMap::iterator imi; 00350 for (imi = imap.begin(); imi != imap.end(); ++imi) { 00351 context->add_package((std::string("interfaces.") + imi->second->type()).c_str()); 00352 context->push_usertype(imi->second, imi->second->type(), "fawkes"); 00353 context->set_field(imi->first.c_str()); 00354 } 00355 } 00356 00357 void 00358 LuaInterfaceImporter::push_multi_interfaces_varname(LuaContext *context, InterfaceListMap &imap) 00359 { 00360 InterfaceListMap::iterator imi; 00361 for (imi = imap.begin(); imi != imap.end(); ++imi) { 00362 context->create_table(0, imi->second.size()); 00363 int idx = 0; 00364 for (std::list<Interface *>::iterator i = imi->second.begin(); i != imi->second.end(); ++i) { 00365 context->add_package((std::string("interfaces.") + (*i)->type()).c_str()); 00366 context->push_usertype(*i, (*i)->type(), "fawkes"); 00367 context->raw_seti(-2, ++idx); 00368 context->push_usertype(*i, (*i)->type(), "fawkes"); 00369 context->set_field((*i)->uid(), -2); 00370 } 00371 context->set_field(imi->first.c_str()); 00372 } 00373 } 00374 00375 void 00376 LuaInterfaceImporter::push_interfaces_uid(LuaContext *context, InterfaceMap &imap) 00377 { 00378 InterfaceMap::iterator imi; 00379 for (imi = imap.begin(); imi != imap.end(); ++imi) { 00380 context->add_package((std::string("interfaces.") + imi->second->type()).c_str()); 00381 context->push_usertype(imi->second, imi->second->type(), "fawkes"); 00382 context->set_field(imi->second->uid()); 00383 } 00384 } 00385 00386 void 00387 LuaInterfaceImporter::push_interfaces(LuaContext *context) 00388 { 00389 00390 // it: interface table, rt: reading table, wt: writing table, rtu: rt by uid, wtu: wt by uid 00391 context->create_table(0, 4); // it 00392 00393 context->create_table(0, __reading_ifs.size() + __ext_rifs.size()); // it rt 00394 push_interfaces_varname(context, __reading_ifs); // it rt 00395 push_interfaces_varname(context, __ext_rifs); // it rt 00396 push_multi_interfaces_varname(context, __reading_multi_ifs); // it rt 00397 context->set_field("reading"); // it 00398 00399 context->create_table(0, __reading_ifs.size() + __ext_rifs.size()); // it rtu 00400 push_interfaces_uid(context, __reading_ifs); // it rtu 00401 push_interfaces_uid(context, __ext_rifs); // it rtu 00402 context->set_field("reading_by_uid"); // it 00403 00404 context->create_table(0, __writing_ifs.size() + __ext_wifs.size()); // it wt 00405 push_interfaces_varname(context, __writing_ifs); // it wt 00406 push_interfaces_varname(context, __ext_wifs); // it wt 00407 context->set_field("writing"); // it 00408 00409 context->create_table(0, __writing_ifs.size()); // it wtu 00410 push_interfaces_uid(context, __writing_ifs); // it wtu 00411 push_interfaces_uid(context, __ext_wifs); // it wtu 00412 context->set_field("writing_by_uid"); // it 00413 00414 context->set_global("interfaces"); // --- 00415 } 00416 00417 /** Push interfaces to Lua environment. 00418 * The interfaces are pushed to the interfaces table described in the class 00419 * documentation. Note that you need to do this only once. The table is 00420 * automatically re-pushed on a Lua restart event. 00421 */ 00422 void 00423 LuaInterfaceImporter::push_interfaces() 00424 { 00425 __interfaces_pushed = true; 00426 push_interfaces(__context); 00427 } 00428 00429 00430 void 00431 LuaInterfaceImporter::lua_restarted(LuaContext *context) 00432 { 00433 try { 00434 if ( __interfaces_pushed ) { 00435 push_interfaces(context); 00436 } 00437 } catch (Exception &e) { 00438 __logger->log_warn("LuaInterfaceImporter", "Failed to re-push interfacs, exception follows"); 00439 __logger->log_warn("LuaInterfaceImporter", e); 00440 throw; 00441 } 00442 } 00443 00444 00445 /** Constructor. 00446 * @param lii LuaInterfaceImporter instance this observer is assigned to 00447 * @param varname variable name 00448 * @param type type of interface 00449 * @param id_pattern ID pattern to observe 00450 */ 00451 LuaInterfaceImporter::InterfaceObserver::InterfaceObserver(LuaInterfaceImporter *lii, 00452 std::string varname, 00453 const char *type, const char *id_pattern) 00454 { 00455 __lii = lii; 00456 __varname = varname; 00457 00458 bbio_add_observed_create(type, id_pattern); 00459 } 00460 00461 00462 void 00463 LuaInterfaceImporter::InterfaceObserver::bb_interface_created(const char *type, const char *id) throw() 00464 { 00465 __lii->add_observed_interface(__varname, type, id); 00466 } 00467 00468 } // end of namespace fawkes