annotate rdf/PluginRDFIndexer.cpp @ 581:2e0c987a12bd

* Pull out the widgetry part of FileFinder into widgets/InteractiveFileFinder (essentially this is just to avoid a dependency from data/fileio to widgets/ which is problematic for non-gui programs)
author Chris Cannam
date Fri, 27 Mar 2009 16:25:52 +0000
parents e340b2fb9471
children b4a8d8221eaf
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@439 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@439 92 QFileInfo fi(dir.filePath(*j));
Chris@489 93 pullFile(fi.absoluteFilePath());
Chris@439 94 }
Chris@439 95
Chris@439 96 QStringList subdirs = dir.entryList
Chris@439 97 (QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable);
Chris@439 98
Chris@439 99 for (QStringList::const_iterator j = subdirs.begin();
Chris@439 100 j != subdirs.end(); ++j) {
Chris@439 101 QDir subdir(dir.filePath(*j));
Chris@439 102 if (subdir.exists()) {
Chris@439 103 entries = subdir.entryList
Chris@439 104 (filters, QDir::Files | QDir::Readable);
Chris@439 105 for (QStringList::const_iterator k = entries.begin();
Chris@439 106 k != entries.end(); ++k) {
Chris@439 107 QFileInfo fi(subdir.filePath(*k));
Chris@489 108 pullFile(fi.absoluteFilePath());
Chris@439 109 }
Chris@439 110 }
Chris@439 111 }
Chris@439 112 }
Chris@489 113
Chris@489 114 reindex();
Chris@439 115 }
Chris@439 116
Chris@461 117 bool
Chris@461 118 PluginRDFIndexer::indexConfiguredURLs()
Chris@461 119 {
Chris@461 120 std::cerr << "PluginRDFIndexer::indexConfiguredURLs" << std::endl;
Chris@461 121
Chris@461 122 QSettings settings;
Chris@461 123 settings.beginGroup("RDF");
Chris@461 124
Chris@461 125 QString indexKey("rdf-indices");
Chris@461 126 QStringList indices = settings.value(indexKey).toStringList();
Chris@461 127
Chris@461 128 for (int i = 0; i < indices.size(); ++i) {
Chris@461 129
Chris@461 130 QString index = indices[i];
Chris@461 131
Chris@461 132 std::cerr << "PluginRDFIndexer::indexConfiguredURLs: index url is "
Chris@461 133 << index.toStdString() << std::endl;
Chris@461 134
Chris@467 135 CachedFile cf(index);
Chris@467 136 if (!cf.isOK()) continue;
Chris@467 137
Chris@467 138 FileSource indexSource(cf.getLocalFilename());
Chris@461 139
Chris@461 140 PlaylistFileReader reader(indexSource);
Chris@461 141 if (!reader.isOK()) continue;
Chris@461 142
Chris@461 143 PlaylistFileReader::Playlist list = reader.load();
Chris@461 144 for (PlaylistFileReader::Playlist::const_iterator j = list.begin();
Chris@461 145 j != list.end(); ++j) {
Chris@461 146 std::cerr << "PluginRDFIndexer::indexConfiguredURLs: url is "
Chris@461 147 << j->toStdString() << std::endl;
Chris@489 148 pullURL(*j);
Chris@461 149 }
Chris@461 150 }
Chris@461 151
Chris@461 152 QString urlListKey("rdf-urls");
Chris@461 153 QStringList urls = settings.value(urlListKey).toStringList();
Chris@461 154
Chris@461 155 for (int i = 0; i < urls.size(); ++i) {
Chris@489 156 pullURL(urls[i]);
Chris@461 157 }
Chris@461 158
Chris@461 159 settings.endGroup();
Chris@489 160 reindex();
Chris@461 161 return true;
Chris@461 162 }
Chris@461 163
Chris@439 164 QString
Chris@439 165 PluginRDFIndexer::getURIForPluginId(QString pluginId)
Chris@439 166 {
Chris@461 167 QMutexLocker locker(&m_mutex);
Chris@461 168
Chris@439 169 if (m_idToUriMap.find(pluginId) == m_idToUriMap.end()) return "";
Chris@439 170 return m_idToUriMap[pluginId];
Chris@439 171 }
Chris@439 172
Chris@439 173 QString
Chris@439 174 PluginRDFIndexer::getIdForPluginURI(QString uri)
Chris@439 175 {
Chris@476 176 m_mutex.lock();
Chris@461 177
Chris@439 178 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 179
Chris@476 180 m_mutex.unlock();
Chris@476 181
Chris@439 182 // Haven't found this uri referenced in any document on the
Chris@439 183 // local filesystem; try resolving the pre-fragment part of
Chris@439 184 // the uri as a document URL and reading that if possible.
Chris@439 185
Chris@439 186 // Because we may want to refer to this document again, we
Chris@439 187 // cache it locally if it turns out to exist.
Chris@439 188
Chris@439 189 cerr << "PluginRDFIndexer::getIdForPluginURI: NOTE: Failed to find a local RDF document describing plugin <" << uri.toStdString() << ">: attempting to retrieve one remotely by guesswork" << endl;
Chris@439 190
Chris@439 191 QString baseUrl = QUrl(uri).toString(QUrl::RemoveFragment);
Chris@439 192
Chris@457 193 indexURL(baseUrl);
Chris@439 194
Chris@476 195 m_mutex.lock();
Chris@476 196
Chris@439 197 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) {
Chris@439 198 m_uriToIdMap[uri] = "";
Chris@439 199 }
Chris@439 200 }
Chris@439 201
Chris@476 202 QString id = m_uriToIdMap[uri];
Chris@476 203 m_mutex.unlock();
Chris@476 204 return id;
Chris@439 205 }
Chris@439 206
Chris@456 207 QStringList
Chris@456 208 PluginRDFIndexer::getIndexedPluginIds()
Chris@456 209 {
Chris@461 210 QMutexLocker locker(&m_mutex);
Chris@461 211
Chris@456 212 QStringList ids;
Chris@489 213 for (StringMap::const_iterator i = m_idToUriMap.begin();
Chris@489 214 i != m_idToUriMap.end(); ++i) {
Chris@456 215 ids.push_back(i->first);
Chris@456 216 }
Chris@456 217 return ids;
Chris@456 218 }
Chris@456 219
Chris@439 220 bool
Chris@489 221 PluginRDFIndexer::pullFile(QString filepath)
Chris@439 222 {
Chris@439 223 QUrl url = QUrl::fromLocalFile(filepath);
Chris@439 224 QString urlString = url.toString();
Chris@489 225 return pullURL(urlString);
Chris@439 226 }
Chris@461 227
Chris@439 228 bool
Chris@439 229 PluginRDFIndexer::indexURL(QString urlString)
Chris@439 230 {
Chris@489 231 bool pulled = pullURL(urlString);
Chris@489 232 if (!pulled) return false;
Chris@489 233 reindex();
Chris@489 234 return true;
Chris@489 235 }
Chris@489 236
Chris@489 237 bool
Chris@489 238 PluginRDFIndexer::pullURL(QString urlString)
Chris@489 239 {
Chris@457 240 Profiler profiler("PluginRDFIndexer::indexURL");
Chris@457 241
Chris@520 242 loadPrefixes();
Chris@520 243
Chris@508 244 // std::cerr << "PluginRDFIndexer::indexURL(" << urlString.toStdString() << ")" << std::endl;
Chris@461 245
Chris@461 246 QMutexLocker locker(&m_mutex);
Chris@461 247
Chris@457 248 QString localString = urlString;
Chris@457 249
Chris@457 250 if (FileSource::isRemote(urlString) &&
Chris@457 251 FileSource::canHandleScheme(urlString)) {
Chris@457 252
Chris@520 253 CachedFile cf(urlString, 0, "application/rdf+xml");
Chris@467 254 if (!cf.isOK()) {
Chris@467 255 return false;
Chris@467 256 }
Chris@467 257
Chris@483 258 localString = QUrl::fromLocalFile(cf.getLocalFilename()).toString();
Chris@457 259 }
Chris@457 260
Chris@489 261 return SimpleSPARQLQuery::addSourceToModel(localString);
Chris@489 262 }
Chris@489 263
Chris@489 264 bool
Chris@489 265 PluginRDFIndexer::reindex()
Chris@489 266 {
Chris@489 267 SimpleSPARQLQuery::QueryType m = SimpleSPARQLQuery::QueryFromModel;
Chris@489 268
Chris@439 269 SimpleSPARQLQuery query
Chris@489 270 (m,
Chris@481 271 QString
Chris@481 272 (
Chris@481 273 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@481 274
Chris@481 275 " SELECT ?plugin ?library ?plugin_id "
Chris@481 276
Chris@481 277 " WHERE { "
Chris@481 278 " ?plugin a vamp:Plugin . "
Chris@481 279 " ?plugin vamp:identifier ?plugin_id . "
Chris@481 280
Chris@481 281 " OPTIONAL { "
Chris@481 282 " ?library vamp:available_plugin ?plugin "
Chris@481 283 " } "
Chris@481 284 " } "
Chris@489 285 ));
Chris@439 286
Chris@439 287 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@439 288
Chris@439 289 if (!query.isOK()) {
Chris@489 290 cerr << "ERROR: PluginRDFIndexer::reindex: ERROR: Failed to query plugins from model: "
Chris@439 291 << query.getErrorString().toStdString() << endl;
Chris@439 292 return false;
Chris@439 293 }
Chris@439 294
Chris@439 295 if (results.empty()) {
Chris@489 296 cerr << "PluginRDFIndexer::reindex: NOTE: no vamp:Plugin resources found in indexed documents" << endl;
Chris@439 297 return false;
Chris@439 298 }
Chris@439 299
Chris@439 300 bool foundSomething = false;
Chris@439 301 bool addedSomething = false;
Chris@439 302
Chris@439 303 for (SimpleSPARQLQuery::ResultList::iterator i = results.begin();
Chris@439 304 i != results.end(); ++i) {
Chris@439 305
Chris@439 306 QString pluginUri = (*i)["plugin"].value;
Chris@481 307 QString soUri = (*i)["library"].value;
Chris@439 308 QString identifier = (*i)["plugin_id"].value;
Chris@439 309
Chris@439 310 if (identifier == "") {
Chris@489 311 cerr << "PluginRDFIndexer::reindex: NOTE: No vamp:identifier for plugin <"
Chris@439 312 << pluginUri.toStdString() << ">"
Chris@439 313 << endl;
Chris@439 314 continue;
Chris@439 315 }
Chris@481 316 if (soUri == "") {
Chris@489 317 cerr << "PluginRDFIndexer::reindex: NOTE: No implementation library for plugin <"
Chris@482 318 << pluginUri.toStdString() << ">"
Chris@439 319 << endl;
Chris@439 320 continue;
Chris@439 321 }
Chris@481 322
Chris@481 323 QString sonameQuery =
Chris@481 324 QString(
Chris@481 325 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@481 326 " SELECT ?library_id "
Chris@481 327 " WHERE { "
Chris@489 328 " <%1> vamp:identifier ?library_id "
Chris@481 329 " } "
Chris@481 330 )
Chris@481 331 .arg(soUri);
Chris@481 332
Chris@481 333 SimpleSPARQLQuery::Value sonameValue =
Chris@489 334 SimpleSPARQLQuery::singleResultQuery(m, sonameQuery, "library_id");
Chris@481 335 QString soname = sonameValue.value;
Chris@481 336 if (soname == "") {
Chris@489 337 cerr << "PluginRDFIndexer::reindex: NOTE: No identifier for library <"
Chris@481 338 << soUri.toStdString() << ">"
Chris@481 339 << endl;
Chris@481 340 continue;
Chris@481 341 }
Chris@481 342
Chris@439 343 QString pluginId = PluginIdentifier::createIdentifier
Chris@439 344 ("vamp", soname, identifier);
Chris@439 345
Chris@439 346 foundSomething = true;
Chris@439 347
Chris@489 348 if (m_idToUriMap.find(pluginId) != m_idToUriMap.end()) {
Chris@439 349 continue;
Chris@439 350 }
Chris@439 351
Chris@439 352 m_idToUriMap[pluginId] = pluginUri;
Chris@439 353
Chris@439 354 addedSomething = true;
Chris@439 355
Chris@439 356 if (pluginUri != "") {
Chris@439 357 if (m_uriToIdMap.find(pluginUri) != m_uriToIdMap.end()) {
Chris@489 358 cerr << "PluginRDFIndexer::reindex: WARNING: Found multiple plugins with the same URI:" << endl;
Chris@439 359 cerr << " 1. Plugin id \"" << m_uriToIdMap[pluginUri].toStdString() << "\"" << endl;
Chris@439 360 cerr << " 2. Plugin id \"" << pluginId.toStdString() << "\"" << endl;
Chris@439 361 cerr << "both claim URI <" << pluginUri.toStdString() << ">" << endl;
Chris@439 362 } else {
Chris@439 363 m_uriToIdMap[pluginUri] = pluginId;
Chris@439 364 }
Chris@439 365 }
Chris@439 366 }
Chris@439 367
Chris@439 368 if (!foundSomething) {
Chris@489 369 cerr << "PluginRDFIndexer::reindex: NOTE: Plugins found, but none sufficiently described" << endl;
Chris@439 370 }
Chris@439 371
Chris@439 372 return addedSomething;
Chris@439 373 }
Chris@439 374
Chris@520 375 void
Chris@520 376 PluginRDFIndexer::loadPrefixes()
Chris@520 377 {
Chris@520 378 return;
Chris@520 379 //!!!
Chris@520 380 if (m_prefixesLoaded) return;
Chris@520 381 const char *prefixes[] = {
Chris@520 382 "http://purl.org/ontology/vamp/"
Chris@520 383 };
Chris@520 384 for (size_t i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); ++i) {
Chris@520 385 CachedFile cf(prefixes[i], 0, "application/rdf+xml");
Chris@520 386 if (!cf.isOK()) continue;
Chris@520 387 SimpleSPARQLQuery::addSourceToModel
Chris@520 388 (QUrl::fromLocalFile(cf.getLocalFilename()).toString());
Chris@520 389 }
Chris@520 390 m_prefixesLoaded = true;
Chris@520 391 }
Chris@439 392
Chris@439 393