annotate rdf/RDFTransformFactory.cpp @ 480:3ffce691c9bf

* Add Redland datastore support to SimpleSPARQLQuery
author Chris Cannam
date Thu, 13 Nov 2008 14:23:23 +0000
parents 5746c559af15
children 82ab61fa9223
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@480 146 (m_urlString, 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@480 206 (m_urlString,
Chris@480 207 queryTemplate
Chris@440 208 .arg(QString("?%1").arg(optional))
Chris@440 209 .arg(m_urlString)
Chris@440 210 .arg(QString("?transform vamp:%1 ?%2")
Chris@440 211 .arg(optionals[i]).arg(optional)));
Chris@440 212
Chris@440 213 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@440 214
Chris@440 215 if (!query.isOK()) {
Chris@440 216 m_errorString = query.getErrorString();
Chris@440 217 return transforms;
Chris@439 218 }
Chris@439 219
Chris@440 220 if (results.empty()) continue;
Chris@440 221
Chris@440 222 for (int j = 0; j < results.size(); ++j) {
Chris@440 223
Chris@440 224 QString transformUri = results[j]["transform"].value;
Chris@440 225
Chris@440 226 if (uriTransformMap.find(transformUri) == uriTransformMap.end()) {
Chris@440 227 cerr << "RDFTransformFactory: ERROR: Transform URI <"
Chris@440 228 << transformUri.toStdString() << "> not found in internal map!" << endl;
Chris@440 229 continue;
Chris@440 230 }
Chris@440 231
Chris@440 232 Transform &transform = uriTransformMap[transformUri];
Chris@440 233 const SimpleSPARQLQuery::Value &v = results[j][optional];
Chris@440 234
Chris@440 235 if (v.type == SimpleSPARQLQuery::LiteralValue) {
Chris@440 236
Chris@440 237 if (optional == "program") {
Chris@440 238 transform.setProgram(v.value);
Chris@440 239 } else if (optional == "step_size") {
Chris@440 240 transform.setStepSize(v.value.toUInt());
Chris@440 241 } else if (optional == "block_size") {
Chris@440 242 transform.setBlockSize(v.value.toUInt());
Chris@440 243 } else if (optional == "window_type") {
Chris@440 244 cerr << "NOTE: can't handle window type yet (value is \""
Chris@440 245 << v.value.toStdString() << "\")" << endl;
Chris@440 246 } else if (optional == "sample_rate") {
Chris@440 247 transform.setSampleRate(v.value.toFloat());
Chris@440 248 } else if (optional == "start") {
Chris@440 249 transform.setStartTime
Chris@440 250 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 251 } else if (optional == "duration") {
Chris@440 252 transform.setDuration
Chris@440 253 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 254 } else {
Chris@440 255 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl;
Chris@440 256 }
Chris@440 257 }
Chris@440 258 }
Chris@440 259 }
Chris@440 260
Chris@440 261 for (std::map<QString, Transform>::iterator i = uriTransformMap.begin();
Chris@440 262 i != uriTransformMap.end(); ++i) {
Chris@440 263
Chris@440 264 Transform &transform = i->second;
Chris@440 265
Chris@439 266 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
Chris@439 267 cerr << transform.toXmlString().toStdString() << endl;
Chris@439 268
Chris@439 269 transforms.push_back(transform);
Chris@439 270 }
Chris@439 271
Chris@439 272 return transforms;
Chris@439 273 }
Chris@439 274
Chris@440 275 bool
Chris@440 276 RDFTransformFactoryImpl::setOutput(Transform &transform,
Chris@440 277 QString transformUri,
Chris@440 278 QString pluginDescriptionURL)
Chris@440 279 {
Chris@440 280 SimpleSPARQLQuery outputQuery
Chris@480 281 (m_urlString,
Chris@480 282 QString
Chris@440 283 (
Chris@440 284 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 285
Chris@440 286 " SELECT ?output_id "
Chris@440 287
Chris@440 288 " FROM <%1> "
Chris@440 289 " FROM <%2> "
Chris@440 290
Chris@440 291 " WHERE { "
Chris@440 292 " <%3> vamp:output ?output . "
Chris@440 293 " ?output vamp:identifier ?output_id "
Chris@440 294 " } "
Chris@440 295 )
Chris@440 296 .arg(m_urlString)
Chris@440 297 .arg(pluginDescriptionURL)
Chris@440 298 .arg(transformUri));
Chris@440 299
Chris@440 300 SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute();
Chris@440 301
Chris@440 302 if (!outputQuery.isOK()) {
Chris@440 303 m_errorString = outputQuery.getErrorString();
Chris@440 304 return false;
Chris@440 305 }
Chris@440 306
Chris@440 307 if (outputQuery.wasCancelled()) {
Chris@440 308 m_errorString = "Query cancelled";
Chris@440 309 return false;
Chris@440 310 }
Chris@440 311
Chris@440 312 for (int j = 0; j < outputResults.size(); ++j) {
Chris@440 313 QString outputId = outputResults[j]["output_id"].value;
Chris@440 314 transform.setOutput(outputId);
Chris@440 315 }
Chris@440 316
Chris@440 317 return true;
Chris@440 318 }
Chris@440 319
Chris@440 320
Chris@440 321 bool
Chris@440 322 RDFTransformFactoryImpl::setParameters(Transform &transform,
Chris@440 323 QString transformUri,
Chris@440 324 QString pluginDescriptionURL)
Chris@440 325 {
Chris@440 326 SimpleSPARQLQuery paramQuery
Chris@480 327 (m_urlString,
Chris@480 328 QString
Chris@440 329 (
Chris@440 330 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 331
Chris@440 332 " SELECT ?param_id ?param_value "
Chris@440 333
Chris@440 334 " FROM <%1> "
Chris@440 335 " FROM <%2> "
Chris@440 336
Chris@440 337 " WHERE { "
Chris@440 338 " <%3> vamp:parameter_binding ?binding . "
Chris@440 339 " ?binding vamp:parameter ?param ; "
Chris@440 340 " vamp:value ?param_value . "
Chris@440 341 " ?param vamp:identifier ?param_id "
Chris@440 342 " } "
Chris@440 343 )
Chris@440 344 .arg(m_urlString)
Chris@440 345 .arg(pluginDescriptionURL)
Chris@440 346 .arg(transformUri));
Chris@440 347
Chris@440 348 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
Chris@440 349
Chris@440 350 if (!paramQuery.isOK()) {
Chris@440 351 m_errorString = paramQuery.getErrorString();
Chris@440 352 return false;
Chris@440 353 }
Chris@440 354
Chris@440 355 if (paramQuery.wasCancelled()) {
Chris@440 356 m_errorString = "Query cancelled";
Chris@440 357 return false;
Chris@440 358 }
Chris@440 359
Chris@440 360 for (int j = 0; j < paramResults.size(); ++j) {
Chris@440 361
Chris@440 362 QString paramId = paramResults[j]["param_id"].value;
Chris@440 363 QString paramValue = paramResults[j]["param_value"].value;
Chris@440 364
Chris@440 365 if (paramId == "" || paramValue == "") continue;
Chris@440 366
Chris@440 367 transform.setParameter(paramId, paramValue.toFloat());
Chris@440 368 }
Chris@440 369
Chris@440 370 return true;
Chris@440 371 }
Chris@440 372