/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.graph;
import org.apache.jena.datatypes.RDFDatatype ;
import org.apache.jena.graph.impl.LiteralLabel ;
import org.apache.jena.shared.JenaException ;
import org.apache.jena.shared.PrefixMapping ;
/**
A Node has five subtypes: Node_Blank, Node_Anon, Node_URI,
Node_Variable, and Node_ANY.
Nodes are only constructed by the node factory methods, and they will
attempt to re-use existing nodes with the same label if they are recent
enough.
*/
public abstract class Node {
final protected Object label;
static final int THRESHOLD = 10000;
/**
The canonical instance of Node_ANY. No other instances are required.
*/
public static final Node ANY = new Node_ANY();
static final String RDFprefix = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
/**
Visit a Node and dispatch on it to the appropriate method from the
NodeVisitor <code>v</code>.
@param v the visitor to apply to the node
@return the value returned by the applied method
*/
public abstract Object visitWith( NodeVisitor v );
/**
Answer true iff this node is concrete, ie not variable, ie URI, blank, or literal.
*/
public abstract boolean isConcrete();
/**
Answer true iff this node is a literal node [subclasses override]
*/
public boolean isLiteral()
{ return false; }
/**
Answer true iff this node is a blank node [subclasses override]
*/
public boolean isBlank()
{ return false; }
/**
Answer true iff this node is a URI node [subclasses override]
*/
public boolean isURI()
{ return false; }
/**
Answer true iff this node is a variable node - subclasses override
*/
public boolean isVariable()
{ return false; }
/** get the blank node id if the node is blank, otherwise die horribly */
public BlankNodeId getBlankNodeId()
{ throw new UnsupportedOperationException( this + " is not a blank node" ); }
/**
Answer the label of this blank node or throw an UnsupportedOperationException
if it's not blank.
*/
public String getBlankNodeLabel()
{ return getBlankNodeId().getLabelString(); }
/**
Answer the literal value of a literal node, or throw an UnsupportedOperationException
if it's not a literal node
*/
public LiteralLabel getLiteral()
{ throw new UnsupportedOperationException( this + " is not a literal node" ); }
/**
Answer the value of this node's literal value, if it is a literal;
otherwise die horribly.
*/
public Object getLiteralValue()
{ throw new NotLiteral( this ); }
/**
Answer the lexical form of this node's literal value, if it is a literal;
otherwise die horribly.
*/
public String getLiteralLexicalForm()
{ throw new NotLiteral( this ); }
/**
Answer the language of this node's literal value, if it is a literal;
otherwise die horribly.
*/
public String getLiteralLanguage()
{ throw new NotLiteral( this ); }
/**
Answer the data-type URI of this node's literal value, if it is a
literal; otherwise die horribly.
*/
public String getLiteralDatatypeURI()
{ throw new NotLiteral( this ); }
/**
Answer the RDF datatype object of this node's literal value, if it is
a literal; otherwise die horribly.
*/
public RDFDatatype getLiteralDatatype()
{ throw new NotLiteral( this ); }
public boolean getLiteralIsXML()
{ throw new NotLiteral( this ); }
/**
Exception thrown if a literal-access operation is attemted on a
non-literal node.
*/
public static class NotLiteral extends JenaException
{
public NotLiteral( Node it )
{ super( it + " is not a literal node" ); }
}
/**
Answer the object which is the index value for this Node. The default
is this Node itself; overridden in Node_Literal for literal indexing
purposes. Only concrete nodes should use this method.
*/
public Object getIndexingValue()
{ return this; }
/** get the URI of this node if it has one, else die horribly */
public String getURI()
{ throw new UnsupportedOperationException( this + " is not a URI node" ); }
/** get the namespace part of this node if it's a URI node, else die horribly */
public String getNameSpace()
{ throw new UnsupportedOperationException( this + " is not a URI node" ); }
/** get the localname part of this node if it's a URI node, else die horribly */
public String getLocalName()
{ throw new UnsupportedOperationException( this + " is not a URI node" ); }
/** get a variable nodes name, otherwise die horribly */
public String getName()
{ throw new UnsupportedOperationException( "this (" + this.getClass() + ") is not a variable node" ); }
/** answer true iff this node is a URI node with the given URI */
public boolean hasURI( String uri )
{ return false; }
// DEPRECATED
/** an abstraction to allow code sharing */
static abstract class NodeMaker { abstract Node construct( Object x ); }
@Deprecated
static final NodeMaker makeAnon = new NodeMaker() {
@Override Node construct( Object x ) { return new Node_Blank( x ); }
};
@Deprecated
static final NodeMaker makeLiteral = new NodeMaker() {
@Override Node construct( Object x ) { return new Node_Literal( x ); }
};
@Deprecated
static final NodeMaker makeURI = new NodeMaker() {
@Override Node construct( Object x ) { return new Node_URI( x ); }
};
@Deprecated
static final NodeMaker makeVariable = new NodeMaker() {
@Override Node construct( Object x ) { return new Node_Variable( x ); }
};
/**
The canonical NULL. It appears here so that revised definitions [eg as a bnode]
that require the cache-and-maker system will work; the NodeMaker constants
should be non-null at this point.
*/
@Deprecated
public static final Node NULL = new Node_NULL();
/* package visibility only */ Node( Object label )
{ this.label = label; }
/**
We object strongly to null labels: for example, they make .equals flaky.
@deprecated Use specific {@link NodeFactory} functions.
*/
@Deprecated
public static Node create( NodeMaker maker, Object label )
{
if (label == null) throw new JenaException( "Node.make: null label" );
return maker.construct( label ) ;
}
/**
Nodes only equal other Nodes that have equal labels.
*/
@Override
public abstract boolean equals(Object o);
/**
* Test that two nodes are semantically equivalent.
* In some cases this may be the same as equals, in others
* equals is stricter. For example, two xsd:int literals with
* the same value but different language tag are semantically
* equivalent but distinguished by the java equality function
* in order to support round-tripping.
* <p>Default implementation is to use equals, subclasses should
* override this.</p>
*/
public boolean sameValueAs(Object o)
{ return equals( o ); }
@Override
public int hashCode()
{ return label.hashCode() * 31; }
/**
Answer true iff this node accepts the other one as a match.
The default is an equality test; it is over-ridden in subclasses to
provide the appropriate semantics for literals, ANY, and variables.
@param other a node to test for matching
@return true iff this node accepts the other as a match
*/
public boolean matches( Node other )
{ return equals( other ); }
/**
Answer a human-readable representation of this Node. It will not compress URIs,
nor quote literals (because at the moment too many places use toString() for
something machine-oriented).
*/
@Override
public String toString()
{ return toString( null ); }
/**
Answer a human-readable representation of this Node where literals are
quoted according to <code>quoting</code> but URIs are not compressed.
*/
public String toString( boolean quoting )
{ return toString( null, quoting ); }
/**
Answer a human-readable representation of the Node, quoting literals and
compressing URIs.
*/
public String toString( PrefixMapping pm )
{ return toString( pm, true ); }
/**
Answer a human readable representation of this Node, quoting literals if specified,
and compressing URIs using the prefix mapping supplied.
*/
public String toString( PrefixMapping pm, boolean quoting )
{ return label.toString(); }
}