/*******************************************************************************
* Copyright (c) 2004, 2007-2008 IBM Corporation and Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source: /cvsroot/slrp/glitter/com.ibm.adtech.glitter/src/com/ibm/adtech/glitter/rdf/datatype/TypeMaps.java,v $
* Created by: Lee Feigenbaum (<a href="mailto:feigenbl@us.ibm.com">feigenbl@us.ibm.com</a>)
* Created on: 10/23/06
* Revision: $Id: TypeMaps.java 164 2007-07-31 14:11:09Z mroy $
*
* Contributors: IBM Corporation - initial API and implementation
* Cambridge Semantics Incorporated - Fork to Anzo
*******************************************************************************/
package org.openanzo.rdf.datatype;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.bind.DatatypeConverter;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import org.apache.commons.lang.time.DateUtils;
import org.apache.ws.jaxme.impl.DatatypeConverterImpl;
import org.openanzo.exceptions.AnzoRuntimeException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.rdf.MemURI;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.vocabulary.RDF;
import org.openanzo.rdf.vocabulary.XMLSchema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("all")
/**
* A singleton collection of {@link LexicalToNativeTypeMap}s and {@link NativeToLexicalTypeMap}s for converting between XML Schema types and Java classes.
*
* @author lee
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
public class TypeMaps {
private static final Logger log = LoggerFactory.getLogger(TypeMaps.class);
/*
* WARNING: JAXP doesn't mandate that DatatypeFactory implementations be thread-safe but all implementations
* I've seen are indeed thread-safe on account of being stateless.
*
* Future JAXP edits might mandate thread safety since this bug has been accepted:
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6466177
*/
/** Datatype factory */
public static final DatatypeFactory datatypeFactory;
static {
try {
datatypeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new RuntimeException(e);
}
}
private static boolean initialized = false;
/**
* This method should be called the constructor of each type map so that the DatatypeConverter is initialized. It is important to do this in every class
* since we can't predict which will be loaded first. And the outer class isn't necessarily loaded when a static inner class is loaded. So putting this in
* the outer class's static initializer isn't enough. See
*/
private static void initializeDatatypeConverter() {
if (!initialized) {
DatatypeConverter.setDatatypeConverter(new DatatypeConverterImpl());
initialized = true;
}
}
/**
* Creates a URI in the XSD namespace ending in <tt>base</tt>.
*
* @param base
* @return a URI in the XSD namespace ending in <tt>base</tt>.
*/
static public String xsd(String base) {
return XMLSchema.NAMESPACE + base;
}
private static final Date MIN_DATE = new Date(Long.MIN_VALUE);
/**
* Create an XML Calendar for the time in millis
*
* @param millis
* @return XML Calendar
*/
public static XMLGregorianCalendar getXMLCaledar(long millis) {
GregorianCalendar cal = new GregorianCalendar(DateUtils.UTC_TIME_ZONE);
cal.clear();
cal.setGregorianChange(MIN_DATE);
cal.setTimeInMillis(millis);
return TypeMaps.datatypeFactory.newXMLGregorianCalendar(cal);
}
/**
* Create an XML Calendar for the time in millis
*
* @param millis
* @return XML Calendar
*/
public static XMLGregorianCalendar getXMLCaledar(Date date) {
GregorianCalendar cal = new GregorianCalendar(DateUtils.UTC_TIME_ZONE);
cal.clear();
cal.setGregorianChange(MIN_DATE);
cal.setTime(date);
return TypeMaps.datatypeFactory.newXMLGregorianCalendar(cal);
}
private TypeMaps() {
}
/**
* Type map for string data.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMString implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMString() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return String.class;
}
public URI getOutputDatatype() {
return XMLSchema.STRING;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof String;
}
public String convertToLexicalValue(Object obj) {
return (String) obj;
}
public URI getDatatype() {
return XMLSchema.STRING;
}
public Class<?> getOutputJavaClass() {
return String.class;
}
public Object convertToNativeObject(String value) {
return value;
}
}
/**
* Type map for xsd:integer <--> BigInteger.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMInteger implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMInteger() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return BigInteger.class;
}
public URI getOutputDatatype() {
return XMLSchema.INTEGER;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof BigInteger;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printInteger((BigInteger) obj);
}
public URI getDatatype() {
return XMLSchema.INTEGER;
}
public Class<?> getOutputJavaClass() {
return BigInteger.class;
}
public Object convertToNativeObject(String value) {
// strip off leading +'s since our impl. doesn't handle them
if (value.charAt(0) == '+')
value = value.substring(1);
return DatatypeConverter.parseInteger(value);
}
}
/**
* Type map for xsd:int <--> Integer.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMInt implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMInt() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Integer.class;
}
public URI getOutputDatatype() {
return XMLSchema.INT;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Integer;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printInt((Integer) obj);
}
public URI getDatatype() {
return XMLSchema.INT;
}
public Class<?> getOutputJavaClass() {
return Integer.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseInt(value);
}
}
/**
* Type map for xsd:long <--> Long.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMLong implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMLong() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Long.class;
}
public URI getOutputDatatype() {
return XMLSchema.LONG;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Long;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printLong((Long) obj);
}
public URI getDatatype() {
return XMLSchema.LONG;
}
public Class<?> getOutputJavaClass() {
return Long.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseLong(value);
}
}
/**
* Type map for xsd:short <--> Short.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMShort implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMShort() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Short.class;
}
public URI getOutputDatatype() {
return XMLSchema.SHORT;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Short;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printShort((Short) obj);
}
public URI getDatatype() {
return XMLSchema.SHORT;
}
public Class<?> getOutputJavaClass() {
return Short.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseShort(value);
}
}
/**
* Type map for xsd:decimal <--> BigDecimal.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMDecimal implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMDecimal() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return BigDecimal.class;
}
public URI getOutputDatatype() {
return XMLSchema.DECIMAL;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof BigDecimal;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printDecimal((BigDecimal) obj);
}
public URI getDatatype() {
return XMLSchema.DECIMAL;
}
public Class<?> getOutputJavaClass() {
return BigDecimal.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseDecimal(value);
}
}
/**
* Type map for xsd:float <--> Float.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMFloat implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMFloat() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Float.class;
}
public URI getOutputDatatype() {
return XMLSchema.FLOAT;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Float;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printFloat((Float) obj);
}
public URI getDatatype() {
return XMLSchema.FLOAT;
}
public Class<?> getOutputJavaClass() {
return Float.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseFloat(value);
}
}
/**
* Type map for xsd:double <--> Double.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMDouble implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMDouble() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Double.class;
}
public URI getOutputDatatype() {
return XMLSchema.DOUBLE;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Double;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printDouble((Double) obj);
}
public URI getDatatype() {
return XMLSchema.DOUBLE;
}
public Class<?> getOutputJavaClass() {
return Double.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseDouble(value);
}
}
/**
* Type map for xsd:boolean <--> Boolean.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMBoolean implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMBoolean() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Boolean.class;
}
public URI getOutputDatatype() {
return XMLSchema.BOOLEAN;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Boolean;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printBoolean((Boolean) obj);
}
public URI getDatatype() {
return XMLSchema.BOOLEAN;
}
public Class<?> getOutputJavaClass() {
return Boolean.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseBoolean(value);
}
}
/**
* Type map for xsd:byte <--> Byte.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMByte implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMByte() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Byte.class;
}
public URI getOutputDatatype() {
return XMLSchema.BYTE;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Byte;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printByte((Byte) obj);
}
public URI getDatatype() {
return XMLSchema.BYTE;
}
public Class<?> getOutputJavaClass() {
return Byte.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseByte(value);
}
}
/**
* Type map for xsd:base64Binary <--> byte[].
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMBase64Binary implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMBase64Binary() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return byte[].class;
}
public URI getOutputDatatype() {
return XMLSchema.BASE64BINARY;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof byte[];
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printBase64Binary((byte[]) obj);
}
public URI getDatatype() {
return XMLSchema.BASE64BINARY;
}
public Class<?> getOutputJavaClass() {
return byte[].class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseBase64Binary(value);
}
}
/**
* Type map for xsd:anyURI <--> org.openanzo.rdf.URI.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMAnyUri implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
public TMAnyUri() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return URI.class;
}
public URI getOutputDatatype() {
return XMLSchema.ANYURI;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof URI;
}
public String convertToLexicalValue(Object obj) {
return ((URI) obj).toString();
}
public URI getDatatype() {
return XMLSchema.ANYURI;
}
public Class<?> getOutputJavaClass() {
return URI.class;
}
public Object convertToNativeObject(String value) {
return MemURI.create(value);
}
}
/**
* Type map for xsd:hexBinary --> byte[].
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMHexBinary implements LexicalToNativeTypeMap {
public TMHexBinary() {
initializeDatatypeConverter();
}
public URI getDatatype() {
return XMLSchema.HEXBINARY;
}
public Class<?> getOutputJavaClass() {
return byte[].class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseHexBinary(value);
}
}
/**
* Type map for xsd:unsignedInt --> Long.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMUnsignedInt implements LexicalToNativeTypeMap {
public TMUnsignedInt() {
initializeDatatypeConverter();
}
public URI getDatatype() {
return XMLSchema.UNSIGNED_INT;
}
public Class<?> getOutputJavaClass() {
return Long.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseUnsignedInt(value);
}
}
/**
* Type map for xsd:unsignedShort --> Integer.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMUnsignedShort implements LexicalToNativeTypeMap {
public TMUnsignedShort() {
initializeDatatypeConverter();
}
public URI getDatatype() {
return XMLSchema.UNSIGNED_SHORT;
}
public Class<?> getOutputJavaClass() {
return Integer.class;
}
public Object convertToNativeObject(String value) {
return DatatypeConverter.parseUnsignedShort(value);
}
}
/**
* Type map for xsd:unsignedByte --> Short.
*
* @author lee <lee@cambridgesemantics.com>
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMUnsignedByte implements LexicalToNativeTypeMap {
public TMUnsignedByte() {
initializeDatatypeConverter();
}
public URI getDatatype() {
return XMLSchema.UNSIGNED_BYTE;
}
public Class<?> getOutputJavaClass() {
return Short.class;
}
public Object convertToNativeObject(String value) {
int val = DatatypeConverter.parseUnsignedShort(value);
if (val >= 0 && val <= 255) {
return val;
} else {
throw new NumberFormatException("Value out of range. Value:\"" + value);
}
}
}
/**
* Maps java.util.Date --> xsd:dateTime using UTC as the time zone.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMJavaDate implements NativeToLexicalTypeMap {
public TMJavaDate() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Date.class;
}
public URI getOutputDatatype() {
return XMLSchema.DATETIME;
}
public boolean canConvertToLexicalValue(Object obj) {
// Even though Timestamp, java.sql.Date, and java.sql.Time extend java.util.Date, their documentation
// warns that they should not be treated as java.util.Date instances. The extension is used for
// implementation inheritance rather than subtyping. We'll add a check here to prevent nasty issues
// related to that. In particular, the most common issue is that the Timetamp's precision would
// appear to drop from nanoseconds to seconds...not even milliseconds...seconds.
return obj instanceof Date && !(obj instanceof Timestamp) && !(obj instanceof Time) && !(obj instanceof java.sql.Date);
}
public String convertToLexicalValue(Object obj) {
Calendar cal = Calendar.getInstance(DateUtils.UTC_TIME_ZONE);
cal.setTime((Date) obj);
return DatatypeConverter.printDateTime(cal);
}
}
/**
* Maps java.sql.Timestamp --> xsd:dateTime using UTC as the time zone and preserving the Timestamp's nanosecond precision.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMSQLTimestamp implements NativeToLexicalTypeMap {
public TMSQLTimestamp() {
initializeDatatypeConverter();
}
private static final Date MIN_DATE = new Date(Long.MIN_VALUE);
public Class<?> getJavaClass() {
return Timestamp.class;
}
public URI getOutputDatatype() {
return XMLSchema.DATETIME;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Timestamp;
}
public String convertToLexicalValue(Object obj) {
Timestamp timestamp = (Timestamp) obj;
// Truncate the time to seconds precision since we'll get the fractional seconds from the Timestamp#getNanos()
// method below. Thus preventing loss of precision in the final lexical value.
long wholeSecondTime = (timestamp.getTime() / 1000) * 1000;
// It's annoyingly round-about to create a java.util.Calendar just to get an XMLGregorianCalendar.
// This wouldn't be needed if you could create an XMLGregorianCalendar using 'milliseconds since the epoch'.
// Oh well.
GregorianCalendar cal = new GregorianCalendar(DateUtils.UTC_TIME_ZONE);
cal.clear();
cal.setGregorianChange(MIN_DATE);
cal.setTimeInMillis(wholeSecondTime);
XMLGregorianCalendar xmlCal = datatypeFactory.newXMLGregorianCalendar(cal);
int nanoseconds = timestamp.getNanos();
String xmlval;
if (nanoseconds > 0) {
// The toXMLFormat() method of XMLGregorianCalendar can generate
// an invalid string when using fractional seconds in JDK5 and JDK6. See
// http://bugs.sun.com/view_bug.do?bug_id=2154623 which was originally filed as
// http://bugs.sun.com/view_bug.do?bug_id=6608696.
// The problem is that JDK5 changed the semantics of BigDecimal#toString() from underneath the
// XMLGregorianCalendar code. So you can end up with fractional seconds in scientific notation (ex. 5E-9).
// Looks like it will be fixed in JDK7 according to those bug reports.
// So we write a workaround here to output the fractional seconds ourselves using
// to correct BigDecimal#toPlainString() method.
// First set the time zone to undefined so and the fractional seconds to null so that the string ends
// string generated by the XMLGregorianCalendar will stop at the seconds field. We'll then
// Add the fractional seconds string and the time zone string ourselves.
xmlCal.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
xmlCal.setFractionalSecond(null);
BigDecimal fractionalSecond = BigDecimal.valueOf(timestamp.getNanos(), 9).stripTrailingZeros(); // nano is 10^-9
String fractionalSecondStr = fractionalSecond.toPlainString(); // This will always be something like "0.043" so we get rid of the first character when appending to the XML string.
xmlval = xmlCal.toXMLFormat() + fractionalSecondStr.substring(1) + "Z";
} else if (nanoseconds == 0) {
xmlCal.setFractionalSecond(null); // Doing this makes it so that no trailing zeroes are output.
xmlval = xmlCal.toXMLFormat();
} else {
throw new AnzoRuntimeException(ExceptionConstants.IO.INVALID_DATETIME);
}
return xmlval;
}
}
/**
* Maps java.sql.Time --> xsd:time without any time zone.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMSQLTime implements NativeToLexicalTypeMap {
public TMSQLTime() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Time.class;
}
public URI getOutputDatatype() {
return XMLSchema.TIME;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Time;
}
public String convertToLexicalValue(Object obj) {
return ((Time) obj).toString();
}
}
/**
* Maps java.sql.Date --> xsd:date without any time zone.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMSQLDate implements NativeToLexicalTypeMap {
public TMSQLDate() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return java.sql.Date.class;
}
public URI getOutputDatatype() {
return XMLSchema.DATE;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof java.sql.Date;
}
public String convertToLexicalValue(Object obj) {
return ((java.sql.Date) obj).toString();
}
}
/**
* Maps java.util.Calendar --> xsd:dateTime using UTC as the time zone and preserving the Timestamp's nanosecond precision.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMJavaCalendar implements NativeToLexicalTypeMap {
public TMJavaCalendar() {
initializeDatatypeConverter();
}
public Class<?> getJavaClass() {
return Calendar.class;
}
public URI getOutputDatatype() {
return XMLSchema.DATETIME;
}
public boolean canConvertToLexicalValue(Object obj) {
return obj instanceof Calendar;
}
public String convertToLexicalValue(Object obj) {
return DatatypeConverter.printDateTime((Calendar) obj);
}
}
/**
* Generic type map for types that convert to and from XMLGregorianCalendar. In particular, the XML Schema types xsd:dateTime, xsd:date, xsd:time,
* xsd:gYearMonth, xsd:gYear, xsd:gMonthDay, xsd:gDay, or xsd:gMonth.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMXMLGregorianCalendar implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
private final QName xsdType;
private final URI xsdDatatypeUri;
protected TMXMLGregorianCalendar(QName xsdType) {
if (xsdType.equals(DatatypeConstants.DATETIME)) {
xsdDatatypeUri = XMLSchema.DATETIME;
} else if (xsdType.equals(DatatypeConstants.DATE)) {
xsdDatatypeUri = XMLSchema.DATE;
} else if (xsdType.equals(DatatypeConstants.TIME)) {
xsdDatatypeUri = XMLSchema.TIME;
} else if (xsdType.equals(DatatypeConstants.GDAY)) {
xsdDatatypeUri = XMLSchema.GDAY;
} else if (xsdType.equals(DatatypeConstants.GMONTH)) {
xsdDatatypeUri = XMLSchema.GMONTH;
} else if (xsdType.equals(DatatypeConstants.GMONTHDAY)) {
xsdDatatypeUri = XMLSchema.GMONTHDAY;
} else if (xsdType.equals(DatatypeConstants.GYEAR)) {
xsdDatatypeUri = XMLSchema.GYEAR;
} else if (xsdType.equals(DatatypeConstants.GYEARMONTH)) {
xsdDatatypeUri = XMLSchema.GYEARMONTH;
} else {
throw new AnzoRuntimeException(ExceptionConstants.IO.UNSUPPORTED_DATATYPE, "xsd:dateTime, xsd:date, xsd:time, xsd:gYearMonth, xsd:gYear, xsd:gMonthDay, xsd:gDay, or xsd:gMonth");
}
this.xsdType = xsdType;
}
public Class<?> getJavaClass() {
return XMLGregorianCalendar.class;
}
public URI getOutputDatatype() {
return xsdDatatypeUri;
}
public boolean canConvertToLexicalValue(Object obj) {
if (obj instanceof XMLGregorianCalendar) {
try {
return ((XMLGregorianCalendar) obj).getXMLSchemaType().equals(xsdType);
} catch (IllegalStateException e) {
// Thrown by XMLGregorianCalendar#getXMLSchemaType() if the object doesn't have the appropriate
// fields to be one of the XML Schema built-in types.
log.debug(LogUtils.GLITTER_MARKER, "Native value does not apply to this mapper.", e);
}
}
return false;
}
public String convertToLexicalValue(Object obj) {
return ((XMLGregorianCalendar) obj).toXMLFormat();
}
public URI getDatatype() {
return xsdDatatypeUri;
}
public Class<?> getOutputJavaClass() {
return XMLGregorianCalendar.class;
}
public Object convertToNativeObject(String value) {
XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar(value);
if (cal.getXMLSchemaType().equals(xsdType)) {
return cal;
} else {
throw new IllegalArgumentException();
}
}
}
/**
* Generic type map for types that convert to and from javax.xml.datatype.Duration. In particular, the XML Schema types xsd:duration, xsd:yearMonthDuration,
* and xsd:dayTimeDuration.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMDuration implements LexicalToNativeTypeMap, NativeToLexicalTypeMap {
private final QName xsdType;
private final URI xsdDatatypeUri;
protected TMDuration(QName xsdType) {
if (xsdType.equals(DatatypeConstants.DURATION)) {
xsdDatatypeUri = XMLSchema.DURATION;
} else if (xsdType.equals(DatatypeConstants.DURATION_DAYTIME)) {
xsdDatatypeUri = XMLSchema.DURATION_DAYTIME;
} else if (xsdType.equals(DatatypeConstants.DURATION_YEARMONTH)) {
xsdDatatypeUri = XMLSchema.DURATION_YEARMONTH;
} else {
throw new AnzoRuntimeException(ExceptionConstants.IO.UNSUPPORTED_DATATYPE, "xsd:duration, xsd:yearMonthDuration, or xsd:dayTimeDuration");
}
this.xsdType = xsdType;
}
public Class<?> getJavaClass() {
return Duration.class;
}
public URI getOutputDatatype() {
return xsdDatatypeUri;
}
public boolean canConvertToLexicalValue(Object obj) {
if (obj instanceof Duration) {
try {
return ((Duration) obj).getXMLSchemaType().equals(xsdType);
} catch (IllegalStateException e) {
// Thrown by Duration#getXMLSchemaType() if the object doesn't have the appropriate
// fields to be one of the XML Schema built-in types.
log.debug(LogUtils.GLITTER_MARKER, "Native value does not apply to this mapper.", e);
}
}
return false;
}
public String convertToLexicalValue(Object obj) {
return ((Duration) obj).toString();
}
public URI getDatatype() {
return xsdDatatypeUri;
}
public Class<?> getOutputJavaClass() {
return Duration.class;
}
public Object convertToNativeObject(String value) {
Duration duration = datatypeFactory.newDuration(value);
if (DatatypeConstants.DURATION.equals(xsdType))
return duration;
try {
if (duration.getXMLSchemaType().equals(xsdType)) {
return duration;
} else {
throw new IllegalArgumentException();
}
} catch (IllegalStateException ise) {
throw new IllegalArgumentException(ise);
}
}
}
/**
* Type map for http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral --> String.
*
* @author Jordi Albornoz Mulligan (<a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>)
*/
static class TMXmlLiteralString implements LexicalToNativeTypeMap {
public TMXmlLiteralString() {
initializeDatatypeConverter();
}
public URI getDatatype() {
return RDF.XMLLiteral;
}
public Class<?> getOutputJavaClass() {
return String.class;
}
public Object convertToNativeObject(String value) {
return value;
}
}
}