/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-06 Wolfgang M. Meier
* wolfgang@exist-db.org
* http://exist.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.xquery.value;
import java.text.Collator;
import org.exist.util.Collations;
import org.exist.xquery.Constants;
import org.exist.xquery.XPathException;
/**
* @author Wolfgang Meier (wolfgang@exist-db.org)
*/
public class UntypedAtomicValue extends AtomicValue {
private String value;
public UntypedAtomicValue(String value) {
this.value = value;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#getType()
*/
public int getType() {
//return Type.ATOMIC;
return Type.UNTYPED_ATOMIC;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.Sequence#getStringValue()
*/
public String getStringValue() throws XPathException {
return value;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.Sequence#convertTo(int)
*/
public AtomicValue convertTo(int requiredType) throws XPathException {
switch (requiredType) {
case Type.ATOMIC :
case Type.ITEM :
case Type.UNTYPED_ATOMIC :
return this;
case Type.STRING :
return new StringValue(value);
case Type.ANY_URI :
return new AnyURIValue(value);
case Type.BOOLEAN :
String trimmed = StringValue.trimWhitespace(value);
if (trimmed.equals("0") || trimmed.equals("false"))
return BooleanValue.FALSE;
else if (trimmed.equals("1") || trimmed.equals("true"))
return BooleanValue.TRUE;
else
throw new XPathException("FORG0001: cannot cast '" +
Type.getTypeName(this.getItemType()) + "(\"" + getStringValue() + "\")' to " +
Type.getTypeName(requiredType));
case Type.FLOAT :
return new FloatValue(value);
case Type.DOUBLE :
return new DoubleValue(this);
case Type.NUMBER :
//TODO : more complicated
return new DoubleValue(this);
case Type.DECIMAL :
return new DecimalValue(getStringValue());
case Type.INTEGER :
case Type.NON_POSITIVE_INTEGER :
case Type.NEGATIVE_INTEGER :
case Type.LONG :
case Type.INT :
case Type.SHORT :
case Type.BYTE :
case Type.NON_NEGATIVE_INTEGER :
case Type.UNSIGNED_LONG :
case Type.UNSIGNED_INT :
case Type.UNSIGNED_SHORT :
case Type.UNSIGNED_BYTE :
return new IntegerValue(value, requiredType);
case Type.BASE64_BINARY :
return new Base64Binary(value);
case Type.HEX_BINARY :
return new HexBinary(value);
case Type.DATE_TIME :
return new DateTimeValue(value);
case Type.TIME :
return new TimeValue(value);
case Type.DATE :
return new DateValue(value);
case Type.GYEAR :
return new GYearValue(value);
case Type.GMONTH :
return new GMonthValue(value);
case Type.GDAY :
return new GDayValue(value);
case Type.GYEARMONTH :
return new GYearMonthValue(value);
case Type.GMONTHDAY :
return new GMonthDayValue(value);
case Type.DURATION :
return new DurationValue(value);
case Type.YEAR_MONTH_DURATION :
return new YearMonthDurationValue(value);
case Type.DAY_TIME_DURATION :
DayTimeDurationValue dtdv = new DayTimeDurationValue(value);
return new DayTimeDurationValue(dtdv.getCanonicalDuration());
default :
throw new XPathException("FORG0001: cannot cast '" +
Type.getTypeName(this.getItemType()) + "(\"" + getStringValue() + "\")' to " +
Type.getTypeName(requiredType));
}
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#compareTo(int, org.exist.xquery.value.AtomicValue)
*/
public boolean compareTo(Collator collator, int operator, AtomicValue other) throws XPathException {
if (other.isEmpty())
return false;
if (Type.subTypeOf(other.getType(), Type.STRING) ||
Type.subTypeOf(other.getType(), Type.UNTYPED_ATOMIC)) {
int cmp = Collations.compare(collator, value, other.getStringValue());
switch (operator) {
case Constants.EQ :
return cmp == 0;
case Constants.NEQ :
return cmp != 0;
case Constants.LT :
return cmp < 0;
case Constants.LTEQ :
return cmp <= 0;
case Constants.GT :
return cmp > 0;
case Constants.GTEQ :
return cmp >= 0;
default :
throw new XPathException("Type error: cannot apply operand to string value");
}
}
throw new XPathException(
"Type error: operands are not comparable; expected xdt:untypedAtomic; got "
+ Type.getTypeName(other.getType()));
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#compareTo(org.exist.xquery.value.AtomicValue)
*/
public int compareTo(Collator collator, AtomicValue other) throws XPathException {
return Collations.compare(collator, value, other.getStringValue());
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#max(org.exist.xquery.value.AtomicValue)
*/
public AtomicValue max(Collator collator, AtomicValue other) throws XPathException {
if (Type.subTypeOf(other.getType(), Type.UNTYPED_ATOMIC))
return Collations.compare(collator, value, ((UntypedAtomicValue) other).value) > 0 ? this : other;
else
return Collations.compare(collator, value, other.getStringValue()) > 0
? this
: other;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#min(org.exist.xquery.value.AtomicValue)
*/
public AtomicValue min(Collator collator, AtomicValue other) throws XPathException {
if (Type.subTypeOf(other.getType(), Type.UNTYPED_ATOMIC))
return Collations.compare(collator, value, ((UntypedAtomicValue) other).value) < 0 ? this : other;
else
return Collations.compare(collator, value, other.getStringValue()) < 0
? this
: other;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#startsWith(org.exist.xquery.value.AtomicValue)
*/
public boolean startsWith(Collator collator, AtomicValue other) throws XPathException {
return Collations.startsWith(collator, value, other.getStringValue());
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#endsWith(org.exist.xquery.value.AtomicValue)
*/
public boolean endsWith(Collator collator, AtomicValue other) throws XPathException {
return Collations.endsWith(collator, value, other.getStringValue());
}
/* (non-Javadoc)
* @see org.exist.xquery.value.AtomicValue#contains(org.exist.xquery.value.AtomicValue)
*/
public boolean contains(Collator collator, AtomicValue other) throws XPathException {
return Collations.indexOf(collator, value, other.getStringValue()) != Constants.STRING_NOT_FOUND;
}
public boolean effectiveBooleanValue() throws XPathException {
// If its operand is a singleton value of type xs:string, xs:anyURI, xs:untypedAtomic,
//or a type derived from one of these, fn:boolean returns false if the operand value has zero length; otherwise it returns true.
return value.length() > 0;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.Item#conversionPreference(java.lang.Class)
*/
public int conversionPreference(Class javaClass) {
if (javaClass.isAssignableFrom(StringValue.class))
return 0;
if (javaClass == String.class || javaClass == CharSequence.class)
return 1;
if (javaClass == Character.class || javaClass == char.class)
return 2;
if (javaClass == Double.class || javaClass == double.class)
return 10;
if (javaClass == Float.class || javaClass == float.class)
return 11;
if (javaClass == Long.class || javaClass == long.class)
return 12;
if (javaClass == Integer.class || javaClass == int.class)
return 13;
if (javaClass == Short.class || javaClass == short.class)
return 14;
if (javaClass == Byte.class || javaClass == byte.class)
return 15;
if (javaClass == Boolean.class || javaClass == boolean.class)
return 16;
if (javaClass == Object.class)
return 20;
return Integer.MAX_VALUE;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.Item#toJavaObject(java.lang.Class)
*/
public Object toJavaObject(Class target) throws XPathException {
if (target.isAssignableFrom(UntypedAtomicValue.class))
return this;
else if (
target == Object.class
|| target == String.class
|| target == CharSequence.class)
return value;
else if (target == double.class || target == Double.class) {
DoubleValue v = (DoubleValue) convertTo(Type.DOUBLE);
return new Double(v.getValue());
} else if (target == float.class || target == Float.class) {
FloatValue v = (FloatValue) convertTo(Type.FLOAT);
return new Float(v.value);
} else if (target == long.class || target == Long.class) {
IntegerValue v = (IntegerValue) convertTo(Type.LONG);
return new Long(v.getInt());
} else if (target == int.class || target == Integer.class) {
IntegerValue v = (IntegerValue) convertTo(Type.INT);
return new Integer(v.getInt());
} else if (target == short.class || target == Short.class) {
IntegerValue v = (IntegerValue) convertTo(Type.SHORT);
return new Short((short) v.getInt());
} else if (target == byte.class || target == Byte.class) {
IntegerValue v = (IntegerValue) convertTo(Type.BYTE);
return new Byte((byte) v.getInt());
} else if (target == boolean.class || target == Boolean.class) {
return Boolean.valueOf(effectiveBooleanValue());
} else if (target == char.class || target == Character.class) {
if (value.length() > 1 || value.length() == 0)
throw new XPathException("cannot convert string with length = 0 or length > 1 to Java character");
return new Character(value.charAt(0));
}
throw new XPathException(
"cannot convert value of type "
+ Type.getTypeName(getType())
+ " to Java object of type "
+ target.getName());
}
}