interface.cpp

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

Generated on Tue Feb 22 13:31:26 2011 for Fawkes API by  doxygen 1.4.7