OpenTracker

An Open Architecture for Reconfigurable Tracking based on XML | Contact

Context.cxx

Go to the documentation of this file.
00001 /* ========================================================================
00002  * Copyright (c) 2006,
00003  * Institute for Computer Graphics and Vision
00004  * Graz University of Technology
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions are
00009  * met:
00010  *
00011  * Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the following disclaimer.
00013  *
00014  * Redistributions in binary form must reproduce the above copyright
00015  * notice, this list of conditions and the following disclaimer in the
00016  * documentation and/or other materials provided with the distribution.
00017  *
00018  * Neither the name of the Graz University of Technology nor the names of
00019  * its contributors may be used to endorse or promote products derived from
00020  * this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00023  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00024  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00025  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00026  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00028  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  * ========================================================================
00034  * PROJECT: OpenTracker
00035  * ======================================================================== */
00042 /* ======================================================================= */
00043 
00044 
00045 #include <stdlib.h>
00046 #include "../tool/FixWinCE.h"
00047 #include <ace/OS.h>
00048 #include <ace/FILE.h>
00049 
00050 #include <algorithm>
00051 
00052 #include "../OpenTracker.h"
00053 
00054 // selects between usage of XERCES and TinyXML
00055 #include "../tool/XMLSelection.h"
00056 
00057 #ifdef USE_XERCES
00058 #include <xercesc/dom/DOM.hpp>
00059 #include <xercesc/util/XMLString.hpp>
00060 #include <xercesc/util/XMLUniDefs.hpp>
00061 #endif //USE_XERCES
00062 
00063 #include "ConfigurationParser.h"
00064 
00065 
00066 #ifdef USE_XERCES
00067 XERCES_CPP_NAMESPACE_USE;
00068 const XMLCh ud_node[] = { chLatin_n, chLatin_o, chLatin_d, chLatin_e, chNull };
00069 #endif //USE_XERCES
00070 
00071 //using namespace std;
00072 
00073 // constructor method.
00074 
00075 namespace ot {
00076 
00077     Context::Context( int init ) :
00078         rootNode( NULL ),
00079         cleanUp( false ),
00080         rootNamespace( "" )
00081     {
00082         if( init != 0 )
00083         {
00084             initializeContext( *this );
00085             cleanUp = true;
00086         }
00087         else {
00088             cleanUp = false;
00089         }
00090         directories.push_back(".");
00091     }
00092 
00093     // Destructor method.
00094     Context::~Context()
00095     {
00096         if( cleanUp )
00097         {
00098             for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00099             {
00100                 delete (*it).second;
00101             }
00102         }
00103         modules.clear();
00104         if (rootNode != NULL) {
00105             delete rootNode;
00106         }
00107     }
00108 
00109     // adds a new factory to the NodeFactoryContainer
00110 
00111     void Context::addFactory(NodeFactory& newfactory)
00112     {
00113         factory.addFactory( newfactory );
00114     }
00115 
00116     // removes a factory from the NodeFactoryContainer
00117 
00118     void Context::removeFactory(NodeFactory & oldfactory)
00119     {
00120         factory.removeFactory( oldfactory );
00121     }
00122 
00123     // adds a module to the contexts collection
00124 
00125     void Context::addModule(const std::string & name, Module & module)
00126     {
00127         modules[name] = &module;
00128         module.context = this;
00129     }
00130 
00131     // returns a module indexed by its configuration elements name
00132 
00133     Module * Context::getModule(const std::string & name)
00134     {
00135         ModuleMap::iterator it = modules.find( name );
00136         if( it != modules.end())
00137             return (*it).second;
00138         return NULL;
00139     }
00140 
00141     // removes a module
00142 
00143     void Context::removeModule(Module & module)
00144     {
00145         ModuleMap::iterator it = modules.begin();
00146         while( it != modules.end())
00147         {
00148             if((*it).second == &module )
00149                 modules.erase( it-- );
00150             it++;
00151         }
00152     }
00153 
00154     // calls start on all modules to do some initialization.
00155 
00156     void Context::start()
00157     {
00158         for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00159         {
00160             (*it).second->start();
00161         }
00162     }
00163 
00164     // calls close on all modules to close any resources.
00165 
00166     void Context::close()
00167     {
00168         for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00169         {
00170             (*it).second->close();
00171         }
00172         // HACK: give some threads time to close down
00173         OSUtils::sleep(1000);
00174     }
00175 
00176     // parses the file and builds the tree.
00177 
00178     void Context::parseConfiguration(const std::string& filename)
00179     {
00180 #ifdef USE_XERCES
00181         file = filename;
00182         std::string::size_type limit = file.find_last_of( "/\\" );
00183         if( limit != std::string::npos )
00184             addDirectoryFirst( file.substr(0, limit));
00185 
00186         ConfigurationParser parser( *this );
00187         rootNode = parser.parseConfigurationFile( filename );
00188         DOMDocument * doc = ((DOMNode *)(rootNode->parent))->getOwnerDocument();
00189         doc->setUserData( ud_node, this, NULL );
00190 
00191         const XMLCh* xmlspace = ((DOMNode *)(rootNode->parent))->getNamespaceURI();
00192         if (xmlspace != NULL) {
00193             char * tempName = XMLString::transcode( xmlspace );
00194             rootNamespace = tempName;
00195             XMLString::release( &tempName );
00196         }
00197         else {
00198             rootNamespace = "";
00199         }
00200 #endif //USE_XERCES
00201 
00202 
00203 #ifdef USE_TINYXML
00204         file = filename;
00205         std::string::size_type limit = file.find_last_of( "/\\" );
00206         if( limit != std::string::npos )
00207             addDirectoryFirst( file.substr(0, limit));
00208 
00209         ConfigurationParser parser( *this );
00210         rootNode = parser.parseConfigurationFile( filename );
00211         TiXmlDocument * doc = ((TiXmlNode *)(rootNode->parent))->GetDocument();
00212         doc->SetUserData(this);
00213 #endif //USE_TINYXML
00214     }
00215 
00216     // calls pullEvent on all modules to get data out again.
00217 
00218     void Context::pullEvents()
00219     {
00220         for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00221         {
00222             (*it).second->pullEvent();
00223         }
00224     }
00225 
00226     // This method calls pushEvent on all modules to get new data into the shared data tree.
00227 
00228     void Context::pushEvents()
00229     {
00230         for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00231         {
00232             (*it).second->pushEvent();
00233         }
00234     }
00235 
00236     // This method implements the main loop and runs until it is stopped somehow.
00237 
00238     void Context::run()
00239     {
00240         start();
00241         while ( stop() == 0 )
00242         {
00243             // push and pull parts of the main loop
00244             pushEvents();
00245             pullEvents();
00246         }
00247         close();
00248     }
00249 
00250     // This method implements the main loop and runs until it is stopped somehow.
00251     // This differs from the run() method in that a (crude) attempt is made 
00252     // to run at a particular rate. Affected by OS-specific implementation 
00253     // of wakeup and preemption events; however, can act as a throttle.
00254 
00255     void Context::runAtRate(double rate)
00256     {
00257         double t1 = OSUtils::currentTime(); // in milliseconds
00258         start();
00259         while ( stop() == 0 )
00260         {
00261             // push and pull parts of the main loop
00262             pushEvents();
00263             pullEvents();
00264             double t2 = OSUtils::currentTime(); // in milliseconds
00265             double sleep_time = 1/rate*1000.0 - (t2 - t1);
00266             if (sleep_time > 0.f) {
00267                 OSUtils::sleep(sleep_time);
00268             }
00269             t1 = t2;
00270         }
00271         close();
00272     }
00273 
00274     // tests all modules for stopping
00275 
00276     int Context::stop()
00277     {
00278         int value = 0;
00279         for( ModuleMap::iterator it = modules.begin(); it != modules.end(); it++ )
00280         {
00281             value |= (*it).second->stop();
00282         }
00283         return value;
00284     }
00285 
00286     // creates a new node from a given element name and an attribute table
00287 
00288     Node * Context::createNode( const std::string & name, StringTable & attributes)
00289     {
00290 #ifdef USE_XERCES
00291         Node * value = factory.createNode( name , attributes );
00292         if( value != NULL )
00293         {
00294             // add a correctly created DOM_Element to the node here and return
00295             DOMDocument * doc = ((DOMNode *)(rootNode->parent))->getOwnerDocument();
00296             std::auto_ptr<XMLCh> tempName ( XMLString::transcode( name.c_str()));
00297             std::auto_ptr<XMLCh> tempNS ( XMLString::transcode(rootNamespace.c_str()));
00298             DOMElement * el = doc->createElementNS( tempNS.get(), tempName.get());
00299             value->setParent( el );
00300             // set attributes on the element node
00301             KeyIterator keys(attributes);
00302             while( keys.hasMoreKeys())
00303             {
00304                 const std::string & key = keys.nextElement();
00305                 value->put( key, attributes.get( key ));
00306                 std::auto_ptr<XMLCh> attName ( XMLString::transcode( key.c_str()));
00307                 std::auto_ptr<XMLCh> attVal ( XMLString::transcode( attributes.get( key ).c_str()));
00308                 el->setAttributeNS(tempNS.get(), attName.get(), attVal.get());
00309             }
00310         }
00311         return value;
00312 #endif //USE_XERCES
00313 
00314 
00315 #ifdef USE_TINYXML
00316         Node * value = factory.createNode( name , attributes );
00317         if( value != NULL )
00318         {
00319             // add a correctly created DOM_Element to the node here and return
00320             TiXmlDocument * doc = ((TiXmlNode *)(rootNode->parent))->GetDocument();
00321             const char * tempName = name.c_str();
00322             const char * tempNS = rootNamespace.c_str();
00323             TiXmlElement * el = new TiXmlElement(tempName);
00324             value->setParent( el );
00325             // set attributes on the element node
00326             KeyIterator keys(attributes);
00327             while( keys.hasMoreKeys())
00328             {
00329                 const std::string & key = keys.nextElement();
00330                 value->put( key, attributes.get( key ));
00331                 const char * attName = key.c_str();
00332                 const char * attVal = attributes.get( key ).c_str();
00333                 el->SetAttribute(attName, attVal);
00334             }
00335         }
00336         return value;
00337 #endif //USE_TINYXML
00338     }
00339 
00340 #ifdef USE_TINYXML
00341     TiXmlElement *
00342     findElementRecursive(TiXmlElement* element, const std::string & id)
00343     {
00344     // does this element have the attribute we search for?
00345     if(element->Attribute(id.c_str()))
00346             return element;
00347 
00348     // walk through all children
00349     TiXmlElement* child = element->FirstChildElement();
00350     while(child)
00351     {
00352             if(TiXmlElement * found = findElementRecursive(child, id))
00353                 return found;
00354             child = child->NextSiblingElement();
00355     }
00356 
00357     // walk through all siblings
00358     TiXmlElement* sibling = element->NextSiblingElement();
00359     while(sibling)
00360     {
00361             if(TiXmlElement * found = findElementRecursive(sibling, id))
00362                 return found;
00363             sibling = sibling->NextSiblingElement();
00364     }
00365 
00366     // finally give up
00367     return NULL;
00368     }
00369 #endif //USE_TINYXML
00370 
00371     Node * Context::getRootNode()
00372     {
00373         return rootNode;
00374     }
00375 
00376     Node * Context::findNode(const std::string & id)
00377     {
00378 #ifdef USE_XERCES
00379         // search for the right node via the DOM_Document API
00380         std::auto_ptr<XMLCh> tempId ( XMLString::transcode( id.c_str()));
00381         DOMElement * el = ((DOMNode *)(rootNode->parent))->getOwnerDocument()->getElementById( tempId.get());
00382         if( el != 0 )
00383             return (Node *)el->getUserData(ud_node);
00384         return NULL;
00385 #endif //USE_XERCES
00386 
00387 
00388 #ifdef USE_TINYXML
00389     TiXmlElement* el = findElementRecursive(((TiXmlNode*)rootNode->parent)->GetDocument()->RootElement(), id);
00390         if( el != 0 )
00391             return (Node *)el->GetUserData();
00392         return NULL;
00393 #endif //USE_TINYXML
00394     }
00395 
00396     // add a directory to the front of the directory stack
00397 
00398     void Context::addDirectoryFirst( const std::string & dir )
00399     {
00400         if( std::find( directories.begin(), directories.end(), dir) == directories.end())
00401         {
00402             directories.insert(directories.begin(), dir);
00403         }
00404     }
00405 
00406     // add a directory to the end of the directory stack
00407 
00408     void Context::addDirectoryLast( const std::string & dir )
00409     {
00410         if( std::find( directories.begin(), directories.end(), dir) == directories.end())
00411         {
00412             directories.push_back(dir);
00413         }
00414     }
00415 
00416     // remove a directory from the directory stack
00417 
00418     void Context::removeDirectory( const std::string & dir )
00419     {
00420         std::vector<std::string>::iterator it = std::find( directories.begin(), directories.end(), dir);
00421         if( it != directories.end())
00422         {
00423             directories.erase(it);
00424         }
00425     }
00426 
00427     // searches for a file by prepending a stack of directory names
00428 
00429     bool Context::findFile( const std::string & filename, std::string & fullname )
00430     {
00431         ACE_stat stat;
00432         if( filename.at(0) == '/' || filename.at(0) == '\\' ) // don't deal with paths from root !
00433         {
00434             if( ACE_OS::stat( ACE_TEXT_CHAR_TO_TCHAR(filename.c_str()), &stat ) != 0 )
00435             {
00436                 return false;
00437             }
00438             fullname = filename;
00439             return true;
00440         }
00441         std::vector<std::string>::iterator it;
00442         for( it = directories.begin(); it != directories.end(); it++ )
00443         {
00444             std::string name = (*it) + "/" + filename;
00445             if( ACE_OS::stat( ACE_TEXT_CHAR_TO_TCHAR(name.c_str()), &stat ) == 0 )
00446             {
00447                 fullname = name;
00448                 return true;
00449             }
00450         }
00451         return false;
00452     }
00453 
00454 
00455     void Context::newVideoFrame(const unsigned char* image, int width, int height, PIXEL_FORMAT format) {
00456         for(VideoUserVector::iterator it=videoUsers.begin(); it!=videoUsers.end(); it++)
00457             (*it)->newVideoFrame(image, width, height, format);
00458     }
00459 
00460 
00461     void Context::registerVideoUser(VideoUser* videoUser)
00462     {
00463         for(VideoUserVector::iterator it=videoUsers.begin(); it!=videoUsers.end(); it++)
00464             if(*it == videoUser)
00465                 return;
00466 
00467         videoUsers.push_back(videoUser);
00468     }
00469 
00470 
00471     void Context::unregisterVideoUser(VideoUser* videoUser)
00472     {
00473         for(VideoUserVector::iterator it=videoUsers.begin(); it!=videoUsers.end(); it++)
00474             if(*it == videoUser)
00475             {
00476                 videoUsers.erase(it);
00477                 return;
00478             }
00479     }
00480 
00481 
00482 } // namespace ot
00483 
00484 /* 
00485  * ------------------------------------------------------------
00486  *   End of Context.cxx
00487  * ------------------------------------------------------------
00488  *   Automatic Emacs configuration follows.
00489  *   Local Variables:
00490  *   mode:c++
00491  *   c-basic-offset: 4
00492  *   eval: (c-set-offset 'substatement-open 0)
00493  *   eval: (c-set-offset 'case-label '+)
00494  *   eval: (c-set-offset 'statement 'c-lineup-runin-statements)
00495  *   eval: (setq indent-tabs-mode nil)
00496  *   End:
00497  * ------------------------------------------------------------ 
00498  */

copyright (c) 2006 Graz University of Technology