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