annotate rdf/RDFTransformFactory.cpp @ 728:f2de9a42830e dataquay

Convert a bit more of RDFTransformFactory to Dataquay
author Chris Cannam
date Sat, 19 May 2012 12:50:36 +0100
parents 211efc770335
children 11289d40a57a
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 "RDFTransformFactory.h"
Chris@439 17
Chris@439 18 #include <map>
Chris@439 19 #include <vector>
Chris@439 20
Chris@494 21 #include <QTextStream>
Chris@592 22 #include <QUrl>
Chris@494 23
Chris@439 24 #include <iostream>
Chris@439 25 #include <cmath>
Chris@439 26
Chris@439 27 #include "PluginRDFIndexer.h"
Chris@494 28 #include "PluginRDFDescription.h"
Chris@439 29 #include "base/ProgressReporter.h"
Chris@503 30 #include "plugin/PluginIdentifier.h"
Chris@439 31
Chris@439 32 #include "transform/TransformFactory.h"
Chris@439 33
Chris@727 34 #include <dataquay/BasicStore.h>
Chris@727 35 #include <dataquay/PropertyObject.h>
Chris@727 36
Chris@439 37 using std::cerr;
Chris@439 38 using std::endl;
Chris@439 39
Chris@727 40 using Dataquay::Uri;
Chris@727 41 using Dataquay::Node;
Chris@727 42 using Dataquay::Nodes;
Chris@727 43 using Dataquay::Triple;
Chris@727 44 using Dataquay::Triples;
Chris@727 45 using Dataquay::BasicStore;
Chris@727 46 using Dataquay::PropertyObject;
Chris@439 47
Chris@439 48
Chris@439 49 class RDFTransformFactoryImpl
Chris@439 50 {
Chris@439 51 public:
Chris@439 52 RDFTransformFactoryImpl(QString url);
Chris@439 53 virtual ~RDFTransformFactoryImpl();
Chris@439 54
Chris@493 55 bool isRDF();
Chris@439 56 bool isOK();
Chris@439 57 QString getErrorString() const;
Chris@439 58
Chris@439 59 std::vector<Transform> getTransforms(ProgressReporter *);
Chris@439 60
Chris@494 61 static QString writeTransformToRDF(const Transform &, QString);
Chris@494 62
Chris@439 63 protected:
Chris@727 64 BasicStore *m_store;
Chris@439 65 QString m_urlString;
Chris@439 66 QString m_errorString;
Chris@493 67 bool m_isRDF;
Chris@489 68 bool setOutput(Transform &, QString);
Chris@489 69 bool setParameters(Transform &, QString);
Chris@439 70 };
Chris@439 71
Chris@439 72
Chris@439 73 QString
Chris@439 74 RDFTransformFactory::getKnownExtensions()
Chris@439 75 {
Chris@439 76 return "*.rdf *.n3 *.ttl";
Chris@439 77 }
Chris@439 78
Chris@439 79 RDFTransformFactory::RDFTransformFactory(QString url) :
Chris@439 80 m_d(new RDFTransformFactoryImpl(url))
Chris@439 81 {
Chris@439 82 }
Chris@439 83
Chris@439 84 RDFTransformFactory::~RDFTransformFactory()
Chris@439 85 {
Chris@439 86 delete m_d;
Chris@439 87 }
Chris@439 88
Chris@439 89 bool
Chris@493 90 RDFTransformFactory::isRDF()
Chris@493 91 {
Chris@493 92 return m_d->isRDF();
Chris@493 93 }
Chris@493 94
Chris@493 95 bool
Chris@439 96 RDFTransformFactory::isOK()
Chris@439 97 {
Chris@439 98 return m_d->isOK();
Chris@439 99 }
Chris@439 100
Chris@439 101 QString
Chris@439 102 RDFTransformFactory::getErrorString() const
Chris@439 103 {
Chris@439 104 return m_d->getErrorString();
Chris@439 105 }
Chris@439 106
Chris@439 107 std::vector<Transform>
Chris@439 108 RDFTransformFactory::getTransforms(ProgressReporter *r)
Chris@439 109 {
Chris@439 110 return m_d->getTransforms(r);
Chris@439 111 }
Chris@439 112
Chris@494 113 QString
Chris@494 114 RDFTransformFactory::writeTransformToRDF(const Transform &t, QString f)
Chris@494 115 {
Chris@494 116 return RDFTransformFactoryImpl::writeTransformToRDF(t, f);
Chris@494 117 }
Chris@494 118
Chris@439 119 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) :
Chris@727 120 m_store(new BasicStore),
Chris@493 121 m_urlString(url),
Chris@493 122 m_isRDF(false)
Chris@439 123 {
Chris@727 124 //!!! retrieve data if remote... then
Chris@727 125 m_store->addPrefix("vamp", Uri("http://purl.org/ontology/vamp/"));
Chris@727 126 try {
Chris@727 127 m_store->import(QUrl::fromLocalFile(url), BasicStore::ImportIgnoreDuplicates);
Chris@727 128 m_isRDF = true;
Chris@727 129 } catch (...) { }
Chris@439 130 }
Chris@439 131
Chris@439 132 RDFTransformFactoryImpl::~RDFTransformFactoryImpl()
Chris@439 133 {
Chris@727 134 delete m_store;
Chris@439 135 }
Chris@439 136
Chris@439 137 bool
Chris@493 138 RDFTransformFactoryImpl::isRDF()
Chris@493 139 {
Chris@493 140 return m_isRDF;
Chris@493 141 }
Chris@493 142
Chris@493 143 bool
Chris@439 144 RDFTransformFactoryImpl::isOK()
Chris@439 145 {
Chris@439 146 return (m_errorString == "");
Chris@439 147 }
Chris@439 148
Chris@439 149 QString
Chris@439 150 RDFTransformFactoryImpl::getErrorString() const
Chris@439 151 {
Chris@439 152 return m_errorString;
Chris@439 153 }
Chris@439 154
Chris@439 155 std::vector<Transform>
Chris@439 156 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter)
Chris@439 157 {
Chris@439 158 std::vector<Transform> transforms;
Chris@439 159
Chris@440 160 std::map<QString, Transform> uriTransformMap;
Chris@439 161
Chris@727 162 Nodes tnodes = m_store->match
Chris@727 163 (Triple(Node(), "a", m_store->expand("vamp:Transform"))).a();
Chris@439 164
Chris@728 165 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@728 166
Chris@727 167 foreach (Node tnode, tnodes) {
Chris@439 168
Chris@727 169 Node pnode = m_store->matchFirst
Chris@727 170 (Triple(tnode, "vamp:plugin", Node())).c;
Chris@440 171
Chris@728 172 if (pnode == Node()) {
Chris@728 173 cerr << "RDFTransformFactory: WARNING: No vamp:plugin for "
Chris@728 174 << "vamp:Transform node " << tnode
Chris@728 175 << ", skipping this transform" << endl;
Chris@728 176 continue;
Chris@728 177 }
Chris@440 178
Chris@728 179 QString transformUri = tnode.value;
Chris@728 180 QString pluginUri = pnode.value;
Chris@439 181
Chris@439 182 QString pluginId = indexer->getIdForPluginURI(pluginUri);
Chris@439 183 if (pluginId == "") {
Chris@439 184 cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
Chris@686 185 << pluginUri << "> for transform <"
Chris@686 186 << transformUri << ">, skipping this transform"
Chris@440 187 << endl;
Chris@440 188 continue;
Chris@440 189 }
Chris@440 190
Chris@439 191 Transform transform;
Chris@439 192 transform.setPluginIdentifier(pluginId);
Chris@439 193
Chris@489 194 if (!setOutput(transform, transformUri)) {
Chris@439 195 return transforms;
Chris@439 196 }
Chris@439 197
Chris@489 198 if (!setParameters(transform, transformUri)) {
Chris@439 199 return transforms;
Chris@439 200 }
Chris@439 201
Chris@440 202 uriTransformMap[transformUri] = transform;
Chris@439 203
Chris@489 204 static const char *optionals[] = {
Chris@489 205 "program",
Chris@508 206 "summary_type",
Chris@489 207 "step_size",
Chris@489 208 "block_size",
Chris@489 209 "window_type",
Chris@489 210 "sample_rate",
Chris@489 211 "start",
Chris@489 212 "duration"
Chris@489 213 };
Chris@489 214
Chris@489 215 for (int j = 0; j < sizeof(optionals)/sizeof(optionals[0]); ++j) {
Chris@439 216
Chris@489 217 QString optional = optionals[j];
Chris@489 218
Chris@728 219 Node onode = m_store->matchFirst
Chris@728 220 (Triple(Uri(transformUri), optional, Node())).c;
Chris@440 221
Chris@728 222 if (onode.type != Node::Literal) continue;
Chris@440 223
Chris@728 224 if (optional == "program") {
Chris@728 225 transform.setProgram(onode.value);
Chris@728 226 } else if (optional == "summary_type") {
Chris@728 227 transform.setSummaryType
Chris@728 228 (transform.stringToSummaryType(onode.value));
Chris@728 229 } else if (optional == "step_size") {
Chris@728 230 transform.setStepSize(onode.value.toUInt());
Chris@728 231 } else if (optional == "block_size") {
Chris@728 232 transform.setBlockSize(onode.value.toUInt());
Chris@728 233 } else if (optional == "window_type") {
Chris@728 234 transform.setWindowType
Chris@728 235 (Window<float>::getTypeForName
Chris@728 236 (onode.value.toLower().toStdString()));
Chris@728 237 } else if (optional == "sample_rate") {
Chris@728 238 transform.setSampleRate(onode.value.toFloat());
Chris@728 239 } else if (optional == "start") {
Chris@728 240 transform.setStartTime
Chris@728 241 (RealTime::fromXsdDuration(onode.value.toStdString()));
Chris@728 242 } else if (optional == "duration") {
Chris@728 243 transform.setDuration
Chris@728 244 (RealTime::fromXsdDuration(onode.value.toStdString()));
Chris@728 245 } else {
Chris@728 246 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional << "\"" << endl;
Chris@440 247 }
Chris@440 248 }
Chris@440 249
Chris@690 250 SVDEBUG << "RDFTransformFactory: NOTE: Transform is: " << endl;
Chris@686 251 cerr << transform.toXmlString() << endl;
Chris@439 252
Chris@439 253 transforms.push_back(transform);
Chris@439 254 }
Chris@439 255
Chris@439 256 return transforms;
Chris@439 257 }
Chris@439 258
Chris@440 259 bool
Chris@440 260 RDFTransformFactoryImpl::setOutput(Transform &transform,
Chris@489 261 QString transformUri)
Chris@440 262 {
Chris@728 263 Node outputNode = m_store->matchFirst
Chris@728 264 (Triple(Uri(transformUri), "vamp:output", Node())).c;
Chris@728 265
Chris@728 266 if (outputNode == Node()) return true;
Chris@489 267
Chris@728 268 if (outputNode.type != Node::URI && outputNode.type != Node::Blank) {
Chris@728 269 m_errorString = QString("vamp:output for output of transform <%1> is not a URI or blank node").arg(transformUri);
Chris@728 270 return false;
Chris@489 271 }
Chris@728 272
Chris@728 273 // Now, outputNode might be the subject of a triple within m_store
Chris@728 274 // that tells us the vamp:identifier, or it might be the subject
Chris@728 275 // of a triple within the indexer that tells us it
Chris@728 276
Chris@728 277 Node identNode = m_store->matchFirst
Chris@728 278 (Triple(outputNode, "vamp:identifier", Node())).c;
Chris@728 279
Chris@728 280 if (identNode == Node()) {
Chris@728 281 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@728 282 const BasicStore *index = indexer->getIndex();
Chris@728 283 identNode = index->matchFirst
Chris@728 284 (Triple(outputNode, "vamp:identifier", Node())).c;
Chris@728 285 }
Chris@728 286
Chris@728 287 if (identNode == Node() || identNode.type != Node::Literal) {
Chris@494 288 m_errorString = QString("No vamp:identifier found for output of transform <%1>, or vamp:identifier is not a literal").arg(transformUri);
Chris@489 289 return false;
Chris@489 290 }
Chris@489 291
Chris@728 292 transform.setOutput(identNode.value);
Chris@440 293
Chris@440 294 return true;
Chris@440 295 }
Chris@440 296
Chris@440 297
Chris@440 298 bool
Chris@440 299 RDFTransformFactoryImpl::setParameters(Transform &transform,
Chris@489 300 QString transformUri)
Chris@440 301 {
Chris@440 302 SimpleSPARQLQuery paramQuery
Chris@489 303 (SimpleSPARQLQuery::QueryFromModel,
Chris@480 304 QString
Chris@440 305 (
Chris@440 306 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 307
Chris@440 308 " SELECT ?param_id ?param_value "
Chris@440 309
Chris@440 310 " WHERE { "
Chris@489 311 " <%1> vamp:parameter_binding ?binding . "
Chris@440 312 " ?binding vamp:parameter ?param ; "
Chris@440 313 " vamp:value ?param_value . "
Chris@440 314 " ?param vamp:identifier ?param_id "
Chris@440 315 " } "
Chris@440 316 )
Chris@440 317 .arg(transformUri));
Chris@440 318
Chris@440 319 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
Chris@440 320
Chris@440 321 if (!paramQuery.isOK()) {
Chris@440 322 m_errorString = paramQuery.getErrorString();
Chris@440 323 return false;
Chris@440 324 }
Chris@440 325
Chris@440 326 if (paramQuery.wasCancelled()) {
Chris@440 327 m_errorString = "Query cancelled";
Chris@440 328 return false;
Chris@440 329 }
Chris@440 330
Chris@440 331 for (int j = 0; j < paramResults.size(); ++j) {
Chris@440 332
Chris@440 333 QString paramId = paramResults[j]["param_id"].value;
Chris@440 334 QString paramValue = paramResults[j]["param_value"].value;
Chris@440 335
Chris@440 336 if (paramId == "" || paramValue == "") continue;
Chris@440 337
Chris@440 338 transform.setParameter(paramId, paramValue.toFloat());
Chris@440 339 }
Chris@440 340
Chris@440 341 return true;
Chris@440 342 }
Chris@440 343
Chris@494 344 QString
Chris@494 345 RDFTransformFactoryImpl::writeTransformToRDF(const Transform &transform,
Chris@494 346 QString uri)
Chris@494 347 {
Chris@494 348 QString str;
Chris@494 349 QTextStream s(&str);
Chris@494 350
Chris@503 351 // assumes the usual prefixes are available; requires that uri be
Chris@503 352 // a local fragment (e.g. ":transform") rather than a uri enclosed
Chris@503 353 // in <>, so that we can suffix it if need be
Chris@494 354
Chris@494 355 QString pluginId = transform.getPluginIdentifier();
Chris@494 356 QString pluginUri = PluginRDFIndexer::getInstance()->getURIForPluginId(pluginId);
Chris@494 357
Chris@503 358 if (pluginUri != "") {
Chris@503 359 s << uri << " a vamp:Transform ;" << endl;
Chris@592 360 s << " vamp:plugin <" << QUrl(pluginUri).toEncoded().data() << "> ;" << endl;
Chris@503 361 } else {
Chris@686 362 std::cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No plugin URI available for plugin id \"" << pluginId << "\", writing synthetic plugin and library resources" << std::endl;
Chris@503 363 QString type, soname, label;
Chris@503 364 PluginIdentifier::parseIdentifier(pluginId, type, soname, label);
Chris@503 365 s << uri << "_plugin a vamp:Plugin ;" << endl;
Chris@503 366 s << " vamp:identifier \"" << label << "\" .\n" << endl;
Chris@503 367 s << uri << "_library a vamp:PluginLibrary ;" << endl;
Chris@503 368 s << " vamp:identifier \"" << soname << "\" ;" << endl;
Chris@503 369 s << " vamp:available_plugin " << uri << "_plugin .\n" << endl;
Chris@503 370 s << uri << " a vamp:Transform ;" << endl;
Chris@503 371 s << " vamp:plugin " << uri << "_plugin ;" << endl;
Chris@503 372 }
Chris@503 373
Chris@494 374 PluginRDFDescription description(pluginId);
Chris@503 375 QString outputId = transform.getOutput();
Chris@503 376 QString outputUri = description.getOutputUri(outputId);
Chris@494 377
Chris@494 378 if (transform.getOutput() != "" && outputUri == "") {
Chris@686 379 std::cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No output URI available for transform output id \"" << transform.getOutput() << "\", writing a synthetic output resource" << std::endl;
Chris@494 380 }
Chris@494 381
Chris@494 382 if (transform.getStepSize() != 0) {
Chris@494 383 s << " vamp:step_size \"" << transform.getStepSize() << "\"^^xsd:int ; " << endl;
Chris@494 384 }
Chris@494 385 if (transform.getBlockSize() != 0) {
Chris@494 386 s << " vamp:block_size \"" << transform.getBlockSize() << "\"^^xsd:int ; " << endl;
Chris@494 387 }
Chris@494 388 if (transform.getStartTime() != RealTime::zeroTime) {
Chris@494 389 s << " vamp:start \"" << transform.getStartTime().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
Chris@494 390 }
Chris@494 391 if (transform.getDuration() != RealTime::zeroTime) {
Chris@494 392 s << " vamp:duration \"" << transform.getDuration().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
Chris@494 393 }
Chris@494 394 if (transform.getSampleRate() != 0) {
Chris@494 395 s << " vamp:sample_rate \"" << transform.getSampleRate() << "\"^^xsd:float ; " << endl;
Chris@494 396 }
Chris@494 397
Chris@494 398 QString program = transform.getProgram();
Chris@494 399 if (program != "") {
Chris@494 400 s << " vamp:program \"\"\"" << program << "\"\"\" ;" << endl;
Chris@494 401 }
Chris@494 402
Chris@508 403 QString summary = transform.summaryTypeToString(transform.getSummaryType());
Chris@508 404 if (summary != "") {
Chris@508 405 s << " vamp:summary_type \"" << summary << "\" ;" << endl;
Chris@508 406 }
Chris@508 407
Chris@494 408 Transform::ParameterMap parameters = transform.getParameters();
Chris@494 409 for (Transform::ParameterMap::const_iterator i = parameters.begin();
Chris@494 410 i != parameters.end(); ++i) {
Chris@494 411 QString name = i->first;
Chris@494 412 float value = i->second;
Chris@494 413 s << " vamp:parameter_binding [" << endl;
Chris@494 414 s << " vamp:parameter [ vamp:identifier \"" << name << "\" ] ;" << endl;
Chris@494 415 s << " vamp:value \"" << value << "\"^^xsd:float ;" << endl;
Chris@494 416 s << " ] ;" << endl;
Chris@494 417 }
Chris@494 418
Chris@494 419 if (outputUri != "") {
Chris@592 420 s << " vamp:output <" << QUrl(outputUri).toEncoded().data() << "> ." << endl;
Chris@503 421 } else if (outputId != "") {
Chris@503 422 s << " vamp:output [ vamp:identifier \"" << outputId << "\" ] ." << endl;
Chris@494 423 } else {
Chris@494 424 s << " ." << endl;
Chris@494 425 }
Chris@494 426
Chris@494 427 return str;
Chris@494 428 }
Chris@494 429