annotate rdf/PluginRDFDescription.cpp @ 1844:5b1b03c1d8d4

Accept more than one library URI for a plugin; consistency checks for packs
author Chris Cannam
date Mon, 20 Apr 2020 15:42:51 +0100
parents 3ec563af0a4f
children 6f626cfdba51
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 "PluginRDFDescription.h"
Chris@439 17
Chris@439 18 #include "PluginRDFIndexer.h"
Chris@439 19
Chris@457 20 #include "base/Profiler.h"
Chris@457 21
Chris@439 22 #include "plugin/PluginIdentifier.h"
Chris@439 23
Chris@725 24 #include <dataquay/BasicStore.h>
Chris@725 25
Chris@439 26 #include <iostream>
Chris@439 27
Chris@725 28 using Dataquay::Uri;
Chris@725 29 using Dataquay::Node;
Chris@725 30 using Dataquay::Nodes;
Chris@725 31 using Dataquay::Triple;
Chris@725 32 using Dataquay::Triples;
Chris@725 33 using Dataquay::BasicStore;
Chris@725 34
Chris@1844 35 #define DEBUG_PLUGIN_RDF_DESCRIPTION 1
Chris@1844 36
Chris@439 37 PluginRDFDescription::PluginRDFDescription(QString pluginId) :
Chris@439 38 m_pluginId(pluginId),
Chris@439 39 m_haveDescription(false)
Chris@439 40 {
Chris@439 41 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@489 42 m_pluginUri = indexer->getURIForPluginId(pluginId);
Chris@489 43 if (m_pluginUri == "") {
Chris@439 44 cerr << "PluginRDFDescription: WARNING: No RDF description available for plugin ID \""
Chris@686 45 << pluginId << "\"" << endl;
Chris@439 46 } else {
Chris@489 47 // All the data we need should be in our RDF model already:
Chris@489 48 // if it's not there, we don't know where to find it anyway
Chris@489 49 if (index()) {
Chris@439 50 m_haveDescription = true;
Chris@439 51 }
Chris@439 52 }
Chris@439 53 }
Chris@439 54
Chris@439 55 PluginRDFDescription::~PluginRDFDescription()
Chris@439 56 {
Chris@439 57 }
Chris@439 58
Chris@439 59 bool
Chris@439 60 PluginRDFDescription::haveDescription() const
Chris@439 61 {
Chris@439 62 return m_haveDescription;
Chris@439 63 }
Chris@439 64
Chris@457 65 QString
Chris@457 66 PluginRDFDescription::getPluginName() const
Chris@457 67 {
Chris@457 68 return m_pluginName;
Chris@457 69 }
Chris@457 70
Chris@457 71 QString
Chris@457 72 PluginRDFDescription::getPluginDescription() const
Chris@457 73 {
Chris@457 74 return m_pluginDescription;
Chris@457 75 }
Chris@457 76
Chris@457 77 QString
Chris@457 78 PluginRDFDescription::getPluginMaker() const
Chris@457 79 {
Chris@457 80 return m_pluginMaker;
Chris@457 81 }
Chris@457 82
Chris@462 83 QString
Chris@462 84 PluginRDFDescription::getPluginInfoURL() const
Chris@462 85 {
Chris@462 86 return m_pluginInfoURL;
Chris@462 87 }
Chris@462 88
Chris@1843 89 QString
Chris@1843 90 PluginRDFDescription::getPluginDownloadURL() const
Chris@1843 91 {
Chris@1843 92 return m_pluginDownloadURL;
Chris@1843 93 }
Chris@1843 94
Chris@1843 95 std::set<PluginRDFDescription::DownloadType>
Chris@1843 96 PluginRDFDescription::getPluginDownloadTypes() const
Chris@1843 97 {
Chris@1843 98 return m_pluginDownloadTypes;
Chris@1843 99 }
Chris@1843 100
Chris@1843 101 std::map<QString, PluginRDFDescription::Pack>
Chris@1843 102 PluginRDFDescription::getPluginFoundInPacks() const
Chris@1843 103 {
Chris@1843 104 return m_pluginFoundInPacks;
Chris@1843 105 }
Chris@1843 106
Chris@457 107 QStringList
Chris@457 108 PluginRDFDescription::getOutputIds() const
Chris@457 109 {
Chris@457 110 QStringList ids;
Chris@457 111 for (OutputDispositionMap::const_iterator i = m_outputDispositions.begin();
Chris@457 112 i != m_outputDispositions.end(); ++i) {
Chris@457 113 ids.push_back(i->first);
Chris@457 114 }
Chris@457 115 return ids;
Chris@457 116 }
Chris@457 117
Chris@457 118 QString
Chris@457 119 PluginRDFDescription::getOutputName(QString outputId) const
Chris@457 120 {
Chris@457 121 if (m_outputNames.find(outputId) == m_outputNames.end()) {
Chris@457 122 return "";
Chris@457 123 }
Chris@457 124 return m_outputNames.find(outputId)->second;
Chris@457 125 }
Chris@457 126
Chris@439 127 PluginRDFDescription::OutputDisposition
Chris@439 128 PluginRDFDescription::getOutputDisposition(QString outputId) const
Chris@439 129 {
Chris@439 130 if (m_outputDispositions.find(outputId) == m_outputDispositions.end()) {
Chris@439 131 return OutputDispositionUnknown;
Chris@439 132 }
Chris@439 133 return m_outputDispositions.find(outputId)->second;
Chris@439 134 }
Chris@439 135
Chris@439 136 QString
Chris@439 137 PluginRDFDescription::getOutputEventTypeURI(QString outputId) const
Chris@439 138 {
Chris@439 139 if (m_outputEventTypeURIMap.find(outputId) ==
Chris@439 140 m_outputEventTypeURIMap.end()) {
Chris@439 141 return "";
Chris@439 142 }
Chris@439 143 return m_outputEventTypeURIMap.find(outputId)->second;
Chris@439 144 }
Chris@439 145
Chris@439 146 QString
Chris@440 147 PluginRDFDescription::getOutputFeatureAttributeURI(QString outputId) const
Chris@440 148 {
Chris@440 149 if (m_outputFeatureAttributeURIMap.find(outputId) ==
Chris@440 150 m_outputFeatureAttributeURIMap.end()) {
Chris@440 151 return "";
Chris@440 152 }
Chris@440 153 return m_outputFeatureAttributeURIMap.find(outputId)->second;
Chris@440 154 }
Chris@440 155
Chris@440 156 QString
Chris@440 157 PluginRDFDescription::getOutputSignalTypeURI(QString outputId) const
Chris@440 158 {
Chris@440 159 if (m_outputSignalTypeURIMap.find(outputId) ==
Chris@440 160 m_outputSignalTypeURIMap.end()) {
Chris@440 161 return "";
Chris@440 162 }
Chris@440 163 return m_outputSignalTypeURIMap.find(outputId)->second;
Chris@440 164 }
Chris@440 165
Chris@440 166 QString
Chris@439 167 PluginRDFDescription::getOutputUnit(QString outputId) const
Chris@439 168 {
Chris@439 169 if (m_outputUnitMap.find(outputId) == m_outputUnitMap.end()) {
Chris@439 170 return "";
Chris@439 171 }
Chris@439 172 return m_outputUnitMap.find(outputId)->second;
Chris@439 173 }
Chris@439 174
Chris@494 175 QString
Chris@494 176 PluginRDFDescription::getOutputUri(QString outputId) const
Chris@494 177 {
Chris@494 178 if (m_outputUriMap.find(outputId) == m_outputUriMap.end()) {
Chris@494 179 return "";
Chris@494 180 }
Chris@494 181 return m_outputUriMap.find(outputId)->second;
Chris@494 182 }
Chris@494 183
Chris@439 184 bool
Chris@489 185 PluginRDFDescription::index()
Chris@439 186 {
Chris@489 187 Profiler profiler("PluginRDFDescription::index");
Chris@439 188
Chris@457 189 bool success = true;
Chris@489 190 if (!indexMetadata()) success = false;
Chris@489 191 if (!indexOutputs()) success = false;
Chris@457 192
Chris@457 193 return success;
Chris@457 194 }
Chris@457 195
Chris@457 196 bool
Chris@489 197 PluginRDFDescription::indexMetadata()
Chris@457 198 {
Chris@489 199 Profiler profiler("PluginRDFDescription::index");
Chris@489 200
Chris@725 201 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@725 202 const BasicStore *index = indexer->getIndex();
Chris@725 203 Uri plugin(m_pluginUri);
Chris@457 204
Chris@730 205 Node n = index->complete
Chris@730 206 (Triple(plugin, index->expand("vamp:name"), Node()));
Chris@730 207
Chris@725 208 if (n.type == Node::Literal && n.value != "") {
Chris@725 209 m_pluginName = n.value;
Chris@457 210 }
Chris@457 211
Chris@730 212 n = index->complete
Chris@730 213 (Triple(plugin, index->expand("dc:description"), Node()));
Chris@730 214
Chris@725 215 if (n.type == Node::Literal && n.value != "") {
Chris@725 216 m_pluginDescription = n.value;
Chris@457 217 }
Chris@457 218
Chris@730 219 n = index->complete
Chris@730 220 (Triple(plugin, index->expand("foaf:maker"), Node()));
Chris@730 221
Chris@725 222 if (n.type == Node::URI || n.type == Node::Blank) {
Chris@730 223 n = index->complete(Triple(n, index->expand("foaf:name"), Node()));
Chris@725 224 if (n.type == Node::Literal && n.value != "") {
Chris@725 225 m_pluginMaker = n.value;
Chris@725 226 }
Chris@457 227 }
Chris@457 228
Chris@462 229 // If we have a more-information URL for this plugin, then we take
Chris@725 230 // that. Otherwise, a more-information URL for the plugin library
Chris@725 231 // would do nicely.
Chris@462 232
Chris@730 233 n = index->complete
Chris@730 234 (Triple(plugin, index->expand("foaf:page"), Node()));
Chris@730 235
Chris@725 236 if (n.type == Node::URI && n.value != "") {
Chris@725 237 m_pluginInfoURL = n.value;
Chris@725 238 }
Chris@462 239
Chris@1844 240 // There may be more than one library node claiming this
Chris@1844 241 // plugin. That's because older RDF descriptions tend to use a
Chris@1844 242 // library node URI derived from the description's own URI, so it
Chris@1844 243 // varies depending on where you read the description from. It's
Chris@1844 244 // common therefore to end up with both a file: URI (from an
Chris@1844 245 // installed older version) and an http: one (from an online
Chris@1844 246 // updated version). We have no way to pick an authoritative one,
Chris@1844 247 // but it's also common that only one of them will have the
Chris@1844 248 // resources we need anyway, so let's iterate through them all.
Chris@1844 249
Chris@1844 250 Nodes libnodes = index->match
Chris@1844 251 (Triple(Node(), index->expand("vamp:available_plugin"), plugin))
Chris@1844 252 .subjects();
Chris@730 253
Chris@1844 254 for (Node libn: libnodes) {
Chris@1844 255
Chris@1844 256 if (libn.type != Node::URI || libn.value == "") {
Chris@1844 257 continue;
Chris@1844 258 }
Chris@1843 259
Chris@1843 260 n = index->complete
Chris@1843 261 (Triple(libn, index->expand("foaf:page"), Node()));
Chris@1844 262
Chris@1844 263 if (n.type == Node::URI && n.value != "") {
Chris@1843 264 m_pluginInfoURL = n.value;
Chris@1843 265 }
Chris@1843 266
Chris@1843 267 n = index->complete
Chris@1843 268 (Triple(libn, index->expand("doap:download-page"), Node()));
Chris@1843 269
Chris@725 270 if (n.type == Node::URI && n.value != "") {
Chris@1843 271 m_pluginDownloadURL = n.value;
Chris@1843 272
Chris@1843 273 n = index->complete
Chris@1843 274 (Triple(libn, index->expand("vamp:has_source"), Node()));
Chris@1843 275 if (n.type == Node::Literal && n.value == "true") {
Chris@1843 276 m_pluginDownloadTypes.insert(DownloadSourceCode);
Chris@1843 277 }
Chris@1843 278
Chris@1843 279 Nodes binaries = index->match
Chris@1843 280 (Triple(libn, index->expand("vamp:has_binary"), Node()))
Chris@1843 281 .objects();
Chris@1843 282
Chris@1843 283 for (Node bin: binaries) {
Chris@1843 284 if (bin.type != Node::Literal) continue;
Chris@1843 285 if (bin.value == "linux32") {
Chris@1843 286 m_pluginDownloadTypes.insert(DownloadLinux32);
Chris@1843 287 } else if (bin.value == "linux64") {
Chris@1843 288 m_pluginDownloadTypes.insert(DownloadLinux64);
Chris@1843 289 } else if (bin.value == "win32") {
Chris@1843 290 m_pluginDownloadTypes.insert(DownloadWindows);
Chris@1843 291 } else if (bin.value == "osx") {
Chris@1843 292 m_pluginDownloadTypes.insert(DownloadMac);
Chris@1843 293 }
Chris@1843 294 }
Chris@462 295 }
Chris@1844 296
Chris@1844 297 Nodes packs = index->match
Chris@1844 298 (Triple(Node(), index->expand("vamp:available_library"), libn))
Chris@1844 299 .subjects();
Chris@1844 300
Chris@1844 301 SVCERR << packs.size() << " matching pack(s) for library node "
Chris@1844 302 << libn << endl;
Chris@1844 303
Chris@1844 304 for (Node packn: packs) {
Chris@1844 305 if (packn.type != Node::URI) continue;
Chris@1844 306
Chris@1844 307 Pack pack;
Chris@1844 308 n = index->complete
Chris@1844 309 (Triple(packn, index->expand("dc:title"), Node()));
Chris@1844 310 if (n.type == Node::Literal) {
Chris@1844 311 pack.name = n.value;
Chris@1844 312 }
Chris@1844 313 n = index->complete
Chris@1844 314 (Triple(packn, index->expand("foaf:page"), Node()));
Chris@1844 315 if (n.type == Node::URI) {
Chris@1844 316 pack.downloadURL = n.value;
Chris@1844 317 }
Chris@1844 318
Chris@1844 319 if (pack.name != "" && pack.downloadURL != "") {
Chris@1844 320 m_pluginFoundInPacks[packn.value] = pack;
Chris@1844 321 }
Chris@1844 322 }
Chris@462 323 }
Chris@462 324
Chris@1844 325 #ifdef DEBUG_PLUGIN_RDF_DESCRIPTION
Chris@1844 326 SVCERR << "PluginRDFDescription::indexMetadata:" << endl;
Chris@1844 327 SVCERR << " * id: " << m_pluginId << endl;
Chris@1844 328 SVCERR << " * uri: <" << m_pluginUri << ">" << endl;
Chris@1844 329 SVCERR << " * name: " << m_pluginName << endl;
Chris@1844 330 SVCERR << " * description: " << m_pluginDescription << endl;
Chris@1844 331 SVCERR << " * maker: " << m_pluginMaker << endl;
Chris@1844 332 SVCERR << " * info url: <" << m_pluginInfoURL << ">" << endl;
Chris@1844 333 SVCERR << " * download url: <" << m_pluginDownloadURL << ">" << endl;
Chris@1844 334 SVCERR << " * download types:" << endl;
Chris@1844 335 for (auto t: m_pluginDownloadTypes) {
Chris@1844 336 SVCERR << " * " << int(t) << endl;
Chris@1844 337 }
Chris@1844 338 SVCERR << " * packs:" << endl;
Chris@1844 339 for (auto t: m_pluginFoundInPacks) {
Chris@1844 340 SVCERR << " * " << t.first << " { name: " << t.second.name
Chris@1844 341 << ", download url: " << t.second.downloadURL << " }" << endl;
Chris@1844 342 }
Chris@1844 343 SVCERR << endl;
Chris@1844 344 #endif
Chris@1843 345
Chris@457 346 return true;
Chris@457 347 }
Chris@457 348
Chris@457 349 bool
Chris@489 350 PluginRDFDescription::indexOutputs()
Chris@457 351 {
Chris@457 352 Profiler profiler("PluginRDFDescription::indexOutputs");
Chris@489 353
Chris@725 354 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@725 355 const BasicStore *index = indexer->getIndex();
Chris@725 356 Uri plugin(m_pluginUri);
Chris@457 357
Chris@730 358 Nodes outputs = index->match
Chris@730 359 (Triple(plugin, index->expand("vamp:output"), Node())).objects();
Chris@439 360
Chris@725 361 if (outputs.empty()) {
Chris@718 362 cerr << "ERROR: PluginRDFDescription::indexURL: NOTE: No outputs defined for <"
Chris@686 363 << m_pluginUri << ">" << endl;
Chris@439 364 return false;
Chris@439 365 }
Chris@439 366
Chris@725 367 foreach (Node output, outputs) {
Chris@439 368
Chris@725 369 if ((output.type != Node::URI && output.type != Node::Blank) ||
Chris@725 370 output.value == "") {
Chris@725 371 cerr << "ERROR: PluginRDFDescription::indexURL: No valid URI for output " << output << " of plugin <" << m_pluginUri << ">" << endl;
Chris@718 372 return false;
Chris@718 373 }
Chris@725 374
Chris@730 375 Node n = index->complete(Triple(output, index->expand("vamp:identifier"), Node()));
Chris@725 376 if (n.type != Node::Literal || n.value == "") {
Chris@725 377 cerr << "ERROR: PluginRDFDescription::indexURL: No vamp:identifier for output <" << output << ">" << endl;
Chris@718 378 return false;
Chris@718 379 }
Chris@725 380 QString outputId = n.value;
Chris@718 381
Chris@730 382 m_outputUriMap[outputId] = output.value;
Chris@730 383
Chris@730 384 n = index->complete(Triple(output, Uri("a"), Node()));
Chris@725 385 QString outputType;
Chris@725 386 if (n.type == Node::URI) outputType = n.value;
Chris@718 387
Chris@730 388 n = index->complete(Triple(output, index->expand("vamp:unit"), Node()));
Chris@725 389 QString outputUnit;
Chris@725 390 if (n.type == Node::Literal) outputUnit = n.value;
Chris@718 391
Chris@439 392 if (outputType.contains("DenseOutput")) {
Chris@439 393 m_outputDispositions[outputId] = OutputDense;
Chris@439 394 } else if (outputType.contains("SparseOutput")) {
Chris@439 395 m_outputDispositions[outputId] = OutputSparse;
Chris@439 396 } else if (outputType.contains("TrackLevelOutput")) {
Chris@439 397 m_outputDispositions[outputId] = OutputTrackLevel;
Chris@457 398 } else {
Chris@457 399 m_outputDispositions[outputId] = OutputDispositionUnknown;
Chris@439 400 }
Chris@732 401 // cerr << "output " << output << " -> id " << outputId << ", type " << outputType << ", unit "
Chris@732 402 // << outputUnit << ", disposition " << m_outputDispositions[outputId] << endl;
Chris@439 403
Chris@718 404 if (outputUnit != "") {
Chris@718 405 m_outputUnitMap[outputId] = outputUnit;
Chris@439 406 }
Chris@440 407
Chris@730 408 n = index->complete(Triple(output, index->expand("dc:title"), Node()));
Chris@725 409 if (n.type == Node::Literal && n.value != "") {
Chris@725 410 m_outputNames[outputId] = n.value;
Chris@457 411 }
Chris@457 412
Chris@730 413 n = index->complete(Triple(output, index->expand("vamp:computes_event_type"), Node()));
Chris@732 414 // cerr << output << " -> computes_event_type " << n << endl;
Chris@725 415 if (n.type == Node::URI && n.value != "") {
Chris@725 416 m_outputEventTypeURIMap[outputId] = n.value;
Chris@440 417 }
Chris@440 418
Chris@730 419 n = index->complete(Triple(output, index->expand("vamp:computes_feature"), Node()));
Chris@725 420 if (n.type == Node::URI && n.value != "") {
Chris@725 421 m_outputFeatureAttributeURIMap[outputId] = n.value;
Chris@725 422 }
Chris@440 423
Chris@730 424 n = index->complete(Triple(output, index->expand("vamp:computes_signal_type"), Node()));
Chris@725 425 if (n.type == Node::URI && n.value != "") {
Chris@725 426 m_outputSignalTypeURIMap[outputId] = n.value;
Chris@440 427 }
Chris@439 428 }
Chris@439 429
Chris@439 430 return true;
Chris@439 431 }
Chris@439 432