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

NepomukDaemons

ontologymanagermodel.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 "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         // 1. all statements need to have a proper context set
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         // 2. make sure we have a proper relation between the data and metadata graphs
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         // set proper context on all data statements (This is a bit ugly but we cannot iterate and modify at the same time!)
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         // add the metadata
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     // Create temp memory model
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     // so we dont have to care about deleting out tmpModel anymore.
00217     ObjectGarbageCollector modelGarbageCollector( tmpModel );
00218 
00219     // import the data into our tmp model
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     // all the data has been read into the temp model
00244     // now we make sure it has a proper layout (one main and one metadata graph)
00245     // ------------------------------------
00246     QList<Node> graphs = tmpModel->listContexts().allNodes();
00247     if ( graphs.count() == 0 ) {
00248         // simple: we have to create all data manually
00249         createMetadata( tmpModel, ontoUri );
00250     }
00251     else if ( graphs.count() == 2 ) {
00252         // proper number of graphs. Make sure we have all the necessary information
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     // store the modification date of the ontology file in the metadata graph and reuse it to know if we have to update
00266     // ------------------------------------
00267     QUrl dataGraphUri, metadataGraphUri;
00268     if ( findGraphUris( tmpModel, ontoUri, dataGraphUri, metadataGraphUri ) ) {
00269         // remove any modification date data there is
00270         tmpModel->removeAllStatements( dataGraphUri, Soprano::Vocabulary::NAO::lastModified(), Node() );
00271 
00272         // set the new modification date
00273         tmpModel->addStatement( dataGraphUri, Soprano::Vocabulary::NAO::lastModified(), LiteralValue( QDateTime::currentDateTime() ), metadataGraphUri );
00274 
00275         // now it is time to merge the new data in
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                 // FIXME: here we should cleanup, but then again, if adding the statement
00287                 // fails, removing will probably also fail. So the only real solution
00288                 // would be a transaction.
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         // now removing the ontology is simple
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"

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.4
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