00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "ontologymanagermodel.h"
00020
00021 #include <QtCore/QUrl>
00022 #include <QtCore/QDateTime>
00023
00024 #include <Soprano/Backend>
00025 #include <Soprano/StorageModel>
00026 #include <Soprano/PluginManager>
00027 #include <Soprano/Global>
00028 #include <Soprano/NodeIterator>
00029 #include <Soprano/StatementIterator>
00030 #include <Soprano/QueryResultIterator>
00031 #include <Soprano/Vocabulary/RDF>
00032 #include <Soprano/Vocabulary/RDFS>
00033 #include <Soprano/Vocabulary/NRL>
00034 #include <Soprano/Vocabulary/NAO>
00035 #include <Soprano/Vocabulary/XMLSchema>
00036
00037 #include <KDebug>
00038
00039
00040 using namespace Soprano;
00041
00042
00043
00044 namespace {
00049 QUrl createMetadataGraphUri( const QUrl& uri ) {
00050 QString s( uri.toString() );
00051 if ( s.endsWith( '#' ) )
00052 s[s.length()-1] = '/';
00053 else if ( !s.endsWith( '/' ) )
00054 s += '/';
00055 s += "metadata";
00056 return QUrl( s );
00057 }
00058
00069 bool findGraphUris( Soprano::Model* model, const QUrl& ns, QUrl& dataGraphUri, QUrl& metaDataGraphUri ) {
00070 QString query = QString( "select ?dg ?mdg where { "
00071 "?dg <%1> \"%2\"^^<%3> . "
00072 "?mdg <%4> ?dg . "
00073 "}" )
00074 .arg( Soprano::Vocabulary::NAO::hasDefaultNamespace().toString() )
00075 .arg( ns.toString() )
00076 .arg( Soprano::Vocabulary::XMLSchema::string().toString() )
00077 .arg( Soprano::Vocabulary::NRL::coreGraphMetadataFor().toString() );
00078
00079 QueryResultIterator it = model->executeQuery( query, Soprano::Query::QueryLanguageSparql );
00080 if ( it.next() ) {
00081 metaDataGraphUri = it.binding("mdg").uri();
00082 dataGraphUri = it.binding("dg").uri();
00083 return true;
00084 }
00085 else {
00086 return false;
00087 }
00088 }
00089
00099 bool ensureDataLayout( Soprano::Model* tmpModel, const QUrl& ns )
00100 {
00101
00102 StatementIterator it = tmpModel->listStatements();
00103 while ( it.next() ) {
00104 if ( !it.current().context().isValid() ) {
00105 kDebug() << "Invalid data in ontology" << ns << *it;
00106 return false;
00107 }
00108 }
00109
00110
00111 QUrl dataGraphUri, metaDataGraphUri;
00112 if ( !findGraphUris( tmpModel, ns, dataGraphUri, metaDataGraphUri ) ) {
00113 kDebug() << "Invalid data in ontology" << ns << "Could not find datagraph and metadatagraph relation.";
00114 return false;
00115 }
00116
00117 return true;
00118 }
00119
00126 void createMetadata( Soprano::Model* tmpModel, const QUrl& ns )
00127 {
00128 Q_ASSERT( ns.isValid() );
00129 QUrl dataGraphUri( ns );
00130 dataGraphUri.setFragment( QString() );
00131 QUrl metaDataGraphUri = createMetadataGraphUri( dataGraphUri );
00132
00133
00134 QList<Statement> allStatements = tmpModel->listStatements().allStatements();
00135 tmpModel->removeAllStatements();
00136 foreach( Statement s, allStatements ) {
00137 s.setContext( dataGraphUri );
00138 tmpModel->addStatement( s );
00139 }
00140
00141
00142 tmpModel->addStatement( Soprano::Statement( metaDataGraphUri, Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::NRL::GraphMetadata(), metaDataGraphUri ) );
00143 tmpModel->addStatement( Soprano::Statement( metaDataGraphUri, Soprano::Vocabulary::NRL::coreGraphMetadataFor(), dataGraphUri, metaDataGraphUri ) );
00144 tmpModel->addStatement( Soprano::Statement( dataGraphUri, Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::NRL::Ontology(), metaDataGraphUri ) );
00145 tmpModel->addStatement( Soprano::Statement( dataGraphUri, Soprano::Vocabulary::NAO::hasDefaultNamespace(), LiteralValue( ns.toString() ), metaDataGraphUri ) );
00146 }
00147
00151 class ObjectGarbageCollector
00152 {
00153 public:
00154 ObjectGarbageCollector( QObject* o )
00155 : m_object( o ) {
00156 }
00157 ~ObjectGarbageCollector() {
00158 delete m_object;
00159 }
00160
00161 private:
00162 QObject* m_object;
00163 };
00164 }
00165
00166
00167 class Nepomuk::OntologyManagerModel::Private
00168 {
00169 public:
00170 Private( OntologyManagerModel* p )
00171 : q( p ) {
00172 }
00173
00174 private:
00175 OntologyManagerModel* q;
00176 };
00177
00178
00179
00180
00181
00182 Nepomuk::OntologyManagerModel::OntologyManagerModel( Soprano::Model* parentModel, QObject* parent )
00183 : FilterModel( parentModel ),
00184 d( new Private( this ) )
00185 {
00186 setParent( parent );
00187 }
00188
00189
00190 Nepomuk::OntologyManagerModel::~OntologyManagerModel()
00191 {
00192 delete d;
00193 }
00194
00195
00196 bool Nepomuk::OntologyManagerModel::updateOntology( Soprano::StatementIterator data, const QUrl& ns )
00197 {
00198 clearError();
00199
00200
00201
00202 const Soprano::Backend* backend = Soprano::PluginManager::instance()->discoverBackendByFeatures( Soprano::BackendFeatureStorageMemory );
00203 if ( !backend ) {
00204 kDebug() << "No Soprano backend found that can handle memory models!";
00205 setError( "No Soprano backend found that can handle memory models." );
00206 return false;
00207 }
00208
00209 Soprano::Model* tmpModel = backend->createModel( BackendSettings() << BackendSetting( Soprano::BackendOptionStorageMemory ) );
00210 if ( !tmpModel ) {
00211 kDebug() << "Failed to create temp memory model!";
00212 setError( backend->lastError() );
00213 return false;
00214 }
00215
00216
00217 ObjectGarbageCollector modelGarbageCollector( tmpModel );
00218
00219
00220 while ( data.next() ) {
00221 tmpModel->addStatement( *data );
00222 }
00223
00224 QUrl ontoUri = ns;
00225 if ( ontoUri.isEmpty() ) {
00226 StatementIterator it = tmpModel->listStatements();
00227 if ( it.next() ) {
00228 ontoUri = it.current().subject().uri();
00229 if ( !ontoUri.fragment().isEmpty() ) {
00230 ontoUri.setFragment( QString() );
00231 }
00232 else {
00233 ontoUri = ontoUri.toString().left( ontoUri.toString().lastIndexOf( '/' )+1 );
00234 }
00235 }
00236 }
00237 if ( ontoUri.isEmpty() ) {
00238 kDebug() << "Failed to determine ontology URI.";
00239 setError( "Failed to determine ontology URI from data." );
00240 return false;
00241 }
00242
00243
00244
00245
00246 QList<Node> graphs = tmpModel->listContexts().allNodes();
00247 if ( graphs.count() == 0 ) {
00248
00249 createMetadata( tmpModel, ontoUri );
00250 }
00251 else if ( graphs.count() == 2 ) {
00252
00253 if ( !ensureDataLayout( tmpModel, ontoUri ) ) {
00254 setError( "The ontology data contains invalid statements.", Soprano::Error::ErrorInvalidArgument );
00255 return false;
00256 }
00257 }
00258 else {
00259 kDebug() << "Invalid data in ontology" << ontoUri << "We need one data and one metadata graph.";
00260 setError( "The ontology data contains invalid statements.", Soprano::Error::ErrorInvalidArgument );
00261 return false;
00262 }
00263
00264
00265
00266
00267 QUrl dataGraphUri, metadataGraphUri;
00268 if ( findGraphUris( tmpModel, ontoUri, dataGraphUri, metadataGraphUri ) ) {
00269
00270 tmpModel->removeAllStatements( dataGraphUri, Soprano::Vocabulary::NAO::lastModified(), Node() );
00271
00272
00273 tmpModel->addStatement( dataGraphUri, Soprano::Vocabulary::NAO::lastModified(), LiteralValue( QDateTime::currentDateTime() ), metadataGraphUri );
00274
00275
00276
00277 if ( ontoModificationDate( ontoUri ).isValid() ) {
00278 if ( !removeOntology( ontoUri ) ) {
00279 return false;
00280 }
00281 }
00282
00283 StatementIterator it = tmpModel->listStatements();
00284 while ( it.next() ) {
00285 if ( addStatement( *it ) != Error::ErrorNone ) {
00286
00287
00288
00289 return false;
00290 }
00291 }
00292
00293 kDebug() << "Successfully updated ontology" << ontoUri;
00294 return true;
00295 }
00296 else {
00297 kDebug() << "BUG! BUG! BUG! BUG! BUG! BUG! Could not find data and metadata graph URIs! This should not happen!";
00298 return false;
00299 }
00300 }
00301
00302
00303 bool Nepomuk::OntologyManagerModel::removeOntology( const QUrl& ns )
00304 {
00305 clearError();
00306
00307 QUrl dataGraphUri, metadataGraphUri;
00308 if ( findGraphUris( this, ns, dataGraphUri, metadataGraphUri ) ) {
00309
00310 removeContext( dataGraphUri );
00311 removeContext( metadataGraphUri );
00312 return true;
00313 }
00314 else {
00315 kDebug() << "Could not find data graph URI for" << ns;
00316 setError( "Could not find ontology " + ns.toString(), Error::ErrorInvalidArgument );
00317 return false;
00318 }
00319 }
00320
00321
00322 QDateTime Nepomuk::OntologyManagerModel::ontoModificationDate( const QUrl& uri )
00323 {
00324 QueryResultIterator it = executeQuery( QString( "select ?date where { "
00325 "?onto <%1> \"%2\"^^<%3> . "
00326 "?onto <%4> ?date . "
00327 "FILTER(DATATYPE(?date) = <%5>) . }" )
00328 .arg( Soprano::Vocabulary::NAO::hasDefaultNamespace().toString() )
00329 .arg( uri.toString() )
00330 .arg( Soprano::Vocabulary::XMLSchema::string().toString() )
00331 .arg( Soprano::Vocabulary::NAO::lastModified().toString() )
00332 .arg( Soprano::Vocabulary::XMLSchema::dateTime().toString() ),
00333 Soprano::Query::QueryLanguageSparql );
00334 if ( it.next() ) {
00335 kDebug() << "Found modification date for" << uri << it.binding( "date" ).literal().toDateTime();
00336 return it.binding( "date" ).literal().toDateTime();
00337 }
00338 else {
00339 return QDateTime();
00340 }
00341 }
00342
00343 #include "ontologymanagermodel.moc"