KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > graph > Node


1 /*
2   (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
3   [See end of file]
4   $Id: Node.java,v 1.45 2005/03/14 15:57:57 chris-dollin Exp $
5 */

6
7 package com.hp.hpl.jena.graph;
8
9 import com.hp.hpl.jena.rdf.model.AnonId;
10
11 import com.hp.hpl.jena.datatypes.*;
12 import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
13 import com.hp.hpl.jena.graph.impl.*;
14 import com.hp.hpl.jena.shared.*;
15
16 import org.apache.commons.logging.*;
17
18 /**
19     A Node has five subtypes: Node_Blank, Node_Anon, Node_URI,
20     Node_Variable, and Node_ANY.
21     Nodes are only constructed by the node factory methods, and they will
22     attempt to re-use existing nodes with the same label if they are recent
23     enough.
24     @author Jeremy Carroll and Chris Dollin
25 */

26
27 public abstract class Node {
28     
29     final protected Object JavaDoc label;
30     static final int THRESHOLD = 10000;
31     
32     static final NodeCache present = new NodeCache();
33     // static final HashMap present = new HashMap( THRESHOLD * 2 );
34

35     static final Log log = LogFactory.getLog( Node.class );
36
37     /**
38         The canonical instance of Node_ANY; no-one else need use the
39         constructor.
40     */

41     public static final Node ANY = new Node_ANY();
42        
43     static final String JavaDoc RDFprefix = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
44     
45     /**
46         Returns a Node described by the string, primarily for testing purposes.
47         The string represents a URI, a numeric literal, a string literal, a bnode label,
48         or a variable.
49         <ul>
50         <li> 'some text' :: a string literal with that text
51         <li> 'some text'someLanguage:: a string literal with that text and language
52         <li> 'some text'someURI:: a typed literal with that text and datatype
53         <li> digits :: a literal [OF WHAT TYPE] with that [numeric] value
54         <li> _XXX :: a bnode with an AnonId built from _XXX
55         <li> ?VVV :: a variable with name VVV
56         <li> &PPP :: to be done
57         <li> name:stuff :: the URI; name may be expanded using the Extended map
58         </ul>
59         @param x the string describing the node
60         @return a node of the appropriate type with the appropriate label
61     */

62     public static Node create( String JavaDoc x )
63         { return create( PrefixMapping.Extended, x ); }
64         
65     /**
66         As for create(String), but the PrefixMapping used to translate URI strings
67         is an additional argument.
68         @param pm the PrefixMapping for translating pre:X strings
69         @param x the string encoding the node to create
70         @return a node with the appropriate type and label
71     */

72     public static Node create( PrefixMapping pm, String JavaDoc x )
73         {
74         if (x.equals( "" ))
75             throw new JenaException( "Node.create does not accept an empty string as argument" );
76         char first = x.charAt( 0 );
77         if (first == '\'' || first == '\"')
78             return Node.createLiteral( newString( pm, first, x ) );
79         if (Character.isDigit( first ))
80             return Node.createLiteral( new LiteralLabel( x, "", XSDDatatype.XSDinteger ) );
81         if (first == '_')
82             return Node.createAnon( new AnonId( x ) );
83         if (x.equals( "??" ))
84             return Node.ANY;
85         if (first == '?')
86             return Node.createVariable( x.substring( 1 ) );
87         if (first == '&')
88             return Node.createURI( "q:" + x.substring( 1 ) );
89         int colon = x.indexOf( ':' );
90         String JavaDoc d = pm.getNsPrefixURI( "" );
91         return colon < 0
92             ? Node.createURI( (d == null ? "eh:/" : d) + x )
93             : Node.createURI( pm.expandPrefix( x ) )
94             ;
95         }
96             
97     private static RDFDatatype getType( String JavaDoc s )
98         { return TypeMapper.getInstance().getSafeTypeByName( s ); }
99     
100     private static LiteralLabel literal( PrefixMapping pm, String JavaDoc spelling, String JavaDoc langOrType )
101         {
102         String JavaDoc content = unEscape( spelling );
103         int colon = langOrType.indexOf( ':' );
104         return colon < 0
105             ? new LiteralLabel( content, langOrType, false )
106             : new LiteralLabel( content, "", getType( pm.expandPrefix( langOrType ) ) )
107             ;
108         }
109     
110     private static String JavaDoc unEscape( String JavaDoc spelling )
111         {
112         if (spelling.indexOf( '\\' ) < 0) return spelling;
113         StringBuffer JavaDoc result = new StringBuffer JavaDoc( spelling.length() );
114         int start = 0;
115         while (true)
116             {
117             int b = spelling.indexOf( '\\', start );
118             if (b < 0) break;
119             result.append( spelling.substring( start, b ) );
120             result.append( unEscape( spelling.charAt( b + 1 ) ) );
121             start = b + 2;
122             }
123         result.append( spelling.substring( start ) );
124         return result.toString();
125         }
126     
127     private static char unEscape( char ch )
128         {
129         switch (ch)
130             {
131             case '\\':
132             case '\"':
133             case '\'': return ch;
134             case 'n': return '\n';
135             case 's': return ' ';
136             case 't': return '\t';
137             default: return 'Z';
138             }
139         }
140     
141     private static LiteralLabel newString( PrefixMapping pm, char quote, String JavaDoc nodeString )
142         {
143         int close = nodeString.lastIndexOf( quote );
144         return literal( pm, nodeString.substring( 1, close ), nodeString.substring( close + 1 ) );
145         }
146     
147     /** make a blank node with the specified label */
148     public static Node createAnon( AnonId id )
149         { return create( makeAnon, id ); }
150         
151     /** make a literal node with the specified literal value */
152     public static Node createLiteral( LiteralLabel lit )
153         { return create( makeLiteral, lit ); }
154         
155     /** make a URI node with the specified URIref string */
156     public static Node createURI( String JavaDoc uri )
157         { return create( makeURI, uri ); }
158        
159     /** make a blank node with a fresh anon id */
160     public static Node createAnon()
161         { return createAnon( new AnonId() ); }
162         
163     /** make a variable node with a given name */
164     public static Node createVariable( String JavaDoc name )
165         { return create( makeVariable, Node_Variable.variable( name ) ); }
166         
167     public static Node createLiteral( String JavaDoc value )
168         { return createLiteral( value, "", false ); }
169     
170     /** make a literal with specified language and XMLishness.
171         _lit_ must *not* be null. This intermediate implementation logs
172         a warning to allow users moving over to Jena2 to correct their
173         code. When they've had the opportunity, arrange to throw an
174         exception, and delete _nullLiteralsGenerateWarnings_ and
175         update the regression tests as directed.
176         @param isXml If true then lit is exclusive canonical XML of type rdf:XMLLiteral, and no checking will be invoked.
177     */

178     public static Node createLiteral( String JavaDoc lit, String JavaDoc lang, boolean isXml )
179         {
180         if (lit == null) throw new NullPointerException JavaDoc( "null for literals has been illegal since Jena 2.0" );
181 // {
182
// // throw new SomeSuitableException( "null in createLiteral" );
183
// System.err.println /* log.warn */ ( "null treated as empty string in createLiteral: this will become illegal." );
184
// lit = "";
185
// }
186
return createLiteral( new LiteralLabel( lit, lang, isXml ) );
187         }
188         
189     /**
190      * Build a typed literal node from its lexical form. The
191      * lexical form will be parsed now and the value stored. If
192      * the form is not legal this will throw an exception.
193      *
194      * @param lex the lexical form of the literal
195      * @param lang the optional language tag
196      * @param dtype the type of the literal, null for old style "plain" literals
197      * @throws DatatypeFormatException if lex is not a legal form of dtype
198      */

199     public static Node createLiteral( String JavaDoc lex, String JavaDoc lang, RDFDatatype dtype )
200         throws DatatypeFormatException
201         { return createLiteral( new LiteralLabel( lex, lang, dtype ) ); }
202     
203     public static Node createUncachedLiteral( Object JavaDoc value, String JavaDoc lang, RDFDatatype dtype )
204         throws DatatypeFormatException
205         { return new Node_Literal( new LiteralLabel( value, lang, dtype ) ); }
206                                                    
207     /**
208         Visit a Node and dispatch on it to the appropriate method from the
209         NodeVisitor <code>v</code>.
210         
211         @param v the visitor to apply to the node
212         @return the value returned by the applied method
213      */

214     public abstract Object JavaDoc visitWith( NodeVisitor v );
215      
216     /**
217         Answer true iff this node is concrete, ie not variable, ie URI, blank, or literal.
218     */

219     public abstract boolean isConcrete();
220         
221     /** is this a literal node - overridden in Node_Literal */
222     public boolean isLiteral()
223         { return false; }
224     
225     /** is this a blank node - overridden in Node_Blank */
226     public boolean isBlank()
227         { return false; }
228     
229     /** is this a URI node - overridden in Node_URI */
230     public boolean isURI()
231         { return false; }
232         
233     /** is this a variable node - overridden in Node_Variable */
234     public boolean isVariable()
235         { return false; }
236
237     /** get the blank node id if the node is blank, otherwise die horribly */
238     public AnonId getBlankNodeId()
239         { throw new UnsupportedOperationException JavaDoc( this + " is not a blank node" ); }
240     
241     /** get the literal value of a literal node, otherwise die horribly */
242     public LiteralLabel getLiteral()
243         { throw new UnsupportedOperationException JavaDoc( this + " is not a literal node" ); }
244     
245     /** get the URI of this node if it has one, else die horribly */
246     public String JavaDoc getURI()
247         { throw new UnsupportedOperationException JavaDoc( this + " is not a URI node" ); }
248     
249     /** get the namespace part of this node if it's a URI node, else die horribly */
250     public String JavaDoc getNameSpace()
251         { throw new UnsupportedOperationException JavaDoc( this + " is not a URI node" ); }
252     
253     /** get the localname part of this node if it's a URI node, else die horribly */
254     public String JavaDoc getLocalName()
255         { throw new UnsupportedOperationException JavaDoc( this + " is not a URI node" ); }
256
257     /** get a variable nodes name, otherwise die horribly */
258     public String JavaDoc getName()
259         { throw new UnsupportedOperationException JavaDoc( "this (" + this.getClass() + ") is not a variable node" ); }
260     
261     /** answer true iff this node is a URI node with the given URI */
262     public boolean hasURI( String JavaDoc uri )
263         { return false; }
264         
265     /** an abstraction to allow code sharing */
266     static abstract class NodeMaker { abstract Node construct( Object JavaDoc x ); }
267
268     static final NodeMaker makeAnon = new NodeMaker()
269         { Node construct( Object JavaDoc x ) { return new Node_Blank( x ); } };
270         
271     static final NodeMaker makeLiteral = new NodeMaker()
272         { Node construct( Object JavaDoc x ) { return new Node_Literal( x ); } };
273         
274     static final NodeMaker makeURI = new NodeMaker()
275         { Node construct( Object JavaDoc x ) { return new Node_URI( x ); } };
276         
277     static final NodeMaker makeVariable = new NodeMaker()
278         { Node construct( Object JavaDoc x ) { return new Node_Variable( x ); } };
279         
280     /**
281         The canonical NULL. It appears here so that revised definitions [eg as a bnode]
282         that require the cache-and-maker system will work; the NodeMaker constants
283         should be non-null at this point.
284     */

285     public static final Node NULL = new Node_NULL();
286     
287     /**
288         keep the distinguishing label value.
289     */

290     
291     /* package visibility only */ Node( Object JavaDoc label )
292         { this.label = label; }
293         
294     static private boolean caching = true;
295     
296     /**
297         provided only for testing purposes. _cache(false)_ switches off caching and
298         clears the cache. _cache(true)_ switches caching [back] on. This allows
299         structural equality to be tested.
300     */

301     public static void cache( boolean wantCache )
302         {
303         if (wantCache == false) present.clear();
304         caching = wantCache;
305         }
306         
307     /**
308         We object strongly to null labels: for example, they make .equals flaky. We reuse nodes
309         from the recent cache if we can. Otherwise, the maker knows how to construct a new
310         node of the correct class, and we add that node to the cache. create is
311         synchronised to avoid threading problems - a separate thread might zap the
312         cache entry that get is currently looking at.
313     */

314     public static synchronized Node create( NodeMaker maker, Object JavaDoc label )
315         {
316         if (label == null) throw new JenaException( "Node.make: null label" );
317         Node node = (Node) present.get( label );
318         return node == null ? cacheNewNode( label, maker.construct( label ) ) : node;
319         }
320         
321     /**
322          cache the node <code>n</code> under the key <code>label</code>,
323          and return that node.
324     */

325     private static Node cacheNewNode( Object JavaDoc label, Node n )
326         {
327         if (present.size() > THRESHOLD) { /* System.err.println( "> trashing node cache" ); */ present.clear(); }
328         if (caching) present.put( label, n );
329         return n;
330         }
331         
332     /**
333         Nodes only equal other Nodes that have equal labels.
334     */

335     public abstract boolean equals(Object JavaDoc o);
336     
337     /**
338      * Test that two nodes are semantically equivalent.
339      * In some cases this may be the sames as equals, in others
340      * equals is stricter. For example, two xsd:int literals with
341      * the same value but different language tag are semantically
342      * equivalent but distinguished by the java equality function
343      * in order to support round tripping.
344      * <p>Default implementation is to use equals, subclasses should
345      * override this.</p>
346      */

347     public boolean sameValueAs(Object JavaDoc o) {
348         return equals(o);
349     }
350
351     public int hashCode() {
352         return label.hashCode();
353     }
354     
355     /**
356         Answer true iff this node accepts the other one as a match.
357         The default is an equality test; it is over-ridden in subclasses to
358         provide the appropriate semantics for literals, ANY, and variables.
359         
360         @param other a node to test for matching
361         @return true iff this node accepts the other as a match
362     */

363     public boolean matches( Node other )
364         { return equals( other ); }
365
366     /**
367         Answer a human-readable representation of this Node. It will not compress URIs,
368         nor quote literals (because at the moment too many places use toString() for
369         something machine-oriented).
370     */

371     public String JavaDoc toString()
372         { return toString( null ); }
373     
374     /**
375          Answer a human-readable representation of this Node where literals are
376          quoted according to <code>quoting</code> but URIs are not compressed.
377     */

378     public String JavaDoc toString( boolean quoting )
379         { return toString( null, quoting ); }
380     
381     /**
382         Answer a human-readable representation of the Node, quoting literals and
383         compressing URIs.
384     */

385     public String JavaDoc toString( PrefixMapping pm )
386         { return toString( pm, true ); }
387         
388     /**
389         Answer a human readable representation of this Node, quoting literals if specified,
390         and compressing URIs using the prefix mapping supplied.
391     */

392     public String JavaDoc toString( PrefixMapping pm, boolean quoting )
393         { return label.toString(); }
394         
395 }
396
397 /*
398     (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
399     All rights reserved.
400
401     Redistribution and use in source and binary forms, with or without
402     modification, are permitted provided that the following conditions
403     are met:
404
405     1. Redistributions of source code must retain the above copyright
406        notice, this list of conditions and the following disclaimer.
407
408     2. Redistributions in binary form must reproduce the above copyright
409        notice, this list of conditions and the following disclaimer in the
410        documentation and/or other materials provided with the distribution.
411
412     3. The name of the author may not be used to endorse or promote products
413        derived from this software without specific prior written permission.
414
415     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
416     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
417     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
418     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
419     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
420     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
421     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
422     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
423     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
424     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
425 */

426
Popular Tags