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