001: /*
002: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * [See end of file]
004: */
005:
006: package com.hp.hpl.jena.n3;
007:
008: import org.apache.commons.logging.Log;
009: import org.apache.commons.logging.LogFactory;
010:
011: import com.hp.hpl.jena.JenaRuntime;
012: import com.hp.hpl.jena.util.iterator.*;
013: import com.hp.hpl.jena.rdf.model.*;
014: import com.hp.hpl.jena.shared.JenaException;
015: import com.hp.hpl.jena.vocabulary.OWL;
016: import com.hp.hpl.jena.vocabulary.XSD;
017: import com.hp.hpl.jena.vocabulary.RDF;
018:
019: import java.util.*;
020: import java.io.*;
021: import java.math.BigDecimal;
022: import java.net.URI;
023: import java.net.URISyntaxException;
024: import java.text.*;
025:
026: /** Common framework for implementing N3 writers.
027: *
028: * @author Andy Seaborne
029: * @version $Id: N3JenaWriterCommon.java,v 1.41 2008/02/08 16:13:20 andy_seaborne Exp $
030: */
031:
032: public class N3JenaWriterCommon implements RDFWriter {
033: static Log logger = LogFactory.getLog(N3JenaWriterCommon.class);
034:
035: // N3 writing proceeds in 2 stages.
036: // First, it analysis the model to be written to extract information
037: // that is going to be specially formatted (RDF lists, one ref anon nodes)
038: // Second do the writing walk.
039:
040: // The simple N3 writer does nothing during preparation.
041:
042: Map writerPropertyMap = null;
043:
044: // BaseURI - <#>
045: // final boolean doAbbreviatedBaseURIref = getBooleanValue("abbrevBaseURI", true) ;
046: boolean alwaysAllocateBNodeLabel = false;
047:
048: // Common variables
049: RDFErrorHandler errorHandler = null;
050:
051: static final String NS_W3_log = "http://www.w3.org/2000/10/swap/log#";
052:
053: Map prefixMap = new HashMap(); // Prefixes to actually use
054: Map bNodesMap = null; // BNodes seen.
055: int bNodeCounter = 0;
056:
057: // Specific properties that have a short form.
058: static Map wellKnownPropsMap = new HashMap();
059: static {
060: wellKnownPropsMap.put(NS_W3_log + "implies", "=>");
061: wellKnownPropsMap.put(OWL.sameAs.getURI(), "=");
062: wellKnownPropsMap.put(RDF.type.getURI(), "a");
063: }
064:
065: // Work variables controlling the output
066: IndentedWriter out = null;
067: //Removed base URI specials - look for "// BaseURI - <#>" & doAbbreviatedBaseURIref
068: //String baseURIref = null ;
069: //String baseURIrefHash = null ;
070:
071: // Min spacing of items
072: int minGap = getIntValue("minGap", 1);
073: String minGapStr = pad(minGap);
074:
075: // Gap from subject to property
076: int indentProperty = getIntValue("indentProperty", 6);
077:
078: // Width of property before wrapping.
079: // This is not necessarily a control of total width
080: // e.g. the pretty writer may be writing properties inside indented one ref bNodes
081: int widePropertyLen = getIntValue("widePropertyLen", 20);
082:
083: // Column for property when an object follows a property on the same line
084: int propertyCol = getIntValue("propertyColumn", 8);
085:
086: // Minimum gap from property to object when object on a new line.
087: int indentObject = propertyCol;
088:
089: // If a subject is shorter than this, the first property may go on same line.
090: int subjectColumn = getIntValue("subjectColumn", indentProperty);
091: // Require shortSubject < subjectCol (strict less than)
092: int shortSubject = subjectColumn - minGap;
093:
094: boolean useWellKnownPropertySymbols = getBooleanValue(
095: "usePropertySymbols", true);
096:
097: boolean allowTripleQuotedStrings = getBooleanValue(
098: "useTripleQuotedStrings", true);
099: boolean allowDoubles = getBooleanValue("useDoubles", true);
100: boolean allowDecimals = getBooleanValue("useDecimals", true);
101:
102: // ----------------------------------------------------
103: // Jena RDFWriter interface
104:
105: public RDFErrorHandler setErrorHandler(RDFErrorHandler errHandler) {
106: RDFErrorHandler old = errorHandler;
107: errorHandler = errHandler;
108: return old;
109: }
110:
111: public Object setProperty(String propName, Object propValue) {
112: if (!(propValue instanceof String)) {
113: logger.warn("N3.setProperty: Property for '" + propName
114: + "' is not a string");
115: propValue = propValue.toString();
116: }
117:
118: // Store absolute name of property
119: propName = absolutePropName(propName);
120: if (writerPropertyMap == null)
121: writerPropertyMap = new HashMap();
122: Object oldValue = writerPropertyMap.get(propName);
123: writerPropertyMap.put(propName, propValue);
124: return oldValue;
125: }
126:
127: /** Write the model out in N3. The writer should be one suitable for UTF-8 which
128: * excludes a PrintWriter or a FileWriter which use default character set.
129: *
130: * Examples:
131: * <pre>
132: * try {
133: * Writer w = new BufferedWriter(new OutputStreamWriter(output, "UTF-8")) ;
134: * model.write(w, base) ;
135: * try { w.flush() ; } catch (IOException ioEx) {}
136: * } catch (java.io.UnsupportedEncodingException ex) {} //UTF-8 is required so can't happen
137: * </pre>
138: * or
139: * <pre>
140: * try {
141: * OutputStream out = new FileOutputStream(file) ;
142: * Writer w = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")) ;
143: * model.write(w, base) ;
144: * }
145: * catch (java.io.UnsupportedEncodingException ex) {}
146: * catch (java.io.FileNotFoundException noFileEx) { ... }
147: * </pre>
148: * @see #write(Model,Writer,String)
149: */
150:
151: public void write(Model baseModel, Writer _out, String base) {
152: if (!(_out instanceof BufferedWriter))
153: _out = new BufferedWriter(_out);
154: out = new IndentedWriter(_out);
155:
156: // BaseURI - <#>
157: // if ( base != null )
158: // {
159: // baseURIref = base ;
160: // if ( !base.endsWith("#") &&! isOpaque(base) )
161: // baseURIrefHash = baseURIref+"#" ;
162: // }
163:
164: processModel(baseModel);
165: }
166:
167: /** Write the model out in N3, encoded in in UTF-8
168: * @see #write(Model,Writer,String)
169: */
170:
171: public synchronized void write(Model model, OutputStream output,
172: String base) {
173: try {
174: Writer w = new BufferedWriter(new OutputStreamWriter(
175: output, "UTF-8"));
176: write(model, w, base);
177: try {
178: w.flush();
179: } catch (IOException ioEx) {
180: }
181: } catch (java.io.UnsupportedEncodingException ex) {
182: System.err.println("Failed to create UTF-8 writer");
183: }
184: }
185:
186: // ----------------------------------------------------
187: // The assumed processing model is:
188: // Writing N3 involves ordering the graph into:
189: // -- Subjects
190: // -- Property lists within subjects
191: // -- Object lists with in properties
192:
193: // A derived class may choose to intercept and implement at any of these levels.
194:
195: // Standard layout is:
196: // subject
197: // property1 value1 ;
198: // property2 value2 ;
199: // property3 value3 .
200:
201: // Normal hook points for subclasses.
202:
203: protected void startWriting() {
204: }
205:
206: protected void finishWriting() {
207: }
208:
209: protected void prepare(Model model) {
210: }
211:
212: protected void processModel(Model baseModel) {
213: prefixMap = baseModel.getNsPrefixMap();
214: Model model = ModelFactory.withHiddenStatements(baseModel);
215: bNodesMap = new HashMap();
216:
217: // If no base defined for the model, but one given to writer,
218: // then use this.
219: String base2 = (String) prefixMap.get("");
220:
221: // BaseURI - <#>
222: // if ( base2 == null && baseURIrefHash != null )
223: // prefixMap.put("", baseURIrefHash) ;
224:
225: for (Iterator iter = prefixMap.keySet().iterator(); iter
226: .hasNext();) {
227: String prefix = (String) iter.next();
228: if (prefix.indexOf('.') != -1)
229: iter.remove();
230: }
231:
232: startWriting();
233: prepare(model);
234:
235: writeHeader(model);
236: writePrefixes(model);
237:
238: if (prefixMap.size() != 0)
239: out.println();
240:
241: // Do the output.
242: writeModel(model);
243:
244: // Release intermediate memory - allows reuse of a writer
245: finishWriting();
246: bNodesMap = null;
247: }
248:
249: protected void writeModel(Model model) {
250: // Needed only for no prefixes, no blank first line.
251: boolean doingFirst = true;
252: ResIterator rIter = listSubjects(model);
253: for (; rIter.hasNext();) {
254: // Subject:
255: // First - it is something we will write out as a structure in an object field?
256: // That is, a RDF list or the object of exactly one statement.
257: Resource subject = rIter.nextResource();
258: if (skipThisSubject(subject)) {
259: if (N3JenaWriter.DEBUG)
260: out.println("# Skipping: "
261: + formatResource(subject));
262: continue;
263: }
264:
265: // We really are going to print something via writeTriples
266: if (doingFirst)
267: doingFirst = false;
268: else
269: out.println();
270:
271: writeOneGraphNode(subject);
272:
273: }
274: rIter.close();
275: }
276:
277: protected ResIterator listSubjects(Model model) {
278: return model.listSubjects();
279: }
280:
281: protected void writeOneGraphNode(Resource subject) {
282: // New top level item.
283: // Does not take effect until newline.
284: out.incIndent(indentProperty);
285: writeSubject(subject);
286: ClosableIterator iter = preparePropertiesForSubject(subject);
287: writePropertiesForSubject(subject, iter);
288: out.decIndent(indentProperty);
289: out.println(" .");
290: }
291:
292: protected void writePropertiesForSubject(Resource subj,
293: ClosableIterator iter) {
294: // For each property.
295: for (; iter.hasNext();) {
296: Property property = (Property) iter.next();
297:
298: // Object list
299: writeObjectList(subj, property);
300:
301: if (iter.hasNext())
302: out.println(" ;");
303: }
304: iter.close();
305: }
306:
307: // Hook called on every resource.
308: // Since there is spacing bewteen resource frames, need to know
309: // whether an item will cause any output.
310: protected boolean skipThisSubject(Resource r) {
311: return false;
312: }
313:
314: // This is the hook called within writeModel.
315: // NB May not be at the top level (indent = 0)
316:
317: protected void writeSubject(Resource subject) {
318: String subjStr = formatResource(subject);
319: out.print(subjStr);
320: // May be very short : if so, stay on this line.
321:
322: // Currently at end of subject.
323: // NB shortSubject is (subjectColumn-minGap) so there is a gap.
324:
325: if (subjStr.length() < shortSubject) {
326: out.print(pad(subjectColumn - subjStr.length()));
327: } else
328: // Does not fit this line.
329: out.println();
330: }
331:
332: protected void writeHeader(Model model) {
333: // BaseURI - <#>
334: // if (baseURIref != null && !baseURIref.equals("") )
335: // out.println("# Base: " + baseURIref);
336: }
337:
338: protected IndentedWriter getOutput() {
339: return out;
340: }
341:
342: protected Map getPrefixes() {
343: return prefixMap;
344: }
345:
346: protected void writePrefixes(Model model) {
347: for (Iterator pIter = prefixMap.keySet().iterator(); pIter
348: .hasNext();) {
349: String p = (String) pIter.next();
350: String u = (String) prefixMap.get(p);
351:
352: // BaseURI - <#>
353: // // Special cases: N3 handling of base names.
354: // if (doAbbreviatedBaseURIref && p.equals(""))
355: // {
356: // if (baseURIrefHash != null && u.equals(baseURIrefHash))
357: // u = "#";
358: // if (baseURIref != null && u.equals(baseURIref))
359: // u = "";
360: // }
361:
362: String tmp = "@prefix " + p + ": ";
363: out.print(tmp);
364: out.print(pad(16 - tmp.length()));
365: // NB Starts with a space to ensure a gap.
366: out.println(" <" + u + "> .");
367: }
368:
369: }
370:
371: protected void writeObjectList(Resource subject, Property property) {
372: String propStr = formatProperty(property);
373:
374: // if (wellKnownPropsMap.containsKey(property.getURI()))
375: // propStr = (String) wellKnownPropsMap.get(property.getURI());
376: // else
377: // propStr = formatResource(property);
378:
379: // Write with object lists as clusters of statements with the same property
380: // Looks more like a machine did it but fewer bad cases.
381:
382: StmtIterator sIter = subject.listProperties(property);
383: for (; sIter.hasNext();) {
384: Statement stmt = sIter.nextStatement();
385: String objStr = formatNode(stmt.getObject());
386:
387: out.print(propStr);
388: out.incIndent(indentObject);
389:
390: if ((propStr.length() + minGap) <= widePropertyLen) {
391: // Property col allows for min gap but widePropertyLen > propertyCol
392: // (which looses alignment - this is intentional.
393: // Ensure there is at least min gap.
394:
395: int padding = calcPropertyPadding(propStr);
396: out.print(pad(padding));
397:
398: // if ( propStr.length() < propertyWidth )
399: // out.print( pad(propertyCol-minGap-propStr.length()) ) ;
400: // out.print(minGapStr) ;
401: } else
402: // Does not fit this line.
403: out.println();
404:
405: // Write one object - simple writing.
406:
407: out.print(objStr);
408: out.decIndent(indentObject);
409:
410: if (sIter.hasNext()) {
411: out.println(" ;");
412: }
413: }
414: sIter.close();
415:
416: }
417:
418: protected String formatNode(RDFNode node) {
419: if (node instanceof Literal)
420: return formatLiteral((Literal) node);
421: else
422: return formatResource((Resource) node);
423: }
424:
425: protected void writeObject(RDFNode node) {
426: if (node instanceof Literal) {
427: writeLiteral((Literal) node);
428: return;
429: }
430:
431: Resource rObj = (Resource) node;
432:
433: out.print(formatResource(rObj));
434: }
435:
436: protected void writeLiteral(Literal literal) {
437: out.print(formatLiteral(literal));
438: }
439:
440: protected ClosableIterator preparePropertiesForSubject(Resource r) {
441: // Properties to do.
442: Set properties = new HashSet();
443:
444: StmtIterator sIter = r.listProperties();
445: for (; sIter.hasNext();)
446: properties.add(sIter.nextStatement().getPredicate());
447: sIter.close();
448: return WrappedIterator.create(properties.iterator());
449: }
450:
451: // Utility operations
452: protected String formatResource(Resource r) {
453: if (r.isAnon()) {
454: if (!alwaysAllocateBNodeLabel) {
455: // Does anything point to it?
456: StmtIterator sIter = r.getModel().listStatements(null,
457: null, r);
458:
459: if (!sIter.hasNext()) {
460: sIter.close();
461: // This bNode is not referenced so don't need the bNode Id.
462: // Must be a subject - indent better be zero!
463: // This only happens for subjects because object bNodes
464: // referred to once (the other case for [] syntax)
465: // are handled elsewhere (by oneRef set)
466:
467: // Later: use [ prop value ] for this.
468: return "[]";
469: }
470: sIter.close();
471: }
472: if (!bNodesMap.containsKey(r))
473: bNodesMap.put(r, "_:b" + (++bNodeCounter));
474: return (String) bNodesMap.get(r);
475:
476: }
477:
478: // It has a URI.
479:
480: if (r.equals(RDF.nil))
481: return "()";
482:
483: return formatURI(r.getURI());
484: }
485:
486: protected String formatLiteral(Literal literal) {
487: String datatype = literal.getDatatypeURI();
488: String lang = literal.getLanguage();
489: String s = literal.getLexicalForm();
490:
491: if (datatype != null) {
492: // Special form we know how to handle?
493: // Assume valid text
494: if (datatype.equals(XSD.integer.getURI())) {
495: try {
496: new java.math.BigInteger(s);
497: return s;
498: } catch (NumberFormatException nfe) {
499: }
500: // No luck. Continue.
501: // Continuing is always safe.
502: }
503:
504: if (datatype.equals(XSD.decimal.getURI())) {
505: // Must have ., can't have e or E
506: if (s.indexOf('.') >= 0 && s.indexOf('e') == -1
507: && s.indexOf('E') == -1) {
508: // See if parsable.
509: try {
510: BigDecimal d = new BigDecimal(s);
511: return s;
512: } catch (NumberFormatException nfe) {
513: }
514: }
515: }
516:
517: if (this .allowDoubles
518: && datatype.equals(XSD.xdouble.getURI())) {
519: // Must have 'e' or 'E' (N3 and Turtle now read 2.3 as a decimal).
520: if (s.indexOf('e') >= 0 || s.indexOf('E') >= 0) {
521: try {
522: // Validate it.
523: Double.parseDouble(s);
524: return s;
525: } catch (NumberFormatException nfe) {
526: }
527: // No luck. Continue.
528: }
529: }
530: }
531: // Format the text - with escaping.
532: StringBuffer sbuff = new StringBuffer();
533: boolean singleQuoteLiteral = true;
534:
535: String quoteMarks = "\"";
536:
537: // Things that force the use of """ strings
538: if (this .allowTripleQuotedStrings
539: && (s.indexOf("\n") != -1 || s.indexOf("\r") != -1 || s
540: .indexOf("\f") != -1)) {
541: quoteMarks = "\"\"\"";
542: singleQuoteLiteral = false;
543: }
544:
545: sbuff.append(quoteMarks);
546: string(sbuff, s, singleQuoteLiteral);
547: sbuff.append(quoteMarks);
548:
549: // Format the language tag
550: if (lang != null && lang.length() > 0) {
551: sbuff.append("@");
552: sbuff.append(lang);
553: }
554:
555: // Format the datatype
556: if (datatype != null) {
557: sbuff.append("^^");
558: sbuff.append(formatURI(datatype));
559: }
560: return sbuff.toString();
561: }
562:
563: protected String formatProperty(Property p) {
564: String prop = p.getURI();
565: if (this .useWellKnownPropertySymbols
566: && wellKnownPropsMap.containsKey(prop))
567: return (String) wellKnownPropsMap.get(prop);
568:
569: return formatURI(prop);
570: }
571:
572: protected String formatURI(String uriStr) {
573: String matchURI = "";
574: String matchPrefix = null;
575:
576: // BaseURI - <#>
577: // if ( doAbbreviatedBaseURIref && uriStr.equals(baseURIref) )
578: // return "<>" ;
579:
580: // Try for a prefix and write as qname. Find the longest if several.
581: // Possible optimization: split URI and have URI=> ns: map.
582: // Ordering prefixes by length, then first hit is better.
583: //
584: // Also: could just assume that the split is on / or #
585: // Means we need to find a prefix just once.
586: for (Iterator pIter = prefixMap.keySet().iterator(); pIter
587: .hasNext();) {
588: String p = (String) pIter.next();
589: String u = (String) prefixMap.get(p);
590: if (uriStr.startsWith(u))
591: if (matchURI.length() < u.length()) {
592: matchPrefix = p;
593: matchURI = u;
594: }
595: }
596: if (matchPrefix != null) {
597: String localname = uriStr.substring(matchURI.length());
598:
599: if (checkQName(matchPrefix, localname))
600: return matchPrefix + ":" + localname;
601:
602: // Continue and return quoted URIref
603: }
604:
605: // Not as a qname - write as a quoted URIref
606: // Should we unicode escape here?
607: // It should be right - the writer should be UTF-8 on output.
608: return "<" + uriStr + ">";
609: }
610:
611: // Qnames in N3 aren't really qnames
612: // No dots; digit can be first
613: // These tests must agree, or be more restrictive, than the parser.
614: static boolean checkQName(String ns, String local) {
615: return checkQNameNamespace(ns) && checkQNameLocalname(local);
616: }
617:
618: static boolean checkQNameNamespace(String s) {
619: return checkQNamePart(s);
620: }
621:
622: static boolean checkQNameLocalname(String s) {
623: return checkQNamePart(s);
624: }
625:
626: static boolean checkQNamePart(String s) {
627: boolean isOK = true;
628: CharacterIterator cIter = new StringCharacterIterator(s);
629:
630: for (char ch = cIter.first(); ch != java.text.CharacterIterator.DONE; ch = cIter
631: .next()) {
632: if (Character.isLetterOrDigit(ch))
633: continue;
634: switch (ch) {
635: case '_':
636: case '-':
637: continue;
638: }
639: // Not an acceptable characters
640: isOK = false;
641: break;
642: }
643: return isOK;
644: }
645:
646: final static String WS = "\n\r\t";
647:
648: protected static void string(StringBuffer sbuff, String s,
649: boolean singleQuoteLiteral) {
650: for (int i = 0; i < s.length(); i++) {
651: char c = s.charAt(i);
652:
653: // Escape escapes and quotes
654: if (c == '\\' || c == '"') {
655: sbuff.append('\\');
656: sbuff.append(c);
657: continue;
658: }
659:
660: // Characters to literally output.
661: // This would generate 7-bit safe files
662: // if (c >= 32 && c < 127)
663: // {
664: // sbuff.append(c) ;
665: // continue;
666: // }
667:
668: // Whitespace
669: if (singleQuoteLiteral
670: && (c == '\n' || c == '\r' || c == '\f')) {
671: if (c == '\n')
672: sbuff.append("\\n");
673: if (c == '\t')
674: sbuff.append("\\t");
675: if (c == '\r')
676: sbuff.append("\\r");
677: if (c == '\f')
678: sbuff.append("\\f");
679: continue;
680: }
681:
682: // Output as is (subject to UTF-8 encoding on output that is)
683: sbuff.append(c);
684:
685: // // Unicode escapes
686: // // c < 32, c >= 127, not whitespace or other specials
687: // String hexstr = Integer.toHexString(c).toUpperCase();
688: // int pad = 4 - hexstr.length();
689: // sbuff.append("\\u");
690:// for (; pad > 0; pad--)
691: // sbuff.append("0");
692: // sbuff.append(hexstr);
693: }
694: }
695:
696: protected int calcPropertyPadding(String propStr) {
697: int padding = propertyCol - propStr.length();
698: if (padding < minGap)
699: padding = minGap;
700: return padding;
701: }
702:
703: protected static String pad(int cols) {
704: StringBuffer sb = new StringBuffer();
705: for (int i = 0; i < cols; i++)
706: sb.append(' ');
707: return sb.toString();
708: }
709:
710: // Utilities
711:
712: protected int countProperties(Resource r) {
713: int numProp = 0;
714: StmtIterator sIter = r.listProperties();
715: for (; sIter.hasNext();) {
716: sIter.nextStatement();
717: numProp++;
718: }
719: sIter.close();
720: return numProp;
721: }
722:
723: protected int countProperties(Resource r, Property p) {
724: int numProp = 0;
725: StmtIterator sIter = r.listProperties(p);
726: for (; sIter.hasNext();) {
727: sIter.nextStatement();
728: numProp++;
729: }
730: sIter.close();
731: return numProp;
732: }
733:
734: protected int countArcsTo(Resource resource) {
735: return countArcsTo(null, resource);
736: }
737:
738: protected int countArcsTo(Property prop, Resource resource) {
739: int numArcs = 0;
740: StmtIterator sIter = resource.getModel().listStatements(null,
741: prop, resource);
742: for (; sIter.hasNext();) {
743: sIter.nextStatement();
744: numArcs++;
745: }
746: sIter.close();
747: return numArcs;
748: }
749:
750: protected Iterator rdfListIterator(Resource r) {
751: List list = new ArrayList();
752:
753: for (; !r.equals(RDF.nil);) {
754: StmtIterator sIter = r.getModel().listStatements(r,
755: RDF.first, (RDFNode) null);
756: list.add(sIter.nextStatement().getObject());
757: if (sIter.hasNext())
758: // @@ need to cope with this (unusual) case
759: throw new JenaException("N3: Multi valued list item");
760: sIter = r.getModel().listStatements(r, RDF.rest,
761: (RDFNode) null);
762: r = (Resource) sIter.nextStatement().getObject();
763: if (sIter.hasNext())
764: throw new JenaException("N3: List has two tails");
765: }
766: return list.iterator();
767: }
768:
769: // Convenience operations for accessing system properties.
770:
771: protected String getStringValue(String prop, String defaultValue) {
772: String p = getPropValue(prop);
773:
774: if (p == null)
775: return defaultValue;
776: return p;
777: }
778:
779: protected boolean getBooleanValue(String prop, boolean defaultValue) {
780: String p = getPropValue(prop);
781:
782: if (p == null)
783: return defaultValue;
784:
785: if (p.equalsIgnoreCase("true"))
786: return true;
787:
788: if (p.equals("1"))
789: return true;
790:
791: return false;
792: }
793:
794: protected int getIntValue(String prop, int defaultValue) {
795: String p = getPropValue(prop);
796: if (p == null)
797: return defaultValue;
798: try {
799: return Integer.parseInt(p);
800: } catch (NumberFormatException ex) {
801: logger.warn("Format error for property: " + prop);
802: return defaultValue;
803: }
804: }
805:
806: // May be the absolute or local form of the property name
807:
808: protected String getPropValue(String prop) {
809: prop = absolutePropName(prop);
810: if (writerPropertyMap != null
811: && writerPropertyMap.containsKey(prop)) {
812: Object obj = writerPropertyMap.get(prop);
813: if (!(obj instanceof String))
814: logger.warn("getPropValue: N3 Property for '" + prop
815: + "' is not a string");
816: return (String) obj;
817: }
818: String s = JenaRuntime.getSystemProperty(prop);
819: if (s == null)
820: s = JenaRuntime.getSystemProperty(localPropName(prop));
821: return s;
822: }
823:
824: protected String absolutePropName(String propName) {
825: if (propName.indexOf(':') == -1)
826: return N3JenaWriter.propBase + propName;
827: return propName;
828: }
829:
830: protected String localPropName(String propName) {
831: if (propName.startsWith(N3JenaWriter.propBase))
832: propName = propName.substring(N3JenaWriter.propBase
833: .length());
834: return propName;
835: }
836:
837: private boolean isOpaque(String uri) {
838: try {
839: return new URI(uri).isOpaque();
840: } catch (URISyntaxException ex) {
841: return true;
842: }
843: }
844: }
845:
846: /*
847: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
848: * All rights reserved.
849: *
850: * Redistribution and use in source and binary forms, with or without
851: * modification, are permitted provided that the following conditions
852: * are met:
853: * 1. Redistributions of source code must retain the above copyright
854: * notice, this list of conditions and the following disclaimer.
855: * 2. Redistributions in binary form must reproduce the above copyright
856: * notice, this list of conditions and the following disclaimer in the
857: * documentation and/or other materials provided with the distribution.
858: * 3. The name of the author may not be used to endorse or promote products
859: * derived from this software without specific prior written permission.
860: *
861: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
862: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
863: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
864: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
865: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
866: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
867: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
868: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
869: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
870: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
871: */
|