Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * interface.cpp - BlackBoard Interface 00004 * 00005 * Created: Mon Oct 09 18:54:50 2006 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. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <interface/interface.h> 00025 00026 #include <interface/mediators/interface_mediator.h> 00027 #include <interface/mediators/message_mediator.h> 00028 #include <core/threading/refc_rwlock.h> 00029 #include <core/exceptions/system.h> 00030 #include <utils/time/clock.h> 00031 #include <utils/time/time.h> 00032 00033 #include <cstring> 00034 #include <cstdio> 00035 #include <cstdlib> 00036 #include <typeinfo> 00037 #include <regex.h> 00038 00039 namespace fawkes { 00040 00041 /** @class InterfaceWriteDeniedException <interface/interface.h> 00042 * This exception is thrown if a write has been attempted on a read-only interface. 00043 * @see Interface::write() 00044 * @ingroup Exceptions 00045 */ 00046 00047 /** Constructor. 00048 * @param type type of the interface which caused the exception 00049 * @param id id of the interface which caused the exception 00050 * @param msg additional informative message 00051 */ 00052 InterfaceWriteDeniedException::InterfaceWriteDeniedException(const char *type, 00053 const char *id, 00054 const char *msg) 00055 : Exception("This interface instance '%s' of type '%s' is not opened for writing. %s", 00056 id, type, msg) 00057 { 00058 } 00059 00060 /** @class InterfaceMessageEnqueueException <interface/interface.h> 00061 * This exception is thrown if a write has been attempted on a read-only interface. 00062 * @see Interface::write() 00063 * @ingroup Exceptions 00064 */ 00065 00066 /** Constructor. 00067 * @param type type of the interface which caused the exception 00068 * @param id id of the interface which caused the exception 00069 */ 00070 InterfaceMessageEnqueueException::InterfaceMessageEnqueueException(const char *type, 00071 const char *id) 00072 : Exception("This interface instance '%s' of type '%s' IS opened for writing, but " 00073 "messages can only be enqueued on reading interfaces.", id, type) 00074 { 00075 } 00076 00077 /** @class InterfaceInvalidMessageException <interface/interface.h> 00078 * This exception is thrown if a message has been queued in the interface which is 00079 * not recognized by the interface. 00080 * @ingroup Exceptions 00081 */ 00082 00083 /** Constructor. 00084 * @param interface interface that the invalid message was enqueued to 00085 * @param message enqueued message 00086 */ 00087 InterfaceInvalidMessageException::InterfaceInvalidMessageException(const Interface *interface, 00088 const Message *message) 00089 : Exception("Message of type '%s' cannot be enqueued in interface of type '%s'", 00090 message->type(), interface->type()) 00091 { 00092 } 00093 00094 00095 /** @class InterfaceInvalidException <interface/interface.h> 00096 * This exception is thrown if an interface is invalid and it is attempted to call 00097 * read()/write(). 00098 * @ingroup Exceptions 00099 */ 00100 00101 /** Constructor. 00102 * @param interface invalid interface that the operation was tried on 00103 * @param method the method that was tried to execute 00104 */ 00105 InterfaceInvalidException::InterfaceInvalidException(const Interface *interface, 00106 const char *method) 00107 : Exception("The interface %s (instance serial %u) is invalid. You cannot call %s anymore.", 00108 interface->uid(), interface->serial(), method) 00109 { 00110 } 00111 00112 00113 /** @class Interface <interface/interface.h> 00114 * Base class for all Fawkes BlackBoard interfaces. 00115 * Never use directly. Use interface generator to create interfaces. 00116 * 00117 * Interfaces are identified by a type and an ID. The type is just a textual 00118 * representation of the class name. The ID identifies a specific instance of this 00119 * interface type. Additionally each interface has a hash. The hash is an MD5 00120 * digest of the XML config file that was fed to the interface generator to 00121 * create the interface. It is used to detect incompatible versions of the same 00122 * interface type. 00123 * 00124 * An interface has an internal timestamp. This timestamp indicates when the 00125 * data in the interface has been modified last. The timestamp is usually 00126 * automatically updated. But it some occasions the writer may choose to provide 00127 * its own timestamp data. This can be useful for example for an interface 00128 * providing hardware data to give the exact capture time. 00129 * In the automatic case nothing has to be done manually. The timestamp is 00130 * updated automatically by calling the write() method if and only if the 00131 * data in the interface has actually been modified. The reader can call 00132 * changed() to see if the data changed. 00133 * In the non-automatic case the writer must first disable automatic timestamping 00134 * using set_auto_timestamping(). Then it must provide a timestamp everytime 00135 * before calling write(). Note that setting the timestamp already marks the 00136 * interface as having changed. So set the timestamp only if the data has 00137 * changed and the readers should see this. 00138 * 00139 * @author Tim Niemueller 00140 */ 00141 00142 /** @var Interface::data_ptr 00143 * Pointer to local memory storage 00144 */ 00145 00146 /** @var Interface::data_ts 00147 * Pointer to data casted to timestamp struct. This assumes that the very 00148 * first two entries are 64 bit wide signed integers containing seconds and 00149 * microseconds since the Unix epoch. 00150 */ 00151 00152 /** @var Interface::data_size 00153 * Minimal data size to hold data storage. 00154 */ 00155 00156 /** @var Interface::data_changed 00157 * Indicator if data has changed. 00158 * This must be set by all methods that manipulate internal data or the 00159 * timestamp. Only if set to true a call to write() will update data_ts. 00160 */ 00161 00162 /** @fn bool Interface::message_valid(const Message *message) const = 0 00163 * Check if the message is valid and can be enqueued. 00164 * @param message The message to check 00165 * @return true, if the message is valid and may be enqueued, false otherwise 00166 * 00167 * @fn bool Interface::create_message(const char *type) const = 0 00168 * Create message based on type name. 00169 * This will create a new message of the given type. The type must be given without 00170 * the InterfaceName:: prefix but just the plain class name of the message. 00171 * @param type message type 00172 * @return message of the given type, empty 00173 * @exception UnknownTypeException thrown if this interface cannot create a message 00174 * of the given type. 00175 * 00176 * @fn void Interface::copy_values(const Interface *interface) = 0 00177 * Copy values from another interface. 00178 * The operation will only succeed if the supplied interface is of the same 00179 * type as this instance. 00180 * @param interface interface to copy from 00181 * 00182 * @fn const char * Interface::enum_tostring(const char *enumtype, int val) const = 0 00183 * Convert arbitrary enum value to string. 00184 * Given the string representation of the enum type and the value this method 00185 * returns the string representation of the specific value, or the string 00186 * UNKNOWN if the value is not defined. An exception is thrown if the enum 00187 * type is invalid. 00188 * @param enumtype enum type as string 00189 * @param val value to convert 00190 * @return string representation of value 00191 * @exception UnknownTypeException thrown if enumtype is not specified for 00192 * interface. 00193 */ 00194 00195 /** Constructor */ 00196 Interface::Interface() 00197 { 00198 __write_access = false; 00199 __rwlock = NULL; 00200 __valid = true; 00201 __next_message_id = 0; 00202 __num_fields = 0; 00203 __fieldinfo_list = NULL; 00204 __messageinfo_list = NULL; 00205 __clock = Clock::instance(); 00206 __timestamp = new Time(0, 0); 00207 __local_read_timestamp = new Time(0, 0); 00208 __auto_timestamping = true; 00209 data_changed = false; 00210 memset(__hash, 0, __INTERFACE_HASH_SIZE); 00211 memset(__hash_printable, 0, __INTERFACE_HASH_SIZE * 2 + 1); 00212 00213 data_ptr = NULL; 00214 data_size = 0; 00215 00216 __message_queue = new MessageQueue(); 00217 } 00218 00219 00220 /** Destructor */ 00221 Interface::~Interface() 00222 { 00223 if ( __rwlock) __rwlock->unref(); 00224 delete __message_queue; 00225 // free fieldinfo list 00226 interface_fieldinfo_t *finfol = __fieldinfo_list; 00227 while ( finfol ) { 00228 __fieldinfo_list = __fieldinfo_list->next; 00229 free(finfol); 00230 finfol = __fieldinfo_list; 00231 } 00232 // free messageinfo list 00233 interface_messageinfo_t *minfol = __messageinfo_list; 00234 while ( minfol ) { 00235 __messageinfo_list = __messageinfo_list->next; 00236 free(minfol); 00237 minfol = __messageinfo_list; 00238 } 00239 delete __timestamp; 00240 } 00241 00242 /** Get interface hash. 00243 * The interface is a unique version identifier of an interface. It is the has of 00244 * the input XML file during the generation of the interface. It is meant to be used 00245 * to ensure that all sides are using the exact same version of an interface. 00246 * @return constant byte string containing the hash value of hash_size() length 00247 */ 00248 const unsigned char * 00249 Interface::hash() const 00250 { 00251 return __hash; 00252 } 00253 00254 00255 /** Get printable interface hash. 00256 * @return printable version of hash() 00257 */ 00258 const char * 00259 Interface::hash_printable() const 00260 { 00261 return __hash_printable; 00262 } 00263 00264 00265 /** Set hash. Never use directly. 00266 * @param ihash interface hash 00267 */ 00268 void 00269 Interface::set_hash(unsigned char *ihash) 00270 { 00271 memcpy(__hash, ihash, __INTERFACE_HASH_SIZE); 00272 for (size_t s = 0; s < __INTERFACE_HASH_SIZE; ++s) { 00273 snprintf(&__hash_printable[s*2], 3, "%02X", __hash[s]); 00274 } 00275 } 00276 00277 00278 /** Add an entry to the field info list. 00279 * Never use directly, use the interface generator instead. The info list 00280 * is used for introspection purposes to allow for iterating over all fields 00281 * of an interface. 00282 * @param type field type 00283 * @param name name of the field, this is referenced, not copied 00284 * @param length length of the field 00285 * @param value pointer to the value in the data struct 00286 * @param enumtype name of the enum type, valid only if type == IFT_ENUM. 00287 */ 00288 void 00289 Interface::add_fieldinfo(interface_fieldtype_t type, const char *name, 00290 size_t length, void *value, const char *enumtype) 00291 { 00292 interface_fieldinfo_t *infol = __fieldinfo_list; 00293 interface_fieldinfo_t *newinfo = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t)); 00294 00295 newinfo->type = type; 00296 newinfo->enumtype = enumtype; 00297 newinfo->name = name; 00298 newinfo->length = length; 00299 newinfo->value = value; 00300 newinfo->next = NULL; 00301 00302 if ( infol == NULL ) { 00303 // first entry 00304 __fieldinfo_list = newinfo; 00305 } else { 00306 // append to list 00307 while ( infol->next != NULL ) { 00308 infol = infol->next; 00309 } 00310 infol->next = newinfo; 00311 } 00312 00313 ++__num_fields; 00314 } 00315 00316 00317 /** Add an entry to the message info list. 00318 * Never use directly, use the interface generator instead. The info list 00319 * is used for introspection purposes to allow for iterating over all message 00320 * types of an interface. 00321 * @param type the type of the message 00322 */ 00323 void 00324 Interface::add_messageinfo(const char *type) 00325 { 00326 interface_messageinfo_t *infol = __messageinfo_list; 00327 interface_messageinfo_t *newinfo = (interface_messageinfo_t *)malloc(sizeof(interface_messageinfo_t)); 00328 00329 newinfo->type = type; 00330 newinfo->next = NULL; 00331 00332 if ( infol == NULL ) { 00333 // first entry 00334 __messageinfo_list = newinfo; 00335 } else { 00336 // append to list 00337 while ( infol->next != NULL ) { 00338 infol = infol->next; 00339 } 00340 infol->next = newinfo; 00341 } 00342 } 00343 00344 00345 /** Obtain a list of textual representations of the message types 00346 * available for this interface. 00347 * @return the message types 00348 */ 00349 std::list<const char *> 00350 Interface::get_message_types() 00351 { 00352 std::list<const char *> types; 00353 interface_messageinfo_t *cur = __messageinfo_list; 00354 00355 while ( cur != NULL ) { 00356 types.push_back(cur->type); 00357 cur = cur->next; 00358 } 00359 00360 return types; 00361 } 00362 00363 00364 /** Get size of interface hash. 00365 * Returns the size in bytes of the interface hash. This depends on the used hash. 00366 * @return size of interface hash string 00367 */ 00368 size_t 00369 Interface::hash_size() const 00370 { 00371 return __INTERFACE_HASH_SIZE; 00372 } 00373 00374 00375 /** Get data chunk. 00376 * Use sparsely 00377 * @return const pointer to the data chunk 00378 */ 00379 const void * 00380 Interface::datachunk() const 00381 { 00382 return data_ptr; 00383 } 00384 00385 00386 /** Check if this is a writing instance. 00387 * @return true if this is a writing instance, false otherwise 00388 */ 00389 bool 00390 Interface::is_writer() const 00391 { 00392 return __write_access; 00393 } 00394 00395 00396 /** Mark this interface invalid. 00397 * An interface can become invalid, for example if the connection of a RemoteBlackBoard 00398 * dies. In this case the interface becomes invalid and successive read()/write() calls 00399 * will throw an InterfaceInvalidException. 00400 * @param valid true to mark the interface valid or false to mark it invalid 00401 */ 00402 void 00403 Interface::set_validity(bool valid) 00404 { 00405 __rwlock->lock_for_write(); 00406 __valid = valid; 00407 __rwlock->unlock(); 00408 } 00409 00410 00411 /** Check validity of interface. 00412 * @return true if interface is valid, false otherwise 00413 */ 00414 bool 00415 Interface::is_valid() const 00416 { 00417 return __valid; 00418 } 00419 00420 00421 /** Read from BlackBoard into local copy. 00422 * @exception InterfaceInvalidException thrown if the interface has been marked invalid 00423 */ 00424 void 00425 Interface::read() 00426 { 00427 __rwlock->lock_for_read(); 00428 if ( __valid ) { 00429 memcpy(data_ptr, __mem_data_ptr, data_size); 00430 *__local_read_timestamp = *__timestamp; 00431 __timestamp->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec); 00432 } else { 00433 __rwlock->unlock(); 00434 throw InterfaceInvalidException(this, "read()"); 00435 } 00436 __rwlock->unlock(); 00437 } 00438 00439 00440 /** Write from local copy into BlackBoard memory. 00441 * @exception InterfaceInvalidException thrown if the interface has been marked invalid 00442 */ 00443 void 00444 Interface::write() 00445 { 00446 if ( ! __write_access ) { 00447 throw InterfaceWriteDeniedException(__type, __id, "Cannot write."); 00448 } 00449 00450 __rwlock->lock_for_write(); 00451 if ( __valid ) { 00452 memcpy(__mem_data_ptr, data_ptr, data_size); 00453 if (data_changed) { 00454 if (__auto_timestamping) __timestamp->stamp(); 00455 long sec = 0, usec = 0; 00456 __timestamp->get_timestamp(sec, usec); 00457 data_ts->timestamp_sec = sec; 00458 data_ts->timestamp_usec = usec; 00459 data_changed = false; 00460 } 00461 } else { 00462 __rwlock->unlock(); 00463 throw InterfaceInvalidException(this, "write()"); 00464 } 00465 __rwlock->unlock(); 00466 00467 __interface_mediator->notify_of_data_change(this); 00468 } 00469 00470 00471 /** Get data size. 00472 * @return size in bytes of data segment 00473 */ 00474 unsigned int 00475 Interface::datasize() const 00476 { 00477 return data_size; 00478 } 00479 00480 00481 /** Set type, ID and UID. 00482 * Sets type and ID, UID is generated automatically as Type::ID. 00483 * @param type string, a maxmimum of __INTERFACE_TYPE_SIZE bytes are copied 00484 * @param ID string, a maxmimum of __INTERFACE_ID_SIZE bytes are copied 00485 */ 00486 void 00487 Interface::set_type_id(const char *type, const char *id) 00488 { 00489 strncpy(__type, type, __INTERFACE_TYPE_SIZE); 00490 strncpy(__id, id, __INTERFACE_ID_SIZE); 00491 snprintf(__uid, __INTERFACE_UID_SIZE, "%s::%s", type, id); 00492 } 00493 00494 00495 /** Set instance serial. 00496 * @param instance_serial instance serial 00497 */ 00498 void 00499 Interface::set_instance_serial(unsigned short instance_serial) 00500 { 00501 __instance_serial = instance_serial; 00502 } 00503 00504 00505 /** Set mediators. 00506 * @param iface_mediator interface mediator 00507 * @param msg_mediator message mediator. 00508 */ 00509 void 00510 Interface::set_mediators(InterfaceMediator *iface_mediator, MessageMediator *msg_mediator) 00511 { 00512 __interface_mediator = iface_mediator; 00513 __message_mediator = msg_mediator; 00514 } 00515 00516 00517 /** Set memory data. 00518 * @param serial mem serial 00519 * @param real_ptr pointer to whole chunk 00520 * @param data_ptr pointer to data chunk 00521 */ 00522 void 00523 Interface::set_memory(unsigned int serial, void *real_ptr, void *data_ptr) 00524 { 00525 __mem_serial = serial; 00526 __mem_real_ptr = real_ptr; 00527 __mem_data_ptr = data_ptr; 00528 } 00529 00530 00531 /** Set read/write info. 00532 * @param write_access true to enable write access, false for read-only 00533 * @param rwlock read/write lock for this interface 00534 */ 00535 void 00536 Interface::set_readwrite(bool write_access, RefCountRWLock *rwlock) 00537 { 00538 __write_access = write_access; 00539 __rwlock = rwlock; 00540 } 00541 00542 00543 /** Check equality of two interfaces. 00544 * Two interfaces are the same if their types and identifiers are equal. 00545 * This does not mean that both interfaces are the very same instance for accessing 00546 * the BlackBoard. Instead this just means that both instances will access the same 00547 * chunk of memory in the BlackBoard and the instances MAY be the same. 00548 * If you want to know if two instances are exactly the same compare the instance 00549 * serials using the serial() method. 00550 * @param comp interface to compare current instance with 00551 * @return true, if interfaces point to the same data, false otherwise 00552 */ 00553 bool 00554 Interface::operator==(Interface &comp) const 00555 { 00556 return ( (strncmp(__type, comp.__type, sizeof(__type)) == 0) && 00557 (strncmp(__id, comp.__id, sizeof(__id)) == 0) ); 00558 } 00559 00560 00561 /** Check if interface is of given type. 00562 * @param interface_type type to query 00563 * @return true, if current instance is of given type, false otherwise 00564 */ 00565 bool 00566 Interface::oftype(const char *interface_type) const 00567 { 00568 return (strncmp(this->__type, interface_type, sizeof(this->__type)) == 0); 00569 } 00570 00571 00572 /** Get type of interface. 00573 * @return string with the type of the interface. 00574 */ 00575 const char * 00576 Interface::type() const 00577 { 00578 return __type; 00579 } 00580 00581 00582 /** Get identifier of interface. 00583 * @return string with the identifier of the interface. 00584 */ 00585 const char * 00586 Interface::id() const 00587 { 00588 return __id; 00589 } 00590 00591 00592 /** Get unique identifier of interface. 00593 * As the name suggests this ID denotes a unique memory instance of this interface 00594 * in the blackboard. It is provided by the system and currently returns a string 00595 * of the form "type::id", where type is replaced by the type returned by type() and 00596 * id is the ID returned by id(). 00597 * @return string with the unique identifier of the interface. 00598 */ 00599 const char * 00600 Interface::uid() const 00601 { 00602 return __uid; 00603 } 00604 00605 00606 /** Get instance serial of interface. 00607 * @return instance serial of the interface. 00608 */ 00609 unsigned short 00610 Interface::serial() const 00611 { 00612 return __instance_serial; 00613 } 00614 00615 00616 /** Get memory serial of interface. 00617 * @return memory serial of interface 00618 */ 00619 unsigned int 00620 Interface::mem_serial() const 00621 { 00622 return __mem_serial; 00623 } 00624 00625 00626 /** Get timestamp of last write. 00627 * Note that you need to call read() before this provides useful information. 00628 * @return timestamp of last write. 00629 */ 00630 const Time * 00631 Interface::timestamp() const 00632 { 00633 return __timestamp; 00634 } 00635 00636 00637 /** Set timestamp. 00638 * @param t time stamp to copy time from, if NULL current time is queried 00639 * from clock. 00640 */ 00641 void 00642 Interface::set_timestamp(const Time *t) 00643 { 00644 if (!__auto_timestamping) throw Exception("Auto timestamping enabled, cannot " 00645 "set explicit timestamp"); 00646 if (!__write_access) throw Exception("Timestamp can only be set on writing " 00647 "instance"); 00648 00649 if (t) { 00650 *__timestamp = t; 00651 } else { 00652 __timestamp->stamp(); 00653 } 00654 data_changed = true; 00655 } 00656 00657 00658 /** Set clock to use for timestamping. 00659 * @param clock clock to use from now on 00660 */ 00661 void 00662 Interface::set_clock(Clock *clock) 00663 { 00664 __clock = clock; 00665 __timestamp->set_clock(clock); 00666 } 00667 00668 00669 /** Enable or disable automated timestamping. 00670 * @param enabled true to enable automated timestamping, false to disable 00671 */ 00672 void 00673 Interface::set_auto_timestamping(bool enabled) 00674 { 00675 __auto_timestamping = enabled; 00676 } 00677 00678 00679 /** Check if data has been changed. 00680 * Note that if the data has been modified this method will return true at least 00681 * until the next call to read. From then on it will return false if the data has 00682 * not been modified between the two read() calls and still true otherwise. 00683 * @return true if data has been changed between the last call to read() and 00684 * the one before. 00685 */ 00686 bool 00687 Interface::changed() const 00688 { 00689 return (*__timestamp != __local_read_timestamp); 00690 } 00691 00692 00693 /** Set from a raw data chunk. 00694 * This allows for setting the interface data from a raw chunk. This is not useful 00695 * in general but only in rare situations like network transmission. Do not use it unless 00696 * you really know what you are doing. The method expects the chunk to be exactly of the 00697 * size returned by datasize(). No check is done, a segfault will most likely occur 00698 * if you provide invalid data. 00699 * @param chunk data chunk, must be exactly of the size that is returned by datasize() 00700 */ 00701 void 00702 Interface::set_from_chunk(void *chunk) 00703 { 00704 // This could be checked but should never happen with our generated interfaces anyway 00705 // if ( data_ptr == NULL ) throw NullPointerException("Interface not initialized"); 00706 00707 memcpy(data_ptr, chunk, data_size); 00708 } 00709 00710 /** Check if there is a writer for the interface. 00711 * Use this method to determine if there is any open instance of the interface 00712 * that is writing to the interface. This can also be the queried interface 00713 * instance. 00714 * @return true if a writer for the interface exists, false otherwise 00715 */ 00716 bool 00717 Interface::has_writer() const 00718 { 00719 return __interface_mediator->exists_writer(this); 00720 } 00721 00722 00723 /** Get the number of readers. 00724 * Use this method to determine how many reading instances of the interface 00725 * currently exist. If the current instance is a reading instance it will 00726 * be included in the count number. To determine if you are the last man having 00727 * this interface you can use the following code: 00728 * @code 00729 * // for a writing instance: 00730 * if ( interface->num_readers == 0 ) { 00731 * // we are the last one to have this interface open 00732 * } 00733 * 00734 * // for a reading instance: 00735 * if ( ! interface->has_writer() && (interface->num_readers() == 0) ) { 00736 * // we are the last one to have this interface open 00737 * } 00738 * @endcode 00739 * Note that this can result in a race condition. You have to be registered as 00740 * a BlackBoardEventListener to be sure that you are really the last. 00741 * @return number of readers 00742 */ 00743 unsigned int 00744 Interface::num_readers() const 00745 { 00746 return __interface_mediator->num_readers(this); 00747 } 00748 00749 00750 /** Enqueue message at end of queue. 00751 * This appends the given message to the queue and transmits the message via the 00752 * message mediator. The message is afterwards owned by the other side and will be 00753 * unrefed and freed as soon as it has been processed. If you want to keep this 00754 * message to read a feedback status you have to reference it _before_ enqueuing 00755 * it! 00756 * This can only be called on a reading interface instance. 00757 * @param message Message to enqueue. 00758 * @return message id after message has been queued 00759 * @exception MessageAlreadyQueuedException thrown if the message has already been 00760 * enqueued to an interface. 00761 */ 00762 unsigned int 00763 Interface::msgq_enqueue(Message *message) 00764 { 00765 if ( __write_access ) { 00766 throw InterfaceMessageEnqueueException(__type, __id); 00767 } 00768 00769 if ( message_valid(message) ) { 00770 message->set_interface(this); 00771 message->set_id(next_msg_id()); 00772 // transmit might change the message id! 00773 __message_mediator->transmit(message); 00774 unsigned int msgid = message->id(); 00775 message->unref(); 00776 return msgid; 00777 } else { 00778 throw InterfaceInvalidMessageException(this, message); 00779 } 00780 } 00781 00782 00783 /** Enqueue copy of message at end of queue. 00784 * This method creates a copy of the message and enqueues it. Note that this way 00785 * you cannot receive status message in the message, because the other side will not 00786 * use your message instance but a copy instead. 00787 * 00788 * This is particularly useful if you call from an environment with automatic garbage 00789 * collection that does not honor the referencing feature of message but rather just 00790 * deletes it. 00791 * This can only be called on a reading interface instance. 00792 * @param message Message to enqueue. 00793 * @return message id after message has been queued 00794 * @exception MessageAlreadyQueuedException thrown if the message has already been 00795 * enqueued to an interface. 00796 */ 00797 unsigned int 00798 Interface::msgq_enqueue_copy(Message *message) 00799 { 00800 if ( __write_access ) { 00801 throw InterfaceMessageEnqueueException(__type, __id); 00802 } 00803 if ( message == NULL ) { 00804 throw NullPointerException("Message may not be NULL"); 00805 } 00806 00807 if ( message_valid(message) ) { 00808 Message *mcopy = message->clone(); 00809 mcopy->set_interface(this); 00810 mcopy->set_id(next_msg_id()); 00811 __message_mediator->transmit(mcopy); 00812 unsigned int msgid = mcopy->id(); 00813 mcopy->unref(); 00814 message->set_id(msgid); 00815 return msgid; 00816 } else { 00817 throw InterfaceInvalidMessageException(this, message); 00818 } 00819 } 00820 00821 00822 /** Enqueue message. 00823 * This will enqueue the message without transmitting it via the message mediator. 00824 * This can only be called on a writing interface instance. 00825 * @param message message to enqueue 00826 */ 00827 void 00828 Interface::msgq_append(Message *message) 00829 { 00830 if ( ! __write_access ) { 00831 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00832 "reading instance of an interface (append)."); 00833 } 00834 00835 __message_queue->append(message); 00836 } 00837 00838 00839 /** Remove message from queue. 00840 * Removes the given message from the queue. Note that if you unref()ed the message 00841 * after insertion this will most likely delete the object. It is not safe to use the 00842 * message after removing it from the queue in general. Know what you are doing if 00843 * you want to use it. 00844 * This can only be called on a writing interface instance. 00845 * @param message Message to remove. 00846 */ 00847 void 00848 Interface::msgq_remove(Message *message) 00849 { 00850 if ( ! __write_access ) { 00851 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00852 "reading instance of an interface (remove msg)."); 00853 } 00854 00855 return __message_queue->remove(message); 00856 } 00857 00858 00859 /** Remove message from queue. 00860 * Removes message with the given ID from the queue. 00861 * @param message_id Message ID to remove. 00862 * This can only be called on a writing interface instance. 00863 */ 00864 void 00865 Interface::msgq_remove(unsigned int message_id) 00866 { 00867 if ( ! __write_access ) { 00868 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00869 "reading instance of an interface (remove id)."); 00870 } 00871 00872 return __message_queue->remove(message_id); 00873 } 00874 00875 00876 /** Get size of message queue. 00877 * This can only be called on a writing interface instance. 00878 * @return number of messages in queue. 00879 */ 00880 unsigned int 00881 Interface::msgq_size() 00882 { 00883 if ( ! __write_access ) { 00884 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00885 "reading instance of an interface (size)."); 00886 } 00887 00888 return __message_queue->size(); 00889 } 00890 00891 00892 /** Check if queue is empty. 00893 * This can only be called on a writing interface instance. 00894 * @return true if queue is empty, false otherwise 00895 */ 00896 bool 00897 Interface::msgq_empty() 00898 { 00899 if ( ! __write_access ) { 00900 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00901 "reading instance of an interface (empty)."); 00902 } 00903 00904 return __message_queue->empty(); 00905 } 00906 00907 00908 /** Flush all messages. 00909 * Deletes all messages from the queue. 00910 * This can only be called on a writing interface instance. 00911 */ 00912 void 00913 Interface::msgq_flush() 00914 { 00915 if ( ! __write_access ) { 00916 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00917 "reading instance of an interface (flush)."); 00918 } 00919 00920 __message_queue->flush(); 00921 } 00922 00923 00924 /** Lock message queue. 00925 * Lock the message queue. You have to do this before using the iterator safely. 00926 * This can only be called on a writing interface instance. 00927 */ 00928 void 00929 Interface::msgq_lock() 00930 { 00931 if ( ! __write_access ) { 00932 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00933 "reading instance of an interface (lock)."); 00934 } 00935 00936 __message_queue->lock(); 00937 } 00938 00939 00940 /** Try to lock message queue. 00941 * Try to lock the message queue. Returns immediately and does not wait for lock. 00942 * @return true, if the lock has been aquired, false otherwise. 00943 * @see lock() 00944 * This can only be called on a writing interface instance. 00945 */ 00946 bool 00947 Interface::msgq_try_lock() 00948 { 00949 if ( ! __write_access ) { 00950 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00951 "reading instance of an interface (try_lock)."); 00952 } 00953 00954 return __message_queue->try_lock(); 00955 } 00956 00957 00958 /** Unlock message queue. 00959 * Give free the lock on the message queue. 00960 * This can only be called on a writing interface instance. 00961 */ 00962 void 00963 Interface::msgq_unlock() 00964 { 00965 if ( ! __write_access ) { 00966 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00967 "reading instance of an interface (unlock)."); 00968 } 00969 00970 __message_queue->unlock(); 00971 } 00972 00973 /** Get start iterator for message queue. 00974 * Not that you must have locked the queue before this operation! 00975 * This can only be called on a writing interface instance. 00976 * @return iterator to begin of message queue. 00977 * @exception NotLockedException thrown if message queue is not locked during this operation. 00978 */ 00979 MessageQueue::MessageIterator 00980 Interface::msgq_begin() 00981 { 00982 if ( ! __write_access ) { 00983 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 00984 "reading instance of an interface (begin)."); 00985 } 00986 00987 return __message_queue->begin(); 00988 } 00989 00990 00991 /** Get end iterator for message queue. 00992 * Not that you must have locked the queue before this operation! 00993 * This can only be called on a writing interface instance. 00994 * @return iterator beyond end of message queue. 00995 * @exception NotLockedException thrown if message queue is not locked during this operation. 00996 */ 00997 MessageQueue::MessageIterator 00998 Interface::msgq_end() 00999 { 01000 if ( ! __write_access ) { 01001 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 01002 "reading instance of an interface (end)."); 01003 } 01004 01005 return __message_queue->end(); 01006 } 01007 01008 01009 /** Get the first message from the message queue. 01010 * This can only be called on a writing interface instance. 01011 * @return first message in queue or NULL if there is none 01012 */ 01013 Message * 01014 Interface::msgq_first() 01015 { 01016 if ( ! __write_access ) { 01017 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 01018 "reading instance of an interface (first)."); 01019 } 01020 01021 return __message_queue->first(); 01022 } 01023 01024 /** Erase first message from queue. 01025 * This can only be called on a writing interface instance. 01026 */ 01027 void 01028 Interface::msgq_pop() 01029 { 01030 if ( ! __write_access ) { 01031 throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on " 01032 "reading instance of an interface (pop)."); 01033 } 01034 01035 __message_queue->pop(); 01036 } 01037 01038 01039 /** Get iterator over all fields of this interface instance. 01040 * @return field iterator pointing to the very first value 01041 */ 01042 InterfaceFieldIterator 01043 Interface::fields() 01044 { 01045 return InterfaceFieldIterator(this, __fieldinfo_list); 01046 } 01047 01048 01049 /** Invalid iterator. 01050 * @return invalid iterator reprensenting the end. 01051 */ 01052 InterfaceFieldIterator 01053 Interface::fields_end() 01054 { 01055 return InterfaceFieldIterator(); 01056 } 01057 01058 01059 /** Get the number of fields in the interface. 01060 * @return the number of fields 01061 */ 01062 unsigned int 01063 Interface::num_fields() 01064 { 01065 return __num_fields; 01066 } 01067 01068 01069 /** Parse UID to type and ID strings. 01070 * Note that the returned values (type and id) must be freed once they are 01071 * no longer used. Also verifies lengths of the type and id strings. 01072 * @param uid UID to parse 01073 * @param type upon return contains the type part of the UID, must be freed 01074 * @param id upon return contains the ID part, must be freed 01075 */ 01076 void 01077 Interface::parse_uid(const char *uid, char **type, char **id) 01078 { 01079 regex_t re; 01080 int ec = 0; 01081 // Requires in parse_uid() 01082 #define str(s) #s 01083 #define xstr(s) str(s) 01084 if ((ec = regcomp(&re, 01085 "^([a-zA-Z0-9]{1," xstr(__INTERFACE_TYPE_SIZE) "})::" 01086 "([a-zA-Z0-9 _\\.-]{1," xstr(__INTERFACE_ID_SIZE) "})$", 01087 REG_EXTENDED)) != 0) { 01088 char errbuf[1024]; 01089 regerror(ec, &re, errbuf, 1024); 01090 throw Exception("Failed to created regular expression to parse UID (%s)", 01091 errbuf); 01092 } 01093 regmatch_t matches[3]; 01094 if (regexec(&re, uid, 3, matches, 0) != 0) { 01095 regfree(&re); 01096 throw Exception("Failed to match UID %s, format error.", uid); 01097 } 01098 01099 *type = strndup(&(uid[matches[1].rm_so]), matches[1].rm_eo - matches[1].rm_so); 01100 *id = strndup(&(uid[matches[2].rm_so]), matches[2].rm_eo - matches[2].rm_so); 01101 } 01102 01103 } // end namespace fawkes