001: /*
002: * LICENSE INFORMATION
003: * Copyright 2005-2007 by FZI (http://www.fzi.de).
004: * Licensed under a BSD license (http://www.opensource.org/licenses/bsd-license.php)
005: * <OWNER> = Max Völkel
006: * <ORGANIZATION> = FZI Forschungszentrum Informatik Karlsruhe, Karlsruhe, Germany
007: * <YEAR> = 2007
008: *
009: * Project information at http://semweb4j.org/rdf2go
010: */
011: package org.ontoware.rdf2go.model.impl;
012:
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.io.OutputStream;
016: import java.io.Reader;
017: import java.io.StringWriter;
018: import java.net.URL;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import org.ontoware.aifbcommons.collection.ClosableIterable;
028: import org.ontoware.aifbcommons.collection.ClosableIterator;
029: import org.ontoware.rdf2go.exception.MalformedQueryException;
030: import org.ontoware.rdf2go.exception.ModelRuntimeException;
031: import org.ontoware.rdf2go.exception.QueryLanguageNotSupportedException;
032: import org.ontoware.rdf2go.exception.SyntaxNotSupportedException;
033: import org.ontoware.rdf2go.model.Diff;
034: import org.ontoware.rdf2go.model.DiffReader;
035: import org.ontoware.rdf2go.model.Model;
036: import org.ontoware.rdf2go.model.QueryResultTable;
037: import org.ontoware.rdf2go.model.QueryRow;
038: import org.ontoware.rdf2go.model.Statement;
039: import org.ontoware.rdf2go.model.Syntax;
040: import org.ontoware.rdf2go.model.TriplePattern;
041: import org.ontoware.rdf2go.model.node.BlankNode;
042: import org.ontoware.rdf2go.model.node.DatatypeLiteral;
043: import org.ontoware.rdf2go.model.node.LanguageTagLiteral;
044: import org.ontoware.rdf2go.model.node.Node;
045: import org.ontoware.rdf2go.model.node.NodeOrVariable;
046: import org.ontoware.rdf2go.model.node.PlainLiteral;
047: import org.ontoware.rdf2go.model.node.Resource;
048: import org.ontoware.rdf2go.model.node.ResourceOrVariable;
049: import org.ontoware.rdf2go.model.node.URI;
050: import org.ontoware.rdf2go.model.node.UriOrVariable;
051: import org.ontoware.rdf2go.model.node.Variable;
052: import org.ontoware.rdf2go.model.node.impl.DatatypeLiteralImpl;
053: import org.ontoware.rdf2go.model.node.impl.LanguageTagLiteralImpl;
054: import org.ontoware.rdf2go.model.node.impl.PlainLiteralImpl;
055: import org.ontoware.rdf2go.model.node.impl.URIImpl;
056: import org.ontoware.rdf2go.vocabulary.RDF;
057: import org.slf4j.Logger;
058: import org.slf4j.LoggerFactory;
059:
060: /**
061: * adapter that maps the rdf2go model functions to a smaller subset of methods
062: *
063: * @author mvo
064: *
065: */
066: public abstract class AbstractModel extends AbstractModelRemovePatterns
067: implements Model {
068:
069: private static Logger log = LoggerFactory
070: .getLogger(AbstractModel.class);
071:
072: /**
073: * The underlying implementation.
074: */
075: protected Object model;
076:
077: /**
078: * Uses to store runtime-properties - no related to RDF at all. You could
079: * for example store a user session object here.
080: */
081: private Map<URI, Object> runtimeProperties = new HashMap<URI, Object>();
082:
083: private boolean open = false;
084:
085: public void addAll(Iterator<? extends Statement> other)
086: throws ModelRuntimeException {
087: assertModel();
088: super .addAll(other);
089: }
090:
091: public void addStatement(Resource subject, URI predicate,
092: String literal) throws ModelRuntimeException {
093: assertModel();
094: super .addStatement(subject, predicate, literal);
095: }
096:
097: public void addStatement(Resource subject, URI predicate,
098: String literal, String languageTag)
099: throws ModelRuntimeException {
100: assertModel();
101: super .addStatement(subject, predicate, literal, languageTag);
102: }
103:
104: public void addStatement(Resource subject, URI predicate,
105: String literal, URI datatypeURI)
106: throws ModelRuntimeException {
107: assertModel();
108: super .addStatement(subject, predicate, literal, datatypeURI);
109: }
110:
111: public void addStatement(Statement statement)
112: throws ModelRuntimeException {
113: assertModel();
114: super .addStatement(statement);
115: }
116:
117: // essential methods
118:
119: // core rdf2go model methods
120: // /////////////////////////
121:
122: public void addStatement(String subjectURIString, URI predicate,
123: String literal) throws ModelRuntimeException {
124: assertModel();
125: super .addStatement(subjectURIString, predicate, literal);
126: }
127:
128: public void addStatement(String subjectURIString, URI predicate,
129: String literal, String languageTag)
130: throws ModelRuntimeException {
131: assertModel();
132: super .addStatement(subjectURIString, predicate, literal,
133: languageTag);
134: }
135:
136: public void addStatement(String subjectURIString, URI predicate,
137: String literal, URI datatypeURI)
138: throws ModelRuntimeException {
139: assertModel();
140: super .addStatement(subjectURIString, predicate, literal,
141: datatypeURI);
142: }
143:
144: /**
145: * This method checks if the model is properly initialized and i.e. not
146: * closed.
147: */
148: protected void assertModel() {
149: if (this .getUnderlyingModelImplementation() == null) {
150: throw new ModelRuntimeException("Underlying model is null.");
151: }
152: if (!isOpen())
153: throw new ModelRuntimeException("Model is not open");
154:
155: }
156:
157: /**
158: * Close connection to defined, unterlying implementation
159: */
160: public void close() {
161: if (isOpen()) {
162: this .open = false;
163: } else {
164: log.debug("Model was closed already, ignored.");
165: }
166: }
167:
168: /** OVERWRITE ME */
169: public void commit() {
170: // do nothing
171: }
172:
173: /**
174: * Convenience method. Might have faster implementations. Overwrite me!
175: */
176: public boolean contains(ResourceOrVariable subject,
177: UriOrVariable predicate, NodeOrVariable object)
178: throws ModelRuntimeException {
179: assertModel();
180: ClosableIterator<? extends Statement> cit = findStatements(
181: subject, predicate, object);
182: boolean result = cit.hasNext();
183: cit.close();
184: return result;
185: }
186:
187: /**
188: * Convenience method.
189: */
190: public boolean contains(ResourceOrVariable subject,
191: UriOrVariable predicate, String plainLiteral)
192: throws ModelRuntimeException {
193: assertModel();
194: return contains(subject, predicate, new PlainLiteralImpl(
195: plainLiteral));
196: }
197:
198: /**
199: * Convenience method.
200: */
201: public boolean contains(Statement s) throws ModelRuntimeException {
202: assertModel();
203: return contains(s.getSubject(), s.getPredicate(), s.getObject());
204: }
205:
206: /**
207: * Very inefficient. Please override.
208: */
209: public long countStatements(TriplePattern pattern)
210: throws ModelRuntimeException {
211: assertModel();
212: ClosableIterator<?> it = findStatements(pattern);
213: int count = 0;
214: while (it.hasNext()) {
215: count++;
216: it.next();
217: }
218: it.close();
219: return count;
220: }
221:
222: public DatatypeLiteral createDatatypeLiteral(String literal,
223: URI datatypeURI) throws ModelRuntimeException {
224: return new DatatypeLiteralImpl(literal, datatypeURI);
225: }
226:
227: public LanguageTagLiteral createLanguageTagLiteral(String literal,
228: String languageTag) throws ModelRuntimeException {
229: return new LanguageTagLiteralImpl(literal, languageTag);
230: }
231:
232: public PlainLiteral createPlainLiteral(String literal)
233: throws ModelRuntimeException {
234: return new PlainLiteralImpl(literal);
235: }
236:
237: // ///////////
238: // stubs
239:
240: public Statement createStatement(Resource subject, URI predicate,
241: Node object) {
242: return new StatementImpl(getContextURI(), subject, predicate,
243: object);
244: }
245:
246: public TriplePattern createTriplePattern(
247: ResourceOrVariable subject, UriOrVariable predicate,
248: NodeOrVariable object) {
249: return new TriplePatternImpl(subject, predicate, object);
250: }
251:
252: public URI createURI(String uriString) throws ModelRuntimeException {
253: return new URIImpl(uriString);
254: }
255:
256: /**
257: * Convenience method.
258: */
259: public ClosableIterator<Statement> findStatements(
260: TriplePattern triplepattern) throws ModelRuntimeException {
261: assertModel();
262: return findStatements(triplepattern.getSubject(), triplepattern
263: .getPredicate(), triplepattern.getObject());
264: }
265:
266: /**
267: * Computes a Diff by using HashSets.
268: */
269: public Diff getDiff(Iterator<? extends Statement> other)
270: throws ModelRuntimeException {
271: assertModel();
272:
273: Set<Statement> otherSet = new HashSet<Statement>();
274: while (other.hasNext())
275: otherSet.add(other.next());
276: log.debug("this has " + size() + " triples, other has "
277: + otherSet.size() + " triples");
278:
279: // added Statements = present in other, but not this
280: Set<Statement> added = new HashSet<Statement>();
281: for (Statement s : otherSet) {
282: if (!this .contains(s))
283: added.add(s);
284: }
285:
286: // removed = present here, but no longer in other
287: Set<Statement> removed = new HashSet<Statement>();
288: for (Statement s : this ) {
289: if (!otherSet.contains(s)) {
290: log.debug("otherSet does not contain " + s);
291: removed.add(s);
292: }
293: }
294:
295: log.debug(added.size() + " triples added, " + removed.size()
296: + " removed.");
297:
298: // These iterators are not closable, so we don't have to close them
299: return new DiffImpl(added.iterator(), removed.iterator());
300: }
301:
302: /**
303: * Note: This is a property of the model, not an RDF property
304: *
305: * @param propertyURI
306: * @return stored property value for this model or null
307: */
308: public Object getProperty(URI propertyURI) {
309: return this .runtimeProperties.get(propertyURI);
310: }
311:
312: public Object getUnderlyingModelImplementation() {
313: if (!isOpen())
314: throw new ModelRuntimeException("Model is not open");
315: return this .model;
316: }
317:
318: /** sublcasses should override this method for performance */
319: public boolean isEmpty() {
320: return size() == 0;
321: }
322:
323: public boolean isOpen() {
324: return this .open;
325: }
326:
327: public URI newRandomUniqueURI() {
328: return URIGenerator.createNewRandomUniqueURI();
329: }
330:
331: /**
332: * Open connection to defined, unterlying implementation.
333: */
334: public void open() {
335: if (isOpen()) {
336: log.warn("Model is already open. Ignored.");
337: } else {
338: this .open = true;
339: }
340: }
341:
342: /**
343: * Throws an exception if the syntax is not SPARQL
344: */
345: public ClosableIterable<Statement> queryConstruct(String query,
346: String querylanguage)
347: throws QueryLanguageNotSupportedException,
348: ModelRuntimeException {
349: assertModel();
350: if (querylanguage.equalsIgnoreCase("SPARQL"))
351: return sparqlConstruct(query);
352: // else
353: throw new QueryLanguageNotSupportedException(
354: "Unsupported query language: " + querylanguage);
355: }
356:
357: /**
358: * Throws an exception if the syntax is not SPARQL
359: */
360: public QueryResultTable querySelect(String query,
361: String querylanguage)
362: throws QueryLanguageNotSupportedException,
363: ModelRuntimeException {
364: assertModel();
365: if (querylanguage.equalsIgnoreCase("SPARQL"))
366: return sparqlSelect(query);
367: // else
368: throw new QueryLanguageNotSupportedException(
369: "Unsupported query language: " + querylanguage);
370: }
371:
372: /**
373: * Throws an exception if the syntax is not RDF/XML. Subclasses are
374: * encouraged to overwrite this.
375: */
376: public void readFrom(InputStream in, Syntax syntax)
377: throws IOException, ModelRuntimeException {
378: assertModel();
379: if (syntax == Syntax.RdfXml) {
380: readFrom(in);
381: } else {
382: throw new ModelRuntimeException("Unsupported syntax: "
383: + syntax);
384: }
385: }
386:
387: /**
388: * Throws an exception if the syntax is not RDF/XML. Set baseURI to the
389: * empty string. Subclasses are encouraged to overwrite this.
390: */
391: public void readFrom(InputStream in, Syntax syntax, URL baseURI)
392: throws IOException, ModelRuntimeException {
393: assertModel();
394: if (syntax == Syntax.RdfXml) {
395: readFrom(in);
396: } else {
397: throw new ModelRuntimeException("Unsupported syntax: "
398: + syntax);
399: }
400: }
401:
402: /**
403: * Throws an exception if the syntax is not RDF/XML. Sets base URI to the
404: * empty string (default). Subclasses are encouraged to overwrite this.
405: *
406: * @throws IOException
407: * @throws ModelRuntimeException
408: */
409: public void readFrom(Reader reader, Syntax syntax, URL baseURI)
410: throws ModelRuntimeException, IOException {
411: assertModel();
412: if (syntax == Syntax.RdfXml) {
413: readFrom(reader);
414: } else {
415: throw new ModelRuntimeException("Unsupported syntax: "
416: + syntax);
417: }
418: }
419:
420: public void removeAll() throws ModelRuntimeException {
421: assertModel();
422: super .removeAll();
423: }
424:
425: public void removeAll(Iterator<? extends Statement> statements) {
426: assertModel();
427: super .removeAll(statements);
428: }
429:
430: public void removeStatement(Resource subject, URI predicate,
431: String literal) throws ModelRuntimeException {
432: assertModel();
433: super .removeStatement(subject, predicate, literal);
434: }
435:
436: public void removeStatement(Resource subject, URI predicate,
437: String literal, String languageTag)
438: throws ModelRuntimeException {
439: assertModel();
440: super .removeStatement(subject, predicate, literal, languageTag);
441: }
442:
443: public void removeStatement(Resource subject, URI predicate,
444: String literal, URI datatypeURI)
445: throws ModelRuntimeException {
446: assertModel();
447: super .removeStatement(subject, predicate, literal, datatypeURI);
448: }
449:
450: public void removeStatement(Statement statement)
451: throws ModelRuntimeException {
452: assertModel();
453: super .removeStatement(statement);
454: }
455:
456: public void removeStatement(String subjectURIString, URI predicate,
457: String literal) throws ModelRuntimeException {
458: assertModel();
459: super .removeStatement(subjectURIString, predicate, literal);
460: }
461:
462: public void removeStatement(String subjectURIString, URI predicate,
463: String literal, String languageTag)
464: throws ModelRuntimeException {
465: assertModel();
466: super .removeStatement(subjectURIString, predicate, literal,
467: languageTag);
468: }
469:
470: public void removeStatement(String subjectURIString, URI predicate,
471: String literal, URI datatypeURI)
472: throws ModelRuntimeException {
473: assertModel();
474: super .removeStatement(subjectURIString, predicate, literal,
475: datatypeURI);
476: }
477:
478: public void removeStatements(ResourceOrVariable subject,
479: UriOrVariable predicate, NodeOrVariable object)
480: throws ModelRuntimeException {
481: assertModel();
482: super .removeStatements(subject, predicate, object);
483: }
484:
485: public void removeStatements(TriplePattern triplePattern)
486: throws ModelRuntimeException {
487: assertModel();
488: super .removeStatements(triplePattern);
489: }
490:
491: /**
492: * Convenience method.
493: */
494: public String serialize(Syntax syntax)
495: throws SyntaxNotSupportedException {
496: StringWriter sw = new StringWriter();
497: try {
498: this .writeTo(sw, syntax);
499: } catch (IOException e) {
500: throw new ModelRuntimeException(e);
501: }
502: return sw.getBuffer().toString();
503: }
504:
505: /** OVERWRITE ME */
506: public void setAutocommit(boolean autocommit) {
507: // do nothing
508: }
509:
510: /**
511: * Add an arbitrary property, this will not be persisted and is only
512: * available at runtime. This allows Model to serve as a central data model
513: * in larger applications (like SemVersion.ontoware.org)
514: *
515: * @param propertyURI
516: * @param value
517: */
518: public void setProperty(URI propertyURI, Object value) {
519: this .runtimeProperties.put(propertyURI, value);
520: }
521:
522: /**
523: * This is a really slow implementation, please override.
524: */
525: public long size() throws ModelRuntimeException {
526: assertModel();
527: ClosableIterator<Statement> it = iterator();
528: int count = 0;
529: while (it.hasNext()) {
530: count++;
531: it.next();
532: }
533: it.close();
534: return count;
535: }
536:
537: // work around Sesame not having this yet
538: public boolean sparqlAsk(String query)
539: throws ModelRuntimeException, MalformedQueryException {
540: QueryResultTable table = sparqlSelect(query);
541: ClosableIterator<QueryRow> it = table.iterator();
542: boolean result = it.hasNext();
543: it.close();
544: return result;
545: }
546:
547: /**
548: * Implementations with support for transactions should use them instead of
549: * this implementation.
550: */
551: @Override
552: public synchronized void update(DiffReader diff)
553: throws ModelRuntimeException {
554: assertModel();
555: for (Statement r : diff.getRemoved()) {
556: removeStatement(r);
557: }
558:
559: for (Statement a : diff.getAdded()) {
560: addStatement(a);
561: }
562: }
563:
564: /**
565: * Throws an exception if the syntax is not known
566: */
567: public void writeTo(OutputStream out, Syntax syntax)
568: throws IOException, ModelRuntimeException {
569: assertModel();
570: if (syntax == Syntax.RdfXml) {
571: writeTo(out);
572: } else {
573: throw new ModelRuntimeException("Unsupported syntax: "
574: + syntax);
575: }
576: }
577:
578: /* fast, no need to override */
579: public BlankNode createReficationOf(Statement statement) {
580: BlankNode bnode = createBlankNode();
581: return (BlankNode) createReficationOf(statement, bnode);
582: }
583:
584: public Resource createReficationOf(Statement statement,
585: Resource resource) {
586: Diff diff = new DiffImpl();
587: diff.addStatement(resource, RDF.type, RDF.Statement);
588: diff
589: .addStatement(resource, RDF.subject, statement
590: .getSubject());
591: diff.addStatement(resource, RDF.predicate, statement
592: .getPredicate());
593: diff.addStatement(resource, RDF.object, statement.getObject());
594: update((DiffReader) diff);
595: return resource;
596: }
597:
598: public boolean hasReifications(Statement statement) {
599: return this .sparqlAsk("ASK WHERE { " + " ?res "
600: + RDF.type.toSPARQL() + " " + RDF.Statement + " ."
601: + " ?res " + RDF.subject.toSPARQL() + " "
602: + statement.getSubject().toSPARQL() + " ." + " ?res "
603: + RDF.predicate.toSPARQL() + " "
604: + statement.getPredicate().toSPARQL() + " ." + " ?res "
605: + RDF.object.toSPARQL() + " "
606: + statement.getObject().toSPARQL() + " ." + " }");
607: }
608:
609: /*
610: * inefficient, loads all in memory. should be OK for almost all practical
611: * cases (when each statement has a small number of refications)
612: */
613: public Collection<Resource> getAllReificationsOf(Statement statement) {
614: QueryResultTable table = this
615: .sparqlSelect("SELECT ?res WHERE { " + " ?res "
616: + RDF.type.toSPARQL() + " " + RDF.Statement
617: + " ." + " ?res " + RDF.subject.toSPARQL()
618: + " " + statement.getSubject().toSPARQL()
619: + " ." + " ?res " + RDF.predicate.toSPARQL()
620: + " " + statement.getPredicate().toSPARQL()
621: + " ." + " ?res " + RDF.object.toSPARQL() + " "
622: + statement.getObject().toSPARQL() + " ."
623: + " }");
624: LinkedList<Resource> result = new LinkedList<Resource>();
625: ClosableIterator<QueryRow> it = table.iterator();
626: while (it.hasNext()) {
627: Resource res = it.next().getValue("res").asResource();
628: result.add(res);
629: }
630: it.close();
631: return result;
632: }
633:
634: public void deleteReification(Resource reificationResource) {
635: Diff diff = new DiffImpl();
636: diff.removeStatement(reificationResource, RDF.type,
637: RDF.Statement);
638: ClosableIterator<Statement> it = findStatements(
639: reificationResource, RDF.subject, Variable.ANY);
640: while (it.hasNext()) {
641: diff.removeStatement(it.next());
642: }
643: it.close();
644: it = findStatements(reificationResource, RDF.predicate,
645: Variable.ANY);
646: while (it.hasNext()) {
647: diff.removeStatement(it.next());
648: }
649: it.close();
650: it = findStatements(reificationResource, RDF.object,
651: Variable.ANY);
652: while (it.hasNext()) {
653: diff.removeStatement(it.next());
654: }
655: it.close();
656: update((DiffReader) diff);
657: }
658: }
|