001: package org.ontoware.rdf2go.impl.autopersist;
002:
003: import java.io.File;
004: import java.io.FileNotFoundException;
005: import java.io.FileReader;
006: import java.io.FileWriter;
007: import java.io.IOException;
008: import java.util.Iterator;
009:
010: import org.ontoware.aifbcommons.collection.ClosableIterable;
011: import org.ontoware.aifbcommons.collection.ClosableIterator;
012: import org.ontoware.rdf2go.exception.ModelRuntimeException;
013: import org.ontoware.rdf2go.model.Diff;
014: import org.ontoware.rdf2go.model.Model;
015: import org.ontoware.rdf2go.model.QueryResultTable;
016: import org.ontoware.rdf2go.model.Statement;
017: import org.ontoware.rdf2go.model.Syntax;
018: import org.ontoware.rdf2go.model.impl.DelegatingModel;
019: import org.ontoware.rdf2go.model.node.BlankNode;
020: import org.ontoware.rdf2go.model.node.Node;
021: import org.ontoware.rdf2go.model.node.NodeOrVariable;
022: import org.ontoware.rdf2go.model.node.Resource;
023: import org.ontoware.rdf2go.model.node.ResourceOrVariable;
024: import org.ontoware.rdf2go.model.node.URI;
025: import org.ontoware.rdf2go.model.node.UriOrVariable;
026: import org.ontoware.rdf2go.model.persistent.PersistentModel;
027: import org.slf4j.Logger;
028: import org.slf4j.LoggerFactory;
029:
030: /**
031: * Writes down the RDF model all n uncommited writes.
032: *
033: * @author voelkel
034: *
035: */
036: public class ModelImplAutoPersist extends DelegatingModel implements
037: PersistentModel {
038:
039: private File modelfile;
040:
041: private int openChanges = 0;
042:
043: private int allowedOpenChanges;
044:
045: public static final Syntax DEFAULT_SERIALISATION_LANGUAGE = Syntax.Turtle;
046:
047: private static Logger log = LoggerFactory
048: .getLogger(ModelImplAutoPersist.class);
049:
050: /**
051: *
052: * @param model
053: * a Model
054: * @param openChanges
055: * number of allowed uncommited writes. Setting this to 0 turns
056: * the model to a write-through model.
057: * @throws IOException
058: * @throws ModelImplException
059: */
060: public ModelImplAutoPersist(Model model, File modelfile,
061: int openChanges) throws ModelRuntimeException, IOException {
062: super ();
063:
064: // encodign!
065:
066: if (modelfile == null)
067: throw new IllegalArgumentException(
068: "A modelfile must be specified");
069: this .modelfile = modelfile;
070: if (!model.isOpen()) {
071: model.open();
072: }
073: super .setDelegatedModel(model);
074: this .allowedOpenChanges = openChanges;
075: load();
076: }
077:
078: @Override
079: public BlankNode createBlankNode() {
080: BlankNode bnode = super .createBlankNode();
081: checkChanges();
082: return bnode;
083: }
084:
085: public int openchanges() {
086: return this .openChanges;
087: }
088:
089: public void addAll(Iterator<? extends Statement> other)
090: throws ModelRuntimeException {
091: while (other.hasNext()) {
092: super .addStatement(other.next());
093: checkChanges();
094: }
095: }
096:
097: public void addStatement(Resource subject, URI predicate,
098: Node object) throws ModelRuntimeException {
099: super .addStatement(subject, predicate, object);
100: checkChanges();
101: }
102:
103: public void addStatement(String subjectURIString, URI predicate,
104: String literal) throws ModelRuntimeException {
105: super .addStatement(subjectURIString, predicate, literal);
106: checkChanges();
107: }
108:
109: public void removeStatement(Resource subject, URI predicate,
110: Node object) throws ModelRuntimeException {
111: super .removeStatement(subject, predicate, object);
112: checkChanges();
113: }
114:
115: public ClosableIterator<? extends Statement> findStatements(
116: ResourceOrVariable subject, UriOrVariable predicate,
117: NodeOrVariable object) throws ModelRuntimeException {
118: return super .findStatements(subject, predicate, object);
119: }
120:
121: public QueryResultTable sparqlSelect(String query)
122: throws ModelRuntimeException {
123: log.debug("delegating to a " + super .getClass());
124:
125: log.debug("model size: " + super .size());
126:
127: return super .sparqlSelect(query);
128: }
129:
130: public ClosableIterable<? extends Statement> sparqlConstruct(
131: String query) throws ModelRuntimeException {
132: return super .sparqlConstruct(query);
133: }
134:
135: public Model newInstance() throws ModelRuntimeException {
136: throw new UnsupportedOperationException(
137: "cannot instantiate two RDF2Go models on the same file");
138: }
139:
140: public Object getUnderlyingModelImplementation() {
141: return super .getUnderlyingModelImplementation();
142: }
143:
144: public void setUnderlyingModelImplementation(Object o) {
145: super .setUnderlyingModelImplementation(o);
146: }
147:
148: private void checkChanges() {
149: openChanges++;
150: if (openChanges > allowedOpenChanges) {
151: try {
152: log.info("Reached limit of " + allowedOpenChanges
153: + " open changes. Writing model to "
154: + modelfile.getCanonicalPath());
155: save(modelfile, DEFAULT_SERIALISATION_LANGUAGE);
156: openChanges = 0;
157: } catch (IOException e) {
158: throw new RuntimeException(e);
159: } catch (ModelRuntimeException e) {
160: throw new ModelRuntimeException(e);
161: }
162:
163: }
164: }
165:
166: public void save() throws ModelRuntimeException {
167: try {
168: save(modelfile, DEFAULT_SERIALISATION_LANGUAGE);
169: } catch (IOException e) {
170: throw new ModelRuntimeException(e);
171: }
172: }
173:
174: public void load() throws ModelRuntimeException {
175: assert modelfile != null;
176:
177: if (!modelfile.exists()) {
178: File tmpFile = getTmpFile(modelfile);
179: if (tmpFile.exists()) {
180: tmpFile.renameTo(modelfile);
181: log.warn("Restored data from temp file.");
182: }
183: }
184:
185: if (modelfile.exists())
186: try {
187: FileReader fr = new FileReader(modelfile);
188: assert fr != null;
189: try {
190: readFrom(fr, DEFAULT_SERIALISATION_LANGUAGE);
191: } catch (IOException e) {
192: log.error("exception might be an XML problem", e);
193: // exception might be an XML problem
194: throw new RuntimeException(e);
195: } finally {
196: try {
197: fr.close();
198: } catch (IOException e) {
199: throw new RuntimeException(e);
200: }
201: }
202: } catch (FileNotFoundException e) {
203: throw new RuntimeException(e);
204: }
205: }
206:
207: private static File getTmpFile(File f) {
208: return new File(f + ".tmp");
209: }
210:
211: private static File getOldFile(File f) {
212: return new File(f + ".old");
213: }
214:
215: public void save(File persistentFile, Syntax syntax)
216: throws IOException, ModelRuntimeException {
217:
218: // TODO use Jakarta IOUtils and macke a backup copy
219:
220: // file => old
221: File oldFile = getOldFile(persistentFile);
222: if (persistentFile.exists()) {
223: if (oldFile.exists())
224: oldFile.delete();
225: assert !oldFile.exists();
226:
227: boolean renamed = persistentFile.renameTo(oldFile);
228: assert renamed;
229: assert !persistentFile.exists();
230: assert oldFile.exists();
231: }
232:
233: // ...RDF... => tmp
234: File tmpFile = getTmpFile(persistentFile);
235: // make dirs
236: tmpFile.getParentFile().mkdirs();
237: if (tmpFile.exists())
238: tmpFile.delete();
239:
240: log.debug("writing");
241: FileWriter fw = new FileWriter(tmpFile);
242: super .getDelegatedModel().writeTo(fw, syntax);
243: fw.close();
244:
245: // tmp => file
246: assert tmpFile.exists();
247: // FIXME if the target file exists this might fail
248: persistentFile.delete();
249:
250: boolean renamed = tmpFile.renameTo(persistentFile);
251: assert renamed;
252: assert !tmpFile.exists();
253: assert persistentFile.exists();
254:
255: // del old
256: if (oldFile.exists())
257: oldFile.delete();
258: }
259:
260: /*
261: * (non-Javadoc)
262: *
263: * @see org.ontoware.rdf2go.core.triple.ModelWriter#addStatement(org.ontoware.rdf2go.core.node.Resource,
264: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
265: * java.lang.String)
266: */
267: public void addStatement(Resource subject, URI predicate,
268: String literal, String languageTag)
269: throws ModelRuntimeException {
270: super .addStatement(subject, predicate, literal, languageTag);
271: checkChanges();
272: }
273:
274: /*
275: * (non-Javadoc)
276: *
277: * @see org.ontoware.rdf2go.core.triple.ModelWriter#addStatement(org.ontoware.rdf2go.core.node.Resource,
278: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
279: * org.ontoware.rdf2go.core.node.URI)
280: */
281: public void addStatement(Resource subject, URI predicate,
282: String literal, URI datatypeURI)
283: throws ModelRuntimeException {
284: super .addStatement(subject, predicate, literal, datatypeURI);
285: checkChanges();
286: }
287:
288: /*
289: * (non-Javadoc)
290: *
291: * @see org.ontoware.rdf2go.core.triple.ModelWriter#addStatement(org.ontoware.rdf2go.core.node.Resource,
292: * org.ontoware.rdf2go.core.node.URI, java.lang.String)
293: */
294: public void addStatement(Resource subject, URI predicate,
295: String literal) throws ModelRuntimeException {
296: super .addStatement(subject, predicate, literal);
297: checkChanges();
298: }
299:
300: /*
301: * (non-Javadoc)
302: *
303: * @see org.ontoware.rdf2go.core.common.CommonModelWriter#addStatement(S)
304: */
305: public void addStatement(Statement statement)
306: throws ModelRuntimeException {
307: super .addStatement(statement);
308: checkChanges();
309: }
310:
311: /*
312: * (non-Javadoc)
313: *
314: * @see org.ontoware.rdf2go.core.triple.ModelWriter#addStatement(java.lang.String,
315: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
316: * java.lang.String)
317: */
318: public void addStatement(String subjectURIString, URI predicate,
319: String literal, String languageTag)
320: throws ModelRuntimeException {
321: super .addStatement(subjectURIString, predicate, literal,
322: languageTag);
323: checkChanges();
324: }
325:
326: /*
327: * (non-Javadoc)
328: *
329: * @see org.ontoware.rdf2go.core.triple.ModelWriter#addStatement(java.lang.String,
330: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
331: * org.ontoware.rdf2go.core.node.URI)
332: */
333: public void addStatement(String subjectURIString, URI predicate,
334: String literal, URI datatypeURI)
335: throws ModelRuntimeException {
336: super .addStatement(subjectURIString, predicate, literal,
337: datatypeURI);
338: checkChanges();
339: }
340:
341: /*
342: * (non-Javadoc)
343: *
344: * @see org.ontoware.rdf2go.core.common.CommonModel#newRandomUniqueURI()
345: */
346: public URI newRandomUniqueURI() {
347: URI u = super .newRandomUniqueURI();
348: checkChanges();
349: return u;
350: }
351:
352: /*
353: * (non-Javadoc)
354: *
355: * @see org.ontoware.rdf2go.core.common.CommonModelAddRemove#removeAll()
356: */
357: public void removeAll() throws ModelRuntimeException {
358: super .removeAll();
359: checkChanges();
360: }
361:
362: /*
363: * (non-Javadoc)
364: *
365: * @see org.ontoware.rdf2go.core.common.CommonModelAddRemove#removeAll(org.ontoware.rdf2go.core.common.CommonModelReader)
366: */
367: public void removeAll(Iterator<? extends Statement> other)
368: throws ModelRuntimeException {
369: super .removeAll(other);
370: checkChanges();
371: }
372:
373: /*
374: * (non-Javadoc)
375: *
376: * @see org.ontoware.rdf2go.core.common.CommonModelAddRemove#removeStatement(S)
377: */
378: public void removeStatement(Statement statement)
379: throws ModelRuntimeException {
380: super .removeStatement(statement);
381: checkChanges();
382: }
383:
384: /*
385: * (non-Javadoc)
386: *
387: * @see org.ontoware.rdf2go.core.common.CommonModel#setProperty(org.ontoware.rdf2go.core.node.URI,
388: * java.lang.Object)
389: */
390: public void setProperty(URI propertyURI, Object value) {
391: super .setProperty(propertyURI, value);
392: checkChanges();
393: }
394:
395: /*
396: * (non-Javadoc)
397: *
398: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(org.ontoware.rdf2go.core.node.Resource,
399: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
400: * java.lang.String)
401: */
402: public void removeStatement(Resource subject, URI predicate,
403: String literal, String languageTag)
404: throws ModelRuntimeException {
405: super .removeStatement(subject, predicate, literal, languageTag);
406: checkChanges();
407: }
408:
409: /*
410: * (non-Javadoc)
411: *
412: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(org.ontoware.rdf2go.core.node.Resource,
413: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
414: * org.ontoware.rdf2go.core.node.URI)
415: */
416: public void removeStatement(Resource subject, URI predicate,
417: String literal, URI datatypeURI)
418: throws ModelRuntimeException {
419: super .removeStatement(subject, predicate, literal, datatypeURI);
420: checkChanges();
421: }
422:
423: /*
424: * (non-Javadoc)
425: *
426: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(org.ontoware.rdf2go.core.node.Resource,
427: * org.ontoware.rdf2go.core.node.URI, java.lang.String)
428: */
429: public void removeStatement(Resource subject, URI predicate,
430: String literal) throws ModelRuntimeException {
431: super .removeStatement(subject, predicate, literal);
432: checkChanges();
433: }
434:
435: /*
436: * (non-Javadoc)
437: *
438: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(java.lang.String,
439: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
440: * java.lang.String)
441: */
442: public void removeStatement(String subjectURIString, URI predicate,
443: String literal, String languageTag)
444: throws ModelRuntimeException {
445: super .removeStatement(subjectURIString, predicate, literal,
446: languageTag);
447: checkChanges();
448: }
449:
450: /*
451: * (non-Javadoc)
452: *
453: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(java.lang.String,
454: * org.ontoware.rdf2go.core.node.URI, java.lang.String,
455: * org.ontoware.rdf2go.core.node.URI)
456: */
457: public void removeStatement(String subjectURIString, URI predicate,
458: String literal, URI datatypeURI)
459: throws ModelRuntimeException {
460: super .removeStatement(subjectURIString, predicate, literal,
461: datatypeURI);
462: checkChanges();
463: }
464:
465: /*
466: * (non-Javadoc)
467: *
468: * @see org.ontoware.rdf2go.core.triple.ModelAddRemove#removeStatement(java.lang.String,
469: * org.ontoware.rdf2go.core.node.URI, java.lang.String)
470: */
471: public void removeStatement(String subjectURIString, URI predicate,
472: String literal) throws ModelRuntimeException {
473: super .removeStatement(subjectURIString, predicate, literal);
474: checkChanges();
475: }
476:
477: public void update(Diff diff) throws ModelRuntimeException {
478: super .update(diff);
479: checkChanges();
480: }
481:
482: public void removeStatements(ResourceOrVariable subject,
483: UriOrVariable predicate, NodeOrVariable object)
484: throws ModelRuntimeException {
485: super.removeStatements(subject, predicate, object);
486: checkChanges();
487: }
488:
489: }
|