001: /*
002: * LICENSE INFORMATION
003: * Copyright (c) 2006 - 2007 Aduna and Deutsches Forschungszentrum fuer Kuenstliche Intelligenz DFKI GmbH.
004: * All rights reserved.
005: * Copyright 2005-2007 by FZI (http://www.fzi.de).
006: * Licensed under a BSD license (http://www.opensource.org/licenses/bsd-license.php)
007: * <OWNER> = Max Völkel
008: * <ORGANIZATION> = FZI Forschungszentrum Informatik Karlsruhe, Karlsruhe, Germany
009: * <YEAR> = 2007
010: *
011: * Project information at http://semweb4j.org/rdf2go
012: */
013: package org.ontoware.rdf2go.util;
014:
015: import java.io.BufferedReader;
016: import java.io.File;
017: import java.io.FileReader;
018: import java.io.PrintStream;
019: import java.io.Reader;
020: import java.util.Date;
021: import java.util.HashMap;
022:
023: import org.ontoware.aifbcommons.collection.ClosableIterator;
024: import org.ontoware.rdf2go.RDF2Go;
025: import org.ontoware.rdf2go.Reasoning;
026: import org.ontoware.rdf2go.model.Model;
027: import org.ontoware.rdf2go.model.Statement;
028: import org.ontoware.rdf2go.model.Syntax;
029: import org.ontoware.rdf2go.model.node.Node;
030: import org.ontoware.rdf2go.model.node.Resource;
031: import org.ontoware.rdf2go.model.node.URI;
032: import org.ontoware.rdf2go.model.node.Variable;
033: import org.ontoware.rdf2go.vocabulary.OWL;
034: import org.ontoware.rdf2go.vocabulary.RDF;
035: import org.ontoware.rdf2go.vocabulary.RDFS;
036:
037: /**
038: * reads an RDF/S file and creates an RDF2Go Vocabulary file from it.
039: *
040: * usage:
041: *
042: * <pre>
043: * VocabularyWriter -i <inputrdfsfile> -o <outputdir>
044: * --package <packagename> -a <namespace> -n <nameofjavafile>
045: * -namespacestrict <false|true>
046: *
047: * -namespacestrict If true, only elements from within the namespace (-a)
048: * are generated. Default false.
049: *
050: * Example values:
051: * --package org.semanticdesktop.aperture.outlook.vocabulary
052: * -o src/outlook/org/semanticdesktop/aperture/outlook/vocabulary/
053: * -i doc/ontology/data.rdfs
054: * -a http://aperture.semanticdesktop.org/ontology/data#
055: * -n DATA
056: *
057: *
058: * @author sauermann
059: * $Id: VocabularyWriter.java,v 1.14 2007/02/20 09:13:33 leo_sauermann Exp $
060: *
061: */
062: public class VocabularyWriter {
063:
064: String inputRdf = null;
065:
066: String outputDirName = null;
067:
068: String outputFileName = null;
069:
070: String ns = null;
071:
072: String packageName = null;
073:
074: Model model = null;
075:
076: // output stream
077: PrintStream outP;
078:
079: // transform variables
080: File inputRdfFile;
081:
082: File outputDirFile;
083:
084: File outputFile;
085:
086: boolean namespacestrict = false;
087:
088: // avoid duplicates
089: HashMap<String, String> uriToLocalName = new HashMap<String, String>();
090:
091: public VocabularyWriter() {
092: super ();
093: }
094:
095: public void go(String[] args) throws Exception {
096: getOpt(args);
097: loadOnt();
098: writeVocab();
099: }
100:
101: private void loadOnt() throws Exception {
102: // read
103: Syntax syntax = RDFTool.guessSyntax(this .inputRdfFile
104: .toString());
105: this .model = RDF2Go.getModelFactory().createModel(
106: Reasoning.none);
107: this .model.open();
108: System.out.println("reading from "
109: + this .inputRdfFile.getAbsolutePath() + " in format "
110: + syntax);
111: Reader reader = new BufferedReader(new FileReader(
112: this .inputRdfFile));
113: this .model.readFrom(reader, syntax);
114: reader.close();
115: }
116:
117: private void writeVocab() throws Exception {
118:
119: // prepare output
120: this .outP = new PrintStream(this .outputFile);
121: try {
122: // preamble
123: this .outP.println("package " + this .packageName + ";\n");
124: this .outP
125: .println("import org.ontoware.rdf2go.model.node.URI;");
126: this .outP
127: .println("import org.ontoware.rdf2go.model.node.impl.URIImpl;\n");
128: this .outP.println("/**");
129: this .outP.println(" * Vocabulary File. Created by "
130: + VocabularyWriter.class.getName() + " on "
131: + new Date());
132: this .outP.println(" * input file: " + this .inputRdf);
133: this .outP.println(" * namespace: " + this .ns);
134: this .outP.println(" */");
135: this .outP.println("public interface " + this .outputFileName
136: + " {");
137: this .outP.println(" public static final URI NS_"
138: + this .outputFileName + " = new URIImpl(\""
139: + this .ns + "\",false);\n");
140:
141: // iterate through classes
142: generateElement(RDFS.Class, false);
143: generateElement(OWL.Class, false);
144:
145: // iterate through properties
146: generateElement(RDF.Property, true);
147: generateElement(OWL.DatatypeProperty, true);
148: generateElement(OWL.ObjectProperty, true);
149:
150: // end
151: this .outP.println("}");
152: } finally {
153: this .outP.close();
154: }
155: System.out.println("successfully wrote file to "
156: + this .outputFile);
157: }
158:
159: public void generateElement(URI type, boolean isProperty)
160: throws Exception {
161: ClosableIterator<? extends Statement> queryC = this .model
162: .findStatements(Variable.ANY, RDF.type, type);
163: try {
164: while (queryC.hasNext()) {
165: Statement answer = queryC.next();
166: Resource rx = answer.getSubject();
167: // we do not create constants for blank nodes
168: if (!(rx instanceof URI))
169: continue;
170: URI vx = (URI) rx;
171: String uri = vx.toString();
172: // check URI once and for all
173: boolean valid = this .model.isValidURI(uri);
174: if (!valid) {
175: this .outP.println(" /* cannot export " + uri
176: + ", not a valid URI */");
177: } else {
178: String localName = getLocalName(vx);
179: String javalocalName = asLegalJavaID(localName,
180: !isProperty);
181: if (this .uriToLocalName.containsKey(uri))
182: continue;
183: this .uriToLocalName.put(uri, javalocalName);
184: // check namespace strict?
185: if (this .namespacestrict
186: && !uri.startsWith(this .ns))
187: continue;
188: this .outP.println(" /**");
189: printCommentAndLabel(vx);
190: this .outP.println(" */");
191: this .outP.println(" public static final URI "
192: + javalocalName + " = new URIImpl(\"" + uri
193: + "\", false);\n");
194: }
195: }
196: } finally {
197: queryC.close();
198: }
199: }
200:
201: /**
202: * The RDF2Go interface doesn't support getting a local name from the URI. I
203: * 'borrowed' this snippet from the Sesame LiteralImpl.
204: */
205: private String getLocalName(URI vx) {
206: String fullUri = vx.toString();
207: int splitIdx = fullUri.indexOf('#');
208:
209: if (splitIdx < 0) {
210: splitIdx = fullUri.lastIndexOf('/');
211: }
212:
213: if (splitIdx < 0) {
214: splitIdx = fullUri.lastIndexOf(':');
215: }
216:
217: if (splitIdx < 0) {
218: throw new RuntimeException("Not a legal (absolute) URI: "
219: + fullUri);
220: }
221: return fullUri.substring(splitIdx + 1);
222: }
223:
224: /**
225: * print comment and label of the uri to the passed stream
226: *
227: * @param uri
228: */
229: public void printCommentAndLabel(URI uri) throws Exception {
230:
231: ClosableIterator<? extends Statement> queryC = this .model
232: .findStatements(uri, RDFS.label, Variable.ANY);
233: try {
234: StringBuffer lBuf = new StringBuffer();
235: while (queryC.hasNext()) {
236: Statement answer = queryC.next();
237: Node vl = answer.getObject();
238: lBuf.append(vl.toString().concat(" "));
239: }
240: String l = lBuf.toString();
241: if (l.length() > 0)
242: this .outP.println(" * Label: " + l);
243: } finally {
244: queryC.close();
245: }
246:
247: queryC = this .model.findStatements(uri, RDFS.comment,
248: Variable.ANY);
249: try {
250: String l = "";
251: while (queryC.hasNext()) {
252: Statement answer = queryC.next();
253: Node vl = answer.getObject();
254: l += vl.toString() + " ";
255: }
256: if (l.length() > 0)
257: this .outP.println(" * Comment: " + l);
258: } finally {
259: queryC.close();
260: }
261:
262: queryC = this .model.findStatements(uri, RDFS.domain,
263: Variable.ANY);
264: try {
265: String l = "";
266: while (queryC.hasNext()) {
267: Statement answer = queryC.next();
268: Node vl = answer.getObject();
269: l += vl.toString() + " ";
270: }
271: if (l.length() > 0)
272: this .outP.println(" * Comment: " + l);
273: } finally {
274: queryC.close();
275: }
276:
277: queryC = this .model.findStatements(uri, RDFS.range,
278: Variable.ANY);
279: try {
280: String l = "";
281: while (queryC.hasNext()) {
282: Statement answer = queryC.next();
283: Node vl = answer.getObject();
284: l += vl.toString() + " ";
285: }
286: if (l.length() > 0)
287: this .outP.println(" * Range: " + l);
288: } finally {
289: queryC.close();
290: }
291: }
292:
293: public void getOpt(String[] args) throws Exception {
294: int i = 0;
295: if (args.length == 0) {
296: help();
297: throw new Exception("no arguments given");
298: }
299: // args
300: while ((i < args.length) && args[i].startsWith("-")) {
301: if (args[i].equals("-i")) {
302: i++;
303: this .inputRdf = args[i];
304: } else if (args[i].equals("-o")) {
305: i++;
306: this .outputDirName = args[i];
307: } else if (args[i].equals("-a")) {
308: i++;
309: this .ns = args[i];
310: } else if (args[i].equals("-n")) {
311: i++;
312: this .outputFileName = args[i];
313: } else if (args[i].equals("--package")) {
314: i++;
315: this .packageName = args[i];
316: } else if (args[i].equals("-namespacestrict")) {
317: i++;
318: String s = args[i];
319: if ("false".equals(s))
320: this .namespacestrict = false;
321: else if ("true".equals(s))
322: this .namespacestrict = true;
323: else
324: throw new Exception(
325: "namespacestrict only allows 'true' or 'false', not '"
326: + s + "'");
327:
328: } else
329: throw new Exception("unknow argument " + args[i]);
330: i++;
331: }
332:
333: if (this .inputRdf == null)
334: usage("no input file given");
335: if (this .outputDirName == null)
336: usage("no output dir given");
337: if (this .ns == null)
338: usage("no namespace given");
339: if (this .outputFileName == null)
340: usage("no output classname given");
341: if (this .packageName == null)
342: usage("no package name given");
343:
344: // transform variables
345: this .inputRdfFile = new File(this .inputRdf);
346: this .outputDirFile = new File(this .outputDirName);
347: this .outputFile = new File(this .outputDirFile,
348: this .outputFileName + ".java");
349: }
350:
351: private void help() {
352: System.err
353: .println("Syntax: java VocabularyWriter -i inputfile -o outputdir -a namespace -n classname --package package ");
354: }
355:
356: /**
357: * documentation see class, above.
358: */
359: public static void main(String[] args) throws Exception {
360: new VocabularyWriter().go(args);
361:
362: }
363:
364: /**
365: * Convert s to a legal Java identifier; capitalise first char if cap is
366: * true this method is copied from jena code.
367: */
368: protected String asLegalJavaID(String s, boolean cap) {
369: StringBuilder buf = new StringBuilder();
370: int i = 0;
371:
372: // treat the first character specially - must be able to start a Java
373: // ID, may have to upcase
374: try {
375: for (; !Character.isJavaIdentifierStart(s.charAt(i)); i++) {
376: // TODO (xamde from wth, 11.07.2007) WHY IS THIS BLOCK EMPTY?
377: //if this is fine, please document why
378: }
379: } catch (StringIndexOutOfBoundsException e) {
380: System.err
381: .println("Could not identify legal Java identifier start character in '"
382: + s + "', replacing with __");
383: return "__";
384: }
385: buf.append(cap ? Character.toUpperCase(s.charAt(i)) : s
386: .charAt(i));
387:
388: // copy the remaining characters - replace non-legal chars with '_'
389: for (++i; i < s.length(); i++) {
390: char c = s.charAt(i);
391: buf.append(Character.isJavaIdentifierPart(c) ? c : '_');
392: }
393:
394: // check standard name
395: String result = buf.toString();
396: if (result.equals("class") || result.equals("abstract"))
397: result = result + "_";
398: return result;
399: }
400:
401: private static void usage(String string) throws Exception {
402: throw new Exception(string);
403: }
404:
405: }
|