001: /*
002: * (c) Copyright 2003 Hewlett-Packard Development Company, LP
003: * All rights reserved.
004: *
005: */
006:
007: package com.hp.hpl.jena.db.impl;
008:
009: import java.util.ArrayList;
010: import java.util.Iterator;
011: import java.util.List;
012:
013: import com.hp.hpl.jena.db.GraphRDB;
014: import com.hp.hpl.jena.graph.*;
015: import com.hp.hpl.jena.util.iterator.*;
016: import com.hp.hpl.jena.shared.*;
017: import com.hp.hpl.jena.vocabulary.RDF;
018:
019: /**
020: * @author hkuno
021: * @version $Version$
022: *
023: * TripleStoreGraph is an abstract superclass for TripleStoreGraph
024: * implementations. By "triple store," we mean that the subjects, predicate
025: * and object URI's are stored in a single collection (denormalized).
026: *
027: */
028:
029: public class SpecializedGraphReifier_RDB extends SpecializedGraphBase
030: implements SpecializedGraphReifier {
031:
032: /**
033: * holds PSet
034: */
035: public PSet_ReifStore_RDB m_pset;
036:
037: /**
038: * caches a copy of LSet properties
039: */
040: public DBPropLSet m_dbPropLSet;
041:
042: /**
043: * holds ID of graph in database (defaults to "0")
044: */
045: public IDBID my_GID = null;
046:
047: // cache of reified statement status
048: private ReificationCacheMap m_reifCache;
049:
050: public PSet_ReifStore_RDB m_reif;
051:
052: // constructors
053:
054: /**
055: * Constructor
056: * Create a new instance of a TripleStore graph.
057: */
058: SpecializedGraphReifier_RDB(DBPropLSet lProp, IPSet pSet,
059: Integer dbGraphID) {
060: m_pset = (PSet_ReifStore_RDB) pSet;
061: m_dbPropLSet = lProp;
062: my_GID = new DBIDInt(dbGraphID);
063: m_reifCache = new ReificationCacheMap(this , 1);
064: m_reif = (PSet_ReifStore_RDB) m_pset;
065: }
066:
067: /**
068: * Constructor
069: *
070: * Create a new instance of a TripleStore graph, taking
071: * DBPropLSet and a PSet as arguments
072: */
073: public SpecializedGraphReifier_RDB(IPSet pSet, Integer dbGraphID) {
074: m_pset = (PSet_ReifStore_RDB) pSet;
075: my_GID = new DBIDInt(dbGraphID);
076: m_reifCache = new ReificationCacheMap(this , 1);
077: m_reif = (PSet_ReifStore_RDB) m_pset;
078: }
079:
080: /* (non-Javadoc)
081: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#add(com.hp.hpl.jena.graph.Node, com.hp.hpl.jena.graph.Triple, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
082: */
083: public void add(Node n, Triple t, CompletionFlag complete)
084: throws CannotReifyException {
085: ReificationStatementMask same = new ReificationStatementMask();
086: ReificationStatementMask diff = new ReificationStatementMask();
087: ReificationCache rs = m_reifCache.load(n, t, same, diff);
088: if (rs == null) {
089: m_reif.storeReifStmt(n, t, my_GID);
090: } else {
091: /* node already reifies something. is that a subset of triple t? */
092: if (diff.hasNada()) {
093: boolean didUpdate = false;
094: /* add whatever is missing to reify t */
095: if (!same.hasSubj()) {
096: Triple st = Triple.create(n, RDF.Nodes.subject, t
097: .getSubject());
098: m_reif.updateFrag(n, st,
099: new ReificationStatementMask(st), my_GID);
100: didUpdate = true;
101: }
102: if (!same.hasPred()) {
103: Triple pt = Triple.create(n, RDF.Nodes.predicate, t
104: .getPredicate());
105: m_reif.updateFrag(n, pt,
106: new ReificationStatementMask(pt), my_GID);
107: didUpdate = true;
108: }
109: if (!same.hasObj()) {
110: Triple ot = Triple.create(n, RDF.Nodes.object, t
111: .getObject());
112: m_reif.updateFrag(n, ot,
113: new ReificationStatementMask(ot), my_GID);
114: didUpdate = true;
115: }
116: if (!rs.mask.hasType()) {
117: Triple tt = Triple.create(n, RDF.Nodes.type,
118: RDF.Nodes.Statement);
119: m_reif.updateFrag(n, tt,
120: new ReificationStatementMask(tt), my_GID);
121: didUpdate = true;
122: }
123: if (didUpdate)
124: fragCompact(n);
125: m_reifCache.flushAll();
126: } else {
127: /* node reifies something that is not a subset of triple t */
128: if (rs.mask.isStmt())
129: throw new AlreadyReifiedException(n);
130: else
131: throw new CannotReifyException(n);
132: }
133: }
134: complete.setDone();
135: }
136:
137: /* (non-Javadoc)
138: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#delete(com.hp.hpl.jena.graph.Node, com.hp.hpl.jena.graph.Triple, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
139: */
140: public void delete(Node n, Triple t, CompletionFlag complete) {
141: m_reifCache.flushAll();
142: m_reif.deleteReifStmt(n, t, my_GID);
143: complete.setDone();
144: }
145:
146: /* (non-Javadoc)
147: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#contains(com.hp.hpl.jena.graph.Node, com.hp.hpl.jena.graph.Triple, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
148: */
149: public boolean contains(Node n, Triple t, CompletionFlag complete) {
150: if (true)
151: throw new JenaException(
152: "SpecializedGraphReifier.contains called");
153: return false;
154: }
155:
156: /* (non-Javadoc)
157: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#findReifiedNodes(com.hp.hpl.jena.graph.TripleMatch, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
158: */
159: public ExtendedIterator findReifiedNodes(Triple t,
160: CompletionFlag complete) {
161: complete.setDone();
162: return m_reif.findReifStmtURIByTriple(t, my_GID);
163: }
164:
165: /* (non-Javadoc)
166: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#findReifiedTriple(com.hp.hpl.jena.graph.Node, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
167: */
168: public Triple findReifiedTriple(Node n, CompletionFlag complete) {
169: ResultSetReifIterator it = m_reif.findReifStmt(n, true, my_GID,
170: false);
171: Triple res = null;
172: if (it.hasNext()) {
173: res = (Triple) it.next();
174: }
175: complete.setDone();
176: return res;
177: }
178:
179: /** Find all the triples corresponding to a given reified node.
180: * In a perfect world, there would only ever be one, but when a user calls
181: * add(Triple) there is nothing in RDF that prevents them from adding several
182: * subjects,predicates or objects for the same statement.
183: *
184: * The resulting Triples may be incomplete, in which case some of the
185: * nodes may be Node_ANY.
186: *
187: * For example, if an application had previously done:
188: * add( new Triple( a, rdf.subject A )) and
189: * add( new Triple( a, rdf.object B )) and
190: * add( new Triple( a, rdf.object B2 ))
191: *
192: * Then the result of findReifiedTriple(a, flag) will be an iterator containing
193: * Triple(A, ANY, B) and Triple(ANY, ANY, B2).
194: *
195: * @param n is the Node for which we are querying.
196: * @param complete is true if we know we've returned all the triples which may exist.
197: * @return ExtendedIterator.
198: */
199: public ExtendedIterator findReifiedTriples(Node n,
200: CompletionFlag complete) {
201: complete.setDone();
202: return m_reif.findReifStmt(n, false, my_GID, true);
203: }
204:
205: /**
206: * Attempt to add all the triples from a graph to the specialized graph
207: *
208: * Caution - this call changes the graph passed in, deleting from
209: * it each triple that is successfully added.
210: *
211: * Node that when calling add, if complete is true, then the entire
212: * graph was added successfully and the graph g will be empty upon
213: * return. If complete is false, then some triples in the graph could
214: * not be added. Those triples remain in g after the call returns.
215: *
216: * If the triple can't be stored for any reason other than incompatability
217: * (for example, a lack of disk space) then the implemenation should throw
218: * a runtime exception.
219: *
220: * @param g is a graph containing triples to be added
221: * @param complete is true if a subsequent call to contains(triple) will return true for any triple in g.
222: */
223: public void add(Graph g, CompletionFlag complete) {
224: throw new AddDeniedException("sorry, not implemented");
225: }
226:
227: /* (non-Javadoc)
228: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#add(com.hp.hpl.jena.graph.Triple, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
229: */
230: public void add(Triple frag, CompletionFlag complete)
231: throws AlreadyReifiedException {
232: ReificationStatementMask fragMask = new ReificationStatementMask(
233: frag);
234: if (fragMask.hasNada())
235: return;
236:
237: boolean fragHasType = fragMask.hasType();
238: Node stmtURI = frag.getSubject();
239: ReificationCache cachedFrag = m_reifCache.load(stmtURI);
240: if (cachedFrag == null) {
241: // not in database
242: m_reif.storeFrag(stmtURI, frag, fragMask, my_GID);
243: complete.setDone();
244:
245: } else {
246: ReificationStatementMask cachedMask = cachedFrag
247: .getStmtMask();
248: if (cachedMask.hasIntersect(fragMask)) {
249: // see if this is a duplicate fragment
250: boolean dup = fragHasType && cachedMask.hasType();
251: if (dup == false) {
252: // not a type fragement; have to search db to check for dup
253: ExtendedIterator it = m_reif.findFrag(stmtURI,
254: frag, fragMask, my_GID);
255: dup = it.hasNext();
256: if (dup == false) {
257: if (cachedMask.isStmt())
258: throw new AlreadyReifiedException(frag
259: .getSubject());
260: // cannot perform a reificiation; store fragment
261: m_reif.storeFrag(stmtURI, frag, fragMask,
262: my_GID);
263: m_reifCache.flush(cachedFrag);
264: }
265: }
266: } else {
267: // reification may be possible; update if possible, else compact
268: if (cachedFrag.canMerge(fragMask)) {
269: if (cachedFrag.canUpdate(fragMask)) {
270: m_reif.updateFrag(stmtURI, frag, fragMask,
271: my_GID);
272: cachedFrag.update(fragMask);
273: } else
274: fragCompact(stmtURI);
275: } else {
276: // reification not possible
277: m_reif.storeFrag(stmtURI, frag, fragMask, my_GID);
278: }
279: }
280: }
281: complete.setDone();
282: }
283:
284: /* (non-Javadoc)
285: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#delete(com.hp.hpl.jena.graph.Triple, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
286: */
287: public void delete(Triple frag, CompletionFlag complete) {
288: ReificationStatementMask fragMask = new ReificationStatementMask(
289: frag);
290: if (fragMask.hasNada())
291: return;
292:
293: Node stmtURI = frag.getSubject();
294:
295: ResultSetReifIterator it = m_reif.findFrag(stmtURI, frag,
296: fragMask, my_GID);
297: if (it.hasNext()) {
298: if (it.getFragCount() == 1) {
299: /* last fragment in this tuple; can just delete it */
300: m_reif.deleteFrag(frag, fragMask, my_GID);
301: it.close();
302: } else {
303: /* remove fragment from row */
304: m_reif.nullifyFrag(stmtURI, fragMask, my_GID);
305:
306: /* compact remaining fragments, if possible */
307: it.close();
308: fragCompact(stmtURI);
309: }
310: // remove cache entry, if any
311: ReificationCache cachedFrag = m_reifCache.lookup(stmtURI);
312: if (cachedFrag != null)
313: m_reifCache.flush(cachedFrag);
314: }
315: complete.setDone();
316: }
317:
318: /* fragCompact
319: *
320: * Compact fragments for a given statement URI.
321: *
322: * first, find the unique row for stmtURI that with the HasType Statement fragment.
323: * if no such row exists, we are done. then, get all fragments for stmtURI and
324: * try to merge them with the hasType fragment, deleting each as they are merged.
325: */
326: protected void fragCompact(Node stmtURI) {
327: ResultSetReifIterator itHasType;
328: Triple t;
329:
330: itHasType = m_reif.findReifStmt(stmtURI, true, my_GID, false);
331: if (itHasType.hasNext()) {
332: /* something to do */
333: t = (Triple) itHasType.next();
334: if (itHasType.hasNext())
335: throw new JenaException(
336: "Multiple HasType fragments for URI");
337: ReificationStatementMask htMask = new ReificationStatementMask(
338: t);
339: itHasType.close();
340:
341: // now, look at fragments and try to merge them with the hasType fragement
342: ResultSetReifIterator itFrag = m_reif.findReifStmt(stmtURI,
343: false, my_GID, false);
344: ReificationStatementMask upMask = new ReificationStatementMask();
345: while (itFrag.hasNext()) {
346: t = (Triple) itFrag.next();
347: if (itFrag.getHasType())
348: continue;
349: ReificationStatementMask fm = new ReificationStatementMask(
350: rowToFrag(stmtURI, t));
351: if (htMask.hasIntersect(fm))
352: break; // can't merge all fragments
353: // at this point, we can merge in the current fragment
354: m_reif.updateFrag(stmtURI, t, fm, my_GID);
355: htMask.setMerge(fm);
356: m_reif.deleteFrag(t, fm, my_GID);
357: }
358: }
359: }
360:
361: protected Triple rowToFrag(Node stmtURI, Triple row) {
362: Node pred = null;
363: Node obj = null;
364: int valCnt = 0;
365:
366: if (row.getSubject() != null) {
367: obj = row.getSubject();
368: pred = RDF.Nodes.subject;
369: valCnt++;
370: }
371: if (row.getPredicate() != null) {
372: obj = row.getPredicate();
373: pred = RDF.Nodes.predicate;
374: valCnt++;
375: }
376: if (row.getObject() != null) {
377: obj = row.getObject();
378: pred = RDF.Nodes.object;
379: valCnt++;
380: }
381: if (valCnt != 1)
382: throw new JenaException(
383: "Partially reified row must have exactly one value");
384:
385: return Triple.create(stmtURI, pred, obj);
386: }
387:
388: /* (non-Javadoc)
389: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#add(java.util.List, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
390: */
391: public void add(List triples, CompletionFlag complete) {
392: ArrayList remainingTriples = new ArrayList();
393: for (int i = 0; i < triples.size(); i++) {
394: CompletionFlag partialResult = newComplete();
395: add((Triple) triples.get(i), partialResult);
396: if (!partialResult.isDone())
397: remainingTriples.add(triples.get(i));
398: }
399: triples.clear();
400: if (remainingTriples.isEmpty())
401: complete.setDone();
402: else
403: triples.addAll(remainingTriples);
404: }
405:
406: /* (non-Javadoc)
407: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#delete(java.util.List, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
408: */
409: public void delete(List triples, CompletionFlag complete) {
410: boolean result = true;
411: Iterator it = triples.iterator();
412: while (it.hasNext()) {
413: CompletionFlag partialResult = newComplete();
414: delete((Triple) it.next(), partialResult);
415: result = result && partialResult.isDone();
416: }
417: if (result)
418: complete.setDone();
419: }
420:
421: /* (non-Javadoc)
422: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#tripleCount()
423: */
424: public int tripleCount() {
425: // A very inefficient, but simple implementation
426: ExtendedIterator it = find(null, null, null, newComplete());
427: int count = 0;
428: while (it.hasNext()) {
429: it.next();
430: count++;
431: }
432: it.close();
433: return count;
434: }
435:
436: /* (non-Javadoc)
437: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#find(com.hp.hpl.jena.graph.TripleMatch, com.hp.hpl.jena.db.impl.SpecializedGraph.CompletionFlag)
438: */
439: public ExtendedIterator find(TripleMatch t, CompletionFlag complete) {
440:
441: // Node stmtURI = t.getMatchSubject(); // note: can be null
442: // ResultSetReifIterator it = m_reif.findReifStmt(stmtURI, false, my_GID, true);
443: // return it.filterKeep( new TripleMatchFilter( t.asTriple() ) );
444: ResultSetReifIterator it = m_reif
445: .findReifTripleMatch(t, my_GID);
446: return it;
447: }
448:
449: /**
450: * Tests if a triple is contained in the specialized graph.
451: * @param t is the triple to be tested
452: * @param complete is true if the graph can guarantee that
453: * no other specialized graph could hold any matching triples.
454: * @return boolean result to indicate if the triple was contained
455: */
456: public boolean contains(Triple t, CompletionFlag complete) {
457: // A very inefficient, but simple implementation
458: ExtendedIterator it = find(t, complete);
459: try {
460: return it.hasNext();
461: } finally {
462: it.close();
463: }
464: }
465:
466: /*
467: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#close()
468: */
469: public void close() {
470: m_reif.close();
471: }
472:
473: /*
474: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#clear()
475: */
476: public void clear() {
477: m_reif.removeStatementsFromDB(my_GID);
478: }
479:
480: static boolean isReifProp(Node_URI p) {
481: return p.equals(RDF.Nodes.subject)
482: || p.equals(RDF.Nodes.predicate)
483: || p.equals(RDF.Nodes.object)
484: || p.equals(RDF.Nodes.type);
485: }
486:
487: /* (non-Javadoc)
488: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#graphIdGet()
489: */
490: public int getGraphId() {
491: return ((DBIDInt) my_GID).getIntID();
492: }
493:
494: /* (non-Javadoc)
495: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#PSetGet()
496: */
497: public IPSet getPSet() {
498: return m_pset;
499: }
500:
501: /* (non-Javadoc)
502: * @see com.hp.hpl.jena.db.impl.SpecializedGraphReifier#DBPropLSetGet()
503: */
504: public DBPropLSet getDBPropLSet() {
505: return m_dbPropLSet;
506: }
507:
508: /*
509: * (non-Javadoc)
510: * @see com.hp.hpl.jena.db.impl.SpecializedGraph#subsumes(com.hp.hpl.jena.graph.Triple, int)
511: *
512: * determine if the reifier graph has any triples of the given pattern.
513: * the table below indicates the return value for each reif style for
514: * the various types of patterns.
515: * note: "conc" means the node in the pattern is not a concrete node.
516: *
517: * Pattern Minimal Conv Standard
518: * ANY rdf:subj ANY none none all
519: * ANY rdf:pred ANY none none all
520: * ANY rdf:obj ANY none none all
521: * ANY rdf:type rdf:stmt none none all
522: * ANY rdf:type conc none none none
523: * ANY rdf:type !conc none none some
524: * ANY !conc ANY none none some
525: * else none none none
526: */
527: public char subsumes(Triple pattern, int reifBehavior) {
528: char res = noTriplesForPattern;
529: if (reifBehavior != GraphRDB.OPTIMIZE_ALL_REIFICATIONS_AND_HIDE_NOTHING)
530: return res;
531: Node pred = pattern.getPredicate();
532: if (pred.isConcrete()) {
533: if (pred.equals(RDF.Nodes.subject)
534: || pred.equals(RDF.Nodes.predicate)
535: || pred.equals(RDF.Nodes.object))
536: res = allTriplesForPattern;
537: else if (pred.equals(RDF.Nodes.type)) {
538: Node obj = pattern.getObject();
539: if (obj.equals(RDF.Nodes.Statement))
540: res = allTriplesForPattern;
541: else if (!obj.isConcrete())
542: res = someTriplesForPattern;
543: }
544: } else if ((pred.isVariable()) || pred.equals(Node.ANY)) {
545: res = someTriplesForPattern;
546: } else
547: throw new JenaException("Unexpected predicate: "
548: + pred.toString());
549: return res;
550: }
551: }
552:
553: /*
554: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
555: * All rights reserved.
556: *
557: * Redistribution and use in source and binary forms, with or without
558: * modification, are permitted provided that the following conditions
559: * are met:
560: * 1. Redistributions of source code must retain the above copyright
561: * notice, this list of conditions and the following disclaimer.
562: * 2. Redistributions in binary form must reproduce the above copyright
563: * notice, this list of conditions and the following disclaimer in the
564: * documentation and/or other materials provided with the distribution.
565: * 3. The name of the author may not be used to endorse or promote products
566: * derived from this software without specific prior written permission.
567:
568: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
569: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
570: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
571: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
572: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
573: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
574: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
575: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
576: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
577: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
578: */
|