annotate rdf/RDFTransformFactory.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 5746c559af15
children 3ffce691c9bf
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 "RDFTransformFactory.h"
Chris@439 17
Chris@439 18 #include <map>
Chris@439 19 #include <vector>
Chris@439 20
Chris@439 21 #include <iostream>
Chris@439 22 #include <cmath>
Chris@439 23
Chris@439 24 #include "SimpleSPARQLQuery.h"
Chris@439 25 #include "PluginRDFIndexer.h"
Chris@439 26 #include "base/ProgressReporter.h"
Chris@439 27
Chris@439 28 #include "transform/TransformFactory.h"
Chris@439 29
Chris@439 30 using std::cerr;
Chris@439 31 using std::endl;
Chris@439 32
Chris@439 33 typedef const unsigned char *STR; // redland's expected string type
Chris@439 34
Chris@439 35
Chris@439 36 class RDFTransformFactoryImpl
Chris@439 37 {
Chris@439 38 public:
Chris@439 39 RDFTransformFactoryImpl(QString url);
Chris@439 40 virtual ~RDFTransformFactoryImpl();
Chris@439 41
Chris@439 42 bool isOK();
Chris@439 43 QString getErrorString() const;
Chris@439 44
Chris@439 45 std::vector<Transform> getTransforms(ProgressReporter *);
Chris@439 46
Chris@439 47 protected:
Chris@439 48 QString m_urlString;
Chris@439 49 QString m_errorString;
Chris@440 50 bool setOutput(Transform &, QString, QString);
Chris@440 51 bool setParameters(Transform &, QString, QString);
Chris@439 52 };
Chris@439 53
Chris@439 54
Chris@439 55 QString
Chris@439 56 RDFTransformFactory::getKnownExtensions()
Chris@439 57 {
Chris@439 58 return "*.rdf *.n3 *.ttl";
Chris@439 59 }
Chris@439 60
Chris@439 61 RDFTransformFactory::RDFTransformFactory(QString url) :
Chris@439 62 m_d(new RDFTransformFactoryImpl(url))
Chris@439 63 {
Chris@439 64 }
Chris@439 65
Chris@439 66 RDFTransformFactory::~RDFTransformFactory()
Chris@439 67 {
Chris@439 68 delete m_d;
Chris@439 69 }
Chris@439 70
Chris@439 71 bool
Chris@439 72 RDFTransformFactory::isOK()
Chris@439 73 {
Chris@439 74 return m_d->isOK();
Chris@439 75 }
Chris@439 76
Chris@439 77 QString
Chris@439 78 RDFTransformFactory::getErrorString() const
Chris@439 79 {
Chris@439 80 return m_d->getErrorString();
Chris@439 81 }
Chris@439 82
Chris@439 83 std::vector<Transform>
Chris@439 84 RDFTransformFactory::getTransforms(ProgressReporter *r)
Chris@439 85 {
Chris@439 86 return m_d->getTransforms(r);
Chris@439 87 }
Chris@439 88
Chris@439 89 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) :
Chris@439 90 m_urlString(url)
Chris@439 91 {
Chris@439 92 }
Chris@439 93
Chris@439 94 RDFTransformFactoryImpl::~RDFTransformFactoryImpl()
Chris@439 95 {
Chris@439 96 }
Chris@439 97
Chris@439 98 bool
Chris@439 99 RDFTransformFactoryImpl::isOK()
Chris@439 100 {
Chris@439 101 return (m_errorString == "");
Chris@439 102 }
Chris@439 103
Chris@439 104 QString
Chris@439 105 RDFTransformFactoryImpl::getErrorString() const
Chris@439 106 {
Chris@439 107 return m_errorString;
Chris@439 108 }
Chris@439 109
Chris@439 110 std::vector<Transform>
Chris@439 111 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter)
Chris@439 112 {
Chris@439 113 std::vector<Transform> transforms;
Chris@439 114
Chris@440 115 // We have to do this a very long way round, to work around
Chris@440 116 // rasqal's current inability to handle correctly more than one
Chris@440 117 // OPTIONAL graph in a query
Chris@439 118
Chris@440 119 const char *optionals[] = {
Chris@440 120 "output",
Chris@440 121 "program",
Chris@440 122 "step_size",
Chris@440 123 "block_size",
Chris@440 124 "window_type",
Chris@440 125 "sample_rate",
Chris@440 126 "start",
Chris@440 127 "duration"
Chris@440 128 };
Chris@439 129
Chris@440 130 std::map<QString, Transform> uriTransformMap;
Chris@439 131
Chris@440 132 QString queryTemplate =
Chris@440 133 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@439 134
Chris@440 135 " SELECT ?transform ?plugin %1 "
Chris@440 136
Chris@440 137 " FROM <%2> "
Chris@439 138
Chris@440 139 " WHERE { "
Chris@440 140 " ?transform a vamp:Transform ; "
Chris@440 141 " vamp:plugin ?plugin . "
Chris@440 142 " %3 "
Chris@440 143 " } ";
Chris@440 144
Chris@440 145 SimpleSPARQLQuery transformsQuery
Chris@440 146 (queryTemplate.arg("").arg(m_urlString).arg(""));
Chris@440 147
Chris@440 148 SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute();
Chris@440 149
Chris@440 150 if (!transformsQuery.isOK()) {
Chris@440 151 m_errorString = transformsQuery.getErrorString();
Chris@439 152 return transforms;
Chris@439 153 }
Chris@439 154
Chris@440 155 if (transformResults.empty()) {
Chris@440 156 cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl;
Chris@439 157 return transforms;
Chris@439 158 }
Chris@439 159
Chris@439 160 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@439 161
Chris@440 162 for (int i = 0; i < transformResults.size(); ++i) {
Chris@439 163
Chris@440 164 SimpleSPARQLQuery::KeyValueMap &result = transformResults[i];
Chris@439 165
Chris@439 166 QString transformUri = result["transform"].value;
Chris@439 167 QString pluginUri = result["plugin"].value;
Chris@439 168
Chris@439 169 QString pluginId = indexer->getIdForPluginURI(pluginUri);
Chris@439 170 if (pluginId == "") {
Chris@439 171 cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
Chris@439 172 << pluginUri.toStdString() << "> for transform <"
Chris@440 173 << transformUri.toStdString() << ">, skipping this transform"
Chris@440 174 << endl;
Chris@440 175 continue;
Chris@440 176 }
Chris@440 177
Chris@440 178 QString pluginDescriptionURL =
Chris@440 179 indexer->getDescriptionURLForPluginId(pluginId);
Chris@440 180 if (pluginDescriptionURL == "") {
Chris@440 181 cerr << "RDFTransformFactory: WARNING: No RDF description available for plugin <"
Chris@440 182 << pluginUri.toStdString() << ">, skipping transform <"
Chris@439 183 << transformUri.toStdString() << ">" << endl;
Chris@439 184 continue;
Chris@439 185 }
Chris@439 186
Chris@439 187 Transform transform;
Chris@439 188 transform.setPluginIdentifier(pluginId);
Chris@439 189
Chris@440 190 if (!setOutput(transform, transformUri, pluginDescriptionURL)) {
Chris@439 191 return transforms;
Chris@439 192 }
Chris@439 193
Chris@440 194 if (!setParameters(transform, transformUri, pluginDescriptionURL)) {
Chris@439 195 return transforms;
Chris@439 196 }
Chris@439 197
Chris@440 198 uriTransformMap[transformUri] = transform;
Chris@440 199 }
Chris@439 200
Chris@440 201 for (int i = 0; i < sizeof(optionals)/sizeof(optionals[0]); ++i) {
Chris@439 202
Chris@440 203 QString optional = optionals[i];
Chris@439 204
Chris@440 205 SimpleSPARQLQuery query
Chris@440 206 (queryTemplate
Chris@440 207 .arg(QString("?%1").arg(optional))
Chris@440 208 .arg(m_urlString)
Chris@440 209 .arg(QString("?transform vamp:%1 ?%2")
Chris@440 210 .arg(optionals[i]).arg(optional)));
Chris@440 211
Chris@440 212 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@440 213
Chris@440 214 if (!query.isOK()) {
Chris@440 215 m_errorString = query.getErrorString();
Chris@440 216 return transforms;
Chris@439 217 }
Chris@439 218
Chris@440 219 if (results.empty()) continue;
Chris@440 220
Chris@440 221 for (int j = 0; j < results.size(); ++j) {
Chris@440 222
Chris@440 223 QString transformUri = results[j]["transform"].value;
Chris@440 224
Chris@440 225 if (uriTransformMap.find(transformUri) == uriTransformMap.end()) {
Chris@440 226 cerr << "RDFTransformFactory: ERROR: Transform URI <"
Chris@440 227 << transformUri.toStdString() << "> not found in internal map!" << endl;
Chris@440 228 continue;
Chris@440 229 }
Chris@440 230
Chris@440 231 Transform &transform = uriTransformMap[transformUri];
Chris@440 232 const SimpleSPARQLQuery::Value &v = results[j][optional];
Chris@440 233
Chris@440 234 if (v.type == SimpleSPARQLQuery::LiteralValue) {
Chris@440 235
Chris@440 236 if (optional == "program") {
Chris@440 237 transform.setProgram(v.value);
Chris@440 238 } else if (optional == "step_size") {
Chris@440 239 transform.setStepSize(v.value.toUInt());
Chris@440 240 } else if (optional == "block_size") {
Chris@440 241 transform.setBlockSize(v.value.toUInt());
Chris@440 242 } else if (optional == "window_type") {
Chris@440 243 cerr << "NOTE: can't handle window type yet (value is \""
Chris@440 244 << v.value.toStdString() << "\")" << endl;
Chris@440 245 } else if (optional == "sample_rate") {
Chris@440 246 transform.setSampleRate(v.value.toFloat());
Chris@440 247 } else if (optional == "start") {
Chris@440 248 transform.setStartTime
Chris@440 249 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 250 } else if (optional == "duration") {
Chris@440 251 transform.setDuration
Chris@440 252 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 253 } else {
Chris@440 254 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl;
Chris@440 255 }
Chris@440 256 }
Chris@440 257 }
Chris@440 258 }
Chris@440 259
Chris@440 260 for (std::map<QString, Transform>::iterator i = uriTransformMap.begin();
Chris@440 261 i != uriTransformMap.end(); ++i) {
Chris@440 262
Chris@440 263 Transform &transform = i->second;
Chris@440 264
Chris@439 265 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
Chris@439 266 cerr << transform.toXmlString().toStdString() << endl;
Chris@439 267
Chris@439 268 transforms.push_back(transform);
Chris@439 269 }
Chris@439 270
Chris@439 271 return transforms;
Chris@439 272 }
Chris@439 273
Chris@440 274 bool
Chris@440 275 RDFTransformFactoryImpl::setOutput(Transform &transform,
Chris@440 276 QString transformUri,
Chris@440 277 QString pluginDescriptionURL)
Chris@440 278 {
Chris@440 279 SimpleSPARQLQuery outputQuery
Chris@440 280 (QString
Chris@440 281 (
Chris@440 282 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 283
Chris@440 284 " SELECT ?output_id "
Chris@440 285
Chris@440 286 " FROM <%1> "
Chris@440 287 " FROM <%2> "
Chris@440 288
Chris@440 289 " WHERE { "
Chris@440 290 " <%3> vamp:output ?output . "
Chris@440 291 " ?output vamp:identifier ?output_id "
Chris@440 292 " } "
Chris@440 293 )
Chris@440 294 .arg(m_urlString)
Chris@440 295 .arg(pluginDescriptionURL)
Chris@440 296 .arg(transformUri));
Chris@440 297
Chris@440 298 SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute();
Chris@440 299
Chris@440 300 if (!outputQuery.isOK()) {
Chris@440 301 m_errorString = outputQuery.getErrorString();
Chris@440 302 return false;
Chris@440 303 }
Chris@440 304
Chris@440 305 if (outputQuery.wasCancelled()) {
Chris@440 306 m_errorString = "Query cancelled";
Chris@440 307 return false;
Chris@440 308 }
Chris@440 309
Chris@440 310 for (int j = 0; j < outputResults.size(); ++j) {
Chris@440 311 QString outputId = outputResults[j]["output_id"].value;
Chris@440 312 transform.setOutput(outputId);
Chris@440 313 }
Chris@440 314
Chris@440 315 return true;
Chris@440 316 }
Chris@440 317
Chris@440 318
Chris@440 319 bool
Chris@440 320 RDFTransformFactoryImpl::setParameters(Transform &transform,
Chris@440 321 QString transformUri,
Chris@440 322 QString pluginDescriptionURL)
Chris@440 323 {
Chris@440 324 SimpleSPARQLQuery paramQuery
Chris@440 325 (QString
Chris@440 326 (
Chris@440 327 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 328
Chris@440 329 " SELECT ?param_id ?param_value "
Chris@440 330
Chris@440 331 " FROM <%1> "
Chris@440 332 " FROM <%2> "
Chris@440 333
Chris@440 334 " WHERE { "
Chris@440 335 " <%3> vamp:parameter_binding ?binding . "
Chris@440 336 " ?binding vamp:parameter ?param ; "
Chris@440 337 " vamp:value ?param_value . "
Chris@440 338 " ?param vamp:identifier ?param_id "
Chris@440 339 " } "
Chris@440 340 )
Chris@440 341 .arg(m_urlString)
Chris@440 342 .arg(pluginDescriptionURL)
Chris@440 343 .arg(transformUri));
Chris@440 344
Chris@440 345 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
Chris@440 346
Chris@440 347 if (!paramQuery.isOK()) {
Chris@440 348 m_errorString = paramQuery.getErrorString();
Chris@440 349 return false;
Chris@440 350 }
Chris@440 351
Chris@440 352 if (paramQuery.wasCancelled()) {
Chris@440 353 m_errorString = "Query cancelled";
Chris@440 354 return false;
Chris@440 355 }
Chris@440 356
Chris@440 357 for (int j = 0; j < paramResults.size(); ++j) {
Chris@440 358
Chris@440 359 QString paramId = paramResults[j]["param_id"].value;
Chris@440 360 QString paramValue = paramResults[j]["param_value"].value;
Chris@440 361
Chris@440 362 if (paramId == "" || paramValue == "") continue;
Chris@440 363
Chris@440 364 transform.setParameter(paramId, paramValue.toFloat());
Chris@440 365 }
Chris@440 366
Chris@440 367 return true;
Chris@440 368 }
Chris@440 369