annotate rdf/PluginRDFIndexer.cpp @ 718:f3fd2988fc9b

Fix incorrect query structure for output type URIs. This led to some output RDF features being written with type URIs intended for different outputs. Also revert some SVDEBUGs to cerrs -- they are intended as user-visible errors or warnings rather than debug
author Chris Cannam
date Mon, 09 Jan 2012 16:28:54 +0000
parents 1424aa29ae95
children c789deb83bd4
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@439 7 This file copyright 2008 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@439 18 #include "SimpleSPARQLQuery.h"
Chris@439 19
Chris@467 20 #include "data/fileio/CachedFile.h"
Chris@471 21 #include "data/fileio/FileSource.h"
Chris@461 22 #include "data/fileio/PlaylistFileReader.h"
Chris@439 23 #include "plugin/PluginIdentifier.h"
Chris@439 24
Chris@457 25 #include "base/Profiler.h"
Chris@457 26
Chris@475 27 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@439 28
Chris@439 29 #include <QFileInfo>
Chris@439 30 #include <QDir>
Chris@439 31 #include <QUrl>
Chris@461 32 #include <QDateTime>
Chris@461 33 #include <QSettings>
Chris@461 34 #include <QFile>
Chris@439 35
Chris@439 36 #include <iostream>
Chris@439 37 using std::cerr;
Chris@439 38 using std::endl;
Chris@439 39 using std::vector;
Chris@439 40 using std::string;
Chris@439 41 using Vamp::PluginHostAdapter;
Chris@439 42
Chris@439 43 PluginRDFIndexer *
Chris@439 44 PluginRDFIndexer::m_instance = 0;
Chris@439 45
Chris@520 46 bool
Chris@520 47 PluginRDFIndexer::m_prefixesLoaded = false;
Chris@520 48
Chris@439 49 PluginRDFIndexer *
Chris@439 50 PluginRDFIndexer::getInstance()
Chris@439 51 {
Chris@439 52 if (!m_instance) m_instance = new PluginRDFIndexer();
Chris@439 53 return m_instance;
Chris@439 54 }
Chris@439 55
Chris@439 56 PluginRDFIndexer::PluginRDFIndexer()
Chris@439 57 {
Chris@477 58 indexInstalledURLs();
Chris@477 59 }
Chris@477 60
Chris@477 61 PluginRDFIndexer::~PluginRDFIndexer()
Chris@477 62 {
Chris@477 63 QMutexLocker locker(&m_mutex);
Chris@477 64 }
Chris@477 65
Chris@477 66 void
Chris@477 67 PluginRDFIndexer::indexInstalledURLs()
Chris@477 68 {
Chris@439 69 vector<string> paths = PluginHostAdapter::getPluginPath();
Chris@439 70
Chris@439 71 QStringList filters;
Chris@439 72 filters << "*.n3";
Chris@439 73 filters << "*.N3";
Chris@439 74 filters << "*.rdf";
Chris@439 75 filters << "*.RDF";
Chris@439 76
Chris@439 77 // Search each Vamp plugin path for a .rdf file that either has
Chris@439 78 // name "soname", "soname:label" or "soname/label" plus RDF
Chris@439 79 // extension. Use that order of preference, and prefer n3 over
Chris@439 80 // rdf extension.
Chris@439 81
Chris@439 82 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
Chris@718 83
Chris@439 84 QDir dir(i->c_str());
Chris@439 85 if (!dir.exists()) continue;
Chris@439 86
Chris@439 87 QStringList entries = dir.entryList
Chris@439 88 (filters, QDir::Files | QDir::Readable);
Chris@439 89
Chris@439 90 for (QStringList::const_iterator j = entries.begin();
Chris@439 91 j != entries.end(); ++j) {
Chris@718 92
Chris@439 93 QFileInfo fi(dir.filePath(*j));
Chris@489 94 pullFile(fi.absoluteFilePath());
Chris@439 95 }
Chris@439 96
Chris@439 97 QStringList subdirs = dir.entryList
Chris@439 98 (QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable);
Chris@439 99
Chris@439 100 for (QStringList::const_iterator j = subdirs.begin();
Chris@439 101 j != subdirs.end(); ++j) {
Chris@718 102
Chris@439 103 QDir subdir(dir.filePath(*j));
Chris@439 104 if (subdir.exists()) {
Chris@439 105 entries = subdir.entryList
Chris@439 106 (filters, QDir::Files | QDir::Readable);
Chris@439 107 for (QStringList::const_iterator k = entries.begin();
Chris@439 108 k != entries.end(); ++k) {
Chris@439 109 QFileInfo fi(subdir.filePath(*k));
Chris@489 110 pullFile(fi.absoluteFilePath());
Chris@439 111 }
Chris@439 112 }
Chris@439 113 }
Chris@439 114 }
Chris@489 115
Chris@489 116 reindex();
Chris@439 117 }
Chris@439 118
Chris@461 119 bool
Chris@461 120 PluginRDFIndexer::indexConfiguredURLs()
Chris@461 121 {
Chris@690 122 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs" << endl;
Chris@461 123
Chris@461 124 QSettings settings;
Chris@461 125 settings.beginGroup("RDF");
Chris@461 126
Chris@461 127 QString indexKey("rdf-indices");
Chris@461 128 QStringList indices = settings.value(indexKey).toStringList();
Chris@461 129
Chris@461 130 for (int i = 0; i < indices.size(); ++i) {
Chris@461 131
Chris@461 132 QString index = indices[i];
Chris@461 133
Chris@690 134 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs: index url is "
Chris@687 135 << index << endl;
Chris@461 136
Chris@467 137 CachedFile cf(index);
Chris@467 138 if (!cf.isOK()) continue;
Chris@467 139
Chris@467 140 FileSource indexSource(cf.getLocalFilename());
Chris@461 141
Chris@461 142 PlaylistFileReader reader(indexSource);
Chris@461 143 if (!reader.isOK()) continue;
Chris@461 144
Chris@461 145 PlaylistFileReader::Playlist list = reader.load();
Chris@461 146 for (PlaylistFileReader::Playlist::const_iterator j = list.begin();
Chris@461 147 j != list.end(); ++j) {
Chris@690 148 SVDEBUG << "PluginRDFIndexer::indexConfiguredURLs: url is "
Chris@687 149 << j->toStdString() << endl;
Chris@489 150 pullURL(*j);
Chris@461 151 }
Chris@461 152 }
Chris@461 153
Chris@461 154 QString urlListKey("rdf-urls");
Chris@461 155 QStringList urls = settings.value(urlListKey).toStringList();
Chris@461 156
Chris@461 157 for (int i = 0; i < urls.size(); ++i) {
Chris@489 158 pullURL(urls[i]);
Chris@461 159 }
Chris@461 160
Chris@461 161 settings.endGroup();
Chris@489 162 reindex();
Chris@461 163 return true;
Chris@461 164 }
Chris@461 165
Chris@439 166 QString
Chris@439 167 PluginRDFIndexer::getURIForPluginId(QString pluginId)
Chris@439 168 {
Chris@461 169 QMutexLocker locker(&m_mutex);
Chris@461 170
Chris@439 171 if (m_idToUriMap.find(pluginId) == m_idToUriMap.end()) return "";
Chris@439 172 return m_idToUriMap[pluginId];
Chris@439 173 }
Chris@439 174
Chris@439 175 QString
Chris@439 176 PluginRDFIndexer::getIdForPluginURI(QString uri)
Chris@439 177 {
Chris@476 178 m_mutex.lock();
Chris@461 179
Chris@439 180 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 181
Chris@476 182 m_mutex.unlock();
Chris@476 183
Chris@439 184 // Haven't found this uri referenced in any document on the
Chris@439 185 // local filesystem; try resolving the pre-fragment part of
Chris@439 186 // the uri as a document URL and reading that if possible.
Chris@439 187
Chris@439 188 // Because we may want to refer to this document again, we
Chris@439 189 // cache it locally if it turns out to exist.
Chris@439 190
Chris@686 191 cerr << "PluginRDFIndexer::getIdForPluginURI: NOTE: Failed to find a local RDF document describing plugin <" << uri << ">: attempting to retrieve one remotely by guesswork" << endl;
Chris@439 192
Chris@439 193 QString baseUrl = QUrl(uri).toString(QUrl::RemoveFragment);
Chris@439 194
Chris@457 195 indexURL(baseUrl);
Chris@439 196
Chris@476 197 m_mutex.lock();
Chris@476 198
Chris@439 199 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 200 m_uriToIdMap[uri] = "";
Chris@439 201 }
Chris@439 202 }
Chris@439 203
Chris@476 204 QString id = m_uriToIdMap[uri];
Chris@476 205 m_mutex.unlock();
Chris@476 206 return id;
Chris@439 207 }
Chris@439 208
Chris@456 209 QStringList
Chris@456 210 PluginRDFIndexer::getIndexedPluginIds()
Chris@456 211 {
Chris@461 212 QMutexLocker locker(&m_mutex);
Chris@461 213
Chris@456 214 QStringList ids;
Chris@489 215 for (StringMap::const_iterator i = m_idToUriMap.begin();
Chris@489 216 i != m_idToUriMap.end(); ++i) {
Chris@456 217 ids.push_back(i->first);
Chris@456 218 }
Chris@456 219 return ids;
Chris@456 220 }
Chris@456 221
Chris@439 222 bool
Chris@489 223 PluginRDFIndexer::pullFile(QString filepath)
Chris@439 224 {
Chris@439 225 QUrl url = QUrl::fromLocalFile(filepath);
Chris@439 226 QString urlString = url.toString();
Chris@489 227 return pullURL(urlString);
Chris@439 228 }
Chris@461 229
Chris@439 230 bool
Chris@439 231 PluginRDFIndexer::indexURL(QString urlString)
Chris@439 232 {
Chris@489 233 bool pulled = pullURL(urlString);
Chris@489 234 if (!pulled) return false;
Chris@489 235 reindex();
Chris@489 236 return true;
Chris@489 237 }
Chris@489 238
Chris@489 239 bool
Chris@489 240 PluginRDFIndexer::pullURL(QString urlString)
Chris@489 241 {
Chris@457 242 Profiler profiler("PluginRDFIndexer::indexURL");
Chris@457 243
Chris@520 244 loadPrefixes();
Chris@520 245
Chris@690 246 // SVDEBUG << "PluginRDFIndexer::indexURL(" << urlString << ")" << endl;
Chris@461 247
Chris@461 248 QMutexLocker locker(&m_mutex);
Chris@461 249
Chris@457 250 QString localString = urlString;
Chris@457 251
Chris@457 252 if (FileSource::isRemote(urlString) &&
Chris@457 253 FileSource::canHandleScheme(urlString)) {
Chris@457 254
Chris@520 255 CachedFile cf(urlString, 0, "application/rdf+xml");
Chris@467 256 if (!cf.isOK()) {
Chris@467 257 return false;
Chris@467 258 }
Chris@467 259
Chris@483 260 localString = QUrl::fromLocalFile(cf.getLocalFilename()).toString();
Chris@457 261 }
Chris@457 262
Chris@489 263 return SimpleSPARQLQuery::addSourceToModel(localString);
Chris@489 264 }
Chris@489 265
Chris@489 266 bool
Chris@489 267 PluginRDFIndexer::reindex()
Chris@489 268 {
Chris@489 269 SimpleSPARQLQuery::QueryType m = SimpleSPARQLQuery::QueryFromModel;
Chris@489 270
Chris@439 271 SimpleSPARQLQuery query
Chris@489 272 (m,
Chris@481 273 QString
Chris@481 274 (
Chris@481 275 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@481 276
Chris@481 277 " SELECT ?plugin ?library ?plugin_id "
Chris@481 278
Chris@481 279 " WHERE { "
Chris@481 280 " ?plugin a vamp:Plugin . "
Chris@481 281 " ?plugin vamp:identifier ?plugin_id . "
Chris@481 282
Chris@481 283 " OPTIONAL { "
Chris@481 284 " ?library vamp:available_plugin ?plugin "
Chris@481 285 " } "
Chris@481 286 " } "
Chris@489 287 ));
Chris@439 288
Chris@439 289 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@439 290
Chris@439 291 if (!query.isOK()) {
Chris@489 292 cerr << "ERROR: PluginRDFIndexer::reindex: ERROR: Failed to query plugins from model: "
Chris@686 293 << query.getErrorString() << endl;
Chris@439 294 return false;
Chris@439 295 }
Chris@439 296
Chris@439 297 if (results.empty()) {
Chris@718 298 cerr << "PluginRDFIndexer::reindex: NOTE: no vamp:Plugin resources found in indexed documents" << endl;
Chris@439 299 return false;
Chris@439 300 }
Chris@439 301
Chris@439 302 bool foundSomething = false;
Chris@439 303 bool addedSomething = false;
Chris@439 304
Chris@439 305 for (SimpleSPARQLQuery::ResultList::iterator i = results.begin();
Chris@439 306 i != results.end(); ++i) {
Chris@439 307
Chris@439 308 QString pluginUri = (*i)["plugin"].value;
Chris@481 309 QString soUri = (*i)["library"].value;
Chris@439 310 QString identifier = (*i)["plugin_id"].value;
Chris@439 311
Chris@439 312 if (identifier == "") {
Chris@718 313 cerr << "PluginRDFIndexer::reindex: NOTE: No vamp:identifier for plugin <"
Chris@686 314 << pluginUri << ">"
Chris@439 315 << endl;
Chris@439 316 continue;
Chris@439 317 }
Chris@481 318 if (soUri == "") {
Chris@718 319 cerr << "PluginRDFIndexer::reindex: NOTE: No implementation library for plugin <"
Chris@686 320 << pluginUri << ">"
Chris@439 321 << endl;
Chris@439 322 continue;
Chris@439 323 }
Chris@481 324
Chris@481 325 QString sonameQuery =
Chris@481 326 QString(
Chris@481 327 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@481 328 " SELECT ?library_id "
Chris@481 329 " WHERE { "
Chris@489 330 " <%1> vamp:identifier ?library_id "
Chris@481 331 " } "
Chris@481 332 )
Chris@481 333 .arg(soUri);
Chris@481 334
Chris@481 335 SimpleSPARQLQuery::Value sonameValue =
Chris@489 336 SimpleSPARQLQuery::singleResultQuery(m, sonameQuery, "library_id");
Chris@481 337 QString soname = sonameValue.value;
Chris@481 338 if (soname == "") {
Chris@718 339 cerr << "PluginRDFIndexer::reindex: NOTE: No identifier for library <"
Chris@686 340 << soUri << ">"
Chris@481 341 << endl;
Chris@481 342 continue;
Chris@481 343 }
Chris@481 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 }
Chris@439 376
Chris@520 377 void
Chris@520 378 PluginRDFIndexer::loadPrefixes()
Chris@520 379 {
Chris@520 380 return;
Chris@520 381 //!!!
Chris@520 382 if (m_prefixesLoaded) return;
Chris@520 383 const char *prefixes[] = {
Chris@520 384 "http://purl.org/ontology/vamp/"
Chris@520 385 };
Chris@520 386 for (size_t i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); ++i) {
Chris@520 387 CachedFile cf(prefixes[i], 0, "application/rdf+xml");
Chris@520 388 if (!cf.isOK()) continue;
Chris@520 389 SimpleSPARQLQuery::addSourceToModel
Chris@520 390 (QUrl::fromLocalFile(cf.getLocalFilename()).toString());
Chris@520 391 }
Chris@520 392 m_prefixesLoaded = true;
Chris@520 393 }
Chris@439 394
Chris@439 395