00001 #include "CondCore/ORA/interface/Configuration.h"
00002 #include "CondCore/ORA/interface/Exception.h"
00003 #include "ContainerSchema.h"
00004 #include "DatabaseSession.h"
00005 #include "IDatabaseSchema.h"
00006 #include "MappingToSchema.h"
00007 #include "MappingDatabase.h"
00008 #include "MappingGenerator.h"
00009 #include "MappingRules.h"
00010 #include "ClassUtils.h"
00011
00012 #include "RelationalAccess/ISchema.h"
00013
00014 namespace ora {
00015
00016 void getTableHierarchyFromMappingElement( const MappingElement& source,
00017 std::map<std::string, std::set<std::string> >& tableList ){
00018 const std::string& tableName = source.tableName();
00019 std::map<std::string, std::set<std::string> >::iterator iTab = tableList.find( tableName );
00020 if( iTab ==tableList.end() ){
00021 std::set<std::string> dependencies;
00022 tableList.insert(std::make_pair( tableName, dependencies ) );
00023 }
00024 for( MappingElement::const_iterator iElem = source.begin();
00025 iElem != source.end(); iElem++ ){
00026 std::map<std::string, std::set<std::string> >::iterator iT = tableList.find( tableName );
00027 const std::string& innerTable = iElem->second.tableName();
00028 if( innerTable != tableName ){
00029 iT->second.insert( innerTable );
00030 }
00031 getTableHierarchyFromMappingElement( iElem->second, tableList );
00032 }
00033 }
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 void addFromTableHierarchy( const std::string& tableName,
00046 std::map<std::string, std::set<std::string> >& tableList,
00047 std::vector<std::string>& orderedList ){
00048 orderedList.push_back( tableName );
00049 std::map<std::string, std::set<std::string> >::const_iterator iDeps = tableList.find( tableName );
00050 if(iDeps != tableList.end() ){
00051 for( std::set<std::string>::const_iterator iDt = iDeps->second.begin();
00052 iDt != iDeps->second.end(); iDt++ ){
00053 addFromTableHierarchy( *iDt, tableList, orderedList );
00054 }
00055 }
00056 }
00057
00058 }
00059
00060 ora::ContainerSchema::ContainerSchema( int containerId,
00061 const std::string& containerName,
00062 const Reflex::Type& containerType,
00063 DatabaseSession& session ):
00064 m_containerId( containerId ),
00065 m_containerName( containerName ),
00066 m_className( containerType.Name( Reflex::SCOPED ) ),
00067 m_classDict( containerType ),
00068 m_session( session ),
00069 m_loaded( false ),
00070 m_containerSchemaSequences( session.schema() ),
00071 m_mapping(),
00072 m_dependentMappings(){
00073 }
00074
00075 ora::ContainerSchema::ContainerSchema( int containerId,
00076 const std::string& containerName,
00077 const std::string& className,
00078 DatabaseSession& session ):
00079 m_containerId( containerId ),
00080 m_containerName( containerName ),
00081 m_className( className ),
00082 m_classDict(),
00083 m_session( session ),
00084 m_loaded( false ),
00085 m_containerSchemaSequences( session.schema() ),
00086 m_mapping(),
00087 m_dependentMappings(){
00088 }
00089
00090 ora::ContainerSchema::~ContainerSchema(){
00091 for( std::map<std::string,MappingTree*>::iterator iDep = m_dependentMappings.begin();
00092 iDep != m_dependentMappings.end(); ++iDep ){
00093 delete iDep->second;
00094 }
00095 }
00096
00097 void ora::ContainerSchema::initClassDict(){
00098 if( !m_classDict ) m_classDict = ClassUtils::lookupDictionary( m_className, false );
00099 if( !m_classDict ) throwException("Container class \""+m_className+"\" has not been found in the dictionary.",
00100 "ContainerSchema::initClassDict");
00101 }
00102
00103 void ora::ContainerSchema::create(){
00104
00105 initClassDict();
00106 std::string newMappingVersion = m_session.mappingDatabase().newMappingVersionForContainer( m_containerName );
00107 MappingGenerator mapGen( m_session.schema().storageSchema() );
00108 mapGen.createNewMapping( m_containerName, m_classDict, m_mapping );
00109
00110
00111
00112
00113 m_mapping.setVersion( newMappingVersion );
00114 m_session.mappingDatabase().storeMapping( m_mapping );
00115 m_session.mappingDatabase().insertClassVersion( m_classDict, 0, m_containerId, newMappingVersion, true );
00116 MappingToSchema mapping2Schema( m_session.schema().storageSchema() );
00117 m_mapping.tables();
00118 mapping2Schema.create( m_mapping );
00119 m_loaded = true;
00120 }
00121
00122 void ora::ContainerSchema::drop(){
00123
00124 std::set<std::string> containerMappingVersions;
00125 if( m_session.mappingDatabase().getMappingVersionsForContainer( m_containerId, containerMappingVersions )){
00126 std::map< std::string, std::set<std::string> > tableHierarchy;
00127 std::set<std::string> topLevelTables;
00128 for( std::set<std::string>::const_iterator iV = containerMappingVersions.begin();
00129 iV!= containerMappingVersions.end(); ++iV ){
00130 MappingTree mapping;
00131 if( m_session.mappingDatabase().getMappingByVersion( *iV, mapping ) ){
00132 topLevelTables.insert( mapping.topElement().tableName() );
00133 getTableHierarchyFromMappingElement( mapping.topElement(), tableHierarchy );
00134 m_containerSchemaSequences.erase( MappingRules::sequenceNameForDependentClass( m_containerName, mapping.className()));
00135 }
00136 }
00137
00138 std::vector<std::string> orderedTableList;
00139 for(std::set<std::string>::const_iterator iMainT = topLevelTables.begin();
00140 iMainT != topLevelTables.end(); ++iMainT ){
00141 addFromTableHierarchy( *iMainT, tableHierarchy, orderedTableList );
00142 }
00143 for(std::vector<std::string>::reverse_iterator iTable = orderedTableList.rbegin();
00144 iTable != orderedTableList.rend(); iTable++ ){
00145 m_session.schema().storageSchema().dropIfExistsTable( *iTable );
00146 }
00147 }
00148 for( std::set<std::string>::const_iterator iM = containerMappingVersions.begin();
00149 iM != containerMappingVersions.end(); ++iM ){
00150 m_session.mappingDatabase().removeMapping( *iM );
00151 }
00152 m_containerSchemaSequences.erase( MappingRules::sequenceNameForContainer( m_containerName ));
00153
00154 }
00155
00156 void ora::ContainerSchema::evolve(){
00157 MappingGenerator mapGen( m_session.schema().storageSchema() );
00158
00159 MappingTree baseMapping;
00160 if( !m_session.mappingDatabase().getBaseMappingForContainer( m_classDict.Name(Reflex::SCOPED), m_containerId, baseMapping )){
00161 throwException("Base mapping has not been found in the database.",
00162 "ContainerSchema::evolve");
00163 }
00164 mapGen.createNewMapping( m_containerName, m_classDict, baseMapping, m_mapping );
00165 std::string newMappingVersion = m_session.mappingDatabase().newMappingVersionForContainer( m_containerName );
00166 m_mapping.setVersion( newMappingVersion );
00167 m_session.mappingDatabase().storeMapping( m_mapping );
00168 m_session.mappingDatabase().insertClassVersion( m_classDict, 0, m_containerId, newMappingVersion );
00169 MappingToSchema mapping2Schema( m_session.schema().storageSchema() );
00170 mapping2Schema.alter( m_mapping );
00171 m_loaded = true;
00172 }
00173
00174 void ora::ContainerSchema::evolve( const Reflex::Type& dependentClass, MappingTree& baseMapping ){
00175 std::string className = dependentClass.Name(Reflex::SCOPED);
00176 MappingGenerator mapGen( m_session.schema().storageSchema() );
00177 std::map<std::string,MappingTree*>::iterator iDep =
00178 m_dependentMappings.insert( std::make_pair( className, new MappingTree ) ).first;
00179 if( baseMapping.className() != dependentClass.Name(Reflex::SCOPED) ){
00180 throwException("Provided base mapping does not map class \""+dependentClass.Name(Reflex::SCOPED)+"\".",
00181 "ContainerSchema::evolve");
00182 }
00183 mapGen.createNewDependentMapping( dependentClass, m_mapping, baseMapping, *iDep->second );
00184 std::string newMappingVersion = m_session.mappingDatabase().newMappingVersionForContainer( m_containerName );
00185 iDep->second->setVersion( newMappingVersion );
00186 m_session.mappingDatabase().storeMapping( *iDep->second );
00187 m_session.mappingDatabase().insertClassVersion( dependentClass, 1, m_containerId, newMappingVersion, false );
00188 }
00189
00190 const Reflex::Type& ora::ContainerSchema::type(){
00191 return m_classDict;
00192 }
00193
00194 ora::MappingTree& ora::ContainerSchema::mapping( bool writeEnabled ){
00195 initClassDict();
00196 if(!m_loaded ){
00197 if( !m_session.mappingDatabase().getMappingForContainer( m_classDict, m_containerId, m_mapping ) ){
00198
00199 if( writeEnabled && m_session.configuration().properties().getFlag( Configuration::automaticSchemaEvolution() )){
00200 evolve();
00201 }
00202 } else {
00203 m_loaded = true;
00204 }
00205
00206 }
00207 if( m_mapping.topElement().find( m_className )==m_mapping.topElement().end() ){
00208 throwException( "Mapping for container class \""+m_className+"\" could not be loaded.",
00209 "ContainerSchema::mapping");
00210 }
00211 return m_mapping;
00212 }
00213
00214 bool ora::ContainerSchema::loadMappingForDependentClass( const Reflex::Type& dependentClassDict ){
00215 if( !dependentClassDict ) throwException("The dependent class has not been found in the dictionary.",
00216 "ContainerSchema::loadMappingForDependentClass");
00217 std::string className = dependentClassDict.Name(Reflex::SCOPED);
00218 std::map<std::string,MappingTree*>::iterator iDep = m_dependentMappings.find( className );
00219 if( iDep == m_dependentMappings.end() ){
00220
00221 iDep = m_dependentMappings.insert( std::make_pair( className, new MappingTree ) ).first;
00222 if( ! m_session.mappingDatabase().getMappingForContainer( dependentClassDict, m_containerId, *iDep->second ) ){
00223 m_dependentMappings.erase( className );
00224 return false;
00225 }
00226 }
00227 return true;
00228 }
00229
00230 void ora::ContainerSchema::create( const Reflex::Type& dependentClassDict ){
00231 std::string className = dependentClassDict.Name(Reflex::SCOPED);
00232 std::map<std::string,MappingTree*>::iterator iDep =
00233 m_dependentMappings.insert( std::make_pair( className, new MappingTree ) ).first;
00234 MappingGenerator mapGen( m_session.schema().storageSchema() );
00235 MappingToSchema mapping2Schema( m_session.schema().storageSchema() );
00236 mapGen.createNewDependentMapping( dependentClassDict, m_mapping, *iDep->second );
00237 mapping2Schema.create( *iDep->second );
00238 std::string newMappingVersion = m_session.mappingDatabase().newMappingVersionForContainer( m_containerName );
00239 iDep->second->setVersion( newMappingVersion );
00240 m_session.mappingDatabase().storeMapping( *iDep->second );
00241 m_session.mappingDatabase().insertClassVersion( dependentClassDict, 1, m_containerId, newMappingVersion, true );
00242 }
00243
00244 void ora::ContainerSchema::extend( const Reflex::Type& dependentClassDict ){
00245 std::string className = dependentClassDict.Name(Reflex::SCOPED);
00246 MappingTree baseMapping;
00247 if( !m_session.mappingDatabase().getBaseMappingForContainer( className,
00248 m_containerId, baseMapping ) ){
00249 create( dependentClassDict );
00250 } else {
00251 evolve( dependentClassDict, baseMapping );
00252 }
00253 }
00254
00255 bool ora::ContainerSchema::extendIfRequired( const Reflex::Type& dependentClassDict ){
00256 bool ret = false;
00257 if( ! loadMappingForDependentClass( dependentClassDict ) ){
00258 extend( dependentClassDict );
00259 ret = true;
00260 }
00261 return ret;
00262 }
00263
00264 ora::MappingElement& ora::ContainerSchema::mappingForDependentClass( const Reflex::Type& dependentClassDict,
00265 bool writeEnabled ){
00266 std::string className = dependentClassDict.Name(Reflex::SCOPED);
00267 if( ! loadMappingForDependentClass( dependentClassDict ) ){
00268 if( writeEnabled ){
00269
00270 MappingTree baseMapping;
00271 if( !m_session.mappingDatabase().getBaseMappingForContainer( className,
00272 m_containerId, baseMapping ) ){
00273
00274 if( m_session.configuration().properties().getFlag( Configuration::automaticDatabaseCreation()) ||
00275 m_session.configuration().properties().getFlag( Configuration::automaticContainerCreation() ) ){
00276 create( dependentClassDict );
00277 }
00278 } else {
00279
00280 if( m_session.configuration().properties().getFlag( Configuration::automaticSchemaEvolution() )){
00281 evolve( dependentClassDict, baseMapping );
00282 }
00283 }
00284 }
00285 }
00286 std::map<std::string,MappingTree*>::iterator iDep = m_dependentMappings.find( className );
00287 if( iDep == m_dependentMappings.end() ){
00288 throwException( "Mapping for class \""+ className + "\" is not available in the database.",
00289 "ContainerSchema::mappingForDependentClass");
00290 }
00291 return iDep->second->topElement();
00292 }
00293
00294 bool ora::ContainerSchema::mappingForDependentClasses( std::vector<ora::MappingElement>& destination ){
00295 return m_session.mappingDatabase().getDependentMappingsForContainer( m_containerId, destination );
00296 }
00297
00298 ora::Sequences& ora::ContainerSchema::containerSequences(){
00299 return m_containerSchemaSequences;
00300 }
00301
00302 ora::IBlobStreamingService* ora::ContainerSchema::blobStreamingService(){
00303 return m_session.configuration().blobStreamingService();
00304 }
00305
00306 ora::IReferenceHandler* ora::ContainerSchema::referenceHandler(){
00307 return m_session.configuration().referenceHandler();
00308 }
00309
00310 const std::string& ora::ContainerSchema::mappingVersion(){
00311 return m_mapping.version();
00312 }
00313
00314 int ora::ContainerSchema::containerId(){
00315 return m_containerId;
00316 }
00317
00318 const std::string& ora::ContainerSchema::containerName(){
00319 return m_containerName;
00320 }
00321
00322 const std::string& ora::ContainerSchema::className(){
00323 return m_className;
00324 }
00325
00326 coral::ISchema& ora::ContainerSchema::storageSchema(){
00327 return m_session.schema().storageSchema();
00328 }
00329
00330 ora::DatabaseSession& ora::ContainerSchema::dbSession(){
00331 return m_session;
00332 }
00333
00334
00335