// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library; import java.math.BigDecimal; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.UUID; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import openadk.library.impl.ElementSorter; import openadk.library.impl.SIFIOFormatter; /** * A class that converts native datatypes supported by SIF to their textual * representation. * * @author Andrew Elmhrost * @version 2.0 */ public abstract class SIFFormatter { /** * Converts a Java <c>Calendar</c> value to a SIF data value * * @param date * @return The date formatted as a string, using SIF formatting requirements */ public abstract String toDateString(Calendar date); /** * Converts a Java <c>Calendar</c> value to a SIF datetime value * * @param date * @return The datetime formatted as a string, using SIF formatting * requirements */ public abstract String toDateTimeString(Calendar date); /** * Converts a Java <c>Calendar</c> value to a SIF time value * * @param time * @return The time formatted as a string, using SIF formatting requirements */ public abstract String toTimeString(Calendar time); /** * Converts a Java <c>BigDecimal</c> value to a SIF decimal value * * @param decimalValue * @return The BigDecimal formatted as a string, using SIF formatting * requirements */ public abstract String toString(BigDecimal decimalValue); /** * Converts a Java <c>Boolean</c> value to a SIF boolean value * * @param boolValue * @return The boolean formatted as a string, using SIF formatting * requirements */ public abstract String toString(Boolean boolValue); /** * Converts an a SIF XML date value to a Java <c>Calendar</c> value * * @param dateValue * @return A Calendar that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the value cannot be parsed */ public abstract Calendar toDate(String dateValue); /** * Parses a datetime value from the provided string. NOTE: SIF 1.x does not * support datetime values. * * @param xmlValue * @return A Calendar that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the date cannot be parsed */ public abstract Calendar toDateTime(String xmlValue); /** * Parses a time value from the provided string. NOTE: SIF 1.x does not * support time values. * * @param xmlValue * @return A Calendar that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the value cannot be parsed */ public abstract Calendar toTime(String xmlValue); /** * Converts an a SIF XML decimal value to a Java <c>BigDecimal</c> value * * @param decimalValue * @return A Decimal that has been parsed from the SIF String representation * @throws IllegalArgumentException * If the value cannot be parsed */ public abstract BigDecimal toDecimal(String decimalValue); /** * Converts an a SIF XML duration value to a Java <c>Duration</c> value * * @param xmlValue * A Duration formatted as a String or NULL * @return An XML Duration that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the value cannot be parsed */ public abstract Duration toDuration(String xmlValue); /** * Converts a Java <c>Duration</c> value to a SIF duration value * * @param d * @return The Duration formatted as a string, using SIF formatting * requirements * @throws IllegalArgumentException * If the duration cannot be parsed * @throws UnsupportedOperationException * in SIF 1.1, since Durations are not used */ public abstract String toString(Duration d); /** * Converts an a SIF XML boolean value to a Java <c>Boolean</c> value * * @param inValue * A boolean formatted as a String or NULL * @return A Boolean that has been parsed from the String representation * @throws IllegalArgumentException * If the value cannot be parsed */ public abstract Boolean toBoolean(String inValue); /** * @return The Content-Type HttpHeader that should be used */ public String getContentType() { return SIFIOFormatter.CONTENT_TYPE; } /** * @return the Charset used by SIF to encode XML to a binary transport */ public Charset getCharset() { return SIFIOFormatter.CHARSET; } /** * Returns true if the formatter supports XML Namespaces. If this value * returns true, XML Namespaces will be declared when writing SIF Elements, * and the xsi:nil attribute will be enabled * * @return true if the formatter supports namespaces */ public abstract boolean supportsNamespaces(); /** * Adds a SIFElement parsed from a specific version of SIF to the parent. * The formatter instance may use version-specific rules to ensure that the * hierarchy is properly maintained when the source of the content is from * this version of SIF * * @param contentParent * The element to add content to * @param content * The element to add * @param version * The version of SIF that the SIFElement is being constructed * from * @return Returns the child that has been added to the parent */ public SIFElement addChild(SIFElement contentParent, SIFElement content, SIFVersion version) { return contentParent.addChild(content); } /** * Adds a SimpleField parsed from a specific version of SIF to the parent. * * @param contentParent * The element to add content to * @param fieldDef * The metadata definition of the field to set * @param data * The value to set to the field * @param version * The version of SIF that the SIFElement is being constructed * from */ public SimpleField setField( SIFElement contentParent, ElementDef fieldDef, SIFSimpleType data, SIFVersion version ) { return contentParent.setField( fieldDef, data ); } /** * Gets the content from the SIFElement for the specified version of SIF. * Only elements that apply to the requested version of SIF will be * returned. * * @param element * The element to retrieve content from * @param version * @return The content of the specified parent */ @SuppressWarnings("unchecked") public List<Element> getContent(SIFElement element, SIFVersion version) { List<Element> returnValue = new ArrayList<Element>(); List<SimpleField> fields = element.getFields(); for (SimpleField val : fields) { ElementDef def = val.getElementDef(); if ( def.isSupported( version ) && !def.isAttribute( version ) && def.isField() ){ returnValue.add(val); } } List<? extends SIFElement> children = element.getChildList(); for (SIFElement val : children) { ElementDef def = val.getElementDef(); if( def.isSupported( version ) ) { returnValue.add(val); } } Collections.sort( returnValue, ElementSorter.getInstance(version) ); return returnValue; } /** * Gets the fields from the SIFElement for the specified version of SIF. * Only the fields that apply to the requested version of SIF will be * returned. * * @param element * @param version * @return Returns the fields of the SIFElement */ @SuppressWarnings("unchecked") public List<SimpleField> getFields(SIFElement element, SIFVersion version) { List<SimpleField> fields = element.getFields(); // remove any fields that do not belong in this version of SIF for( int a = fields.size() - 1; a > -1 ; a-- ){ SimpleField field = fields.get( a ); ElementDef def = field.getElementDef(); if( version.compareTo(def.getEarliestVersion()) < 0 || version.compareTo(def.getLatestVersion()) > 0 ){ fields.remove( a ); } } Collections.sort(fields, ElementSorter.getInstance(version)); return fields; } public abstract String toString( Integer value ); /** * Converts an a SIF XML int value to a Java <c>int</c> value * * @param value * @return An Integer that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the value cannot be parsed */ public Integer toInteger(String value) { if( value == null ){ return null; } value = value.trim(); if( value.length() == 0 ){ return null; } return Integer.parseInt( value ); } /** * Converts an a SIF XML float value to a Java <c>Float</c> value * * @param floatValue * @return A float that has been parsed from the SIF String * representation * @throws IllegalArgumentException * If the value cannot be parsed */ public Float toFloat(String floatValue) { if (floatValue == null ) { return null; } floatValue = floatValue.trim(); if( floatValue.length() == 0 ){ return null; } if( floatValue.indexOf( 'N' ) > -1 ){ // Parse for INF, -INF and NaN if( floatValue.equalsIgnoreCase( "INF" ) ){ return Float.POSITIVE_INFINITY; } else if( floatValue.equalsIgnoreCase( "-INF" ) ){ return Float.NEGATIVE_INFINITY; } else if( floatValue.equalsIgnoreCase( "NaN" ) ){ return Float.NaN; } } return Float.parseFloat( floatValue); } public Long toLong(String longValue) { if (longValue == null ) { return null; } longValue = longValue.trim(); if( longValue.length() == 0 ){ return null; } return Long.parseLong( longValue ); } public String toString(Long longValue) { if (longValue == null) { return null; } return longValue.toString(); } public String toString(Float floatValue) { if (floatValue == null) { return null; } if( floatValue == Float.POSITIVE_INFINITY ){ return "INF"; }else if( floatValue == Float.NEGATIVE_INFINITY ){ return "-INF"; } else if( floatValue == Float.NaN ){ return "NaN"; } return floatValue.toString(); } /** * Converts a UUID to a string using the SIF format * * @param guid * the UUID to convert * @return the UUID formatted as a SIFRefId */ public static String UUIDToRefID(UUID guid) { String value = guid.toString(); return value.replace("-", "").toUpperCase(); } /** * Converts a SIF RefId to a Java UUID * * @param sifRefId * the string formatted as a SIF refId * @return a UUID * @throws IllegalArgumentException * if sifRefid does not conform to the string representation of * a SIF RefId */ public static UUID RefIDToUUID(String sifRefId) { if (sifRefId == null) { throw new IllegalArgumentException("Argument cannot be null"); } if (sifRefId.length() != 32) { throw new IllegalArgumentException( "RefId is not in proper format. Expected 32 characters, was " + sifRefId.length()); } return UUID.fromString(addGuidDashesToRefID(sifRefId)); } private static String addGuidDashesToRefID(String refID) { // TODO: There's got to be a better way to do this. StringBuilder a_Builder = new StringBuilder(refID); if (refID.length() > 23) { a_Builder.insert(8, '-'); a_Builder.insert(13, '-'); a_Builder.insert(18, '-'); a_Builder.insert(23, '-'); } return a_Builder.toString(); } public synchronized static DatatypeFactory getDataTypeFactory() { if (sXmlDataTypeFactory == null) { try { sXmlDataTypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException dce) { ADK.getLog().error("Unable to load XMLDatatypeFactory: " + dce, dce); } } return sXmlDataTypeFactory; } private static DatatypeFactory sXmlDataTypeFactory; }