annotate rdf/PluginRDFIndexer.cpp @ 728:f2de9a42830e dataquay

Convert a bit more of RDFTransformFactory to Dataquay
author Chris Cannam
date Sat, 19 May 2012 12:50:36 +0100
parents 211efc770335
children 27c861cce97b
rev   line source
Chris@439 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@439 2
Chris@439 3 /*
Chris@439 4 Sonic Visualiser
Chris@439 5 An audio file viewer and annotation editor.
Chris@439 6 Centre for Digital Music, Queen Mary, University of London.
Chris@727 7 This file copyright 2008-2012 QMUL.
Chris@439 8
Chris@439 9 This program is free software; you can redistribute it and/or
Chris@439 10 modify it under the terms of the GNU General Public License as
Chris@439 11 published by the Free Software Foundation; either version 2 of the
Chris@439 12 License, or (at your option) any later version. See the file
Chris@439 13 COPYING included with this distribution for more information.
Chris@439 14 */
Chris@439 15
Chris@439 16 #include "PluginRDFIndexer.h"
Chris@439 17
Chris@467 18 #include "data/fileio/CachedFile.h"
Chris@471 19 #include "data/fileio/FileSource.h"
Chris@461 20 #include "data/fileio/PlaylistFileReader.h"
Chris@439 21 #include "plugin/PluginIdentifier.h"
Chris@439 22
Chris@457 23 #include "base/Profiler.h"
Chris@457 24
Chris@475 25 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@439 26
Chris@725 27 #include <dataquay/BasicStore.h>
Chris@725 28 #include <dataquay/RDFException.h>
Chris@725 29
Chris@439 30 #include <QFileInfo>
Chris@439 31 #include <QDir>
Chris@439 32 #include <QUrl>
Chris@461 33 #include <QDateTime>
Chris@461 34 #include <QSettings>
Chris@461 35 #include <QFile>
Chris@439 36
Chris@439 37 #include <iostream>
Chris@439 38 using std::cerr;
Chris@439 39 using std::endl;
Chris@439 40 using std::vector;
Chris@439 41 using std::string;
Chris@439 42 using Vamp::PluginHostAdapter;
Chris@439 43
Chris@725 44 using Dataquay::Uri;
Chris@725 45 using Dataquay::Node;
Chris@725 46 using Dataquay::Nodes;
Chris@725 47 using Dataquay::Triple;
Chris@725 48 using Dataquay::Triples;
Chris@725 49 using Dataquay::BasicStore;
Chris@725 50 using Dataquay::RDFException;
Chris@725 51 using Dataquay::RDFDuplicateImportException;
Chris@725 52
Chris@439 53 PluginRDFIndexer *
Chris@439 54 PluginRDFIndexer::m_instance = 0;
Chris@439 55
Chris@439 56 PluginRDFIndexer *
Chris@439 57 PluginRDFIndexer::getInstance()
Chris@439 58 {
Chris@439 59 if (!m_instance) m_instance = new PluginRDFIndexer();
Chris@439 60 return m_instance;
Chris@439 61 }
Chris@439 62
Chris@725 63 PluginRDFIndexer::PluginRDFIndexer() :
Chris@725 64 m_index(new Dataquay::BasicStore)
Chris@439 65 {
Chris@725 66 m_index->addPrefix("vamp", Uri("http://purl.org/ontology/vamp/"));
Chris@725 67 m_index->addPrefix("foaf", Uri("http://xmlns.com/foaf/0.1/"));
Chris@725 68 m_index->addPrefix("dc", Uri("http://purl.org/dc/elements/1.1/"));
Chris@477 69 indexInstalledURLs();
Chris@477 70 }
Chris@477 71
Chris@725 72 const BasicStore *
Chris@725 73 PluginRDFIndexer::getIndex()
Chris@725 74 {
Chris@725 75 return m_index;
Chris@725 76 }
Chris@725 77
Chris@477 78 PluginRDFIndexer::~PluginRDFIndexer()
Chris@477 79 {
Chris@477 80 QMutexLocker locker(&m_mutex);
Chris@477 81 }
Chris@477 82
Chris@477 83 void
Chris@477 84 PluginRDFIndexer::indexInstalledURLs()
Chris@477 85 {
Chris@439 86 vector<string> paths = PluginHostAdapter::getPluginPath();
Chris@439 87
Chris@439 88 QStringList filters;
Chris@439 89 filters << "*.n3";
Chris@439 90 filters << "*.N3";
Chris@439 91 filters << "*.rdf";
Chris@439 92 filters << "*.RDF";
Chris@439 93
Chris@439 94 // Search each Vamp plugin path for a .rdf file that either has
Chris@439 95 // name "soname", "soname:label" or "soname/label" plus RDF
Chris@439 96 // extension. Use that order of preference, and prefer n3 over
Chris@439 97 // rdf extension.
Chris@439 98
Chris@439 99 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
Chris@718 100
Chris@439 101 QDir dir(i->c_str());
Chris@439 102 if (!dir.exists()) continue;
Chris@439 103
Chris@439 104 QStringList entries = dir.entryList
Chris@439 105 (filters, QDir::Files | QDir::Readable);
Chris@439 106
Chris@439 107 for (QStringList::const_iterator j = entries.begin();
Chris@439 108 j != entries.end(); ++j) {
Chris@718 109
Chris@439 110 QFileInfo fi(dir.filePath(*j));
Chris@489 111 pullFile(fi.absoluteFilePath());
Chris@439 112 }
Chris@439 113
Chris@439 114 QStringList subdirs = dir.entryList
Chris@439 115 (QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable);
Chris@439 116
Chris@439 117 for (QStringList::const_iterator j = subdirs.begin();
Chris@439 118 j != subdirs.end(); ++j) {
Chris@718 119
Chris@439 120 QDir subdir(dir.filePath(*j));
Chris@439 121 if (subdir.exists()) {
Chris@439 122 entries = subdir.entryList
Chris@439 123 (filters, QDir::Files | QDir::Readable);
Chris@439 124 for (QStringList::const_iterator k = entries.begin();
Chris@439 125 k != entries.end(); ++k) {
Chris@439 126 QFileInfo fi(subdir.filePath(*k));
Chris@489 127 pullFile(fi.absoluteFilePath());
Chris@439 128 }
Chris@439 129 }
Chris@439 130 }
Chris@439 131 }
Chris@489 132
Chris@489 133 reindex();
Chris@439 134 }
Chris@439 135
Chris@461 136 bool
Chris@461 137 PluginRDFIndexer::indexConfiguredURLs()
Chris@461 138 {
Chris@690 139 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs" << endl;
Chris@461 140
Chris@461 141 QSettings settings;
Chris@461 142 settings.beginGroup("RDF");
Chris@461 143
Chris@461 144 QString indexKey("rdf-indices");
Chris@461 145 QStringList indices = settings.value(indexKey).toStringList();
Chris@461 146
Chris@461 147 for (int i = 0; i < indices.size(); ++i) {
Chris@461 148
Chris@461 149 QString index = indices[i];
Chris@461 150
Chris@690 151 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs: index url is "
Chris@687 152 << index << endl;
Chris@461 153
Chris@467 154 CachedFile cf(index);
Chris@467 155 if (!cf.isOK()) continue;
Chris@467 156
Chris@467 157 FileSource indexSource(cf.getLocalFilename());
Chris@461 158
Chris@461 159 PlaylistFileReader reader(indexSource);
Chris@461 160 if (!reader.isOK()) continue;
Chris@461 161
Chris@461 162 PlaylistFileReader::Playlist list = reader.load();
Chris@461 163 for (PlaylistFileReader::Playlist::const_iterator j = list.begin();
Chris@461 164 j != list.end(); ++j) {
Chris@690 165 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs: url is "
Chris@687 166 << j->toStdString() << endl;
Chris@489 167 pullURL(*j);
Chris@461 168 }
Chris@461 169 }
Chris@461 170
Chris@461 171 QString urlListKey("rdf-urls");
Chris@461 172 QStringList urls = settings.value(urlListKey).toStringList();
Chris@461 173
Chris@461 174 for (int i = 0; i < urls.size(); ++i) {
Chris@489 175 pullURL(urls[i]);
Chris@461 176 }
Chris@461 177
Chris@461 178 settings.endGroup();
Chris@489 179 reindex();
Chris@461 180 return true;
Chris@461 181 }
Chris@461 182
Chris@439 183 QString
Chris@439 184 PluginRDFIndexer::getURIForPluginId(QString pluginId)
Chris@439 185 {
Chris@461 186 QMutexLocker locker(&m_mutex);
Chris@461 187
Chris@439 188 if (m_idToUriMap.find(pluginId) == m_idToUriMap.end()) return "";
Chris@439 189 return m_idToUriMap[pluginId];
Chris@439 190 }
Chris@439 191
Chris@439 192 QString
Chris@439 193 PluginRDFIndexer::getIdForPluginURI(QString uri)
Chris@439 194 {
Chris@476 195 m_mutex.lock();
Chris@461 196
Chris@439 197 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 198
Chris@476 199 m_mutex.unlock();
Chris@476 200
Chris@439 201 // Haven't found this uri referenced in any document on the
Chris@439 202 // local filesystem; try resolving the pre-fragment part of
Chris@439 203 // the uri as a document URL and reading that if possible.
Chris@439 204
Chris@439 205 // Because we may want to refer to this document again, we
Chris@439 206 // cache it locally if it turns out to exist.
Chris@439 207
Chris@686 208 cerr << "PluginRDFIndexer::getIdForPluginURI: NOTE: Failed to find a local RDF document describing plugin <" << uri << ">: attempting to retrieve one remotely by guesswork" << endl;
Chris@439 209
Chris@439 210 QString baseUrl = QUrl(uri).toString(QUrl::RemoveFragment);
Chris@439 211
Chris@457 212 indexURL(baseUrl);
Chris@439 213
Chris@476 214 m_mutex.lock();
Chris@476 215
Chris@439 216 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 217 m_uriToIdMap[uri] = "";
Chris@439 218 }
Chris@439 219 }
Chris@439 220
Chris@476 221 QString id = m_uriToIdMap[uri];
Chris@476 222 m_mutex.unlock();
Chris@476 223 return id;
Chris@439 224 }
Chris@439 225
Chris@456 226 QStringList
Chris@456 227 PluginRDFIndexer::getIndexedPluginIds()
Chris@456 228 {
Chris@461 229 QMutexLocker locker(&m_mutex);
Chris@461 230
Chris@456 231 QStringList ids;
Chris@489 232 for (StringMap::const_iterator i = m_idToUriMap.begin();
Chris@489 233 i != m_idToUriMap.end(); ++i) {
Chris@456 234 ids.push_back(i->first);
Chris@456 235 }
Chris@456 236 return ids;
Chris@456 237 }
Chris@456 238
Chris@439 239 bool
Chris@489 240 PluginRDFIndexer::pullFile(QString filepath)
Chris@439 241 {
Chris@439 242 QUrl url = QUrl::fromLocalFile(filepath);
Chris@439 243 QString urlString = url.toString();
Chris@489 244 return pullURL(urlString);
Chris@439 245 }
Chris@461 246
Chris@439 247 bool
Chris@439 248 PluginRDFIndexer::indexURL(QString urlString)
Chris@439 249 {
Chris@489 250 bool pulled = pullURL(urlString);
Chris@489 251 if (!pulled) return false;
Chris@489 252 reindex();
Chris@489 253 return true;
Chris@489 254 }
Chris@489 255
Chris@489 256 bool
Chris@489 257 PluginRDFIndexer::pullURL(QString urlString)
Chris@489 258 {
Chris@457 259 Profiler profiler("PluginRDFIndexer::indexURL");
Chris@457 260
Chris@690 261 // SVDEBUG << "PluginRDFIndexer::indexURL(" << urlString << ")" << endl;
Chris@461 262
Chris@461 263 QMutexLocker locker(&m_mutex);
Chris@461 264
Chris@725 265 QUrl local = urlString;
Chris@457 266
Chris@457 267 if (FileSource::isRemote(urlString) &&
Chris@457 268 FileSource::canHandleScheme(urlString)) {
Chris@457 269
Chris@520 270 CachedFile cf(urlString, 0, "application/rdf+xml");
Chris@467 271 if (!cf.isOK()) {
Chris@467 272 return false;
Chris@467 273 }
Chris@467 274
Chris@725 275 local = QUrl::fromLocalFile(cf.getLocalFilename());
Chris@725 276
Chris@725 277 } else {
Chris@725 278
Chris@725 279 local = QUrl::fromLocalFile(urlString);
Chris@457 280 }
Chris@457 281
Chris@725 282 try {
Chris@725 283 m_index->import(local, BasicStore::ImportFailOnDuplicates);
Chris@725 284 } catch (RDFDuplicateImportException &e) {
Chris@725 285 cerr << "PluginRDFIndexer::pullURL: Document at " << urlString
Chris@725 286 << " duplicates triples found in earlier loaded document" << endl;
Chris@725 287 return false;
Chris@725 288 } catch (RDFException &e) {
Chris@725 289 cerr << "PluginRDFIndexer::pullURL: Failed to import document from "
Chris@725 290 << urlString << ": " << e.what() << endl;
Chris@725 291 return false;
Chris@725 292 }
Chris@725 293 return true;
Chris@489 294 }
Chris@489 295
Chris@489 296 bool
Chris@489 297 PluginRDFIndexer::reindex()
Chris@489 298 {
Chris@725 299 Triples tt = m_index->match
Chris@725 300 (Triple(Node(), "a", m_index->expand("vamp:Plugin")));
Chris@725 301 Nodes plugins = tt.a();
Chris@439 302
Chris@439 303 bool foundSomething = false;
Chris@439 304 bool addedSomething = false;
Chris@439 305
Chris@725 306 foreach (Node plugin, plugins) {
Chris@725 307
Chris@725 308 if (plugin.type != Node::URI) {
Chris@725 309 cerr << "PluginRDFIndexer::reindex: Plugin has no URI: node is "
Chris@725 310 << plugin << endl;
Chris@439 311 continue;
Chris@439 312 }
Chris@725 313
Chris@725 314 Triple idt = m_index->matchFirst
Chris@725 315 (Triple(plugin, "vamp:identifier", Node()));
Chris@725 316
Chris@725 317 if (idt.c.type != Node::Literal) {
Chris@725 318 cerr << "PluginRDFIndexer::reindex: Plugin " << plugin
Chris@725 319 << " lacks vamp:identifier literal" << endl;
Chris@439 320 continue;
Chris@439 321 }
Chris@481 322
Chris@725 323 Triple libt = m_index->matchFirst
Chris@725 324 (Triple(Node(), "vamp:available_plugin", plugin));
Chris@481 325
Chris@725 326 if (libt.a.type != Node::URI) {
Chris@725 327 cerr << "PluginRDFIndexer::reindex: Plugin " << plugin
Chris@725 328 << " is not vamp:available_plugin in any library" << endl;
Chris@481 329 continue;
Chris@481 330 }
Chris@481 331
Chris@725 332 Triple sot = m_index->matchFirst
Chris@725 333 (Triple(libt.a, "vamp:identifier", Node()));
Chris@725 334
Chris@725 335 if (sot.c.type != Node::Literal) {
Chris@725 336 cerr << "PluginRDFIndexer::reindex: Library " << libt.a
Chris@725 337 << " lacks vamp:identifier for soname" << endl;
Chris@725 338 continue;
Chris@725 339 }
Chris@725 340
Chris@725 341 QString pluginUri = plugin.value;
Chris@725 342 QString identifier = idt.c.value;
Chris@725 343 QString soname = sot.c.value;
Chris@725 344
Chris@439 345 QString pluginId = PluginIdentifier::createIdentifier
Chris@439 346 ("vamp", soname, identifier);
Chris@439 347
Chris@439 348 foundSomething = true;
Chris@439 349
Chris@489 350 if (m_idToUriMap.find(pluginId) != m_idToUriMap.end()) {
Chris@439 351 continue;
Chris@439 352 }
Chris@439 353
Chris@439 354 m_idToUriMap[pluginId] = pluginUri;
Chris@439 355
Chris@439 356 addedSomething = true;
Chris@439 357
Chris@439 358 if (pluginUri != "") {
Chris@439 359 if (m_uriToIdMap.find(pluginUri) != m_uriToIdMap.end()) {
Chris@718 360 cerr << "PluginRDFIndexer::reindex: WARNING: Found multiple plugins with the same URI:" << endl;
Chris@686 361 cerr << " 1. Plugin id \"" << m_uriToIdMap[pluginUri] << "\"" << endl;
Chris@686 362 cerr << " 2. Plugin id \"" << pluginId << "\"" << endl;
Chris@686 363 cerr << "both claim URI <" << pluginUri << ">" << endl;
Chris@439 364 } else {
Chris@439 365 m_uriToIdMap[pluginUri] = pluginId;
Chris@439 366 }
Chris@439 367 }
Chris@439 368 }
Chris@439 369
Chris@439 370 if (!foundSomething) {
Chris@718 371 cerr << "PluginRDFIndexer::reindex: NOTE: Plugins found, but none sufficiently described" << endl;
Chris@439 372 }
Chris@439 373
Chris@439 374 return addedSomething;
Chris@439 375 }