Home | History | Annotate | Download | only in util
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 1996-2016, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  *******************************************************************************
      8  */
      9 
     10 package com.ibm.icu.util;
     11 
     12 import java.util.concurrent.ConcurrentHashMap;
     13 
     14 /**
     15  * Class to store version numbers of the form major.minor.milli.micro.
     16  * @author synwee
     17  * @stable ICU 2.6
     18  */
     19 public final class VersionInfo implements Comparable<VersionInfo>
     20 {
     21     // public data members -------------------------------------------------
     22 
     23     /**
     24      * Unicode 1.0 version
     25      * @stable ICU 2.6
     26      */
     27     public static final VersionInfo UNICODE_1_0;
     28     /**
     29      * Unicode 1.0.1 version
     30      * @stable ICU 2.6
     31      */
     32     public static final VersionInfo UNICODE_1_0_1;
     33     /**
     34      * Unicode 1.1.0 version
     35      * @stable ICU 2.6
     36      */
     37     public static final VersionInfo UNICODE_1_1_0;
     38     /**
     39      * Unicode 1.1.5 version
     40      * @stable ICU 2.6
     41      */
     42     public static final VersionInfo UNICODE_1_1_5;
     43     /**
     44      * Unicode 2.0 version
     45      * @stable ICU 2.6
     46      */
     47     public static final VersionInfo UNICODE_2_0;
     48     /**
     49      * Unicode 2.1.2 version
     50      * @stable ICU 2.6
     51      */
     52     public static final VersionInfo UNICODE_2_1_2;
     53     /**
     54      * Unicode 2.1.5 version
     55      * @stable ICU 2.6
     56      */
     57     public static final VersionInfo UNICODE_2_1_5;
     58     /**
     59      * Unicode 2.1.8 version
     60      * @stable ICU 2.6
     61      */
     62     public static final VersionInfo UNICODE_2_1_8;
     63     /**
     64      * Unicode 2.1.9 version
     65      * @stable ICU 2.6
     66      */
     67     public static final VersionInfo UNICODE_2_1_9;
     68     /**
     69      * Unicode 3.0 version
     70      * @stable ICU 2.6
     71      */
     72     public static final VersionInfo UNICODE_3_0;
     73     /**
     74      * Unicode 3.0.1 version
     75      * @stable ICU 2.6
     76      */
     77     public static final VersionInfo UNICODE_3_0_1;
     78     /**
     79      * Unicode 3.1.0 version
     80      * @stable ICU 2.6
     81      */
     82     public static final VersionInfo UNICODE_3_1_0;
     83     /**
     84      * Unicode 3.1.1 version
     85      * @stable ICU 2.6
     86      */
     87     public static final VersionInfo UNICODE_3_1_1;
     88     /**
     89      * Unicode 3.2 version
     90      * @stable ICU 2.6
     91      */
     92     public static final VersionInfo UNICODE_3_2;
     93 
     94     /**
     95      * Unicode 4.0 version
     96      * @stable ICU 2.6
     97      */
     98     public static final VersionInfo UNICODE_4_0;
     99 
    100     /**
    101      * Unicode 4.0.1 version
    102      * @stable ICU 3.4
    103      */
    104     public static final VersionInfo UNICODE_4_0_1;
    105 
    106     /**
    107      * Unicode 4.1 version
    108      * @stable ICU 3.4
    109      */
    110     public static final VersionInfo UNICODE_4_1;
    111 
    112     /**
    113      * Unicode 5.0 version
    114      * @stable ICU 3.4
    115      */
    116     public static final VersionInfo UNICODE_5_0;
    117 
    118     /**
    119      * Unicode 5.1 version
    120      * @stable ICU 4.2
    121      */
    122     public static final VersionInfo UNICODE_5_1;
    123 
    124     /**
    125      * Unicode 5.2 version
    126      * @stable ICU 4.4
    127      */
    128     public static final VersionInfo UNICODE_5_2;
    129 
    130     /**
    131      * Unicode 6.0 version
    132      * @stable ICU 4.6
    133      */
    134     public static final VersionInfo UNICODE_6_0;
    135 
    136     /**
    137      * Unicode 6.1 version
    138      * @stable ICU 49
    139      */
    140     public static final VersionInfo UNICODE_6_1;
    141 
    142     /**
    143      * Unicode 6.2 version
    144      * @stable ICU 50
    145      */
    146     public static final VersionInfo UNICODE_6_2;
    147 
    148     /**
    149      * Unicode 6.3 version
    150      * @stable ICU 52
    151      */
    152     public static final VersionInfo UNICODE_6_3;
    153 
    154     /**
    155      * Unicode 7.0 version
    156      * @stable ICU 54
    157      */
    158     public static final VersionInfo UNICODE_7_0;
    159 
    160     /**
    161      * Unicode 8.0 version
    162      * @stable ICU 56
    163      */
    164     public static final VersionInfo UNICODE_8_0;
    165 
    166     /**
    167      * Unicode 9.0 version
    168      * @stable ICU 58
    169      */
    170     public static final VersionInfo UNICODE_9_0;
    171 
    172     /**
    173      * Unicode 10.0 version
    174      * @stable ICU 60
    175      */
    176     public static final VersionInfo UNICODE_10_0;
    177 
    178     /**
    179      * ICU4J current release version
    180      * @stable ICU 2.8
    181      */
    182     public static final VersionInfo ICU_VERSION;
    183 
    184     /**
    185      * Data version string for ICU's internal data.
    186      * Used for appending to data path (e.g. icudt43b)
    187      * @internal
    188      * @deprecated This API is ICU internal only.
    189      */
    190     @Deprecated
    191     public static final String ICU_DATA_VERSION_PATH = "60b";
    192 
    193     /**
    194      * Data version in ICU4J.
    195      * @internal
    196      * @deprecated This API is ICU internal only.
    197      */
    198     @Deprecated
    199     public static final VersionInfo ICU_DATA_VERSION;
    200 
    201     /**
    202      * Collation runtime version (sort key generator, string comparisons).
    203      * If the version is different, sort keys for the same string could be different.
    204      * This value may change in subsequent releases of ICU.
    205      * @stable ICU 2.8
    206      */
    207     public static final VersionInfo UCOL_RUNTIME_VERSION;
    208 
    209     /**
    210      * Collation builder code version.
    211      * When this is different, the same tailoring might result
    212      * in assigning different collation elements to code points.
    213      * This value may change in subsequent releases of ICU.
    214      * @stable ICU 2.8
    215      */
    216     public static final VersionInfo UCOL_BUILDER_VERSION;
    217 
    218     /**
    219      * Constant version 1.
    220      * This was intended to be the version of collation tailorings,
    221      * but instead the tailoring data carries a version number.
    222      * @deprecated ICU 54
    223      */
    224     @Deprecated
    225     public static final VersionInfo UCOL_TAILORINGS_VERSION;
    226 
    227 
    228     // public methods ------------------------------------------------------
    229 
    230     /**
    231      * Returns an instance of VersionInfo with the argument version.
    232      * @param version version String in the format of "major.minor.milli.micro"
    233      *                or "major.minor.milli" or "major.minor" or "major",
    234      *                where major, minor, milli, micro are non-negative numbers
    235      *                &lt;= 255. If the trailing version numbers are
    236      *                not specified they are taken as 0s. E.g. Version "3.1" is
    237      *                equivalent to "3.1.0.0".
    238      * @return an instance of VersionInfo with the argument version.
    239      * @exception IllegalArgumentException when the argument version
    240      *                is not in the right format
    241      * @stable ICU 2.6
    242      */
    243     public static VersionInfo getInstance(String version)
    244     {
    245         int length  = version.length();
    246         int array[] = {0, 0, 0, 0};
    247         int count   = 0;
    248         int index   = 0;
    249 
    250         while (count < 4 && index < length) {
    251             char c = version.charAt(index);
    252             if (c == '.') {
    253                 count ++;
    254             }
    255             else {
    256                 c -= '0';
    257                 if (c < 0 || c > 9) {
    258                     throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
    259                 }
    260                 array[count] *= 10;
    261                 array[count] += c;
    262             }
    263             index ++;
    264         }
    265         if (index != length) {
    266             throw new IllegalArgumentException(
    267                                                "Invalid version number: String '" + version + "' exceeds version format");
    268         }
    269         for (int i = 0; i < 4; i ++) {
    270             if (array[i] < 0 || array[i] > 255) {
    271                 throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
    272             }
    273         }
    274 
    275         return getInstance(array[0], array[1], array[2], array[3]);
    276     }
    277 
    278     /**
    279      * Returns an instance of VersionInfo with the argument version.
    280      * @param major major version, non-negative number &lt;= 255.
    281      * @param minor minor version, non-negative number &lt;= 255.
    282      * @param milli milli version, non-negative number &lt;= 255.
    283      * @param micro micro version, non-negative number &lt;= 255.
    284      * @exception IllegalArgumentException when either arguments are negative or &gt; 255
    285      * @stable ICU 2.6
    286      */
    287     public static VersionInfo getInstance(int major, int minor, int milli,
    288                                           int micro)
    289     {
    290         // checks if it is in the hashmap
    291         // else
    292         if (major < 0 || major > 255 || minor < 0 || minor > 255 ||
    293             milli < 0 || milli > 255 || micro < 0 || micro > 255) {
    294             throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
    295         }
    296         int     version = getInt(major, minor, milli, micro);
    297         Integer key     = Integer.valueOf(version);
    298         VersionInfo  result  = MAP_.get(key);
    299         if (result == null) {
    300             result = new VersionInfo(version);
    301             VersionInfo tmpvi = MAP_.putIfAbsent(key, result);
    302             if (tmpvi != null) {
    303                 result = tmpvi;
    304             }
    305         }
    306         return result;
    307     }
    308 
    309     /**
    310      * Returns an instance of VersionInfo with the argument version.
    311      * Equivalent to getInstance(major, minor, milli, 0).
    312      * @param major major version, non-negative number &lt;= 255.
    313      * @param minor minor version, non-negative number &lt;= 255.
    314      * @param milli milli version, non-negative number &lt;= 255.
    315      * @exception IllegalArgumentException when either arguments are
    316      *                                     negative or &gt; 255
    317      * @stable ICU 2.6
    318      */
    319     public static VersionInfo getInstance(int major, int minor, int milli)
    320     {
    321         return getInstance(major, minor, milli, 0);
    322     }
    323 
    324     /**
    325      * Returns an instance of VersionInfo with the argument version.
    326      * Equivalent to getInstance(major, minor, 0, 0).
    327      * @param major major version, non-negative number &lt;= 255.
    328      * @param minor minor version, non-negative number &lt;= 255.
    329      * @exception IllegalArgumentException when either arguments are
    330      *                                     negative or &gt; 255
    331      * @stable ICU 2.6
    332      */
    333     public static VersionInfo getInstance(int major, int minor)
    334     {
    335         return getInstance(major, minor, 0, 0);
    336     }
    337 
    338     /**
    339      * Returns an instance of VersionInfo with the argument version.
    340      * Equivalent to getInstance(major, 0, 0, 0).
    341      * @param major major version, non-negative number &lt;= 255.
    342      * @exception IllegalArgumentException when either arguments are
    343      *                                     negative or &gt; 255
    344      * @stable ICU 2.6
    345      */
    346     public static VersionInfo getInstance(int major)
    347     {
    348         return getInstance(major, 0, 0, 0);
    349     }
    350 
    351     private static volatile VersionInfo javaVersion;
    352 
    353     /**
    354      * @internal
    355      * @deprecated This API is ICU internal only.
    356      */
    357     @Deprecated
    358     public static VersionInfo javaVersion() {
    359         if (javaVersion == null) {
    360             synchronized(VersionInfo.class) {
    361                 if (javaVersion == null) {
    362                     String s = System.getProperty("java.version");
    363                     // clean string
    364                     // preserve only digits, separated by single '.'
    365                     // ignore over 4 digit sequences
    366                     // does not test < 255, very odd...
    367 
    368                     char[] chars = s.toCharArray();
    369                     int r = 0, w = 0, count = 0;
    370                     boolean numeric = false; // ignore leading non-numerics
    371                     while (r < chars.length) {
    372                         char c = chars[r++];
    373                         if (c < '0' || c > '9') {
    374                             if (numeric) {
    375                                 if (count == 3) {
    376                                     // only four digit strings allowed
    377                                     break;
    378                                 }
    379                                 numeric = false;
    380                                 chars[w++] = '.';
    381                                 ++count;
    382                             }
    383                         } else {
    384                             numeric = true;
    385                             chars[w++] = c;
    386                         }
    387                     }
    388                     while (w > 0 && chars[w-1] == '.') {
    389                         --w;
    390                     }
    391 
    392                     String vs = new String(chars, 0, w);
    393 
    394                     javaVersion = VersionInfo.getInstance(vs);
    395                 }
    396             }
    397         }
    398         return javaVersion;
    399     }
    400 
    401     /**
    402      * Returns the String representative of VersionInfo in the format of
    403      * "major.minor.milli.micro"
    404      * @return String representative of VersionInfo
    405      * @stable ICU 2.6
    406      */
    407     @Override
    408     public String toString()
    409     {
    410         StringBuilder result = new StringBuilder(7);
    411         result.append(getMajor());
    412         result.append('.');
    413         result.append(getMinor());
    414         result.append('.');
    415         result.append(getMilli());
    416         result.append('.');
    417         result.append(getMicro());
    418         return result.toString();
    419     }
    420 
    421     /**
    422      * Returns the major version number
    423      * @return the major version number
    424      * @stable ICU 2.6
    425      */
    426     public int getMajor()
    427     {
    428         return (m_version_ >> 24) & LAST_BYTE_MASK_ ;
    429     }
    430 
    431     /**
    432      * Returns the minor version number
    433      * @return the minor version number
    434      * @stable ICU 2.6
    435      */
    436     public int getMinor()
    437     {
    438         return (m_version_ >> 16) & LAST_BYTE_MASK_ ;
    439     }
    440 
    441     /**
    442      * Returns the milli version number
    443      * @return the milli version number
    444      * @stable ICU 2.6
    445      */
    446     public int getMilli()
    447     {
    448         return (m_version_ >> 8) & LAST_BYTE_MASK_ ;
    449     }
    450 
    451     /**
    452      * Returns the micro version number
    453      * @return the micro version number
    454      * @stable ICU 2.6
    455      */
    456     public int getMicro()
    457     {
    458         return m_version_ & LAST_BYTE_MASK_ ;
    459     }
    460 
    461     /**
    462      * Checks if this version information is equals to the argument version
    463      * @param other object to be compared
    464      * @return true if other is equals to this object's version information,
    465      *         false otherwise
    466      * @stable ICU 2.6
    467      */
    468     @Override
    469     public boolean equals(Object other)
    470     {
    471         return other == this;
    472     }
    473 
    474     /**
    475      * Returns the hash code value for this set.
    476      *
    477      * @return the hash code value for this set.
    478      * @see java.lang.Object#hashCode()
    479      * @stable ICU 58
    480      */
    481     @Override
    482     public int hashCode() {
    483         return m_version_;
    484     }
    485 
    486     /**
    487      * Compares other with this VersionInfo.
    488      * @param other VersionInfo to be compared
    489      * @return 0 if the argument is a VersionInfo object that has version
    490      *           information equals to this object.
    491      *           Less than 0 if the argument is a VersionInfo object that has
    492      *           version information greater than this object.
    493      *           Greater than 0 if the argument is a VersionInfo object that
    494      *           has version information less than this object.
    495      * @stable ICU 2.6
    496      */
    497     @Override
    498     public int compareTo(VersionInfo other)
    499     {
    500         return m_version_ - other.m_version_;
    501     }
    502 
    503     // private data members ----------------------------------------------
    504 
    505     /**
    506      * Unicode data version used by the current release.
    507      * Defined here privately for printing by the main() method in this class.
    508      * Should be the same as {@link com.ibm.icu.lang.UCharacter#getUnicodeVersion()}
    509      * which gets the version number from a data file.
    510      * We do not want VersionInfo to have an import dependency on UCharacter.
    511      */
    512     private static final VersionInfo UNICODE_VERSION;
    513 
    514     /**
    515      * Version number stored as a byte for each of the major, minor, milli and
    516      * micro numbers in the 32 bit int.
    517      * Most significant for the major and the least significant contains the
    518      * micro numbers.
    519      */
    520     private int m_version_;
    521     /**
    522      * Map of singletons
    523      */
    524     private static final ConcurrentHashMap<Integer, VersionInfo> MAP_ = new ConcurrentHashMap<Integer, VersionInfo>();
    525     /**
    526      * Last byte mask
    527      */
    528     private static final int LAST_BYTE_MASK_ = 0xFF;
    529     /**
    530      * Error statement string
    531      */
    532     private static final String INVALID_VERSION_NUMBER_ =
    533         "Invalid version number: Version number may be negative or greater than 255";
    534 
    535     // static declaration ------------------------------------------------
    536 
    537     /**
    538      * Initialize versions only after MAP_ has been created
    539      */
    540     static {
    541         UNICODE_1_0   = getInstance(1, 0, 0, 0);
    542         UNICODE_1_0_1 = getInstance(1, 0, 1, 0);
    543         UNICODE_1_1_0 = getInstance(1, 1, 0, 0);
    544         UNICODE_1_1_5 = getInstance(1, 1, 5, 0);
    545         UNICODE_2_0   = getInstance(2, 0, 0, 0);
    546         UNICODE_2_1_2 = getInstance(2, 1, 2, 0);
    547         UNICODE_2_1_5 = getInstance(2, 1, 5, 0);
    548         UNICODE_2_1_8 = getInstance(2, 1, 8, 0);
    549         UNICODE_2_1_9 = getInstance(2, 1, 9, 0);
    550         UNICODE_3_0   = getInstance(3, 0, 0, 0);
    551         UNICODE_3_0_1 = getInstance(3, 0, 1, 0);
    552         UNICODE_3_1_0 = getInstance(3, 1, 0, 0);
    553         UNICODE_3_1_1 = getInstance(3, 1, 1, 0);
    554         UNICODE_3_2   = getInstance(3, 2, 0, 0);
    555         UNICODE_4_0   = getInstance(4, 0, 0, 0);
    556         UNICODE_4_0_1 = getInstance(4, 0, 1, 0);
    557         UNICODE_4_1   = getInstance(4, 1, 0, 0);
    558         UNICODE_5_0   = getInstance(5, 0, 0, 0);
    559         UNICODE_5_1   = getInstance(5, 1, 0, 0);
    560         UNICODE_5_2   = getInstance(5, 2, 0, 0);
    561         UNICODE_6_0   = getInstance(6, 0, 0, 0);
    562         UNICODE_6_1   = getInstance(6, 1, 0, 0);
    563         UNICODE_6_2   = getInstance(6, 2, 0, 0);
    564         UNICODE_6_3   = getInstance(6, 3, 0, 0);
    565         UNICODE_7_0   = getInstance(7, 0, 0, 0);
    566         UNICODE_8_0   = getInstance(8, 0, 0, 0);
    567         UNICODE_9_0   = getInstance(9, 0, 0, 0);
    568         UNICODE_10_0   = getInstance(10, 0, 0, 0);
    569 
    570         ICU_VERSION   = getInstance(60, 2, 0, 0);
    571         ICU_DATA_VERSION = getInstance(60, 2, 0, 0);
    572         UNICODE_VERSION = UNICODE_10_0;
    573 
    574         UCOL_RUNTIME_VERSION = getInstance(9);
    575         UCOL_BUILDER_VERSION = getInstance(9);
    576         UCOL_TAILORINGS_VERSION = getInstance(1);
    577     }
    578 
    579     // private constructor -----------------------------------------------
    580 
    581     /**
    582      * Constructor with int
    583      * @param compactversion a 32 bit int with each byte representing a number
    584      */
    585     private VersionInfo(int compactversion)
    586     {
    587         m_version_ = compactversion;
    588     }
    589 
    590     /**
    591      * Gets the int from the version numbers
    592      * @param major non-negative version number
    593      * @param minor non-negative version number
    594      * @param milli non-negative version number
    595      * @param micro non-negative version number
    596      */
    597     private static int getInt(int major, int minor, int milli, int micro)
    598     {
    599         return (major << 24) | (minor << 16) | (milli << 8) | micro;
    600     }
    601     ///CLOVER:OFF
    602     /**
    603      * Main method prints out ICU version information
    604      * @param args arguments (currently not used)
    605      * @stable ICU 4.6
    606      */
    607     public static void main(String[] args) {
    608         String icuApiVer;
    609 
    610         if (ICU_VERSION.getMajor() <= 4) {
    611             if (ICU_VERSION.getMinor() % 2 != 0) {
    612                 // Development mile stone
    613                 int major = ICU_VERSION.getMajor();
    614                 int minor = ICU_VERSION.getMinor() + 1;
    615                 if (minor >= 10) {
    616                     minor -= 10;
    617                     major++;
    618                 }
    619                 icuApiVer = "" + major + "." + minor + "M" + ICU_VERSION.getMilli();
    620             } else {
    621                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
    622             }
    623         } else {
    624             if (ICU_VERSION.getMinor() == 0) {
    625                 // Development mile stone
    626                 icuApiVer = "" + ICU_VERSION.getMajor() + "M" + ICU_VERSION.getMilli();
    627             } else {
    628                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
    629             }
    630         }
    631 
    632 
    633         System.out.println("International Components for Unicode for Java " + icuApiVer);
    634 
    635         System.out.println("");
    636         System.out.println("Implementation Version: " + ICU_VERSION.getVersionString(2, 4));
    637         System.out.println("Unicode Data Version:   " + UNICODE_VERSION.getVersionString(2, 4));
    638         System.out.println("CLDR Data Version:      " + LocaleData.getCLDRVersion().getVersionString(2, 4));
    639         System.out.println("Time Zone Data Version: " + getTZDataVersion());
    640     }
    641 
    642     /**
    643      * Generate version string separated by dots with
    644      * the specified digit width.  Version digit 0
    645      * after <code>minDigits</code> will be trimmed off.
    646      * @param minDigits Minimum number of version digits
    647      * @param maxDigits Maximum number of version digits
    648      * @return A tailored version string
    649      * @internal
    650      * @deprecated This API is ICU internal only. (For use in CLDR, etc.)
    651      */
    652     @Deprecated
    653     public String getVersionString(int minDigits, int maxDigits) {
    654         if (minDigits < 1 || maxDigits < 1
    655                 || minDigits > 4 || maxDigits > 4 || minDigits > maxDigits) {
    656             throw new IllegalArgumentException("Invalid min/maxDigits range");
    657         }
    658 
    659         int[] digits = new int[4];
    660         digits[0] = getMajor();
    661         digits[1] = getMinor();
    662         digits[2] = getMilli();
    663         digits[3] = getMicro();
    664 
    665         int numDigits = maxDigits;
    666         while (numDigits > minDigits) {
    667             if (digits[numDigits - 1] != 0) {
    668                 break;
    669             }
    670             numDigits--;
    671         }
    672 
    673         StringBuilder verStr = new StringBuilder(7);
    674         verStr.append(digits[0]);
    675         for (int i = 1; i < numDigits; i++) {
    676             verStr.append(".");
    677             verStr.append(digits[i]);
    678         }
    679 
    680         return verStr.toString();
    681     }
    682     ///CLOVER:ON
    683 
    684 
    685     // Moved from TimeZone class
    686     private static volatile String TZDATA_VERSION = null;
    687 
    688     static String getTZDataVersion() {
    689         if (TZDATA_VERSION == null) {
    690             synchronized (VersionInfo.class) {
    691                 if (TZDATA_VERSION == null) {
    692                     UResourceBundle tzbundle = UResourceBundle.getBundleInstance("com/ibm/icu/impl/data/icudt"
    693                             + VersionInfo.ICU_DATA_VERSION_PATH, "zoneinfo64");
    694                     TZDATA_VERSION = tzbundle.getString("TZVersion");
    695                 }
    696             }
    697         }
    698         return TZDATA_VERSION;
    699     }
    700 }
    701