001: /*
002: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: [See end of file]
004: $Id: Node.java,v 1.59 2008/02/01 11:29:39 chris-dollin Exp $
005: */
006:
007: package com.hp.hpl.jena.graph;
008:
009: import com.hp.hpl.jena.rdf.model.AnonId;
010:
011: import com.hp.hpl.jena.datatypes.*;
012: import com.hp.hpl.jena.graph.impl.*;
013: import com.hp.hpl.jena.graph.test.NodeCreateUtils;
014: import com.hp.hpl.jena.shared.*;
015:
016: /**
017: A Node has five subtypes: Node_Blank, Node_Anon, Node_URI,
018: Node_Variable, and Node_ANY.
019: Nodes are only constructed by the node factory methods, and they will
020: attempt to re-use existing nodes with the same label if they are recent
021: enough.
022: @author Jeremy Carroll and Chris Dollin
023: */
024:
025: public abstract class Node {
026:
027: final protected Object label;
028: static final int THRESHOLD = 10000;
029:
030: static final NodeCache present = new NodeCache();
031:
032: /**
033: The canonical instance of Node_ANY. No other instances are required.
034: */
035: public static final Node ANY = new Node_ANY();
036:
037: static final String RDFprefix = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
038:
039: /**
040: Returns a Node described by the string, primarily for testing purposes.
041: The string represents a URI, a numeric literal, a string literal, a bnode label,
042: or a variable.
043: <ul>
044: <li> 'some text' :: a string literal with that text
045: <li> 'some text'someLanguage:: a string literal with that text and language
046: <li> 'some text'someURI:: a typed literal with that text and datatype
047: <li> digits :: a literal [OF WHAT TYPE] with that [numeric] value
048: <li> _XXX :: a bnode with an AnonId built from _XXX
049: <li> ?VVV :: a variable with name VVV
050: <li> &PPP :: to be done
051: <li> name:stuff :: the URI; name may be expanded using the Extended map
052: </ul>
053: @param x the string describing the node
054: @return a node of the appropriate type with the appropriate label
055: * @deprecated Use {@link NodeCreateUtils#create(String)} instead
056: */
057: public static Node create(String x) {
058: return NodeCreateUtils.create(x);
059: }
060:
061: /**
062: As for create(String), but the PrefixMapping used to translate URI strings
063: is an additional argument.
064: @param pm the PrefixMapping for translating pre:X strings
065: @param x the string encoding the node to create
066: @return a node with the appropriate type and label
067: * @deprecated Use {@link NodeCreateUtils#create(PrefixMapping,String)} instead
068: */
069: public static Node create(PrefixMapping pm, String x) {
070: return NodeCreateUtils.create(pm, x);
071: }
072:
073: public static RDFDatatype getType(String s) {
074: return TypeMapper.getInstance().getSafeTypeByName(s);
075: }
076:
077: /** make a blank node with a fresh anon id */
078: public static Node createAnon() {
079: return createAnon(AnonId.create());
080: }
081:
082: /** make a blank node with the specified label */
083: public static Node createAnon(AnonId id) {
084: return create(makeAnon, id);
085: }
086:
087: /** make a literal node with the specified literal value */
088: public static Node createLiteral(LiteralLabel lit) {
089: return create(makeLiteral, lit);
090: }
091:
092: /** make a URI node with the specified URIref string */
093: public static Node createURI(String uri) {
094: return create(makeURI, uri);
095: }
096:
097: /** make a variable node with a given name */
098: public static Node createVariable(String name) {
099: return create(makeVariable, Node_Variable.variable(name));
100: }
101:
102: public static Node createLiteral(String value) {
103: return createLiteral(value, "", false);
104: }
105:
106: /** make a literal with specified language and XMLishness.
107: _lit_ must *not* be null.
108: @param isXml If true then lit is exclusive canonical XML of type
109: rdf:XMLLiteral, and no checking will be invoked.
110: */
111: public static Node createLiteral(String lit, String lang,
112: boolean isXml) {
113: if (lit == null)
114: throw new NullPointerException(
115: "null for literals has been illegal since Jena 2.0");
116: return createLiteral(new LiteralLabel(lit, lang, isXml));
117: }
118:
119: /**
120: * Build a typed literal node from its lexical form. The
121: * lexical form will be parsed now and the value stored. If
122: * the form is not legal this will throw an exception.
123: *
124: * @param lex the lexical form of the literal
125: * @param lang the optional language tag
126: * @param dtype the type of the literal, null for old style "plain" literals
127: * @throws DatatypeFormatException if lex is not a legal form of dtype
128: */
129: public static Node createLiteral(String lex, String lang,
130: RDFDatatype dtype) throws DatatypeFormatException {
131: return createLiteral(LiteralLabel.createLiteralLabel(lex, lang,
132: dtype));
133: }
134:
135: public static Node createUncachedLiteral(Object value, String lang,
136: RDFDatatype dtype) throws DatatypeFormatException {
137: return new Node_Literal(new LiteralLabel(value, lang, dtype));
138: }
139:
140: /**
141: Visit a Node and dispatch on it to the appropriate method from the
142: NodeVisitor <code>v</code>.
143:
144: @param v the visitor to apply to the node
145: @return the value returned by the applied method
146: */
147: public abstract Object visitWith(NodeVisitor v);
148:
149: /**
150: Answer true iff this node is concrete, ie not variable, ie URI, blank, or literal.
151: */
152: public abstract boolean isConcrete();
153:
154: /**
155: Answer true iff this node is a literal node [subclasses override]
156: */
157: public boolean isLiteral() {
158: return false;
159: }
160:
161: /**
162: Answer true iff this node is a blank node [subclasses override]
163: */
164: public boolean isBlank() {
165: return false;
166: }
167:
168: /**
169: Answer true iff this node is a URI node [subclasses override]
170: */
171: public boolean isURI() {
172: return false;
173: }
174:
175: /**
176: Answer true iff this node is a variable node - subclasses override
177: */
178: public boolean isVariable() {
179: return false;
180: }
181:
182: /** get the blank node id if the node is blank, otherwise die horribly */
183: public AnonId getBlankNodeId() {
184: throw new UnsupportedOperationException(this
185: + " is not a blank node");
186: }
187:
188: /**
189: Answer the label of this blank node or throw an UnsupportedOperationException
190: if it's not blank.
191: */
192: public String getBlankNodeLabel() {
193: return getBlankNodeId().getLabelString();
194: }
195:
196: /**
197: Answer the literal value of a literal node, or throw an UnsupportedOperationException
198: if it's not a literal node
199: */
200: public LiteralLabel getLiteral() {
201: throw new UnsupportedOperationException(this
202: + " is not a literal node");
203: }
204:
205: /**
206: Answer the value of this node's literal value, if it is a literal;
207: otherwise die horribly.
208: */
209: public Object getLiteralValue() {
210: throw new NotLiteral(this );
211: }
212:
213: /**
214: Answer the lexical form of this node's literal value, if it is a literal;
215: otherwise die horribly.
216: */
217: public String getLiteralLexicalForm() {
218: throw new NotLiteral(this );
219: }
220:
221: /**
222: Answer the language of this node's literal value, if it is a literal;
223: otherwise die horribly.
224: */
225: public String getLiteralLanguage() {
226: throw new NotLiteral(this );
227: }
228:
229: /**
230: Answer the data-type URI of this node's literal value, if it is a
231: literal; otherwise die horribly.
232: */
233: public String getLiteralDatatypeURI() {
234: throw new NotLiteral(this );
235: }
236:
237: /**
238: Answer the RDF datatype object of this node's literal value, if it is
239: a literal; otherwise die horribly.
240: */
241: public RDFDatatype getLiteralDatatype() {
242: throw new NotLiteral(this );
243: }
244:
245: public boolean getLiteralIsXML() {
246: throw new NotLiteral(this );
247: }
248:
249: /**
250: Exception thrown if a literal-access operation is attemted on a
251: non-literal node.
252: */
253: public static class NotLiteral extends JenaException {
254: public NotLiteral(Node it) {
255: super (it + " is not a literal node");
256: }
257: }
258:
259: /**
260: Answer the object which is the index value for this Node. The default
261: is this Node itself; overridden in Node_Literal for literal indexing
262: purposes. Only concrete nodes should use this method.
263: */
264: public Object getIndexingValue() {
265: return this ;
266: }
267:
268: /** get the URI of this node if it has one, else die horribly */
269: public String getURI() {
270: throw new UnsupportedOperationException(this
271: + " is not a URI node");
272: }
273:
274: /** get the namespace part of this node if it's a URI node, else die horribly */
275: public String getNameSpace() {
276: throw new UnsupportedOperationException(this
277: + " is not a URI node");
278: }
279:
280: /** get the localname part of this node if it's a URI node, else die horribly */
281: public String getLocalName() {
282: throw new UnsupportedOperationException(this
283: + " is not a URI node");
284: }
285:
286: /** get a variable nodes name, otherwise die horribly */
287: public String getName() {
288: throw new UnsupportedOperationException("this ("
289: + this .getClass() + ") is not a variable node");
290: }
291:
292: /** answer true iff this node is a URI node with the given URI */
293: public boolean hasURI(String uri) {
294: return false;
295: }
296:
297: /** an abstraction to allow code sharing */
298: static abstract class NodeMaker {
299: abstract Node construct(Object x);
300: }
301:
302: static final NodeMaker makeAnon = new NodeMaker() {
303: Node construct(Object x) {
304: return new Node_Blank(x);
305: }
306: };
307:
308: static final NodeMaker makeLiteral = new NodeMaker() {
309: Node construct(Object x) {
310: return new Node_Literal(x);
311: }
312: };
313:
314: static final NodeMaker makeURI = new NodeMaker() {
315: Node construct(Object x) {
316: return new Node_URI(x);
317: }
318: };
319:
320: static final NodeMaker makeVariable = new NodeMaker() {
321: Node construct(Object x) {
322: return new Node_Variable(x);
323: }
324: };
325:
326: /**
327: The canonical NULL. It appears here so that revised definitions [eg as a bnode]
328: that require the cache-and-maker system will work; the NodeMaker constants
329: should be non-null at this point.
330: */
331: public static final Node NULL = new Node_NULL();
332:
333: /**
334: keep the distinguishing label value.
335: */
336:
337: /* package visibility only */Node(Object label) {
338: this .label = label;
339: }
340:
341: static private boolean caching = true;
342:
343: /**
344: provided only for testing purposes. _cache(false)_ switches off caching and
345: clears the cache. _cache(true)_ switches caching [back] on. This allows
346: structural equality to be tested.
347: */
348: public static void cache(boolean wantCache) {
349: if (wantCache == false)
350: present.clear();
351: caching = wantCache;
352: }
353:
354: /**
355: We object strongly to null labels: for example, they make .equals flaky. We reuse nodes
356: from the recent cache if we can. Otherwise, the maker knows how to construct a new
357: node of the correct class, and we add that node to the cache. create is
358: synchronised to avoid threading problems - a separate thread might zap the
359: cache entry that get is currently looking at.
360: */
361: public static synchronized Node create(NodeMaker maker, Object label) {
362: if (label == null)
363: throw new JenaException("Node.make: null label");
364: Node node = (Node) present.get(label);
365: return node == null ? cacheNewNode(label, maker
366: .construct(label)) : node;
367: }
368:
369: /**
370: cache the node <code>n</code> under the key <code>label</code>,
371: and return that node.
372: */
373: private static Node cacheNewNode(Object label, Node n) {
374: if (present.size() > THRESHOLD) { /* System.err.println( "> trashing node cache" ); */
375: present.clear();
376: }
377: if (caching)
378: present.put(label, n);
379: return n;
380: }
381:
382: /**
383: Nodes only equal other Nodes that have equal labels.
384: */
385: public abstract boolean equals(Object o);
386:
387: /**
388: * Test that two nodes are semantically equivalent.
389: * In some cases this may be the same as equals, in others
390: * equals is stricter. For example, two xsd:int literals with
391: * the same value but different language tag are semantically
392: * equivalent but distinguished by the java equality function
393: * in order to support round-tripping.
394: * <p>Default implementation is to use equals, subclasses should
395: * override this.</p>
396: */
397: public boolean sameValueAs(Object o) {
398: return equals(o);
399: }
400:
401: public int hashCode() {
402: return label.hashCode() * 31;
403: }
404:
405: /**
406: Answer true iff this node accepts the other one as a match.
407: The default is an equality test; it is over-ridden in subclasses to
408: provide the appropriate semantics for literals, ANY, and variables.
409:
410: @param other a node to test for matching
411: @return true iff this node accepts the other as a match
412: */
413: public boolean matches(Node other) {
414: return equals(other);
415: }
416:
417: /**
418: Answer a human-readable representation of this Node. It will not compress URIs,
419: nor quote literals (because at the moment too many places use toString() for
420: something machine-oriented).
421: */
422: public String toString() {
423: return toString(null);
424: }
425:
426: /**
427: Answer a human-readable representation of this Node where literals are
428: quoted according to <code>quoting</code> but URIs are not compressed.
429: */
430: public String toString(boolean quoting) {
431: return toString(null, quoting);
432: }
433:
434: /**
435: Answer a human-readable representation of the Node, quoting literals and
436: compressing URIs.
437: */
438: public String toString(PrefixMapping pm) {
439: return toString(pm, true);
440: }
441:
442: /**
443: Answer a human readable representation of this Node, quoting literals if specified,
444: and compressing URIs using the prefix mapping supplied.
445: */
446: public String toString(PrefixMapping pm, boolean quoting) {
447: return label.toString();
448: }
449: }
450:
451: /*
452: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
453: All rights reserved.
454:
455: Redistribution and use in source and binary forms, with or without
456: modification, are permitted provided that the following conditions
457: are met:
458:
459: 1. Redistributions of source code must retain the above copyright
460: notice, this list of conditions and the following disclaimer.
461:
462: 2. Redistributions in binary form must reproduce the above copyright
463: notice, this list of conditions and the following disclaimer in the
464: documentation and/or other materials provided with the distribution.
465:
466: 3. The name of the author may not be used to endorse or promote products
467: derived from this software without specific prior written permission.
468:
469: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
470: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
471: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
472: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
473: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
474: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
475: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
476: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
477: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
478: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
479: */
|