• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

NepomukDaemons

ontologyupdatejob.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE Project
00002    Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "ontologyupdatejob.h"
00020 
00021 #include <QtCore/QUrl>
00022 #include <QtCore/QThread>
00023 #include <QtCore/QDateTime>
00024 
00025 #include <Soprano/Backend>
00026 #include <Soprano/StorageModel>
00027 #include <Soprano/PluginManager>
00028 #include <Soprano/Global>
00029 #include <Soprano/NodeIterator>
00030 #include <Soprano/StatementIterator>
00031 #include <Soprano/QueryResultIterator>
00032 #include <Soprano/Vocabulary/RDF>
00033 #include <Soprano/Vocabulary/RDFS>
00034 #include <Soprano/Vocabulary/NRL>
00035 #include <Soprano/Vocabulary/NAO>
00036 #include <Soprano/Vocabulary/XMLSchema>
00037 
00038 #include <KDebug>
00039 
00040 
00041 using namespace Soprano;
00042 
00043 namespace {
00044     QUrl createMetadataGraphUri( const QUrl& uri ) {
00045         QString s( uri.toString() );
00046         if ( s.endsWith( '#' ) )
00047             s[s.length()-1] = '/';
00048         else if ( !s.endsWith( '/' ) )
00049             s += '/';
00050         s += "metadata";
00051         return QUrl( s );
00052     }
00053 
00054     bool findGraphUris( Soprano::Model* model, const QUrl& ns, QUrl& dataGraphUri, QUrl& metaDataGraphUri ) {
00055         QString query = QString( "select ?dg ?mdg where { "
00056                                  "?dg <%1> \"%2\"^^<%3> . "
00057                                  "?mdg <%4> ?dg . "
00058                                  "}" )
00059                         .arg( Soprano::Vocabulary::NAO::hasDefaultNamespace().toString() )
00060                         .arg( ns.toString() )
00061                         .arg( Soprano::Vocabulary::XMLSchema::string().toString() )
00062                         .arg( Soprano::Vocabulary::NRL::coreGraphMetadataFor().toString() );
00063 
00064         QueryResultIterator it = model->executeQuery( query, Soprano::Query::QueryLanguageSparql );
00065         if ( it.next() ) {
00066             metaDataGraphUri = it.binding("mdg").uri();
00067             dataGraphUri = it.binding("dg").uri();
00068             return true;
00069         }
00070         else {
00071             return false;
00072         }
00073     }
00074 }
00075 
00076 
00077 class Nepomuk::OntologyUpdateJob::Private : public QThread
00078 {
00079 public:
00080     Private( Soprano::Model* mainModel, OntologyUpdateJob* job )
00081         : QThread( job ),
00082           m_model( mainModel ),
00083           m_job( job ),
00084           m_success( false ) {
00085     }
00086 
00087     void run();
00088     void _k_slotFinished();
00089 
00090     QUrl baseUri;
00091     Soprano::Model* m_model;
00092 
00093 private:
00094     bool updateOntology();
00095     bool ensureDataLayout( Soprano::Model* tmpModel, const QUrl& ns );
00096     void createMetadata( Soprano::Model* tmpModel, const QUrl& ns );
00097     bool removeOntology( const QUrl& ns );
00098 
00099     OntologyUpdateJob* m_job;
00100     bool m_success;
00101 };
00102 
00103 
00104 void Nepomuk::OntologyUpdateJob::Private::run()
00105 {
00106     m_success = updateOntology();
00107 }
00108 
00109 
00110 bool Nepomuk::OntologyUpdateJob::Private::ensureDataLayout( Soprano::Model* tmpModel, const QUrl& ns )
00111 {
00112     // 1. all statements need to have a proper context set
00113     StatementIterator it = tmpModel->listStatements();
00114     while ( it.next() ) {
00115         if ( !it.current().context().isValid() ) {
00116             kDebug() << "Invalid data in ontology" << ns << *it;
00117             return false;
00118         }
00119     }
00120 
00121     // 2. make sure we have a proper relation between the data and metadata graphs
00122     QUrl dataGraphUri, metaDataGraphUri;
00123     if ( !findGraphUris( tmpModel, ns, dataGraphUri, metaDataGraphUri ) ) {
00124         kDebug() << "Invalid data in ontology" << ns << "Could not find datagraph and metadatagraph relation.";
00125         return false;
00126     }
00127 
00128     return true;
00129 }
00130 
00131 
00132 void Nepomuk::OntologyUpdateJob::Private::createMetadata( Soprano::Model* tmpModel, const QUrl& ns )
00133 {
00134     Q_ASSERT( ns.isValid() );
00135     QUrl dataGraphUri( ns );
00136     dataGraphUri.setFragment( QString() );
00137     QUrl metaDataGraphUri = createMetadataGraphUri( dataGraphUri );
00138 
00139     // set proper context on all data statements (This is a bit ugly but we cannot iterate and modify at the same time!)
00140     QList<Statement> allStatements = tmpModel->listStatements().allStatements();
00141     tmpModel->removeAllStatements();
00142     foreach( Statement s, allStatements ) {
00143         s.setContext( dataGraphUri );
00144         tmpModel->addStatement( s );
00145     }
00146 
00147     // add the metadata
00148     tmpModel->addStatement( Soprano::Statement( metaDataGraphUri, Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::NRL::GraphMetadata(), metaDataGraphUri ) );
00149     tmpModel->addStatement( Soprano::Statement( metaDataGraphUri, Soprano::Vocabulary::NRL::coreGraphMetadataFor(), dataGraphUri, metaDataGraphUri ) );
00150     tmpModel->addStatement( Soprano::Statement( dataGraphUri, Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::NRL::Ontology(), metaDataGraphUri ) );
00151     tmpModel->addStatement( Soprano::Statement( dataGraphUri, Soprano::Vocabulary::NAO::hasDefaultNamespace(), LiteralValue( ns.toString() ), metaDataGraphUri ) );
00152 }
00153 
00154 
00155 bool Nepomuk::OntologyUpdateJob::Private::updateOntology()
00156 {
00157     // Create temp memory model
00158     // ------------------------------------
00159     const Soprano::Backend* backend = Soprano::PluginManager::instance()->discoverBackendByFeatures( Soprano::BackendFeatureStorageMemory );
00160     if ( !backend ) {
00161         kDebug() << "No Soprano backend found that can handle memory models!";
00162         return false;
00163     }
00164 
00165     Soprano::Model* tmpModel = backend->createModel( BackendSettings() << BackendSetting( Soprano::BackendOptionStorageMemory ) );
00166     if ( !tmpModel ) {
00167         kDebug() << "Failed to create temp memory model!";
00168         return false;
00169     }
00170 
00171     Soprano::StatementIterator it = m_job->data();
00172     while ( it.next() ) {
00173         tmpModel->addStatement( *it );
00174     }
00175 
00176     QUrl ontoUri = baseUri;
00177     if ( ontoUri.isEmpty() ) {
00178         it = tmpModel->listStatements();
00179         if ( it.next() ) {
00180             ontoUri = it.current().subject().uri();
00181             if ( !ontoUri.fragment().isEmpty() ) {
00182                 ontoUri.setFragment( QString() );
00183             }
00184             else {
00185                 ontoUri = ontoUri.toString().left( ontoUri.toString().lastIndexOf( '/' )+1 );
00186             }
00187         }
00188     }
00189     if ( ontoUri.isEmpty() ) {
00190         kDebug() << "Failed to determine ontology URI.";
00191         return false;
00192     }
00193 
00194     // all the data has been read into the temp model
00195     // now we make sure it has a proper layout (one main and one metadata graph)
00196     // ------------------------------------
00197     QList<Node> graphs = tmpModel->listContexts().allNodes();
00198     if ( graphs.count() == 0 ) {
00199         // simple: we have to create all data manually
00200         createMetadata( tmpModel, ontoUri );
00201     }
00202     else if ( graphs.count() == 2 ) {
00203         // proper number of graphs. Make sure we have all the necessary information
00204         if ( !ensureDataLayout( tmpModel, ontoUri ) ) {
00205             delete tmpModel;
00206             return false;
00207         }
00208     }
00209     else {
00210         kDebug() << "Invalid data in ontology" << ontoUri << "We need one data and one metadata graph.";
00211         delete tmpModel;
00212         return false;
00213     }
00214 
00215 
00216     // store the modification date of the ontology file in the metadata graph and reuse it to know if we have to update
00217     // ------------------------------------
00218     QUrl dataGraphUri, metadataGraphUri;
00219     if ( findGraphUris( tmpModel, ontoUri, dataGraphUri, metadataGraphUri ) ) {
00220         tmpModel->addStatement( Statement( dataGraphUri, Soprano::Vocabulary::NAO::lastModified(), LiteralValue( QDateTime::currentDateTime() ), metadataGraphUri ) );
00221 
00222         // now it is time to merge the new data in
00223         // ------------------------------------
00224         if ( ontoModificationDate( m_model, ontoUri ).isValid() ) {
00225             removeOntology( ontoUri );
00226         }
00227 
00228         it = tmpModel->listStatements();
00229         while ( it.next() ) {
00230             m_model->addStatement( *it );
00231         }
00232         delete tmpModel;
00233 
00234         kDebug() << "Successfully updated ontology" << ontoUri;
00235         return true;
00236     }
00237     else {
00238         kDebug() << "BUG! Could not find data and metadata graph URIs! This should not happen!";
00239         return false;
00240     }
00241 }
00242 
00243 
00244 bool Nepomuk::OntologyUpdateJob::Private::removeOntology( const QUrl& ns )
00245 {
00246     QUrl dataGraphUri, metadataGraphUri;
00247     if ( findGraphUris( m_model, ns, dataGraphUri, metadataGraphUri ) ) {
00248         // now removing the ontology is simple
00249         m_model->removeContext( dataGraphUri );
00250         m_model->removeContext( metadataGraphUri );
00251         return true;
00252     }
00253     else {
00254         kDebug() << "Could not find data graph URI for" << ns;
00255         return false;
00256     }
00257 }
00258 
00259 
00260 void Nepomuk::OntologyUpdateJob::Private::_k_slotFinished()
00261 {
00262     // FIXME: more detailed error code and message
00263     m_job->setError( m_success ? KJob::NoError : KJob::UserDefinedError );
00264     emit m_job->emitResult();
00265 }
00266 
00267 
00268 Nepomuk::OntologyUpdateJob::OntologyUpdateJob( Soprano::Model* mainModel, QObject* parent )
00269     : KJob( parent ),
00270       d( new Private( mainModel, this ) )
00271 {
00272     // FIXME: connect the thread for more information
00273     connect( d, SIGNAL(finished()), this, SLOT(_k_slotFinished()) );
00274 }
00275 
00276 
00277 Nepomuk::OntologyUpdateJob::~OntologyUpdateJob()
00278 {
00279     delete d;
00280 }
00281 
00282 
00283 void Nepomuk::OntologyUpdateJob::start()
00284 {
00285     d->start();
00286 }
00287 
00288 
00289 void Nepomuk::OntologyUpdateJob::setBaseUri( const QUrl& uri )
00290 {
00291     d->baseUri = uri;
00292 }
00293 
00294 
00295 Soprano::Model* Nepomuk::OntologyUpdateJob::model() const
00296 {
00297     return d->m_model;
00298 }
00299 
00300 
00301 QDateTime Nepomuk::OntologyUpdateJob::ontoModificationDate( Soprano::Model* model, const QUrl& uri )
00302 {
00303     QueryResultIterator it = model->executeQuery( QString( "select ?date where { ?onto <%1> \"%2\"^^<%3> . ?onto <%4> ?date . }" )
00304                                                   .arg( Soprano::Vocabulary::NAO::hasDefaultNamespace().toString() )
00305                                                   .arg( uri.toString() )
00306                                                   .arg( Soprano::Vocabulary::XMLSchema::string().toString() )
00307                                                   .arg( Soprano::Vocabulary::NAO::lastModified().toString() ),
00308                                                   Soprano::Query::QueryLanguageSparql );
00309     if ( it.next() ) {
00310         kDebug() << "Found modification date for" << uri << it.binding( "date" ).literal().toDateTime();
00311         return it.binding( "date" ).literal().toDateTime();
00312     }
00313     else {
00314         return QDateTime();
00315     }
00316 }
00317 
00318 #include "ontologyupdatejob.moc"

NepomukDaemons

Skip menu "NepomukDaemons"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KCMShell
  • KNotify
  • KStyles
  • Nepomuk Daemons
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal