Mercurial > hg > svcore
comparison rdf/PluginRDFIndexer.cpp @ 439:beb2948baa77
* Merge revisions 1041 to 1130 from sv-rdf-import branch
author | Chris Cannam |
---|---|
date | Thu, 18 Sep 2008 12:09:32 +0000 |
parents | |
children | 5746c559af15 |
comparison
equal
deleted
inserted
replaced
438:32c399d06374 | 439:beb2948baa77 |
---|---|
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 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 "SimpleSPARQLQuery.h" | |
19 | |
20 #include "data/fileio/FileSource.h" | |
21 #include "plugin/PluginIdentifier.h" | |
22 | |
23 #include <vamp-sdk/PluginHostAdapter.h> | |
24 | |
25 #include <QFileInfo> | |
26 #include <QDir> | |
27 #include <QUrl> | |
28 | |
29 #include <iostream> | |
30 using std::cerr; | |
31 using std::endl; | |
32 using std::vector; | |
33 using std::string; | |
34 using Vamp::PluginHostAdapter; | |
35 | |
36 PluginRDFIndexer * | |
37 PluginRDFIndexer::m_instance = 0; | |
38 | |
39 PluginRDFIndexer * | |
40 PluginRDFIndexer::getInstance() | |
41 { | |
42 if (!m_instance) m_instance = new PluginRDFIndexer(); | |
43 return m_instance; | |
44 } | |
45 | |
46 PluginRDFIndexer::PluginRDFIndexer() | |
47 { | |
48 vector<string> paths = PluginHostAdapter::getPluginPath(); | |
49 | |
50 QStringList filters; | |
51 filters << "*.n3"; | |
52 filters << "*.N3"; | |
53 filters << "*.rdf"; | |
54 filters << "*.RDF"; | |
55 | |
56 // Search each Vamp plugin path for a .rdf file that either has | |
57 // name "soname", "soname:label" or "soname/label" plus RDF | |
58 // extension. Use that order of preference, and prefer n3 over | |
59 // rdf extension. | |
60 | |
61 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) { | |
62 | |
63 QDir dir(i->c_str()); | |
64 if (!dir.exists()) continue; | |
65 | |
66 QStringList entries = dir.entryList | |
67 (filters, QDir::Files | QDir::Readable); | |
68 | |
69 for (QStringList::const_iterator j = entries.begin(); | |
70 j != entries.end(); ++j) { | |
71 QFileInfo fi(dir.filePath(*j)); | |
72 indexFile(fi.absoluteFilePath()); | |
73 } | |
74 | |
75 QStringList subdirs = dir.entryList | |
76 (QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable); | |
77 | |
78 for (QStringList::const_iterator j = subdirs.begin(); | |
79 j != subdirs.end(); ++j) { | |
80 QDir subdir(dir.filePath(*j)); | |
81 if (subdir.exists()) { | |
82 entries = subdir.entryList | |
83 (filters, QDir::Files | QDir::Readable); | |
84 for (QStringList::const_iterator k = entries.begin(); | |
85 k != entries.end(); ++k) { | |
86 QFileInfo fi(subdir.filePath(*k)); | |
87 indexFile(fi.absoluteFilePath()); | |
88 } | |
89 } | |
90 } | |
91 } | |
92 } | |
93 | |
94 PluginRDFIndexer::~PluginRDFIndexer() | |
95 { | |
96 while (!m_cache.empty()) { | |
97 delete *m_cache.begin(); | |
98 m_cache.erase(m_cache.begin()); | |
99 } | |
100 } | |
101 | |
102 QString | |
103 PluginRDFIndexer::getURIForPluginId(QString pluginId) | |
104 { | |
105 if (m_idToUriMap.find(pluginId) == m_idToUriMap.end()) return ""; | |
106 return m_idToUriMap[pluginId]; | |
107 } | |
108 | |
109 QString | |
110 PluginRDFIndexer::getIdForPluginURI(QString uri) | |
111 { | |
112 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) { | |
113 | |
114 // Haven't found this uri referenced in any document on the | |
115 // local filesystem; try resolving the pre-fragment part of | |
116 // the uri as a document URL and reading that if possible. | |
117 | |
118 // Because we may want to refer to this document again, we | |
119 // cache it locally if it turns out to exist. | |
120 | |
121 cerr << "PluginRDFIndexer::getIdForPluginURI: NOTE: Failed to find a local RDF document describing plugin <" << uri.toStdString() << ">: attempting to retrieve one remotely by guesswork" << endl; | |
122 | |
123 QString baseUrl = QUrl(uri).toString(QUrl::RemoveFragment); | |
124 | |
125 FileSource source(baseUrl); | |
126 if (source.isAvailable()) { | |
127 source.waitForData(); | |
128 if (indexFile(source.getLocalFilename())) { | |
129 m_cache.insert(new FileSource(source)); | |
130 } | |
131 } | |
132 | |
133 if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) { | |
134 m_uriToIdMap[uri] = ""; | |
135 } | |
136 } | |
137 | |
138 return m_uriToIdMap[uri]; | |
139 } | |
140 | |
141 QString | |
142 PluginRDFIndexer::getDescriptionURLForPluginId(QString pluginId) | |
143 { | |
144 if (m_idToDescriptionMap.find(pluginId) == m_idToDescriptionMap.end()) return ""; | |
145 return m_idToDescriptionMap[pluginId]; | |
146 } | |
147 | |
148 QString | |
149 PluginRDFIndexer::getDescriptionURLForPluginURI(QString uri) | |
150 { | |
151 QString id = getIdForPluginURI(uri); | |
152 if (id == "") return ""; | |
153 return getDescriptionURLForPluginId(id); | |
154 } | |
155 | |
156 bool | |
157 PluginRDFIndexer::indexFile(QString filepath) | |
158 { | |
159 QUrl url = QUrl::fromLocalFile(filepath); | |
160 QString urlString = url.toString(); | |
161 return indexURL(urlString); | |
162 } | |
163 | |
164 bool | |
165 PluginRDFIndexer::indexURL(QString urlString) | |
166 { | |
167 // cerr << "PluginRDFIndexer::indexURL: url = <" << urlString.toStdString() << ">" << endl; | |
168 | |
169 SimpleSPARQLQuery query | |
170 (QString | |
171 ( | |
172 " PREFIX vamp: <http://purl.org/ontology/vamp/> " | |
173 | |
174 " SELECT ?plugin ?library_id ?plugin_id " | |
175 " FROM <%1> " | |
176 | |
177 " WHERE { " | |
178 " ?plugin a vamp:Plugin . " | |
179 | |
180 // Make the identifier and library parts optional, so | |
181 // that we can check and report helpfully if one or both | |
182 // is absent instead of just getting no results | |
183 | |
184 " OPTIONAL { ?plugin vamp:identifier ?plugin_id } . " | |
185 | |
186 " OPTIONAL { " | |
187 " ?library a vamp:PluginLibrary ; " | |
188 " vamp:available_plugin ?plugin ; " | |
189 " vamp:identifier ?library_id " | |
190 " } " | |
191 " } " | |
192 ) | |
193 .arg(urlString)); | |
194 | |
195 SimpleSPARQLQuery::ResultList results = query.execute(); | |
196 | |
197 if (!query.isOK()) { | |
198 cerr << "ERROR: PluginRDFIndexer::indexURL: ERROR: Failed to index document at <" | |
199 << urlString.toStdString() << ">: " | |
200 << query.getErrorString().toStdString() << endl; | |
201 return false; | |
202 } | |
203 | |
204 if (results.empty()) { | |
205 cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" | |
206 << urlString.toStdString() | |
207 << "> does not describe any vamp:Plugin resources" << endl; | |
208 return false; | |
209 } | |
210 | |
211 bool foundSomething = false; | |
212 bool addedSomething = false; | |
213 | |
214 for (SimpleSPARQLQuery::ResultList::iterator i = results.begin(); | |
215 i != results.end(); ++i) { | |
216 | |
217 QString pluginUri = (*i)["plugin"].value; | |
218 QString soname = (*i)["library_id"].value; | |
219 QString identifier = (*i)["plugin_id"].value; | |
220 | |
221 if (identifier == "") { | |
222 cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" | |
223 << urlString.toStdString() | |
224 << "> fails to define any vamp:identifier for plugin <" | |
225 << pluginUri.toStdString() << ">" | |
226 << endl; | |
227 continue; | |
228 } | |
229 if (soname == "") { | |
230 cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" | |
231 << urlString.toStdString() << "> does not associate plugin <" | |
232 << pluginUri.toStdString() << "> with any implementation library" | |
233 << endl; | |
234 continue; | |
235 } | |
236 /* | |
237 cerr << "PluginRDFIndexer::indexURL: Document for plugin \"" | |
238 << soname.toStdString() << ":" << identifier.toStdString() | |
239 << "\" (uri <" << pluginUri.toStdString() << ">) is at url <" | |
240 << urlString.toStdString() << ">" << endl; | |
241 */ | |
242 QString pluginId = PluginIdentifier::createIdentifier | |
243 ("vamp", soname, identifier); | |
244 | |
245 foundSomething = true; | |
246 | |
247 if (m_idToDescriptionMap.find(pluginId) != m_idToDescriptionMap.end()) { | |
248 cerr << "PluginRDFIndexer::indexURL: NOTE: Plugin id \"" | |
249 << pluginId.toStdString() << "\", described in document at <" | |
250 << urlString.toStdString() | |
251 << ">, has already been described in document <" | |
252 << m_idToDescriptionMap[pluginId].toStdString() | |
253 << ">: ignoring this new description" << endl; | |
254 continue; | |
255 } | |
256 | |
257 m_idToDescriptionMap[pluginId] = urlString; | |
258 m_idToUriMap[pluginId] = pluginUri; | |
259 | |
260 addedSomething = true; | |
261 | |
262 if (pluginUri != "") { | |
263 if (m_uriToIdMap.find(pluginUri) != m_uriToIdMap.end()) { | |
264 cerr << "PluginRDFIndexer::indexURL: WARNING: Found multiple plugins with the same URI:" << endl; | |
265 cerr << " 1. Plugin id \"" << m_uriToIdMap[pluginUri].toStdString() << "\"" << endl; | |
266 cerr << " described in <" << m_idToDescriptionMap[m_uriToIdMap[pluginUri]].toStdString() << ">" << endl; | |
267 cerr << " 2. Plugin id \"" << pluginId.toStdString() << "\"" << endl; | |
268 cerr << " described in <" << urlString.toStdString() << ">" << endl; | |
269 cerr << "both claim URI <" << pluginUri.toStdString() << ">" << endl; | |
270 } else { | |
271 m_uriToIdMap[pluginUri] = pluginId; | |
272 } | |
273 } | |
274 } | |
275 | |
276 if (!foundSomething) { | |
277 cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" | |
278 << urlString.toStdString() | |
279 << "> does not sufficiently describe any plugins" << endl; | |
280 } | |
281 | |
282 return addedSomething; | |
283 } | |
284 | |
285 | |
286 |