Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

CdbBdbSchemaUtils.cc

Go to the documentation of this file.
00001 // File and Version Information:
00002 //      $Id: CdbBdbSchemaUtils.cc,v 1.7 2004/10/21 20:35:52 gapon Exp $
00003 #include "BaBar/BaBar.hh"
00004 
00005 /// The implementation of the CdbBdbSchemaUtils class.
00006 /**
00007   * @see CdbBdbSchemaUtils
00008   */
00009 
00010 #include "BaBar/BaBar.hh"
00011 
00012 #include "CdbBdb/CdbBdbSchemaUtils.hh"
00013 
00014 #include <ooas.h>
00015 
00016 #include <assert.h>
00017 
00018 #include <iostream>
00019 #include <iomanip>
00020 using std::cerr;
00021 using std::cout;
00022 using std::endl;
00023 using std::setfill;
00024 using std::setw;
00025 
00026 namespace {
00027 
00028   /// Browse the class description and find build its partial dependency tree
00029   /**
00030     * The function will browse through the hierarchy of the specified class to
00031     * find its base classes (including internal ones defined by Objectivity/DB).
00032     *
00033     * According to the definition of the tree, a class can't be defined
00034     * to be a base class to itself.
00035     *
00036     * The results will be put into the supplied dependency tree.
00037     *
00038     * @return the "true" if the operation finished successfully.
00039     */
00040     bool buildPartialDependencyTreeForClass(                                const ooas::d_Class& theClassDsc,
00041                                              std::map<ooTypeNumber, std::vector<ooTypeNumber> >& theDependencyTree )
00042     {
00043         if( !theClassDsc ) return false;
00044 
00045         ooTypeNumber classTypeNumber = theClassDsc.id( );
00046 
00047       // Skip already analysed classes
00048 
00049         if( theDependencyTree.end( ) != theDependencyTree.find( classTypeNumber )) return true;
00050 
00051       // Initialize an empty entry in the tree for the current type
00052 
00053         theDependencyTree[classTypeNumber] = std::vector<ooTypeNumber>( );
00054 
00055       // Now look into base classes
00056 
00057         ooas::attribute_iterator attributeItr = theClassDsc.defines_attribute_begin( );
00058         while( attributeItr != theClassDsc.defines_attribute_end( )) {
00059 
00060             const ooas::d_Attribute& attrDsc = *attributeItr;
00061             if( attrDsc.is_base_class( )) {
00062 
00063                 const ooas::d_Class& baseClassDsc = attrDsc.class_type_of( );
00064 
00065               // Updated supplied data structures
00066 
00067                 ooTypeNumber baseClassTypeNumber = baseClassDsc.id( );
00068 
00069                 theDependencyTree[classTypeNumber].push_back( baseClassTypeNumber );
00070 
00071               // Proceed down to the found base class
00072 
00073                 if( !buildPartialDependencyTreeForClass( baseClassDsc,
00074                                                          theDependencyTree )) return false;
00075             }
00076             ++attributeItr;
00077         }
00078         return true;
00079     }
00080 
00081   /// Fill the dependency matrix for specified derived class
00082   /**
00083     * This is a recursive algorithm filing the dependency matrix from the dependency
00084     * tree. According to the definition of the matrix, a class can't be defined
00085     * to be a base class to itself.
00086     */
00087     void fillDependencyMatrixForClass(                                                           ooTypeNumber theDerivedClassTypeNumber,
00088                                                                                                  ooTypeNumber theBaseClassTypeNumber,
00089                                                       std::map<ooTypeNumber, CdbBdbSchemaUtils::LocalTypeID>& theTypeNumberToLocalTypeId,
00090                                                           std::map<ooTypeNumber, std::vector<ooTypeNumber> >& theDependencyTree,
00091                                                                                                        bool** derivedVsBase )
00092     {
00093         const std::vector<ooTypeNumber>* baseClasses = &(theDependencyTree[theBaseClassTypeNumber]);
00094 
00095         size_t num = (*baseClasses).size( );
00096         for( size_t i = 0; i < num; ++i )
00097             fillDependencyMatrixForClass( theDerivedClassTypeNumber,
00098                                           (*baseClasses)[i],
00099                                           theTypeNumberToLocalTypeId,
00100                                           theDependencyTree,
00101                                           derivedVsBase );
00102 
00103       // According to the defenition of the dependency matrix
00104       // the class can't be base to itself in this data structures.
00105 
00106         if( theDerivedClassTypeNumber != theBaseClassTypeNumber ) {;
00107 
00108             CdbBdbSchemaUtils::LocalTypeID derived = theTypeNumberToLocalTypeId[theDerivedClassTypeNumber];
00109             CdbBdbSchemaUtils::LocalTypeID base    = theTypeNumberToLocalTypeId[theBaseClassTypeNumber];
00110 
00111             derivedVsBase[derived][base] = true;
00112         }
00113     }
00114 };
00115 
00116 ////////////////////
00117 // NESTED CLASSES //
00118 ////////////////////
00119 
00120 CdbBdbSchemaUtils::Node::Node( const ooTypeNumber theTypeNumber ) :
00121     typeNumber(theTypeNumber)
00122 { }
00123 
00124 CdbBdbSchemaUtils::Tree::Tree( ) :
00125     _isLoaded(false)
00126 { }
00127 
00128 CdbBdbSchemaUtils::Tree::~Tree( )
00129 {
00130     reset( );
00131 }
00132 
00133 const CdbBdbSchemaUtils::Node*
00134 CdbBdbSchemaUtils::Tree::type_to_node( const ooTypeNumber theTypeNumber ) const
00135 {
00136     if( !_isLoaded ) {
00137         cerr << "CdbBdbSchemaUtils::Tree::type_to_node() - ERROR." << endl
00138              << "    Inproper use of a non-loaded dependency tree object. Check if the caller" << endl
00139              << "    application has explicitly requested to load the tree." << endl;
00140         return 0;
00141     }
00142     std::map<ooTypeNumber, Node*>::const_iterator itr = all.find( theTypeNumber );
00143     return ( all.end( ) == itr ? 0 : itr->second );
00144 }
00145 
00146 void
00147 CdbBdbSchemaUtils::Tree::reset( )
00148 {
00149    _isLoaded = false;
00150 
00151     std::map<ooTypeNumber, Node*>::iterator itr = all.begin( );
00152     while( all.begin( ) != itr ) {
00153         delete itr->second;
00154         ++itr;
00155     }
00156     all.clear( );
00157     root.clear( );
00158 }
00159 
00160 bool
00161 CdbBdbSchemaUtils::Tree::load( const std::map<ooTypeNumber, std::vector<ooTypeNumber> >& thePartialTree,
00162                                                                                     bool debugModeFlag )
00163 {
00164     reset( );
00165 
00166   // Build a list of "very base" classes which do not have any base classes.
00167 
00168     std::map<ooTypeNumber, std::vector<ooTypeNumber> >::const_iterator itr = thePartialTree.begin( );
00169     while( thePartialTree.end( ) != itr ) {
00170 
00171         // Node* node =
00172         type_to_node( thePartialTree,
00173                       itr->first,
00174                       debugModeFlag );
00175         ++itr;
00176     }
00177 
00178     _isLoaded = true;
00179 
00180     return true;
00181 }
00182 
00183 CdbBdbSchemaUtils::Node*
00184 CdbBdbSchemaUtils::Tree::type_to_node( const std::map<ooTypeNumber, std::vector<ooTypeNumber> >& thePartialTree,
00185                                                                               const ooTypeNumber theTypeNumber,
00186                                                                                             bool debugModeFlag )
00187 {
00188     assert( !_isLoaded );  // a bug in the current class's implementation
00189 
00190     Node* thisNode = 0;
00191     do {
00192 
00193       // Verify parameters. Opimize access to the partial tree element.
00194 
00195         std::map<ooTypeNumber, std::vector<ooTypeNumber> >::const_iterator partialItr = thePartialTree.find( theTypeNumber );
00196         if( thePartialTree.end( ) == partialItr ) {
00197 
00198             cerr << "CdbBdbSchemaUtils::Tree::type_to_node() - FATAL INTERNAL ERROR" << endl
00199                  << "    Inconsistent schema information got from the federation. Something" << endl
00200                  << "    may be broken in the current code's implementation." << endl
00201                  << "    The input type number is: " << theTypeNumber << endl;
00202 
00203             ::abort( );
00204         }
00205 
00206       // Skip the input type if it's alredy procssed
00207 
00208         std::map<ooTypeNumber, Node*>::iterator itr = all.find( theTypeNumber );
00209         if( all.end( ) != itr ) {
00210 
00211             thisNode = itr->second;
00212 
00213 ////////////////////////////////////////////////////////////////////////////////////
00214 if( debugModeFlag ) {
00215 cout << "Tree::type_to_node() ALREADY PROCESSED TYPE " << theTypeNumber << endl;
00216 }
00217 ////////////////////////////////////////////////////////////////////////////////////
00218 
00219             break;
00220         }
00221 
00222       // Create and register a node for the type
00223 
00224         thisNode = new Node( theTypeNumber );
00225         all[theTypeNumber] = thisNode;
00226 
00227       // Check if it's a very base class (no subclasses). Put it into a separate
00228       // data structure.
00229 
00230         int numBase = partialItr->second.size( );
00231         if( 0 == numBase ) {
00232 
00233             root[theTypeNumber] = thisNode;
00234 
00235 ////////////////////////////////////////////////////////////////////////////
00236 if( debugModeFlag ) {
00237 cout << "Tree::type_to_node() VERY BASE TYPE " << theTypeNumber << endl;
00238 }
00239 ////////////////////////////////////////////////////////////////////////////
00240             break;
00241         }
00242 
00243       // Register this node as a subclass of its imediate base types
00244 
00245 ///////////////////////////////////////////////////////////////////////////
00246 if( debugModeFlag ) {
00247 cout << "Tree::type_to_node() SUBCLASS TYPE " << theTypeNumber << endl;
00248 }
00249 ///////////////////////////////////////////////////////////////////////////
00250 
00251         for( int i = 0; i < numBase; ++i ) {
00252 
00253             ooTypeNumber baseTypeNumber = partialItr->second[i];
00254                    Node* baseNode       = type_to_node( thePartialTree,
00255                                                         baseTypeNumber,
00256                                                         debugModeFlag );
00257 
00258             baseNode->subclasses  [ theTypeNumber] = thisNode;
00259             thisNode->superclasses[baseTypeNumber] = baseNode;
00260 
00261 ////////////////////////////////////////////////////////////////////////////////
00262 if( debugModeFlag ) {
00263 cout << "Tree::type_to_node()   ADDED BASE TYPE " << baseTypeNumber << endl;
00264 }
00265 ////////////////////////////////////////////////////////////////////////////////
00266         }
00267 
00268     } while( false );
00269 
00270     return thisNode;
00271 }
00272 
00273 ////////////////
00274 // HOST CLASS //
00275 ////////////////
00276 
00277 bool
00278 CdbBdbSchemaUtils::debugMode = false;
00279 
00280 CdbBdbSchemaUtils&
00281 CdbBdbSchemaUtils::instance( )
00282 {
00283     static CdbBdbSchemaUtils myInstance;
00284     return myInstance;
00285 }
00286 
00287 CdbBdbSchemaUtils::CdbBdbSchemaUtils( ) :
00288     _derivedVsBase    (0),
00289     _derivedVsBaseSize(0)
00290 {
00291     if( !update( )) {
00292         cerr << "CdbBdbSchemaUtils::CdbBdbSchemaUtils( ) - FATAL INTERNAL ERROR IN THE CONSTRUCTOR." << endl
00293              << "    Unable to load/update schema information from the current federation." << endl;
00294         ::abort( );
00295     }
00296 }
00297 
00298 CdbBdbSchemaUtils::~CdbBdbSchemaUtils( )
00299 {
00300     clearCache( );
00301 }
00302 
00303 bool
00304 CdbBdbSchemaUtils::isA( const ooTypeNumber theDerivedTypeNumber,
00305                         const ooTypeNumber theBaseTypeNumber ) const
00306 {
00307   // Check if these types are known to the schema. Get the local
00308   // identifiers for these types.
00309 
00310     std::map<ooTypeNumber, LocalTypeID>::const_iterator derivedItr = _typeNumberToLocalTypeId.find( theDerivedTypeNumber );
00311     std::map<ooTypeNumber, LocalTypeID>::const_iterator    baseItr = _typeNumberToLocalTypeId.find(    theBaseTypeNumber );
00312 
00313     if( _typeNumberToLocalTypeId.end( ) == derivedItr ) return false;
00314     if( _typeNumberToLocalTypeId.end( ) ==    baseItr ) return false;
00315     
00316     LocalTypeID derived = derivedItr->second;
00317     LocalTypeID base    =    baseItr->second;
00318 
00319   // Return result
00320 
00321     return ( derived == base ) || _derivedVsBase[derived][base];
00322 }
00323 
00324 bool
00325 CdbBdbSchemaUtils::typeNumberToClassName( const ooTypeNumber theTypeNumber,
00326                                                 std::string& theClassName ) const
00327 {
00328     std::map<ooTypeNumber, std::string>::const_iterator classNameItr = _typeNumberToName.find( theTypeNumber );
00329     if( _typeNumberToName.end( ) != classNameItr ) {
00330         theClassName = classNameItr->second;
00331         return true;
00332     }
00333     return false;
00334 }
00335 
00336 bool
00337 CdbBdbSchemaUtils::classNameToTypeNumber(   const char* theClassName,
00338                                           ooTypeNumber& theTypeNumber ) const
00339 {
00340     if( 0 == theClassName ) return false;
00341 
00342     std::map<std::string, ooTypeNumber>::const_iterator typeNumberItr = _nameToTypeNumber.find( std::string( theClassName ));
00343     if( _nameToTypeNumber.end( ) != typeNumberItr ) {
00344         theTypeNumber = typeNumberItr->second;
00345         return true;
00346     }
00347     return false;
00348 }
00349 
00350 bool
00351 CdbBdbSchemaUtils::loadDependencyTree( Tree& theTree ) const
00352 {
00353     return theTree.load( _dependencyTree,
00354                          debugMode );
00355 }
00356 
00357 bool
00358 CdbBdbSchemaUtils::update( )
00359 {
00360     clearCache( );
00361 
00362   // Pass I: Browse the schema and fill up dictionaries for classes.
00363 
00364     const ooas::d_Module& topModule = ooas::d_Module::top_level( );
00365 
00366 /////////////////////////////////////////////////////////////////////////////////////////////////////
00367 if( debugMode ) {
00368     cout << "MODULE: NAME=\"" << topModule.name( ) << "\", ID=" << topModule.id( ) << endl;
00369 }
00370 /////////////////////////////////////////////////////////////////////////////////////////////////////
00371 
00372     ooas::meta_object_iterator metaObjectItr = topModule.defines_begin( );
00373     while( metaObjectItr != topModule.defines_end( )) {
00374 
00375         const ooas::d_Meta_Object& metaObject = *metaObjectItr;
00376         if( metaObject.is_module( )) {
00377 
00378             const ooas::d_Module& module = (const ooas::d_Module&)metaObject;
00379 
00380 ///////////////////////////////////////////////////////////////////////////////////////////////
00381 if( debugMode ) {
00382     cout << "MODULE: NAME=\"" << module.name( ) << "\", ID=" << module.id( ) << endl;
00383 }
00384 ///////////////////////////////////////////////////////////////////////////////////////////////
00385 
00386             ooas::type_iterator typeItr = module.defines_types_begin( );
00387             while( typeItr != module.defines_types_end( )) {
00388 
00389                 const ooas::d_Type& type = *typeItr;
00390                 if( type.is_class( )) {
00391 
00392                     const ooas::d_Class& classType = (const ooas::d_Class&)type;
00393 
00394                     registerClass( _derivedVsBaseSize++,
00395                                    classType.name( ),
00396                                    classType.type_number( ));
00397                 }
00398                 ++typeItr;
00399             }
00400 
00401         } else if( metaObject.is_class( )) {    // We're only interested in classes. In reality
00402                                                 // there are also modules, basic types, references,
00403                                                 // associations, etc.
00404                                                 // To catch them we'd need to ask ::is_type().
00405 
00406             const ooas::d_Class& classType = (const ooas::d_Class&)metaObject;
00407 
00408             registerClass( _derivedVsBaseSize++,
00409                            classType.name( ),
00410                            classType.type_number( ));
00411         }
00412         ++metaObjectItr;
00413     }
00414 
00415 //////////////////////////////////////////////////////////////////////////////////////////
00416 if( debugMode ) {
00417     cout << "TOTAL OF " << _derivedVsBaseSize << " classes were found." << endl;
00418 }
00419 //////////////////////////////////////////////////////////////////////////////////////////
00420 
00421   // Create and initialize the matrix representing dependancy graph for
00422   // found classes.
00423 
00424     _derivedVsBase = new bool*[_derivedVsBaseSize];
00425     for( LocalTypeID derived = 0; derived < _derivedVsBaseSize; ++derived ) {
00426 
00427         _derivedVsBase[derived] = new bool[_derivedVsBaseSize];
00428         for( LocalTypeID base = 0; base < _derivedVsBaseSize; ++base ) {
00429 
00430             _derivedVsBase[derived][base] = false;
00431         }
00432     }
00433 
00434   // Pass II: Browse the schema of each class and fill up the dependency
00435   //          tree for each found class.
00436 
00437     {
00438         std::map<ooTypeNumber, std::string>::iterator classTypeNumberItr = _typeNumberToName.begin( );
00439         while( classTypeNumberItr != _typeNumberToName.end( )) {
00440 
00441             ooTypeNumber classTypeNumber = classTypeNumberItr->first;
00442             if( !::buildPartialDependencyTreeForClass( topModule.resolve_class( classTypeNumber ),
00443                                                        _dependencyTree )) {
00444 
00445                 cerr << "CdbBdbSchemaUtils::update( ) - ERROR." << endl
00446                      << "    Unable to obtain schema information for the class with type number: " << classTypeNumber << endl;
00447                 return false;
00448             }
00449             ++classTypeNumberItr;
00450         }
00451     }
00452 
00453   // Pass III: Browse the dependancy tree for each class and fill up the dependency
00454   //           matrix
00455     
00456     {
00457         std::map<ooTypeNumber, std::vector<ooTypeNumber> >::iterator classTypeNumberItr = _dependencyTree.begin( );
00458         while( classTypeNumberItr != _dependencyTree.end( )) {
00459 
00460             ooTypeNumber classTypeNumber = classTypeNumberItr->first;
00461 
00462             fillDependencyMatrixForClass( classTypeNumber,
00463                                           classTypeNumber,
00464                                           _typeNumberToLocalTypeId,
00465                                           _dependencyTree,
00466                                           _derivedVsBase );
00467             ++classTypeNumberItr;
00468         }
00469     }
00470 
00471     return true;
00472 }
00473 
00474 void
00475 CdbBdbSchemaUtils::clearCache( )
00476 {
00477     _nameToTypeNumber.clear( );
00478     _typeNumberToName.clear( );
00479 
00480     _localTypeIdToTypeNumber.clear( );
00481     _typeNumberToLocalTypeId.clear( );
00482 
00483     _dependencyTree.clear( );
00484 
00485     for( LocalTypeID i = 0; i < _derivedVsBaseSize; ++i ) delete [] _derivedVsBase[i];
00486     delete [] _derivedVsBase;
00487 
00488     _derivedVsBase     = 0;
00489     _derivedVsBaseSize = 0;
00490 }
00491 
00492 void
00493 CdbBdbSchemaUtils::registerClass(  const LocalTypeID theLocalTypeId,
00494                                          const char* theClassName,
00495                                   const ooTypeNumber theTypeNumber )
00496 {
00497     std::string className = theClassName;
00498 
00499     _nameToTypeNumber[className]     = theTypeNumber;
00500     _typeNumberToName[theTypeNumber] = className;
00501 
00502     _localTypeIdToTypeNumber[theLocalTypeId] = theTypeNumber;
00503     _typeNumberToLocalTypeId[theTypeNumber]  = theLocalTypeId;
00504 
00505 ///////////////////////////////////////////////////////////////////////
00506 if( debugMode ) {
00507     cout << "  "
00508          << setw(10) << setfill( ' ' ) << theLocalTypeId
00509          << " : "
00510          << setw(10) << setfill( ' ' ) << theTypeNumber
00511          << " : "
00512          << "\"" << theClassName << "\"" << endl;
00513 }
00514 ///////////////////////////////////////////////////////////////////////
00515 }
00516 
00517 /////////////////
00518 // End Of File //
00519 /////////////////

Generated on Mon Dec 5 18:22:01 2005 for CDB by doxygen1.3-rc3