// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library; import java.io.Serializable; import java.util.*; /** * Encapsulates a SIF version number.<p> * * The ADK uses instances of SIFVersion rather than strings to identify * versions of SIF. Typically you do not need to obtain a SIFVersion instance * directly except for when initializing the class framework with the * <code>ADK.initialize</code> method. Rather, classes for which SIF version is * a property, such as SIFDataObject and Query, provide a <code>getSIFVersion</code> * method to obtain the version associated with an object.<p> * * @author Eric Petersen * @version 1.0 */ public class SIFVersion implements Serializable, Comparable<SIFVersion> { private static final long serialVersionUID = Element.CURRENT_SERIALIZE_VERSION; private static Hashtable<String, SIFVersion> sVersions; /** The major version number */ private final int fMajor; /** The minor version number */ private final int fMinor; /** The revision number */ private final int fRevision; //// WARNING: MAKE SURE TO UPDATE THE GETINSTANCE METHOD WHEN ADDING NEW VERSIONS //// /** Identifies the SIF 1.1 Specification */ public static final SIFVersion SIF11 = new SIFVersion( 1, 1, 0 ); /** Identifies the SIF 1.5r1 Specification */ public static final SIFVersion SIF15r1 = new SIFVersion( 1, 5, 1 ); /** Identifies the SIF 2.0 Specification */ public static final SIFVersion SIF20 = new SIFVersion( 2, 0, 0 ); /** Identifies the SIF 2.0r1 Specification */ public static final SIFVersion SIF20r1 = new SIFVersion( 2, 0, 1 ); /** Identifies the SIF 2.1 Specification */ public static final SIFVersion SIF21 = new SIFVersion( 2, 1, 0 ); /** Identifies the SIF 2.2 Specification */ public static final SIFVersion SIF22 = new SIFVersion( 2, 2, 0 ); /** Identifies the SIF 2.3 Specification */ public static final SIFVersion SIF23 = new SIFVersion( 2, 3, 0 ); /** Identifies the SIF 2.4 Specification */ public static final SIFVersion SIF24 = new SIFVersion( 2, 4, 0 ); /** Identifies the SIF 2.5 Specification */ public static final SIFVersion SIF25 = new SIFVersion( 2, 5, 0 ); /** Identifies the SIF 2.6 Specification */ public static final SIFVersion SIF26 = new SIFVersion( 2, 6, 0 ); //// WARNING: MAKE SURE TO UPDATE THE GETINSTANCE METHOD WHEN ADDING NEW VERSIONS //// /** Identifies the latest SIF Specification supported by the SIFWorks ADK */ public static final SIFVersion LATEST = SIF26; /** * Constructs a version object * * @param major The major version number * @param minor The minor version number * @param revision The revision number */ private SIFVersion( int major, int minor, int revision ) { fMajor = major; fMinor = minor; fRevision = revision; } /** * Gets a SIFVersion instance. This method always returns the same version * instance for the given version numbers. If the version numbers match an official * version supported by the ADK, that version is returned. Otherwise, new version * object is created and returned. The same SIFVersion instance will always be * returned for the same parameters * @return A SIFVersion instance to encapsulate the version information * provided to this method. If the <i>major</i>, <i>minor</i>, and * <i>revision</i> numbers match one of the versions supported by the * ADK (e.g. SIFVersion.SIF10r1, SIFVersion.SIF10r2, etc.), that object * is returned. Otherwise, a new instance is created. Thus, you are * guaranteed to always receive the same SIFVersion instance for a given * version number supported by the ADK. */ private static SIFVersion getInstance( int major, int minor, int revision ) { // Check for versions explicitly supported by the ADK first if( major == 2 ){ if( minor == 0 ){ if( revision == 0 ){ return SIF20; } else if( revision == 1 ){ return SIF20r1; } } if( revision == 0 ){ if( minor == 1 ){ return SIF21; } else if( minor == 2 ){ return SIF22; } else if( minor == 3 ){ return SIF23; } else if( minor == 4 ) { return SIF24; } else if( minor == 5 ) { return SIF25; } else if( minor == 6 ) { return SIF26; } } } else if( major == 1 ) { if( minor == 5 && revision == 1 ){ return SIF15r1; } else if( minor == 1 && revision == 0 ){ return SIF11; } } // No explicit support found. Return a newly-fabricated instance // to support this version of SIF String tag = toString( major, minor, revision ); // An official SIFVersion matching the parameters was not found. // check for an existing parsed instance, or create a new one. if( sVersions == null ){ sVersions = new Hashtable<String,SIFVersion>(); } SIFVersion ver = sVersions.get( tag ); if( ver == null ) { ver = new SIFVersion( major, minor, revision ); sVersions.put( tag, ver ); } return ver; } /** * Gets the major version number * @return the major version number of this SIFVersion */ public int getMajor() { return fMajor; } /** * Gets the minor version number * @return the minor version number of this SIFVersion */ public int getMinor() { return fMinor; } /** * Gets the revision number * @return The revision number of this SIFVersion */ public int getRevision() { return fRevision; } /** * Parse a <code>SIFVersion</code> from a string<p> * * @param versionStr A version string in the format "1.0r1" * @return A SIFVersion instance encapsulating the version string * @exception IllegalArgumentException is thrown if the version string is invalid */ public static SIFVersion parse( String versionStr ) { try { String v = versionStr.toLowerCase(); int i = v.indexOf('.'); int major = Integer.parseInt( v.substring(0,i) ); int minor = 0; int revision = 0; int r = v.indexOf('r'); if( r == -1 ) { String minorStr = v.substring(i+1); if( minorStr.equals( "*" ) ){ // NOTE: This may change to getLatest(major). However, the Test harness does not // support that at the moment. // For now, return 1.5r1 for 1.*, 2.0r1 or higher (based on ADK.getSIFVersion) for 2.* if( major == 1 ){ return SIFVersion.SIF15r1; } else if( major == 2 ){ if( ADK.getSIFVersion().compareTo( SIFVersion.SIF20r1 ) > 0 ){ return ADK.getSIFVersion(); } else { return SIFVersion.SIF20r1; } } else { throw new IllegalArgumentException( "SIFVersion " + versionStr + " is not supported." ); } } else { minor = Integer.parseInt( minorStr ); } } else { minor = Integer.parseInt( v.substring(i+1,r) ); revision = Integer.parseInt( v.substring(r+1) ); } return getInstance( major, minor, revision ); } catch( NumberFormatException nfe ) { throw new IllegalArgumentException( versionStr + " is an invalid version string", nfe ); } } /** * Returns the latest SIFVersion supported by the ADK for the major version * number of SIF specified. For example, passing the value 1 returns * <code>SIFVersion.15r1</code> * @param major * @return The latest version of SIF that the ADK supports for the specified * major version. */ public static SIFVersion getLatest( int major ){ switch( major ){ case 1: return SIFVersion.SIF15r1; case 2: return SIFVersion.LATEST; } return null; } /** * Returns the earliest SIFVersion supported by the ADK for the major version * number of SIF specified. For example, passing the value 1 returns * <code>SIFVersion.SIF11</code> * @param major * @return The latest version of SIF that the ADK supports for the specified * major version. */ public static SIFVersion getEarliest( int major ){ switch( major ){ case 1: return SIFVersion.SIF11; case 2: // NOTE SIFVersion.SIF20 is supported by the ADK, but will be phased // out, and is no longer an official SIF Version return SIFVersion.SIF20r1; } return null; } /** * Parse a <code>SIFVersion</code> from a <i>xmlns</i> attribute value<p> * * If the xmlns attribute is in the form "http://www.sifinfo.org/v1.0r1/messages", * the version identified by the namespace is returned (e.g. "1.0r1"). If the * xmlns attribute is in the form "http://www.sifinfo.org/infrastructure/1.x", * the latest version of SIF identified by the major version number is * returned.<p> * * @param xmlns A SIF xmlns attribute value (e.g. "http://www.sifinfo.org/v1.0r1/messages", * "http://www.sifinfo.org/infrastructure/1x.", etc) * * @return A SIFVersion object encapsulating the version of SIF identified * by the xmlns value, or null if the xmlns is invalid */ public static SIFVersion parseXmlns( String xmlns ) { // // Determine the SIFVersion: // if( xmlns != null ) { if( xmlns.endsWith( ".x" ) ){ // http://www.sifinfo.org/infrastructure/1.x // NOTE: This works until SIF 10.x int location = xmlns.lastIndexOf( '/' ); char majorCh = xmlns.charAt( location + 1 ); if( Character.isDigit( majorCh ) ) { int major = majorCh-48; return getLatest( major ); } } } return null; } /** * Get the SIF namespace for this version of the specification.<p> * * @return If the SIFVersion is less than SIF 1.1, a namespace in the form * "http://www.sifinfo.org/v1.0r2/messages" is returned, where the full * SIF Version number is included in the namespace. For SIF 1.x and * later, a namespace in the form "http://www.sifinfo.org/infrastructure/1.x" * is returned, where only the major version number is included in the * namespace. */ public String getXmlns() { if( compareTo( SIFVersion.SIF11 ) < 0 ) return "http://www.sifinfo.org/v" + toString() + "/messages"; return SIFDTD.XMLNS_BASE + "/" + fMajor + ".x"; } /** * Compare this version to another * @param version The version to compare * @return -1 if this version is earlier than <code>version</code>, 0 if * the versions are equal, or 1 if this version is greater than <code> * version</code> or <code>version</code> is null. */ public int compareTo( SIFVersion version ) { if( version == null ){ return 1; } int compare = compare( fMajor, version.fMajor ); if( compare != 0 ){ return compare; } compare = compare( fMinor, version.fMinor ); if( compare != 0 ){ return compare; } return compare( fRevision, version.fRevision ); } private int compare( int thisValue, int compareValue ) { if( thisValue == compareValue ){ return 0; } if( thisValue > compareValue ){ return 1; } return -1; } /** * Gets the string representation of the version * @return The tag passed to the constructor. If null, a version in the * form <i>major</i>.<i>minor</i>r<i>revision</i> is returned with no * padding. */ public String toString() { return toString( fMajor, fMinor, fRevision ); } private static String toString( int major, int minor, int revision ){ if( revision < 1 ) return String.format( "%s.%s", major, minor ); else return String.format( "%s.%sr%s", major, minor, revision ); } /** * Gets the string representation of the version using an underscore instead * of a period as the delimiter * @return This SIFVersion in symbol format (e.g. 1_5r1) */ public String toSymbol() { if( fRevision < 1 ) return fMajor+"_"+fMinor; else return fMajor+"_"+fMinor+"r"+fRevision; } /** * Evaluates the native wrapped value of this object to see if * it equals the value of the compared object * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if( this == o ) { return true; } if((o != null) && (o instanceof SIFVersion )) { SIFVersion compared = (SIFVersion)o; return fMajor == compared.fMajor && fMinor == compared.fMinor && fRevision == compared.fRevision; } return false; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ public int hashCode() { return fMajor * 100000 + fMinor * 100 + fRevision; } }