|
| 1 | +#include <string.h> |
| 2 | +#include <iostream> |
| 3 | +#include <string> |
| 4 | +#include <vector> |
| 5 | + |
| 6 | +#include <libxml/xmlreader.h> |
| 7 | + |
| 8 | +#include "SimulationDescription.hpp" |
| 9 | +#include "RDFGraph.hpp" |
| 10 | +#include "namespaces.h" |
| 11 | + |
| 12 | +/* Only need to have one world at a time */ |
| 13 | +struct RDFWorld |
| 14 | +{ |
| 15 | + librdf_world* world; |
| 16 | + int counter; |
| 17 | +}; |
| 18 | +static struct RDFWorld* rdfWorld = (struct RDFWorld*)NULL; |
| 19 | +static librdf_world* AccessRDFWorld() |
| 20 | +{ |
| 21 | + if (rdfWorld) ++(rdfWorld->counter); |
| 22 | + else |
| 23 | + { |
| 24 | + rdfWorld = (struct RDFWorld*)malloc(sizeof(struct RDFWorld)); |
| 25 | + rdfWorld->world = librdf_new_world(); |
| 26 | + librdf_world_open(rdfWorld->world); |
| 27 | + rdfWorld->counter = 1; |
| 28 | + } |
| 29 | + return rdfWorld->world; |
| 30 | +} |
| 31 | +static void DeaccessRDFWorld() |
| 32 | +{ |
| 33 | + if (rdfWorld) |
| 34 | + { |
| 35 | + if (rdfWorld->counter > 1) --(rdfWorld->counter); |
| 36 | + else |
| 37 | + { |
| 38 | + librdf_free_world(rdfWorld->world); |
| 39 | + free(rdfWorld); |
| 40 | + rdfWorld = (struct RDFWorld*)NULL; |
| 41 | + } |
| 42 | + } |
| 43 | +} |
| 44 | +static int rdfWorldAccessCount() |
| 45 | +{ |
| 46 | + if (rdfWorld) return rdfWorld->counter; |
| 47 | + else return(0); |
| 48 | +} |
| 49 | + |
| 50 | +/* prototype local methods */ |
| 51 | +static char* getXMLFileContentsAsString(const char* uri); |
| 52 | +static int buildSimulationDescription(RDFGraph* graph,void** nodes,int N, |
| 53 | + void* user_data); |
| 54 | + |
| 55 | + |
| 56 | +RDFGraph::RDFGraph() |
| 57 | +{ |
| 58 | + this->world = AccessRDFWorld(); |
| 59 | + this->storage = (librdf_storage*)NULL; |
| 60 | + this->rdfmodel = (librdf_model*)NULL; |
| 61 | + this->parser = (librdf_parser*)NULL; |
| 62 | + this->uri = (librdf_uri*)NULL; |
| 63 | +} |
| 64 | + |
| 65 | +RDFGraph::~RDFGraph() |
| 66 | +{ |
| 67 | + if (this->storage) librdf_free_storage(this->storage); |
| 68 | + if (this->rdfmodel) librdf_free_model(this->rdfmodel); |
| 69 | + if (this->parser) librdf_free_parser(this->parser); |
| 70 | + if (this->uri) librdf_free_uri(this->uri); |
| 71 | + DeaccessRDFWorld(); |
| 72 | +} |
| 73 | + |
| 74 | +void RDFGraph::print(FILE* file) |
| 75 | +{ |
| 76 | + if (file && this->rdfmodel) |
| 77 | + { |
| 78 | + librdf_model_print(this->rdfmodel,file); |
| 79 | + } |
| 80 | + else std::cerr << "rdfGraphPrint - Invalid argument(s)\n" << std::endl; |
| 81 | +} |
| 82 | + |
| 83 | +int RDFGraph::buildFromURL(const char* uri) |
| 84 | +{ |
| 85 | + int code = -1; |
| 86 | + if (this->world && uri) |
| 87 | + { |
| 88 | + /* do we have any metadata? */ |
| 89 | + char* metadata = getXMLFileContentsAsString(uri); |
| 90 | + /* if not, we can quit now */ |
| 91 | + if (metadata) |
| 92 | + { |
| 93 | + /* make an in-memory storage to store our RDF triples */ |
| 94 | + if (this->storage == NULL) |
| 95 | + { |
| 96 | + char* identifier = (char*)malloc(16); |
| 97 | + sprintf(identifier,"%015d",rdfWorldAccessCount()); |
| 98 | + //DEBUG(0,"rdfGraphBuildFromURI","Making new storage with id: %s\n", |
| 99 | + // identifier); |
| 100 | + this->storage = librdf_new_storage(this->world,"memory", |
| 101 | + identifier,/*options*/NULL); |
| 102 | + free(identifier); |
| 103 | + } |
| 104 | + /* make a new RDF graph */ |
| 105 | + if (this->rdfmodel == NULL) this->rdfmodel = |
| 106 | + librdf_new_model(this->world,this->storage,/*options*/NULL); |
| 107 | + /* and a RDF parser */ |
| 108 | + if (this->parser == NULL) this->parser = |
| 109 | + librdf_new_parser(this->world,/*parser name*/"rdfxml", |
| 110 | + /*mime type*/NULL,/*syntax URI*/NULL); |
| 111 | + if (this->uri == NULL) this->uri = |
| 112 | + librdf_new_uri(this->world,(const unsigned char*)uri); |
| 113 | + /* PARSE the metadata string as RDF/XML */ |
| 114 | + if (librdf_parser_parse_string_into_model(this->parser, |
| 115 | + (unsigned char*)metadata,this->uri,this->rdfmodel) == 0) code = 0; |
| 116 | + free(metadata); |
| 117 | + } |
| 118 | + } |
| 119 | + else std::cerr << "rdfGraphBuildFromURL - Invalid argument(s)" << std::endl; |
| 120 | + return(code); |
| 121 | +} |
| 122 | + |
| 123 | +SimulationDescription* RDFGraph::createSimulationDescription() |
| 124 | +{ |
| 125 | + SimulationDescription* description = new SimulationDescription(); |
| 126 | + // create the SPARQL query to find the simulation |
| 127 | + std::string query = "prefix cs: <"; |
| 128 | + query += CS_NS; |
| 129 | + query += ">"; |
| 130 | + query += " select ?parent ?simulation"; |
| 131 | + query += " where {"; |
| 132 | + query += " ?parent cs:simulation ?simulation"; |
| 133 | + query += " filter isURI(?parent)"; |
| 134 | + query += " }"; |
| 135 | + std::vector<std::string> names(2); |
| 136 | + names[0] = "parent"; |
| 137 | + names[1] = "simulation"; |
| 138 | + int code = this->iterateQueryResults(query.c_str(),names, |
| 139 | + &buildSimulationDescription,(void*)description); |
| 140 | + if (code != 0) |
| 141 | + { |
| 142 | + std::cerr << "RDFGraph::createSimulationDescription(): " |
| 143 | + << "error creating simulation description" << std::endl; |
| 144 | + delete description; |
| 145 | + description = (SimulationDescription*)NULL; |
| 146 | + } |
| 147 | + return(description); |
| 148 | +} |
| 149 | + |
| 150 | +int RDFGraph::iterateQueryResults(const char* query, |
| 151 | + const std::vector<std::string>& names,QueryIterFunc func,void* user_data) |
| 152 | +{ |
| 153 | + int code = -1; |
| 154 | + if (this->rdfmodel) |
| 155 | + { |
| 156 | + librdf_query* q = librdf_new_query(this->world,"sparql",NULL, |
| 157 | + (unsigned char*)query,NULL); |
| 158 | + librdf_query_results* results = |
| 159 | + librdf_model_query_execute(this->rdfmodel,q); |
| 160 | + if (results) |
| 161 | + { |
| 162 | + code = 0; |
| 163 | + while(!librdf_query_results_finished(results)) |
| 164 | + { |
| 165 | + int N = names.size(); |
| 166 | + void** nodes = (void**)malloc(sizeof(void*)*N); |
| 167 | + int i; |
| 168 | + for (i=0;i<N;i++) nodes[i] = |
| 169 | + (void*)librdf_query_results_get_binding_value_by_name( |
| 170 | + results,names[i].c_str()); |
| 171 | + if (nodes) |
| 172 | + { |
| 173 | + code = func(this,nodes,N,user_data); |
| 174 | + for (i=0;i<N;i++) librdf_free_node((librdf_node*)nodes[i]); |
| 175 | + free(nodes); |
| 176 | + } |
| 177 | + librdf_query_results_next(results); |
| 178 | + if (code != 0) break; |
| 179 | + } |
| 180 | + librdf_free_query_results(results); |
| 181 | + } |
| 182 | + librdf_free_query(q); |
| 183 | + } |
| 184 | + else |
| 185 | + { |
| 186 | + std::cerr << "iterateQueryResults: missing RDF model" << std::endl; |
| 187 | + } |
| 188 | + return(code); |
| 189 | +} |
| 190 | + |
| 191 | +bool RDFGraph::nodeIsResource(void* _node) |
| 192 | +{ |
| 193 | + int code = 0; |
| 194 | + if (_node) |
| 195 | + { |
| 196 | + librdf_node* node = (librdf_node*)_node; |
| 197 | + code = librdf_node_is_resource(node); |
| 198 | + } |
| 199 | + if (code) return(true); |
| 200 | + return(false); |
| 201 | +} |
| 202 | + |
| 203 | +char* RDFGraph::nodeGetURI(void* _node) |
| 204 | +{ |
| 205 | + char* uri = (char*)NULL; |
| 206 | + if (_node) |
| 207 | + { |
| 208 | + librdf_node* node = (librdf_node*)_node; |
| 209 | + if (librdf_node_is_resource(node)) uri = |
| 210 | + (char*)librdf_uri_to_string(librdf_node_get_uri(node)); |
| 211 | + } |
| 212 | + else std::cerr << "rdfGraphGetURI -- Invalid argument(s)" << std::endl; |
| 213 | + return(uri); |
| 214 | +} |
| 215 | + |
| 216 | +/* |
| 217 | + * Local methods |
| 218 | + */ |
| 219 | +/** Print the contents of the given RDF node */ |
| 220 | +/*static void printNode(void* _node,FILE* file) |
| 221 | +{ |
| 222 | + if (_node && file) |
| 223 | + { |
| 224 | + librdf_node* node = (librdf_node*)_node; |
| 225 | + librdf_node_print(node,file); |
| 226 | + } |
| 227 | + else std::cerr << "rdfGraphPrint - Invalid argument(s)" << std::endl; |
| 228 | + }*/ |
| 229 | + |
| 230 | +/** Get the contents of the given XML file as a standard C string */ |
| 231 | +static char* getXMLFileContentsAsString(const char* uri) |
| 232 | +{ |
| 233 | + char* string = (char*)NULL; |
| 234 | + if (uri) |
| 235 | + { |
| 236 | + /* ensure startup libxml */ |
| 237 | + xmlInitParser(); |
| 238 | + LIBXML_TEST_VERSION; |
| 239 | + /* make an xml text reader for the given URI */ |
| 240 | + xmlTextReaderPtr reader = xmlNewTextReaderFilename(uri); |
| 241 | + if (reader != NULL) |
| 242 | + { |
| 243 | + /* parse and preserve the entire document */ |
| 244 | + int ret = xmlTextReaderRead(reader); |
| 245 | + xmlTextReaderPreservePattern(reader,BAD_CAST "*",NULL); |
| 246 | + while (ret == 1) ret = xmlTextReaderRead(reader); |
| 247 | + if (ret != 0) |
| 248 | + { |
| 249 | + std::cerr << "getXMLFileContentsAsString" << uri |
| 250 | + << ": failed to parse" << std::endl; |
| 251 | + } |
| 252 | + else |
| 253 | + { |
| 254 | + /* grab the resulting XML document */ |
| 255 | + xmlDocPtr doc = xmlTextReaderCurrentDoc(reader); |
| 256 | + if (doc) |
| 257 | + { |
| 258 | + /* and dump it into the result string */ |
| 259 | + xmlChar* s; |
| 260 | + int l; |
| 261 | + /*xmlDocDump(stdout,doc);*/ |
| 262 | + xmlDocDumpMemory(doc,&s,&l); |
| 263 | + if (s) |
| 264 | + { |
| 265 | + string = (char*)malloc(strlen((const char*)s)+1); |
| 266 | + strcpy(string,(const char*)s); |
| 267 | + /*printf("string: **%s**\n",string);*/ |
| 268 | + xmlFree(s); |
| 269 | + } |
| 270 | + else std::cerr << "getXMLFileContentsAsString" << uri |
| 271 | + << ": failed to dump to string" << std::endl; |
| 272 | + /* free up the XML doc */ |
| 273 | + xmlFreeDoc(doc); |
| 274 | + } |
| 275 | + } |
| 276 | + /* free the reader */ |
| 277 | + xmlFreeTextReader(reader); |
| 278 | + } |
| 279 | + else |
| 280 | + { |
| 281 | + std::cerr << "getXMLFileContentsAsString - " |
| 282 | + << "Unable to make the XML reader for the uri: " << uri |
| 283 | + << std::endl; |
| 284 | + } |
| 285 | + /* Shutdown libxml - don't want to as it may be used elsewhere */ |
| 286 | + //xmlCleanupParser(); |
| 287 | + } |
| 288 | + else std::cerr << "Invalid args: getXMLFileContentsAsString" << std::endl; |
| 289 | + return(string); |
| 290 | +} |
| 291 | + |
| 292 | +/** Callback function for the iterate query results method to build a simulation description. |
| 293 | + * Will only populate the provided simulation description if it is not already a valid description. |
| 294 | + */ |
| 295 | +static int buildSimulationDescription(RDFGraph* graph,void** nodes, |
| 296 | + int N,void* _ptr) |
| 297 | +{ |
| 298 | + int code = -1; |
| 299 | + SimulationDescription* description = (SimulationDescription*)_ptr; |
| 300 | + if (description->isValid()) |
| 301 | + { |
| 302 | + // already have a valid simulation description, look no further |
| 303 | + code = 0; |
| 304 | + std::cout << "Already have a valid simulation description" << std::endl; |
| 305 | + } |
| 306 | + else |
| 307 | + { |
| 308 | + std::cout << "Setting up simulation description" << std::endl; |
| 309 | + void* parent = nodes[0]; |
| 310 | + if (graph->nodeIsResource(parent)) |
| 311 | + { |
| 312 | + char* modelURI = graph->nodeGetURI(parent); |
| 313 | + description->modelURI(modelURI); |
| 314 | + free(modelURI); |
| 315 | + code = 0; |
| 316 | + } |
| 317 | + } |
| 318 | + return(code); |
| 319 | +} |
0 commit comments