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