/* * 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.rdf.model.impl; import org.apache.jena.JenaRuntime ; import org.apache.jena.datatypes.DatatypeFormatException ; import org.apache.jena.datatypes.RDFDatatype ; import org.apache.jena.datatypes.xsd.XSDDatatype ; import org.apache.jena.enhanced.* ; import org.apache.jena.graph.* ; import org.apache.jena.rdf.model.* ; import org.apache.jena.shared.* ; /** An implementation of Literal. */ public class LiteralImpl extends EnhNode implements Literal { final static public Implementation factory = new Implementation() { @Override public boolean canWrap( Node n, EnhGraph eg ) { return n.isLiteral(); } @Override public EnhNode wrap(Node n, EnhGraph eg) { if (!n.isLiteral()) throw new LiteralRequiredException( n ); return new LiteralImpl(n,eg); } }; public LiteralImpl( Node n, ModelCom m) { super( n, m ); } public LiteralImpl( Node n, EnhGraph m ) { super( n, m ); } @Override public Object visitWith( RDFVisitor rv ) { return rv.visitLiteral( this ); } /** Literals are not in any particular model, and so inModel can return this. @param m a model to move the literal into @return this */ @Override public Literal inModel( Model m ) { return getModel() == m ? this : (Literal) m.getRDFNode( asNode() ) ; } @Override public Literal asLiteral() { return this; } @Override public Resource asResource() { throw new ResourceRequiredException( asNode() ); } /** Answer the model this literal was created in, if any, otherwise null. */ @Override public Model getModel() { return (ModelCom) getGraph(); } @Override public String toString() { return asNode().toString( PrefixMapping.Standard, false ); } /** * Return the value of the literal. In the case of plain literals * this will return the literal string. In the case of typed literals * it will return a java object representing the value. In the case * of typed literals representing a java primitive then the appropriate * java wrapper class (Integer etc) will be returned. */ @Override public Object getValue() { return asNode().getLiteralValue(); } /** * Return the datatype of the literal. This will be null in the * case of plain literals. */ @Override public RDFDatatype getDatatype() { return asNode().getLiteralDatatype(); } /** * Return the uri of the datatype of the literal. This will be null in the * case of plain literals. */ @Override public String getDatatypeURI() { return asNode().getLiteralDatatypeURI(); } /** * Return true if this is a "plain" (i.e. old style, not typed) literal. * For RDF 1.1, the most compatible choice is "xsd:string" or "rdf:langString". */ private boolean isPlainLiteral() { if ( JenaRuntime.isRDF11 ) return Util.isLangString(this) || Util.isSimpleString(this) ; else return asNode().getLiteralDatatype() == null; } /** * Return the lexical form of the literal. */ @Override public String getLexicalForm() { return asNode().getLiteralLexicalForm(); } @Override public boolean getBoolean() { Object value = asNode().getLiteralValue(); if (isPlainLiteral()) { // old style plain literal - try parsing the string if (value.equals("true")) { return true; } else if (value.equals("false")) { return false; } else { throw new BadBooleanException( value.toString() ); } } else { // typed literal if (value instanceof Boolean) { return (Boolean) value; } else { throw new DatatypeFormatException(this.toString() + " is not a Boolean"); } } } @Override public byte getByte() { if (isPlainLiteral()) { return Byte.parseByte(getLexicalForm()); } else { return byteValue( asNumber( getValue() ) ); } } @Override public short getShort() { if (isPlainLiteral()) { return Short.parseShort(getLexicalForm()); } else { return shortValue( asNumber( getValue() ) ); } } @Override public int getInt() { if (isPlainLiteral()) { return Integer.parseInt(getLexicalForm()); } else { return intValue( asNumber( getValue() ) ); } } @Override public long getLong() { if (isPlainLiteral()) { return Long.parseLong(getLexicalForm()); } else { return asNumber(getValue()).longValue(); } } @Override public char getChar() { if (isPlainLiteral()) { if (getString().length()==1) { return (getString().charAt(0)); } else { throw new BadCharLiteralException( getString() ); } } else { Object value = getValue(); if (value instanceof Character) { return (Character) value; } else { throw new DatatypeFormatException(value.toString() + " is not a Character"); } } } @Override public float getFloat() { if (isPlainLiteral()) { return Float.parseFloat(getLexicalForm()); } else { return asNumber(getValue()).floatValue(); } } @Override public double getDouble() { if (isPlainLiteral()) { return Double.parseDouble(getLexicalForm()); } else { return asNumber(getValue()).doubleValue(); } } @Override public String getString() { return asNode().getLiteralLexicalForm(); } // @Deprecated public Object getObject(ObjectF f) { // if (isPlainLiteral()) { // try { // return f.createObject(getString()); // } catch (Exception e) { // throw new JenaException(e); // } // } else { // return getValue(); // } // } @Override public String getLanguage() { return asNode().getLiteralLanguage(); } @Override public boolean isWellFormedXML() { return asNode().getLiteralIsXML(); } /** * Test that two literals are semantically equivalent. * In some cases this may be the sames 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. */ @Override public boolean sameValueAs(Literal other) { return asNode().sameValueAs(other.asNode()); } // Internal helper method to convert a value to number private Number asNumber(Object value) { if (value instanceof Number) { return ((Number)value); } else { String message = "Error converting typed value to a number. \n"; message += "Datatype is: " + getDatatypeURI(); if ( getDatatypeURI() == null || ! getDatatypeURI().startsWith(XSDDatatype.XSD)) { message +=" which is not an xsd type."; } message += " \n"; String type = message += "Java representation type is " + (value == null ? "null" : value.getClass().toString()); throw new DatatypeFormatException(message); } } private byte byteValue( Number n ) { return (byte) getIntegralValueInRange( Byte.MIN_VALUE, n, Byte.MAX_VALUE ); } private short shortValue( Number n ) { return (short) getIntegralValueInRange( Short.MIN_VALUE, n, Short.MAX_VALUE ); } private int intValue( Number n ) { return (int) getIntegralValueInRange( Integer.MIN_VALUE, n, Integer.MAX_VALUE ); } private long getIntegralValueInRange( long min, Number n, long max ) { long result = n.longValue(); if (min <= result && result <= max) return result; throw new IllegalArgumentException( "byte value required: " + result ); } }