multi_copy.cpp

00001 
00002 /***************************************************************************
00003  *  multi_copy.cpp - Fawkes WorldModel Multi Interface Copy Fuser
00004  *
00005  *  Created: Tue Jan 13 11:58:33 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 "multi_copy.h"
00024 
00025 #include <core/threading/mutex_locker.h>
00026 #include <blackboard/blackboard.h>
00027 #include <interface/interface.h>
00028 #include <core/exceptions/system.h>
00029 
00030 #include <cstdlib>
00031 #include <cstring>
00032 #include <cstdio>
00033 
00034 using namespace fawkes;
00035 
00036 /** @class WorldModelMultiCopyFuser "multi_copy.h"
00037  * Multi interface copy fuser.
00038  * This fuser simply copies the data of a number of interfaces to another set
00039  * (of the same size) of interfaces.
00040  * The source interfaces are given as pattern with shell wildcards like * and ?.
00041  * The destination IDs is a pattern that contains exactly one "%u". This is
00042  * replaced with a running number for the destination interfaces. The fuser
00043  * registers as an observer and opens any newly created interfaces that match
00044  * the given pattern and creates a write with the ID like the given format for it.
00045  * It accounts for the case where pattern and format are similar and avoids opening
00046  * it's own interfaces causing an infinite loop. Interfaces are never closed.
00047  * @author Tim Niemueller
00048  */
00049 
00050 /** Constructor.
00051  * @param blackboard BlackBoard
00052  * @param type interface type of both interfaces
00053  * @param from_id_pattern pattern for ID of the interfaces to copy from
00054  * @param to_id_format format for ID of the interfaces to copy to
00055  */
00056 WorldModelMultiCopyFuser::WorldModelMultiCopyFuser(fawkes::BlackBoard *blackboard,
00057                                                    const char *type,
00058                                                    const char *from_id_pattern,
00059                                                    const char *to_id_format)
00060 {
00061   __blackboard = blackboard;
00062   __from_id_pattern = from_id_pattern;
00063   __to_id_format = to_id_format;
00064 
00065   std::string::size_type loc = 0;
00066   loc = __to_id_format.find("%");
00067   if ( (loc == std::string::npos) ||
00068        (__to_id_format.find("%", loc+1) != std::string::npos) ||
00069        (__to_id_format.find("%u") == std::string::npos) ) {
00070     throw Exception("to_id_format ('%s') must contain exactly one occurrence of %%u", to_id_format);
00071   }
00072 
00073   std::list<Interface *> exifs;
00074   try {
00075     exifs = blackboard->open_multiple_for_reading(type, from_id_pattern);
00076     unsigned int u = 0;
00077     for (std::list<Interface *>::iterator i = exifs.begin(); i != exifs.end(); ++i) {
00078       char *tid;
00079       if (asprintf(&tid, to_id_format, ++u) != -1) {
00080         std::string sid = tid;
00081         free(tid);
00082         Interface *to_if = blackboard->open_for_writing(type, sid.c_str());
00083         __ifmap[*i] = to_if;
00084       } else {
00085         throw OutOfMemoryException("Could not create interface ID, out of memory");
00086       }
00087     }
00088   } catch (Exception &e) {
00089     for (std::list<Interface *>::iterator i = exifs.begin(); i != exifs.end(); ++i) {
00090       blackboard->close(*i);
00091     }
00092     for (__imi = __ifmap.begin(); __imi != __ifmap.end(); ++__imi) {
00093       blackboard->close(__imi->second);
00094     }
00095     throw;
00096   }
00097 
00098   bbio_add_observed_create(type, from_id_pattern);
00099   blackboard->register_observer(this, BlackBoard::BBIO_FLAG_CREATED);
00100 }
00101 
00102 
00103 /** Destructor. */
00104 WorldModelMultiCopyFuser::~WorldModelMultiCopyFuser()
00105 {
00106   __blackboard->unregister_observer(this);
00107 
00108   __ifmap.lock();
00109   for (__imi = __ifmap.begin(); __imi != __ifmap.end(); ++__imi) {
00110     __blackboard->close(__imi->first);
00111       __blackboard->close(__imi->second);
00112   }
00113   __ifmap.clear();
00114   __ifmap.unlock();
00115 }
00116 
00117 
00118 void
00119 WorldModelMultiCopyFuser::bb_interface_created(const char *type, const char *id) throw()
00120 {
00121   unsigned int u;
00122   if (sscanf(id, __to_id_format.c_str(), &u) == 1) {
00123     // it's our own writing instance, ignore
00124     return;
00125   }
00126 
00127   char *tid;
00128   u = __ifmap.size();
00129   if (asprintf(&tid, __to_id_format.c_str(), u) == -1) {
00130     printf("Could not create ID string, asprintf() ran out of memory");
00131     return;
00132   }
00133   std::string sid = tid;
00134   free(tid);
00135 
00136   Interface *from_if = NULL;
00137   Interface *to_if   = NULL;
00138   
00139   try {
00140     from_if = __blackboard->open_for_reading(type, id);
00141     to_if   = __blackboard->open_for_writing(type, sid.c_str());
00142 
00143     __ifmap.lock();
00144     __ifmap[from_if] = to_if;
00145     __ifmap.unlock();
00146   } catch (Exception &e) {
00147     __blackboard->close(from_if);
00148     __blackboard->close(to_if);
00149     e.print_trace();
00150   }
00151 }
00152 
00153 
00154 void
00155 WorldModelMultiCopyFuser::fuse()
00156 {
00157   MutexLocker lock(__ifmap.mutex());
00158   for (__imi = __ifmap.begin(); __imi != __ifmap.end(); ++__imi) {
00159     if (__imi->first->has_writer()) {
00160       __imi->first->read();
00161       __imi->second->copy_values(__imi->first);
00162       __imi->second->write();
00163     }
00164   }
00165 }