1 // exports
  2 exports.Store = {};
  3 
  4 /**
  5  * @namespace
  6  * 
  7  * The Store module defines the public interface to the RDF store.
  8  */
  9 var Store = exports.Store;
 10 
 11 // imports
 12 var QueryEngine = require("./../../js-query-engine/src/query_engine").QueryEngine;
 13 var QuadBackend = require("./../../js-rdf-persistence/src/quad_backend").QuadBackend;
 14 var Lexicon = require("./../../js-rdf-persistence/src/lexicon").Lexicon;
 15 var RDFJSInterface = require("./../../js-query-engine/src/rdf_js_interface").RDFJSInterface;
 16 var RDFStoreClient = require("./../../js-connection/src/rdfstore_client").RDFStoreClient;
 17 var Worker = require('webworker');
 18 
 19 /**
 20  * Version of the store
 21  */
 22 Store.VERSION = "0.4.15";
 23 
 24 /**
 25  * Create a new RDFStore instance that will be
 26  * executed in a web worker in the browser or a new process
 27  * in Node.js.
 28  * <br/>
 29  * <br/>
 30  * The first argument to this function is the URL/FS location 
 31  * of the store script.
 32  * <br/>
 33  * <br/>
 34  * This parameter is mandatory in the browser. It is safe to
 35  * ignore this parameter in Node.js.
 36  * <br/>
 37  * <br/>
 38  * If support for web workers is not present, a regular
 39  * store object will be initialized and returned.
 40  * <br/>
 41  * <br/>
 42  *
 43  * @param {String} [scriptPath] URL of the RDFStore script
 44  * @param {Object[]} [args] Arguments to be passed to the store that will be created
 45  * @param {Function} callback Callback function that will be invoked with an error flag and the connection/store object.
 46  */
 47 Store.connect = function() {
 48     var path, args, callback;
 49     if(arguments.length == 1) {
 50         path = __dirname;
 51         args = {};
 52         callback = arguments[0];
 53     } if(arguments.length == 2) {
 54         if(typeof(arguments[0]) === 'string') {
 55             path = arguments[0];
 56             args = {};
 57         } else {
 58             path = __dirname+"/index.js";
 59             args = arguments[0];
 60         }
 61         callback = arguments[1];
 62     } else {
 63         path = arguments[0];
 64         args = arguments[1];
 65         callback = arguments[2];
 66     }
 67     try {
 68         if(!!Worker) {
 69             new RDFStoreClient.RDFStoreClient(path, args, function(success,connection) {
 70                 callback(success, connection);
 71             });
 72         } else {
 73             Store.create(args,function(connection){
 74                 callback(false, connection);
 75             });
 76         }
 77     } catch(e) {
 78         Store.create(args,function(connection){
 79             callback(false, connection);
 80         });        
 81     }
 82 };
 83 
 84 /**
 85  * Creates a new instance of the store.
 86  *
 87  * The function accepts two optional arguments.
 88  * <br/>
 89  * If only one argument is passed it must be a
 90  * callback function that will be invoked when the
 91  * store had been created.<br/>
 92  * <br/>
 93  * If two arguments are passed the first one must
 94  * be a map of configuration parameters for the
 95  * store, and the second one the callback function.<br/>
 96  * <br/>
 97  * Take a look at the Store constructor function for
 98  * a detailed list of possible configuration parameters.<br/>
 99  *
100  * @param {Object[]} [args] Arguments to be passed to the store that will be created
101  * @param {Function} [callback] Callback function that will be invoked with an error flag and the connection/store object.
102  */
103 Store.create = function(){
104     if(arguments.length == 1) {
105         return new Store.Store(arguments[0]);
106     } else if(arguments.length == 2) {
107         return new Store.Store(arguments[0], arguments[1]);
108     } else {
109         return new Store.Store();
110     };
111 };
112 
113 /**
114  * Creates a new store.<br/>
115  * <br/>
116  * It accepts two optional arguments, a map of configuration
117  * options for the store and a callback function.<br/>
118  *
119  * @constructor 
120  * @param {Function} [callback] Callback that will be invoked when the store has been created
121  * @param {Object} [params]
122  * <ul>
123  *  <li> persistent:  should use persistence? </li>
124  *  <li> name: if using persistence, the name for this store </li>
125  *  <li> maxCacheSize: if using persistence, maximum size of the index cache </li>
126  * </ul>
127  */
128 Store.Store = function(arg1, arg2) {
129     var callback = null;
130     var params   = null;
131 
132     if(arguments.length == 0) {
133         params ={};
134     } else if(arguments.length == 1) {
135         params   = {};
136         callback = arg1;
137     } else if(arguments.length > 1) {
138         params   = arg1;
139         callback = arg2;
140     } else {
141         throw("An optional argument map and a callback must be provided");
142     }
143 
144     if(params['treeOrder'] == null) {
145         params['treeOrder'] = 15;
146     }
147 
148     this.functionMap = {};
149 
150     var that = this;
151     new Lexicon.Lexicon(function(lexicon){
152         if(params['overwrite'] === true) {
153             // delete lexicon values
154             lexicon.clear();
155         }
156         new QuadBackend.QuadBackend(params, function(backend){
157             if(params['overwrite'] === true) {
158                 // delete index values
159                 backend.clear();
160             }
161             params.backend = backend;
162             params.lexicon =lexicon;
163             that.engine = new QueryEngine.QueryEngine(params);      
164             if(callback) {
165                 callback(that);
166             }
167         });
168     },
169     params['name']);
170 };
171 
172 
173 /**
174  * An instance of RDF JS Interface <code>RDFEnvironment</code>
175  * associated to this graph instance.
176  */
177 Store.Store.prototype.rdf = RDFJSInterface.rdf;
178 
179 /**
180  * Executes a query in the store.<br/>
181  * <br/>
182  * There are two possible ways of invoking this function,
183  * providing a pair of arrays of namespaces that will be
184  * used to compute the union of the default and named
185  * dataset, or without them.
186  * <br/>
187  * <br/>
188  * Both invocations receive as an optional last parameter
189  * a callback function that will receive the return status
190  * of the query and the results.
191  * <br/>
192  * <br/>
193  * Results can have different formats:
194  * <ul>
195  *  <li> SELECT queries: array of binding maps </li>
196  *  <li> CONSTRUCT queries: RDF JS Interface Graph object </li>
197  *  <li> ASK queries: JS boolean value </li>
198  *  <li> LOAD/INSERT... queries: Number of triples modified/inserted </li>
199  * </ul>
200  *  
201  * @arguments: 
202  * @param {String} query
203  * @param {String} [defaultURIs] default namespaces
204  * @param {String} [namespacesURIs] named namespaces
205  * @param {Function} [callback]
206  */
207 Store.Store.prototype.execute = function() {
208     if(arguments.length === 3) {
209         this.executeWithEnvironment(arguments[0],
210                                     arguments[1],
211                                     arguments[2]);
212     } else if(arguments.length === 4) {
213         this.executeWithEnvironment(arguments[0],
214                                     arguments[1],
215                                     arguments[2],
216                                     arguments[3]);
217     } else {
218 
219         var queryString;
220         var callback;
221      
222         if(arguments.length === 1) {
223             queryString = arguments[0];
224             var callback = function(){};
225         } else if(arguments.length === 2) {
226             queryString = arguments[0];
227             callback = arguments [1];
228         }
229         this.engine.execute(queryString, callback);
230     }
231 };
232 
233 /**
234  * A variation of the execute function that expects 
235  * arguments containing values for the default and named 
236  * graphs that will be used in the query.
237  *
238  *
239  * @arguments:
240  * @param {String} query
241  * @param {String} URIs default namespaces
242  * @param {String} URIs named namespaces
243  * @param {Function} [callback]
244  */
245 Store.Store.prototype.executeWithEnvironment = function() {
246     var queryString, defaultGraphs, namedGraphs;
247 
248     if(arguments.length === 3) {
249         queryString   = arguments[0];
250         // JSDoc fails if this is pushed outside 
251         var callback  = function(){};
252         defaultGraphs = arguments[1];
253         namedGraphs   = arguments[2];
254     } else if(arguments.length === 4) {
255         queryString   = arguments[0];
256         var callback      = arguments [3];
257         defaultGraphs = arguments[1];
258         namedGraphs   = arguments[2];
259     }
260     this.engine.execute(queryString, callback, defaultGraphs, namedGraphs);
261 };
262 
263 /**
264  * Retrieves all the quads belonging to a certain graph
265  * in the store as a RDF JS Interface Graph object.<br/>
266  * <br/>
267  * The function accepts as mandatory parameter a callback
268  * function that will receive the returned graph.<br/>
269  * <br/>
270  * Optionally, the URI of the graph can also be passed as
271  * the first argument. If no graph is specified, the
272  * default graph will be returned.<br/>
273  *
274  * @arguments
275  * @param {String} [graphURI] If this parameter is missing, the default graph will be returned
276  * @param {Functon} callback
277  */
278 Store.Store.prototype.graph = function() {
279     var graphUri = null;
280     var callback = null;
281     if(arguments.length === 1) {
282         callback = arguments[0] || function(){};
283         graphUri = this.engine.lexicon.defaultGraphUri;
284     } else if(arguments.length === 2) {
285         callback = arguments[1] || function(){};
286         graphUri = arguments[0];
287     } else {
288         throw("An optional graph URI and a callback function must be provided");
289     }
290 
291     if(this.rdf.resolve(graphUri) != null) {
292         graphUri = this.rdf.resolve(graphUri);
293     }
294 
295     this.engine.execute("CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <" + graphUri + "> { ?s ?p ?o } }", callback);
296 };
297 
298 /**
299  * Retrieves all the quads belonging to a certain node
300  * in the store as a RDF JS Interface Graph object containing
301  * the collection of triples whose subject is the provided
302  * node URI.<br/>
303  * <br/>
304  * The function accepts as mandatory parameters the node URI and 
305  * a callback unction that will receive the returned node.<br/>
306  * <br/>
307  * Optionally, the URI of the graph where the node is contained 
308  * can also be passed as the first argument. <br/>
309  * <br/>
310  * If no graph is specified, the node will be looked into the 
311  * default graph.<br/>
312  *
313  * @arguments
314  * @param {String} nodeURI URI of the node to look for
315  * @param {String} [graphURI] If this parameter is missing, the node will be looked into the default graph
316  * @param {Functon} callback
317  */
318 Store.Store.prototype.node = function() {
319     var graphUri = null;
320     var callback = null;
321     var nodeUri  = null;
322     if(arguments.length === 2) {
323         nodeUri = arguments[0];
324         callback = arguments[1] || function(){};
325         graphUri = this.engine.lexicon.defaultGraphUri;
326     } else if(arguments.length === 3) {
327         nodeUri = arguments[0];
328         graphUri = arguments[1];
329         callback = arguments[2] || function(){};
330     } else {
331         throw("An optional graph URI, node URI and a callback function must be provided");
332     }
333 
334     if(this.rdf.resolve(graphUri) != null) {
335         graphUri = this.rdf.resolve(graphUri);
336     }
337 
338     if(this.rdf.resolve(nodeUri) != null) {
339         nodeUri = this.rdf.resolve(nodeUri);
340     }
341 
342     this.engine.execute("CONSTRUCT { <" + nodeUri + "> ?p ?o } WHERE { GRAPH <" + graphUri + "> { <" + nodeUri + "> ?p ?o } }", callback);
343 };
344 
345 /**
346  * Associates an event listener function to a node URI. Every time the collection
347  * of triples whose subject is the specified node URI changes, because an
348  * insertion or deletion, the provided callback function will be invoked
349  * receiving as a parameter a RDF JS Interface Graph object with the new
350  * collection of triples.<br/>
351  * <br/>
352  * The function accepts two mandatory arguments, the URI of the node to observe
353  * and the function that will receive the event notifications. An optional
354  * third parameter, consisting of a callback function, can be passed and will be invoked
355  * once the store had correctly configured the event listener.<br/>
356  *<br/>
357  * LOAD queries, batch loading data into the store, do not 
358  * trigger events by default. If you wish to be notified
359  * by changes triggered by this kind of queries, invoke
360  * the *setBatchLoadEvents* function with a true argument.<br/>
361  *<br/>
362  * The event listener function can be removed using the stopObservingNode function.
363  *
364  * @arguments
365  * @param {String} nodeURI URI of the node to observe
366  * @param {Function} eventListener Function that will be notified with the events
367  * @param {Function} [callback] Function that will be invoked, once the event listener had been correctly set up.
368  */
369 Store.Store.prototype.startObservingNode = function() {
370     var uri, graphUri, callback;
371 
372     if(arguments.length === 2) {
373         uri = arguments[0];
374         callback = arguments[1];
375         this.engine.callbacksBackend.observeNode(uri, callback, function(){});
376     } else if(arguments.length === 3) {
377         uri = arguments[0];
378         graphUri = arguments[1];
379         callback = arguments[2];
380         this.engine.callbacksBackend.observeNode(uri, graphUri, callback, function(){});
381     }
382 };
383 
384 /**
385  * Removes a callback function associated to a node.<br/>
386  * The event listener function object must be passed as an argument.<br/>
387  *
388  * @arguments
389  * @param {Function} eventListener The event listener function to remove, the same passed as an argument to startObservingNode
390  */
391 Store.Store.prototype.stopObservingNode = function(callback) {
392     this.engine.callbacksBackend.stopObservingNode(callback);
393 };
394 
395 /**
396  * Associates an event listener function to a SPARQL SELECT or
397  * CONSTRUCT query.<br/>
398  * Every time an update (insert, delete...) query modified the 
399  * triples in the store in a way that modifies the output of the
400  * query, the event listener will be invoked with an updated 
401  * result.<br/>
402  *<br/>
403  * LOAD queries, batch loading data into the store, do not 
404  * trigger events by default. If you wish to be notified
405  * by changes triggered by this kind of queries, invoke
406  * the <code>setBatchLoadEvents</code> function with a true argument.<br/>
407  *<br/>
408  * The event listener function can be removed invoking the
409  * <code>stopObservingQuery</code> function. 
410  *
411  * @arguments
412  * @param {String} query SELECT or CONSTRUCT SPARQL query
413  * @param {Function} eventListener the function that will receive the notifications
414  * @param {Function} [callback] optional function that will be invoked when the stored had set up the event listener function.
415  */
416 Store.Store.prototype.startObservingQuery = function() {
417     var query = arguments[0];
418     var callback = arguments[1];
419     var endCallback = arguments[2];
420     if(endCallback!=null) {
421         this.engine.callbacksBackend.observeQuery(query, callback, endCallback);
422     } else {
423         this.engine.callbacksBackend.observeQuery(query, callback, function(){});
424     }
425 };
426 
427 /**
428  * Removes a callback function associated to a SPARQL query.<br/>
429  * The event listener function object must be passed as an argument.
430  *
431  * @arguments
432  * @param {Function} eventListener The event listener function to remove, the same passed as an argument to startObservingQuery
433  */
434 Store.Store.prototype.stopObservingQuery = function(query) {
435     this.engine.callbacksBackend.stopObservingQuery(query);
436 };
437 
438 /**
439  * Associates an event listener to a pattern expressed as the
440  * subject, predicate, object and graph string parameters passed
441  * to the function. To match any value in that position, a <code>null</code>
442  * value can be passed as an argument. e.g. <code>subscribe(null, null, null, g, cb)</code>,
443  * will be notified with any change in the g graph.<br/>
444  * The graph component of the pattern does not support a <code>null</code> value.<br/>
445  *<br/>
446  * Results will be notified as an Array of RDF JS Interface
447  * <code>Triple</code> objects.<br/>
448  *<br/>
449  * LOAD queries, batch loading data into the store, do not 
450  * trigger events by default. If you wish to be notified
451  * by changes triggered by this kind of queries, invoke
452  * the <code>setBatchLoadEvents</code> function with a true argument.
453  *
454  * @arguments
455  * @param {String} s subject or null for any subject
456  * @param {String} p predicate or null for any predicate
457  * @param {String} o object or null for any object
458  * @param {String} g graph or null for any graph
459  * @param {Function} event listener function that will be notified when a change occurs
460  */
461 Store.Store.prototype.subscribe = function(s, p, o, g, callback) {
462     var adapterCb = function(event,triples){
463         var acum = [];
464         var queryEnv = {blanks:{}, outCache:{}};
465         var bindings = [];
466 
467         for(var i=0; i<triples.length; i++) {
468             var triple = triples[i];
469             var s = RDFJSInterface.buildRDFResource(triple.subject,bindings,this.engine,queryEnv);
470             var p = RDFJSInterface.buildRDFResource(triple.predicate,bindings,this.engine,queryEnv);
471             var o = RDFJSInterface.buildRDFResource(triple.object,bindings,this.engine,queryEnv);
472             if(s!=null && p!=null && o!=null) {
473                 triple = new RDFJSInterface.Triple(s,p,o);
474                 acum.push(triple);
475             }
476         }
477 
478         callback(event,acum);
479     };
480 
481     this.functionMap[callback] = adapterCb;
482     this.engine.callbacksBackend.subscribe(s,p,o,g,adapterCb,function(){});
483 };
484 
485 /**
486  * Removes an event listener associated to a certain pattern.
487  * The function passed as an argument to <code>subscribe</code> must be 
488  * passed as an argument.
489  *
490  * @arguments
491  * @param {Function} callback The event listener to be removed
492  */
493 Store.Store.prototype.unsubscribe = function(callback) {
494     var adapterCb = this.functionMap[callback];
495     this.engine.callbacksBackend.unsubscribe(adapterCb);
496     delete this.functionMap[callback];
497 };
498 
499 /**
500  * Register a combination of prefix and URI fragment in the default instance
501  * of the RDF JS Interface API <code>RDFEnvironment</code> object associated
502  * to the store and available through the <code>storeInstance.rdf</code> property.
503  *
504  * @arguments
505  * @param {String} prefix The prefix to be associated
506  * @param {String} URIFragment URI fragment the provided prefix will be resolved
507  */
508 Store.Store.prototype.setPrefix = function(prefix, uri) {
509     this.rdf.setPrefix(prefix, uri);
510 };
511 
512 /**
513  * Defines the URI that will be used by default by the RDF JS Interface
514  * API <code>RDFEnvironment</code> object associated to the store and available
515  * through the <code>storeInstance.rdf</code> property.
516  *
517  * @arguments
518  * @param {String} URIFragment The URI fragment will be used by default
519  */
520 Store.Store.prototype.setDefaultPrefix = function(uri) {
521     this.rdf.setDefaultPrefix(uri);
522 };
523 
524 /**
525  * Inserts a RDF JS Interface API <code>Graph</code> object into the store.
526  * The function receives a mandatory <code>Graph</code> object whose triples
527  * will be inserted. Optionally, a URI string for a graph and a 
528  * callback function can be passed as arguments.<br/>
529  * <br/>
530  * If no graph URI is specified, triples will be inserted into the
531  * default graph.<br/>
532  * <br/>
533  * If the callback function is specified, it will be invoked when all the
534  * triples had been inserted into the store.<br/>
535  *
536  * @arguments
537  * @param {RDFJSInterface.Graph} triples a RDF JS Interface <code>Graph</code> object
538  * @param {String} [graphURI] URI of the graph where the triples will be inserted. If it is missing, triples will be inserted in the default graph
539  * @param {String} [callback] A callback function that will be invoked with a success notification and the number of triples inserted
540  */ 
541 Store.Store.prototype.insert = function() {
542     var graph;
543     var triples;
544     var callback;
545     if(arguments.length === 1) {
546         triples = arguments[0];
547     } else if(arguments.length === 2) {
548         graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
549         triples = arguments[0];
550         callback= arguments[1] || function(){};
551     } else if(arguments.length === 3) {
552         triples = arguments[0];
553         graph = this.rdf.createNamedNode(arguments[1]);
554         callback= arguments[2] || function(){};
555     } else {
556         throw("The triples to insert, an optional graph and callback must be provided");
557     }
558 
559     var query = "";
560     var that = this;
561     triples.forEach(function(triple) {
562         query = query + that._nodeToQuery(triple.subject) + that._nodeToQuery(triple.predicate) + that._nodeToQuery(triple.object) + ".";
563     });
564 
565     if(graph != null) {
566         query = "INSERT DATA { GRAPH " + this._nodeToQuery(graph) +" { "+ query + " } }";
567     } else {
568         query = "INSERT DATA { " + this._nodeToQuery(graph) +" { "+ query + " }";
569     }
570 
571     this.engine.execute(query, callback);
572 };
573 
574 Store.Store.prototype._nodeToQuery = function(term) {
575     if(term.interfaceName === 'NamedNode') {
576         var resolvedUri = this.rdf.resolve(term.valueOf());
577         if(resolvedUri != null) {
578             return "<" + resolvedUri + ">";
579         } else {
580             return "<" + term.valueOf() + ">";
581         }
582     } else if(term.interfaceName === '') {
583         return term.toString();
584     } else {
585         if(term.lang != null) {
586             return "\""+term.valueOf()+"\"@"+term.lang;
587         } else if(term.datatype != null) {
588             return "\""+term.valueOf()+"\"^^<"+term.datatype+">";
589         }
590         return term.toString();
591     }
592 };
593 
594 /**
595  * Removes the triples in a RDF JS Interface API <code>Graph</code> object from the store.
596  * The function receives a mandatory <code>Graph</code> object whose triples
597  * will be removed. Optionally, a URI string for a graph and a 
598  * callback function can be passed as arguments.<br/>
599  * <br/>
600  * If no graph URI is specified, triples will be removed from the
601  * default graph.<br/>
602  * <br/>
603  * If the callback function is specified, it will be invoked when all the
604  * triples had been removed from the store.
605  *
606  * @arguments
607  * @param {RDFJSInterface.Graph} triples a RDF JS Interface <code>Graph</code> object
608  * @param {String} [graphURI] URI of the graph where the triples will be removed from. If it is missing, triples will be removed from the default graph
609  * @param {String} [callback] A callback function that will be invoked with a success notification
610  */ 
611 Store.Store.prototype.delete = function() {
612 
613     var graph;
614     var triples;
615     var callback;
616     if(arguments.length === 1) {
617         triples = arguments[0];
618     } else if(arguments.length === 2) {
619         graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
620         triples = arguments[0];
621         callback= arguments[1] || function(){};
622     } else if(arguments.length === 3) {
623         triples = arguments[0];
624         graph = this.rdf.createNamedNode(arguments[1]);
625         callback= arguments[2] || function(){};
626     } else {
627         throw("The triples to delete, an optional graph and callback must be provided");
628     }
629 
630     var query = "";
631     var that = this;
632     triples.forEach(function(triple) {
633         query = query + that._nodeToQuery(triple.subject) + that._nodeToQuery(triple.predicate) + that._nodeToQuery(triple.object) + ".";
634     });
635 
636     if(graph != null) {
637         query = "DELETE DATA { GRAPH " + this._nodeToQuery(graph) +" { "+ query + " } }";
638     } else {
639         query = "DELETE DATA { " + this._nodeToQuery(graph) +" { "+ query + " }";
640     }
641 
642     this.engine.execute(query, callback);
643 };
644 
645 /** 
646  * Removes all the triples stored in a graph.
647  * 
648  * The URI of the graph and a callback function can be
649  * optinally passed as parameters.<br/>
650  * <br/>
651  * If no graph URI is specified, all triples in the 
652  * default graph will be removed.
653  *
654  * @arguments
655  * @param {String} [graph] the URI of the graph the triples must be removed from
656  * @param {Function} [callback] a function that will be invoked with a success notification
657  */
658 Store.Store.prototype.clear = function() {
659     var graph;
660     var callback;
661 
662     if(arguments.length === 0) {
663         graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
664         var callback= function(){};
665     } else if(arguments.length === 1) {
666         graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
667         callback= arguments[0] || function(){};
668     } else if(arguments.length === 2) {
669         graph = this.rdf.createNamedNode(arguments[0]);
670         callback= arguments[1] || function(){};
671     } else {
672         throw("The optional graph and a callback must be provided");
673     }
674 
675     var query = "CLEAR GRAPH " + this._nodeToQuery(graph);
676     this.engine.execute(query, callback);
677 };
678 
679 /**
680  * Boolean value determining if loading RDF must produce
681  * triple add events and fire callbacks.<br/>
682  * Default value is false.
683  *
684  * @arguments
685  * @param {boolean} mustFireEvents true/false value.
686  */
687 Store.Store.prototype.setBatchLoadEvents = function(mustFireEvents){
688     this.engine.eventsOnBatchLoad = mustFireEvents;
689 };
690 
691 /**
692  * Registers a namespace prefix that will be automatically declared
693  * in all the queries.<br/>
694  * <br/>
695  * The prefix will also be inserte in the default <code>RDFEnvironment</code> object
696  * associated to the <code>rdf</code> property of the store instance.
697  *
698  * @arguments
699  * @param {String} ns the name space to be regsitered
700  * @param {String} prefix the URI fragment associated to the name space
701  */
702 Store.Store.prototype.registerDefaultNamespace = function(ns, prefix) {
703     this.rdf.prefixes.set(ns,prefix);
704     this.engine.registerDefaultNamespace(ns,prefix);
705 };
706 
707 /**
708  * Registers the default namespaces declared in the RDF JS Interfaces
709  * specification in the default Profile.
710  */
711 Store.Store.prototype.registerDefaultProfileNamespaces = function() {
712     var defaultNsMap = this.rdf.prefixes.values();
713     for (var p in defaultNsMap) {
714         this.registerDefaultNamespace(p,defaultNsMap[p]);
715     }
716 };
717 
718 /**
719  * Load triples into a graph in the store. Data can be passed directly to the method
720  * or a remote URI speifying where the data is located can be used.<br/>
721  *<br/>
722  * If the data is passed directly to the load function, the media type stating the format
723  * of the data must also be passed to the function.<br/>
724  *<br/>
725  * If an URI is passed as a parameter, the store will attempt to perform content negotiation
726  * with the remote server and get a representation for the RDF data matching one of the
727  * the RDF parsers registered in the store. In this case, the media type parameter must be
728  * set to the <code>'remote'</code> value.<br/>
729  *<br/>
730  * An additional URI for the graph where the parsed data will be loaded and a callback function
731  * can be also passed as parameters. If no graph is specified, triples will be loaded in the
732  * default graph.<br/>
733  *<br/>
734  * By default loading data will not trigger notification through the events API. If events needs to
735  * be trigger, the functio <code>setBatchLoadEvents</code> must be invoked with a true parameter.
736  *
737  * @arguments
738  * @param {String} mediaType Media type (application/json, text/n3...) of the data to be parsed or the value <code>'remote'</code> if a URI for the data is passed instead
739  * @param {String} [graph] Graph where the parsed triples will be inserted. If it is not specified, triples will be loaded in the default graph
740  * @param {String} data RDF data to be parsed and loaded or an URI where the data will be retrieved after performing content negotiation
741  * @param {Function} callback that will be invoked with a success notification and the number of triples loaded.
742  */
743 Store.Store.prototype.load = function(){
744     var mediaType;
745     var data;
746     var graph;
747     var callback;
748 
749     if(arguments.length === 3) {
750         graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
751         mediaType = arguments[0];
752         data = arguments[1];
753         callback= arguments[2] || function(){};
754     } else if(arguments.length === 4) {
755         mediaType = arguments[0];
756         data = arguments[1];
757         graph = this.rdf.createNamedNode(arguments[2]);
758         callback= arguments[3] || function(){};
759     } else if(arguments.length === 2) {
760         throw("The mediaType of the parser, the data a callback and an optional graph must be provided");
761     }
762 
763     if(mediaType === 'remote') {
764         data = this.rdf.createNamedNode(data);
765         var query = "LOAD <"+data.valueOf()+"> INTO GRAPH <"+graph.valueOf()+">";
766 
767         this.engine.execute(query, callback);
768     } else if(data && typeof(data)==='string' && data.indexOf('file://')=== 0) {
769         var parser = this.engine.rdfLoader.parsers[mediaType];
770 
771         var that = this;
772         this.engine.rdfLoader.loadFromFile(parser, {'token':'uri', 'value':graph.valueOf()}, data, function(success, quads) {
773             if(success) {
774                 that.engine.batchLoad(quads,callback);
775             } else {
776                 callback(success, quads);
777             }
778         });
779 
780 
781     } else {
782         var parser = this.engine.rdfLoader.parsers[mediaType];
783 
784         var that = this;
785 
786         this.engine.rdfLoader.tryToParse(parser, {'token':'uri', 'value':graph.valueOf()}, data, function(success, quads) {
787             if(success) {
788                 that.engine.batchLoad(quads,callback);
789             } else {
790                 callback(success, quads);
791             }
792         });
793     }
794 };
795 
796 /**
797  * Registers a new parser associated to the provided media type. If there is a parser already registered for
798  * that media type, the new parser will replace the old one.<br/>
799  *<br/>
800  * Parsers must implement a function *parse* accepting the data to be parsed as the
801  * first parameter and the destination graph URI as the second one.
802  * They must return an array of objects with properties: 'subject', 'predicate', 'object'
803  * and 'graph' containing lexical representations for these values: 
804  *<br/>
805  *<ul>
806  * <li><code>{literal: '"literal"'}</code></li>
807  * <li><code>{literal: ''"literal"^^<datatype>'}</code></li>
808  * <li><code>{literal: '"literal"@lang'}</code></li>
809  * <li><code>{uri: 'uri'}</code></li>
810  * <li><code>{blank: '_:label'}</code></li>
811  *</ul>
812  *<br/>
813  * The provided media type will be used to perform content negotiation when dealing with remote
814  * resources, or to select the parser in the <code>load</code> function.
815  *
816  * @arguments
817  * @param {String} mediaType the media type for this parser
818  * @param {String} parser an object containing the *parse* function with the parser logic
819  */
820 Store.Store.prototype.registerParser = function(mediaType, parser) {
821     this.engine.rdfLoader.registerParser(mediaType,parser);
822 };
823 
824 /**
825  * Returns the URI of all the graphs currently contained
826  * in the store
827  *
828  * @arguments:
829  * @param {Function} callback function that will receive a success notification and the array of graph URIs
830  */
831 Store.Store.prototype.registeredGraphs = function(callback) {
832     var graphs = this.engine.lexicon.registeredGraphs(true);
833     var acum = [];
834     for(var i=0; i<graphs.length; i++) {
835         var graph = graphs[i];
836         var uri = new RDFJSInterface.NamedNode(graph);
837         acum.push(uri);
838     }
839 
840     return callback(true, acum);    
841 };
842 
843 /** @private */
844 Store.Store.prototype._nodeToQuery = function(term) {
845     if(term.interfaceName === 'NamedNode') {
846         var resolvedUri = this.rdf.resolve(term.valueOf());
847         if(resolvedUri != null) {
848             return "<" + resolvedUri + ">";
849         } else {
850             return "<" + term.valueOf() + ">";
851         }
852     } else if(term.interfaceName === '') {
853         return term.toString();
854     } else {
855         return term.toString();
856     }
857 };
858 
859 /**
860  * Returns the current network transport being used by the
861  * the store.
862  * 
863  * The default transport uses TCP sockets in the Node.js version
864  * and relies on jQuery in the browser version. This can be overriden
865  * using the <code>setNetworkTransport</code> function.
866  */
867 Store.Store.prototype.getNetworkTransport = function() {
868     return NetworkTransport;
869 };
870 
871 /**
872  * Sets the network transport used by the store.<br/>
873  * <br/>
874  * Network transport consist of an object implementing the <code>load</code>
875  * function, receiving the URI to load, a string with the value
876  * of the HTTP 'Accept' header for the store registered parsers,
877  * a callback function where the retrieved data and the success notification
878  * must be returned.<br/>
879  *<br/>
880  * Different examples with implementations of different transports can be found
881  * in the source code of the store:
882  *<ul>
883  * <li>src/js-communication/src/tcp_transport.js</li>
884  * <li>src/js-communication/src/ajax_transport.js</li>
885  *</ul>
886  * @arguments
887  * @param networkTransportImpl object implementing the transport *load* function.
888  */
889 Store.Store.prototype.setNetworkTransport = function(networkTransportImpl) {
890     NetworkTransport = networkTransportImpl;
891 };
892