001: /******************************************************************
002: * File: XSDBaseNumericType.java
003: * Created by: Dave Reynolds
004: * Created on: 09-Feb-03
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: XSDBaseNumericType.java,v 1.21 2008/01/23 16:21:05 der Exp $
009: *****************************************************************/package com.hp.hpl.jena.datatypes.xsd.impl;
010:
011: import java.math.BigDecimal;
012: import java.math.BigInteger;
013:
014: import com.hp.hpl.jena.datatypes.*;
015: import com.hp.hpl.jena.datatypes.xsd.*;
016: import com.hp.hpl.jena.graph.impl.LiteralLabel;
017: import com.hp.hpl.jena.shared.impl.JenaParameters;
018:
019: /**
020: * Base implementation for all numeric datatypes derived from
021: * xsd:decimal. The only purpose of this place holder is
022: * to support the isValidLiteral tests across numeric types. Note
023: * that float and double are not included in this set.
024: *
025: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
026: * @version $Revision: 1.21 $ on $Date: 2008/01/23 16:21:05 $
027: */
028: public class XSDBaseNumericType extends XSDDatatype {
029:
030: /**
031: * Constructor.
032: * @param typeName the name of the XSD type to be instantiated, this is
033: * used to lookup a type definition from the Xerces schema factory.
034: */
035: public XSDBaseNumericType(String typeName) {
036: super (typeName);
037: }
038:
039: /**
040: * Constructor.
041: * @param typeName the name of the XSD type to be instantiated, this is
042: * used to lookup a type definition from the Xerces schema factory.
043: * @param javaClass the java class for which this xsd type is to be
044: * treated as the cannonical representation
045: */
046: public XSDBaseNumericType(String typeName, Class javaClass) {
047: super (typeName, javaClass);
048: }
049:
050: /**
051: * Test whether the given LiteralLabel is a valid instance
052: * of this datatype. This takes into accound typing information
053: * as well as lexical form - for example an xsd:string is
054: * never considered valid as an xsd:integer (even if it is
055: * lexically legal like "1").
056: */
057: public boolean isValidLiteral(LiteralLabel lit) {
058: if (isBaseTypeCompatible(lit)) {
059: String lex = lit.getLexicalForm();
060: if (JenaParameters.enableWhitespaceCheckingOfTypedLiterals) {
061: if (lex.trim().equals(lex)) {
062: return isValid(lit.getLexicalForm());
063: } else {
064: return false;
065: }
066: } else {
067: return isValid(lit.getLexicalForm());
068: }
069: } else {
070: return false;
071: }
072: }
073:
074: /**
075: * Test whether the given object is a legal value form
076: * of this datatype. Brute force implementation.
077: */
078: public boolean isValidValue(Object valueForm) {
079: if (valueForm instanceof Number) {
080: return isValid(valueForm.toString());
081: } else {
082: return false;
083: }
084: }
085:
086: /**
087: * Cannonicalise a java Object value to a normal form.
088: * Primarily used in cases such as xsd:integer to reduce
089: * the Java object representation to the narrowest of the Number
090: * subclasses to ensure that indexing of typed literals works.
091: */
092: public Object cannonicalise(Object value) {
093:
094: if (value instanceof BigInteger) {
095: return cannonicalizeInteger((BigInteger) value);
096: } else if (value instanceof BigDecimal) {
097: return cannonicalizeDecimal((BigDecimal) value);
098: }
099: return suitableInteger(((Number) value).longValue());
100: }
101:
102: /**
103: * Cannonicalize a big decimal
104: */
105: private Object cannonicalizeDecimal(BigDecimal value) {
106: // This could can be simplified by using toBitIntegerExact
107: // once we drop Java 1.4 support
108: if (value.scale() > 0) {
109: // Fractional part could still be zero so have to check in that case
110: try {
111: return cannonicalizeInteger(value.setScale(0)
112: .toBigInteger());
113: } catch (ArithmeticException e) {
114: return value;
115: }
116: } else {
117: return cannonicalizeInteger(value.toBigInteger());
118: }
119: }
120:
121: /**
122: * Cannonicalize a big integer
123: */
124: private Object cannonicalizeInteger(BigInteger value) {
125: if (value.bitLength() > 63) {
126: return value;
127: } else {
128: return suitableInteger(value.longValue());
129: }
130: }
131:
132: /**
133: * Parse a lexical form of this datatype to a value
134: * @throws DatatypeFormatException if the lexical form is not legal
135: */
136: public Object parse(String lexicalForm)
137: throws DatatypeFormatException {
138: checkWhitespace(lexicalForm);
139: return super .parse(lexicalForm);
140: }
141:
142: /**
143: * Check for whitespace violations.
144: * Turned off by default.
145: */
146: protected void checkWhitespace(String lexicalForm) {
147: if (JenaParameters.enableWhitespaceCheckingOfTypedLiterals) {
148: if (!lexicalForm.trim().equals(lexicalForm)) {
149: throw new DatatypeFormatException(lexicalForm, this ,
150: "whitespace violation");
151: }
152: }
153: }
154:
155: /**
156: * Compares two instances of values of the given datatype.
157: * This ignores lang tags and just uses the java.lang.Number
158: * equality.
159: */
160: public boolean isEqual(LiteralLabel value1, LiteralLabel value2) {
161: if (value1.getDatatype() instanceof XSDBaseNumericType
162: && value2.getDatatype() instanceof XSDBaseNumericType) {
163: Number n1 = (Number) value1.getValue();
164: Number n2 = (Number) value2.getValue();
165: // The cannonicalization step should take care of all cross-type cases, leaving
166: // us just that equals doesn't work on BigDecimals in the way you expect
167: if (n1 instanceof BigDecimal && n2 instanceof BigDecimal) {
168: return ((BigDecimal) n1).compareTo((BigDecimal) n2) == 0;
169: }
170: return n1.equals(n2);
171: } else {
172: // At least one arg is not part of the integer hierarchy
173: return false;
174: }
175: }
176: }
177:
178: /*
179: (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, LP
180: All rights reserved.
181:
182: Redistribution and use in source and binary forms, with or without
183: modification, are permitted provided that the following conditions
184: are met:
185:
186: 1. Redistributions of source code must retain the above copyright
187: notice, this list of conditions and the following disclaimer.
188:
189: 2. Redistributions in binary form must reproduce the above copyright
190: notice, this list of conditions and the following disclaimer in the
191: documentation and/or other materials provided with the distribution.
192:
193: 3. The name of the author may not be used to endorse or promote products
194: derived from this software without specific prior written permission.
195:
196: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
197: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
199: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
203: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
204: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
205: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
206: */
|