package org.uncertweb.ps.encoding.xml; import java.lang.reflect.Array; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.xml.bind.DatatypeConverter; import org.jdom.Content; import org.jdom.Text; import org.joda.time.Chronology; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.chrono.ISOChronology; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.uncertweb.ps.encoding.EncodeException; import org.uncertweb.ps.encoding.ParseException; public class PrimitiveEncoding extends AbstractXMLEncoding { private static final String NAMESPACE = "http://www.w3.org/2001/XMLSchema"; private static final List<Class<?>> SUPPORTED_TYPES = Arrays.asList(new Class<?>[] { Double.class, Double[].class, Integer.class, Integer[].class, String.class, String[].class, Float.class, Float[].class, DateMidnight.class, DateMidnight[].class, URI.class, URI[].class, Boolean.class, Boolean[].class }); public <T> T parse(Content content, Class<T> type) throws ParseException { // get text to parse if (!(content instanceof Text)) { throw new ParseException("Can't parse non-text content."); } Text textContent = (Text)content; String[] elementText = textContent.getText().split("\\s+"); // parse class name boolean isArrayClass = type.isArray(); String typeName = parseTypeName(type); String simpleTypeName = parseSimpleTypeName(type); // special case if (simpleTypeName.equals("String") && !isArrayClass) { return type.cast(textContent.getText()); } // parse // TODO: not using full class names could be risky List<Object> objects = new ArrayList<Object>(); for (String text : elementText) { switch (simpleTypeName) { case "DateMidnight": try { DateTime dateTime = new DateTime(DatatypeConverter.parseDate(text)); Chronology chronology = ISOChronology.getInstance(dateTime.getZone()); DateMidnight date = new DateMidnight(dateTime, chronology); objects.add(date); } catch (IllegalArgumentException e) { throw new ParseException("Invalid date format.", e); } break; case "URI": try { objects.add(new URI(text)); } catch (URISyntaxException e) { throw new ParseException("Couldn't parse URI with bad syntax.", e); } break; case "Float": objects.add(Float.parseFloat(text)); break; case "Double": objects.add(Double.parseDouble(text)); break; case "Boolean": Boolean bool; if (text.equals("0")) { bool = false; } else if (text.equals("1")) { bool = true; } else { bool = Boolean.parseBoolean(text); } objects.add(bool); break; case "Integer": objects.add(Integer.parseInt(text)); break; case "String": objects.add(text); break; } } if (isArrayClass) { try { Object array = Array.newInstance(Class.forName(typeName), objects.size()); for (int i = 0; i < objects.size(); i++) { Array.set(array, i, objects.get(i)); } return type.cast(array); } catch (ClassNotFoundException e) { // shouldn't happen, only using java primitive classes return null; } } else { return type.cast(objects.get(0)); } } @Override public boolean isSupportedMimeType(String mimeType) { return super.isSupportedMimeType(mimeType) || mimeType.equals(getDefaultMimeType()); } @Override public String getDefaultMimeType() { return "text/plain"; } @Override public <T> Text encode(T object) throws EncodeException { Class<?> type = object.getClass(); StringBuilder string = new StringBuilder(); if (type.isArray()) { int length = Array.getLength(object); for (int i = 0; i < length; i++) { Text encoded = encode(Array.get(object, i)); string.append(encoded.getText()); string.append(" "); } string.deleteCharAt(string.length() - 1); } else { if (object instanceof DateMidnight) { DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-ddZZ"); string.append(format.print((DateMidnight)object)); } else { string.append(object.toString()); } } return new Text(string.toString()); } @Override public boolean isSupportedType(Class<?> type) { return SUPPORTED_TYPES.contains(type); } @Override public String getNamespace() { return NAMESPACE; } @Override public String getSchemaLocation() { return null; } @Override public Include getInclude(Class<?> type) { // get name for include // TODO: not using full class names could be risky String name = parseSimpleTypeName(type); switch (name) { case "URI": name = "anyURI"; break; case "DateMidnight": name = "date"; break; default: name = name.toLowerCase(); break; } // return include if (type.isArray()) { return new IncludeList(name); } else { return new IncludeType(name); } } private String parseTypeName(Class<?> type) { String typeName = type.getName(); if (typeName.startsWith("[L")) { typeName = typeName.substring(2); } if (typeName.endsWith(";")) { typeName = typeName.substring(0, typeName.length() - 1); } return typeName; } private String parseSimpleTypeName(Class<?> type) { String typeName = parseTypeName(type); return typeName.substring(typeName.lastIndexOf(".") + 1); } }