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.util;
012:
013: import java.io.File;
014: import java.io.FileInputStream;
015: import java.io.FileNotFoundException;
016: import java.io.FileOutputStream;
017: import java.io.FileReader;
018: import java.io.FileWriter;
019: import java.io.IOException;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import org.ontoware.aifbcommons.collection.ClosableIterator;
025: import org.ontoware.rdf2go.RDF2Go;
026: import org.ontoware.rdf2go.exception.ModelRuntimeException;
027: import org.ontoware.rdf2go.model.Model;
028: import org.ontoware.rdf2go.model.ModelSet;
029: import org.ontoware.rdf2go.model.Statement;
030: import org.ontoware.rdf2go.model.Syntax;
031: import org.ontoware.rdf2go.model.node.BlankNode;
032: import org.ontoware.rdf2go.model.node.Node;
033: import org.ontoware.rdf2go.model.node.Resource;
034:
035: /**
036: * Find a lot of convenience functions that are slow but nice and didn't make it
037: * to the Model API.
038: *
039: * @author voelkel
040: *
041: */
042: public class ModelUtils {
043:
044: /**
045: * Count statements in iterable 'it'
046: *
047: * @param it
048: * the iterable
049: * @return the size
050: */
051: public static int size(Iterable<?> it) {
052: int count = 0;
053: Iterator<?> i = it.iterator();
054: while (i.hasNext()) {
055: i.next();
056: count++;
057: }
058: return count;
059: }
060:
061: /**
062: * Count statements in iterator 'it'
063: *
064: * @param i
065: * the iterator
066: * @return the size
067: */
068: public static int size(Iterator<?> i) {
069: int count = 0;
070: while (i.hasNext()) {
071: i.next();
072: count++;
073: }
074: return count;
075: }
076:
077: /**
078: * Copy data from the source modelset to the target modelset. Iterates
079: * through all named models of the source and adds each to the target. If a
080: * named graph already exists in the target, the data will be added to it,
081: * target models will not be replaced.
082: *
083: * @param source
084: * the source, data from here is taken
085: * @param target
086: * the target, data will be put here.
087: * @throws ModelRuntimeException
088: * if the copying process has an error
089: */
090: public static void copy(ModelSet source, ModelSet target)
091: throws ModelRuntimeException {
092: for (Iterator<? extends Model> i = source.getModels(); i
093: .hasNext();) {
094: Model m = i.next();
095: m.open();
096: Model tm = target.getModel(m.getContextURI());
097: tm.open();
098: copy(m, tm);
099: }
100: // copy default model
101: Model m = source.getDefaultModel();
102: m.open();
103: Model tm = target.getDefaultModel();
104: tm.open();
105: copy(m, tm);
106: }
107:
108: /**
109: * If the two models come from different implementations, copying blank
110: * nodes needs special care
111: *
112: * @param source
113: * @param target
114: */
115: public static void copy(Model source, Model target) {
116: if (source.getUnderlyingModelImplementation().equals(
117: target.getUnderlyingModelImplementation().getClass())) {
118: // same implementation, use easy copy
119: ClosableIterator<Statement> it = source.iterator();
120: target.addAll(it);
121: it.close();
122: } else {
123: Map<String, BlankNode> bnodeSourceId2bnodeTarget = new HashMap<String, BlankNode>();
124: ClosableIterator<Statement> it = source.iterator();
125: while (it.hasNext()) {
126: Statement stmt = it.next();
127: boolean blankSubject = stmt.getSubject() instanceof BlankNode;
128: boolean blankObject = stmt.getObject() instanceof BlankNode;
129:
130: if (blankSubject || blankObject) {
131: Resource s;
132: if (blankSubject) {
133: s = transform(stmt.getSubject().asBlankNode(),
134: bnodeSourceId2bnodeTarget, target);
135: } else {
136: s = stmt.getSubject();
137: }
138:
139: Node o;
140: // use mapping from node-IDs in impl-source to blank nodes
141: // in impl-target
142: if (blankObject) {
143: o = transform(stmt.getObject().asBlankNode(),
144: bnodeSourceId2bnodeTarget, target);
145: } else {
146: o = stmt.getObject();
147: }
148: target.addStatement(s, stmt.getPredicate(), o);
149: } else {
150: target.addStatement(stmt);
151: }
152: }
153: it.close();
154: }
155:
156: }
157:
158: private static BlankNode transform(BlankNode source,
159: Map<String, BlankNode> map, Model target) {
160: String bnodeSourceId = source.getInternalID();
161: BlankNode bnodeTarget = map.get(bnodeSourceId);
162: if (bnodeTarget == null) {
163: bnodeTarget = target.createBlankNode();
164: map.put(bnodeSourceId, bnodeTarget);
165: }
166: return bnodeTarget;
167: }
168:
169: /**
170: * Remove data that is listed in the source modelset from the target
171: * modelset. Iterates through all named models of the source and removes the
172: * listed triples from the target.
173: *
174: * @param source
175: * the source, data from here is evaluated
176: * @param target
177: * the target, data contained in source and target are removed
178: * from here
179: * @throws ModelRuntimeException
180: * if the deleting process has an error
181: */
182: public static void removeFrom(ModelSet source, ModelSet target)
183: throws ModelRuntimeException {
184: // remove
185: ClosableIterator<? extends Model> it = source.getModels();
186:
187: while (it.hasNext()) {
188: Model m = it.next();
189: ClosableIterator<Statement> modelIt = m.iterator();
190: target.getModel(m.getContextURI()).removeAll(modelIt);
191: modelIt.close();
192: }
193: it.close();
194: // remove stuff contained in default model
195: ClosableIterator<Statement> modelIt = source.getDefaultModel()
196: .iterator();
197: target.getDefaultModel().removeAll(modelIt);
198: modelIt.close();
199: }
200:
201: /**
202: * @param a
203: * @param b
204: * @param result
205: * @return the result after executing the intersection
206: * @throws ModelRuntimeException
207: */
208: public static Model intersection(Model a, Model b, Model result)
209: throws ModelRuntimeException {
210: for (Statement s : a) {
211: if (b.contains(s)) {
212: result.addStatement(s);
213: }
214: }
215: return result;
216: }
217:
218: /**
219: * @param a
220: * @param b
221: * @param result
222: * @return the result after executing the union
223: * @throws ModelRuntimeException
224: */
225: public static Model union(Model a, Model b, Model result)
226: throws ModelRuntimeException {
227: ClosableIterator<Statement> it = a.iterator();
228: result.addAll(it);
229: it.close();
230: it = b.iterator();
231: result.addAll(it);
232: it.close();
233: return result;
234: }
235:
236: /**
237: * @param a
238: * @param b
239: * @param result
240: * @return the result after executing the complement of b in a (a\b)
241: * @throws ModelRuntimeException
242: */
243: public static Model complement(Model a, Model b, Model result)
244: throws ModelRuntimeException {
245: ClosableIterator<Statement> it = a.iterator();
246: result.addAll(it);
247: it.close();
248: it = b.iterator();
249: result.removeAll(it);
250: it.close();
251: return result;
252: }
253:
254: /**
255: * Convert the input file, interpreted in the inputSyntax to outputFile, in
256: * outputSyntax.
257: *
258: * @param in
259: * input File
260: * @param inSyntax
261: * @param out
262: * output File
263: * @param outSyntax
264: * @throws FileNotFoundException
265: */
266: public static void convert(File in, Syntax inSyntax, File out,
267: Syntax outSyntax) throws FileNotFoundException {
268: if (!in.exists())
269: throw new FileNotFoundException("Input file "
270: + in.getAbsolutePath() + " not found");
271:
272: if (!out.getParentFile().exists())
273: out.getParentFile().mkdirs();
274:
275: Model m = RDF2Go.getModelFactory().createModel();
276: m.open();
277: FileReader fr = null;
278: FileWriter fw = null;
279: try {
280: fr = new FileReader(in);
281: m.readFrom(fr, inSyntax);
282: fw = new FileWriter(out);
283: m.writeTo(fw, outSyntax);
284:
285: } catch (ModelRuntimeException e) {
286: throw new RuntimeException(e);
287: } catch (IOException e) {
288: throw new RuntimeException(e);
289: } finally {
290: if (fr != null)
291: try {
292: fr.close();
293: } catch (IOException e) {
294: throw new RuntimeException(e);
295: }
296: if (fw != null)
297: try {
298: fw.close();
299: } catch (IOException e) {
300: throw new RuntimeException(e);
301: }
302: }
303: m.close();
304: }
305:
306: /**
307: * @param in
308: * @param inSyntax
309: * @return a model with the content from 'in'. Model is open.
310: * @throws ModelRuntimeException
311: * @throws IOException
312: * @deprecated This method creates new models via RDF2Go. If multiple model
313: * factories are used, this might be wrong. Use instead public
314: * static void loadFromFile(File in, Syntax inSyntax, Model
315: * sinkModel)
316: */
317: @Deprecated
318: public static Model loadFromFile(File in, Syntax inSyntax)
319: throws ModelRuntimeException, IOException {
320: Model model = RDF2Go.getModelFactory().createModel();
321: model.open();
322: FileInputStream fin = new FileInputStream(in);
323: model.readFrom(fin, inSyntax);
324: return model;
325: }
326:
327: /**
328: * Convenience method to load data from file in in syntax inSyntax and write
329: * loaded triples to sinkModel.
330: *
331: * @param in
332: * @param inSyntax
333: * @param sinkModel
334: * where to write the loaded content. This model is not cleared.
335: * This model should be open.
336: * @return
337: * @throws ModelRuntimeException
338: * @throws IOException
339: */
340: public static void loadFromFile(File in, Syntax inSyntax,
341: Model sinkModel) throws ModelRuntimeException, IOException {
342: if (!sinkModel.isOpen())
343: throw new IllegalArgumentException("SinkModel must be open");
344: FileInputStream fin = new FileInputStream(in);
345: try {
346: sinkModel.readFrom(fin, inSyntax);
347: } finally {
348: if (fin != null)
349: fin.close();
350: }
351: }
352:
353: public static void writeToFile(Model model, File outFile,
354: Syntax outSyntax) throws ModelRuntimeException, IOException {
355: FileOutputStream fout = new FileOutputStream(outFile);
356: try {
357: model.writeTo(fout, outSyntax);
358: } finally {
359: if (fout != null)
360: fout.close();
361: }
362: }
363:
364: /**
365: * Merge all input files into one model and export to outfile in output
366: * syntax
367: *
368: * @throws IOException
369: * @throws ModelRuntimeException
370: */
371: public static void convert(File[] inFiles, Syntax[] inSyntax,
372: File out, Syntax outSyntax) throws ModelRuntimeException,
373: IOException {
374: Model merged = RDF2Go.getModelFactory().createModel();
375:
376: for (int i = 0; i < inFiles.length; i++) {
377: Model inModel = loadFromFile(inFiles[i], inSyntax[i]);
378: ClosableIterator<Statement> it = inModel.iterator();
379: merged.addAll(it);
380: it.close();
381: }
382: writeToFile(merged, out, outSyntax);
383: }
384: }
|