/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* HUMBOLDT EU Integrated Project #030962
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.io.gml.internal.simpletype;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
import org.apache.xmlbeans.GDate;
import org.apache.xmlbeans.GDateBuilder;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlDate;
import org.apache.xmlbeans.XmlDateTime;
import org.apache.xmlbeans.XmlTime;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import eu.esdihumboldt.hale.common.core.HalePlatform;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.Binding;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.ElementType;
/**
* Utility methods used for simple type conversion
*
* @author Simon Templer
* @partner 01 / Fraunhofer Institute for Computer Graphics Research
* @version $Id$
*/
public class SimpleTypeUtil {
/**
* XML simple type names mapped to the corresponding XmlBeans type
*/
private static final Map<String, Class<? extends XmlAnySimpleType>> TYPE_MAP = new HashMap<String, Class<? extends XmlAnySimpleType>>();
static {
// TODO add additional simple types
// assuming number and string types are correctly converted using
// toString
// time/date types
TYPE_MAP.put("dateTime", XmlDateTime.class); //$NON-NLS-1$
TYPE_MAP.put("date", XmlDate.class); //$NON-NLS-1$
TYPE_MAP.put("time", XmlTime.class); //$NON-NLS-1$
}
/**
* Convert a simple type value to a string
*
* @param <T> the type of the value
* @param value the value
* @param type the type definition of the simple type
* @return the string representation of the value or <code>null</code> if
* the value is <code>null</code>
*/
public static <T> String convertToXml(T value, TypeDefinition type) {
if (value == null) {
return null;
}
ConversionService conversionService = HalePlatform.getService(ConversionService.class);
Class<? extends XmlAnySimpleType> simpleType = getSimpleType(type);
if (simpleType != null) {
try {
XmlAnySimpleType simpleTypeValue = conversionService.convert(value, simpleType);
if (simpleTypeValue instanceof XmlDateTime) {
XmlDateTime xmlDateTime = (XmlDateTime) simpleTypeValue;
// use Zulu time to have a reproducable result
// (as the old Java Date types always assume the current
// time zone!)
//
// XXX this should be removed when time/date types are used
// that are timezone aware
Calendar calendar = xmlDateTime.getCalendarValue();
GDateBuilder builder = new GDateBuilder(calendar);
builder.normalizeToTimeZone(0);
GDate gdate = builder.toGDate();
xmlDateTime.setGDateValue(gdate);
}
if (simpleTypeValue != null) {
return simpleTypeValue.getStringValue();
}
} catch (ConversionException e) {
// ignore
}
}
// try to convert to string
try {
String stringValue = conversionService.convert(value, String.class);
if (stringValue != null) {
return stringValue;
}
} catch (ConversionException e) {
// ignore
}
// fall-back
return value.toString();
}
/**
* Convert a string belonging to a XML simple type to the binding specified
* by the given type definition.
*
* @param value the string value
* @param type the type definition
* @return <code>null</code> if the string was <code>null</code>, the
* converted object with the binding type if possible, otherwise the
* original string
*/
public static Object convertFromXml(String value, TypeDefinition type) {
if (value == null) {
return null;
}
Class<? extends XmlAnySimpleType> simpleType = getSimpleType(type);
Class<?> binding = type.getConstraint(Binding.class).getBinding();
if (List.class.isAssignableFrom(binding)) { // XXX also for collection
// binding?
// we are dealing with a simple type list
// items separated by whitespace
String[] elements = value.split("\\s+");
ElementType elementType = type.getConstraint(ElementType.class);
Class<? extends XmlAnySimpleType> elementSimpleType = null;
if (elementType.getDefinition() != null) {
elementSimpleType = getSimpleType(elementType.getDefinition());
}
Class<?> elementBinding = elementType.getBinding();
List<Object> result = new ArrayList<Object>();
for (String element : elements) {
Object convElement = convertFromXml(element, elementSimpleType, elementBinding);
result.add(convElement);
}
return result;
}
// convert ordinary value
return convertFromXml(value, simpleType, binding);
}
private static Object convertFromXml(String value, Class<? extends XmlAnySimpleType> simpleType,
Class<?> binding) {
ConversionService conversionService = HalePlatform.getService(ConversionService.class);
// try using simple type for conversion
if (simpleType != null && conversionService.canConvert(String.class, simpleType)) {
try {
XmlAnySimpleType simpleValue = conversionService.convert(value, simpleType);
if (simpleValue != null) {
try {
Object bindingValue = conversionService.convert(simpleValue, binding);
return bindingValue;
} catch (ConversionException e) {
// ignore
}
}
return simpleValue;
} catch (ConversionException e) {
// ignore
}
}
// try direct conversion
try {
Object result = conversionService.convert(value, binding);
return result;
} catch (ConversionException e) {
// ignore
}
return value;
}
/**
* Get the XmlBeans simple type class for the given type definition
*
* @param type the type definition
*
* @return the XmlBeans simple type class
*/
private static Class<? extends XmlAnySimpleType> getSimpleType(TypeDefinition type) {
if (type == null) {
return null;
}
if (type.getName().getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
Class<? extends XmlAnySimpleType> simpleType = TYPE_MAP
.get(type.getName().getLocalPart());
if (simpleType != null) {
return simpleType;
}
}
if (type.getSuperType() != null) {
return getSimpleType(type.getSuperType());
}
return null;
}
}