1 /*
   2  * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.misc;
  27 
  28 import java.util.StringTokenizer;
  29 import java.util.jar.Attributes;
  30 import java.util.jar.Attributes.Name;
  31 import java.util.ResourceBundle;
  32 import java.util.MissingResourceException;
  33 import java.text.MessageFormat;
  34 import java.lang.Character.*;
  35 
  36 
  37 /**
  38  * This class holds all necessary information to install or
  39  * upgrade a extension on the user's disk
  40  *
  41  * @deprecated this class will be removed in a future release.
  42  * @author  Jerome Dochez
  43  */
  44 @Deprecated
  45 public class ExtensionInfo {
  46 
  47     /**
  48      * public static values returned by the isCompatible method
  49      */
  50     public static final int COMPATIBLE = 0;
  51     public static final int REQUIRE_SPECIFICATION_UPGRADE = 1;
  52     public static final int REQUIRE_IMPLEMENTATION_UPGRADE = 2;
  53     public static final int REQUIRE_VENDOR_SWITCH = 3;
  54     public static final int INCOMPATIBLE = 4;
  55 
  56     /**
  57      * attributes fully describer an extension. The underlying described
  58      * extension may be installed and requested.
  59      */
  60     public String title;
  61     public String name;
  62     public String specVersion;
  63     public String specVendor;
  64     public String implementationVersion;
  65     public String vendor;
  66     public String vendorId;
  67     public String url;
  68 
  69     // For I18N support
  70     private static final ResourceBundle rb =
  71         ResourceBundle.getBundle("sun.misc.resources.Messages");
  72 
  73 
  74     /**
  75      * Create a new uninitialized extension information object
  76      */
  77     public ExtensionInfo() {
  78     }
  79 
  80     /**
  81      * Create and initialize an extension information object.
  82      * The initialization uses the attributes passed as being
  83      * the content of a manifest file to load the extension
  84      * information from.
  85      * Since manifest file may contain information on several
  86      * extension they may depend on, the extension key parameter
  87      * is prepanded to the attribute name to make the key used
  88      * to retrieve the attribute from the manifest file
  89      *
  90      * @param extensionKey unique extension key in the manifest
  91      * @param attr Attributes of a manifest file
  92      */
  93     public ExtensionInfo(String extensionKey, Attributes attr)
  94         throws NullPointerException
  95     {
  96         String s;
  97         if (extensionKey!=null) {
  98             s = extensionKey + "-";
  99         } else {
 100             s ="";
 101         }
 102 
 103         String attrKey = s + Name.EXTENSION_NAME.toString();
 104         name = attr.getValue(attrKey);
 105         if (name != null)
 106             name = name.trim();
 107 
 108         attrKey = s + Name.SPECIFICATION_TITLE.toString();
 109         title = attr.getValue(attrKey);
 110         if (title != null)
 111             title = title.trim();
 112 
 113         attrKey = s + Name.SPECIFICATION_VERSION.toString();
 114         specVersion = attr.getValue(attrKey);
 115         if (specVersion != null)
 116             specVersion = specVersion.trim();
 117 
 118         attrKey = s + Name.SPECIFICATION_VENDOR.toString();
 119         specVendor = attr.getValue(attrKey);
 120         if (specVendor != null)
 121             specVendor = specVendor.trim();
 122 
 123         attrKey = s + Name.IMPLEMENTATION_VERSION.toString();
 124         implementationVersion = attr.getValue(attrKey);
 125         if (implementationVersion != null)
 126             implementationVersion = implementationVersion.trim();
 127 
 128         attrKey = s + Name.IMPLEMENTATION_VENDOR.toString();
 129         vendor = attr.getValue(attrKey);
 130         if (vendor != null)
 131             vendor = vendor.trim();
 132 
 133         attrKey = s + Name.IMPLEMENTATION_VENDOR_ID.toString();
 134         vendorId = attr.getValue(attrKey);
 135         if (vendorId != null)
 136             vendorId = vendorId.trim();
 137 
 138         attrKey =s + Name.IMPLEMENTATION_URL.toString();
 139         url = attr.getValue(attrKey);
 140         if (url != null)
 141             url = url.trim();
 142     }
 143 
 144     /**
 145      * @return true if the extension described by this extension information
 146      * is compatible with the extension described by the extension
 147      * information passed as a parameter
 148      *
 149      * @param ei the requested extension information to compare to
 150      */
 151     public int isCompatibleWith(ExtensionInfo ei) {
 152 
 153         if (name == null || ei.name == null)
 154             return INCOMPATIBLE;
 155         if (name.compareTo(ei.name)==0) {
 156             // is this true, if not spec version is specified, we consider
 157             // the value as being "any".
 158             if (specVersion == null || ei.specVersion == null)
 159                 return COMPATIBLE;
 160 
 161             int version = compareExtensionVersion(specVersion, ei.specVersion);
 162             if (version<0) {
 163                 // this extension specification is "older"
 164                 if (vendorId != null && ei.vendorId !=null) {
 165                     if (vendorId.compareTo(ei.vendorId)!=0) {
 166                         return REQUIRE_VENDOR_SWITCH;
 167                     }
 168                 }
 169                 return REQUIRE_SPECIFICATION_UPGRADE;
 170             } else {
 171                 // the extension spec is compatible, let's look at the
 172                 // implementation attributes
 173                 if (vendorId != null && ei.vendorId != null) {
 174                     // They care who provides the extension
 175                     if (vendorId.compareTo(ei.vendorId)!=0) {
 176                         // They want to use another vendor implementation
 177                         return REQUIRE_VENDOR_SWITCH;
 178                     } else {
 179                         // Vendor matches, let's see the implementation version
 180                         if (implementationVersion != null && ei.implementationVersion != null) {
 181                             // they care about the implementation version
 182                             version = compareExtensionVersion(implementationVersion, ei.implementationVersion);
 183                             if (version<0) {
 184                                 // This extension is an older implementation
 185                                 return REQUIRE_IMPLEMENTATION_UPGRADE;
 186                             }
 187                         }
 188                     }
 189                 }
 190                 // All othe cases, we consider the extensions to be compatible
 191                 return COMPATIBLE;
 192             }
 193         }
 194         return INCOMPATIBLE;
 195     }
 196 
 197     /**
 198      * helper method to print sensible information on the undelying described
 199      * extension
 200      */
 201     public String toString() {
 202         return "Extension : title(" + title + "), name(" + name + "), spec vendor(" +
 203             specVendor + "), spec version(" + specVersion + "), impl vendor(" +
 204             vendor + "), impl vendor id(" + vendorId + "), impl version(" +
 205             implementationVersion + "), impl url(" + url + ")";
 206     }
 207 
 208     /*
 209      * helper method to compare two versions.
 210      * version are in the x.y.z.t pattern.
 211      *
 212      * @param source version to compare to
 213      * @param target version used to compare against
 214      * @return <pre>{@code
 215      *   < 0 if source < version
 216      *   > 0 if source > version
 217      *   = 0 if source = version}</pre>
 218      */
 219     private int compareExtensionVersion(String source, String target)
 220         throws NumberFormatException
 221     {
 222         source = source.toLowerCase();
 223         target = target.toLowerCase();
 224 
 225         return strictCompareExtensionVersion(source, target);
 226     }
 227 
 228 
 229     /*
 230      * helper method to compare two versions.
 231      * version are in the x.y.z.t pattern.
 232      *
 233      * @param source version to compare to
 234      * @param target version used to compare against
 235      * @return <pre>{@code
 236      *   < 0 if source < version
 237      *   > 0 if source > version
 238      *   = 0 if source = version}</pre>
 239      */
 240     private int strictCompareExtensionVersion(String source, String target)
 241         throws NumberFormatException
 242     {
 243         if (source.equals(target))
 244             return 0;
 245 
 246         StringTokenizer stk = new StringTokenizer(source, ".,");
 247         StringTokenizer ttk = new StringTokenizer(target, ".,");
 248 
 249         // Compare number
 250         int n = 0, m = 0, result = 0;
 251 
 252         // Convert token into meaning number for comparision
 253         if (stk.hasMoreTokens())
 254             n = convertToken(stk.nextToken().toString());
 255 
 256         // Convert token into meaning number for comparision
 257         if (ttk.hasMoreTokens())
 258             m = convertToken(ttk.nextToken().toString());
 259 
 260         if (n > m)
 261             return 1;
 262         else if (m > n)
 263             return -1;
 264         else
 265         {
 266             // Look for index of "." in the string
 267             int sIdx = source.indexOf('.');
 268             int tIdx = target.indexOf('.');
 269 
 270             if (sIdx == -1)
 271                 sIdx = source.length() - 1;
 272 
 273             if (tIdx == -1)
 274                 tIdx = target.length() - 1;
 275 
 276             return strictCompareExtensionVersion(source.substring(sIdx + 1),
 277                                                  target.substring(tIdx + 1));
 278         }
 279     }
 280 
 281     private int convertToken(String token)
 282     {
 283         if (token == null || token.equals(""))
 284             return 0;
 285 
 286         int charValue = 0;
 287         int charVersion = 0;
 288         int patchVersion = 0;
 289         int strLength = token.length();
 290         int endIndex = strLength;
 291         char lastChar;
 292 
 293         Object[] args = {name};
 294         MessageFormat mf = new MessageFormat(rb.getString("optpkg.versionerror"));
 295         String versionError = mf.format(args);
 296 
 297         // Look for "-" for pre-release
 298         int prIndex = token.indexOf('-');
 299 
 300         // Look for "_" for patch release
 301         int patchIndex = token.indexOf('_');
 302 
 303         if (prIndex == -1 && patchIndex == -1)
 304         {
 305             // This is a FCS release
 306             try {
 307                 return Integer.parseInt(token) * 100;
 308             } catch (NumberFormatException e) {
 309                 System.out.println(versionError);
 310                 return 0;
 311             }
 312         }
 313         else if (patchIndex != -1)
 314         {
 315             // This is a patch (update) release
 316             int prversion;
 317             try {
 318                 // Obtain the version
 319                 prversion = Integer.parseInt(token.substring(0, patchIndex));
 320 
 321                 // Check to see if the patch version is in the n.n.n_nnl format (special release)
 322                 lastChar = token.charAt(strLength-1);
 323                 if (Character.isLetter(lastChar)) {
 324                     // letters a-z have values from 10-35
 325                     charValue = Character.getNumericValue(lastChar);
 326                     endIndex = strLength-1;
 327 
 328                     // Obtain the patch version id
 329                     patchVersion = Integer.parseInt(token.substring(patchIndex+1, endIndex));
 330 
 331                     if (charValue >= Character.getNumericValue('a') && charValue <= Character.getNumericValue('z')) {
 332                         // This is a special release
 333                         charVersion = (patchVersion * 100) + charValue;
 334                     } else {
 335                         // character is not a a-z letter, ignore
 336                         charVersion = 0;
 337                         System.out.println(versionError);
 338                     }
 339                 } else {
 340                     // This is a regular update release. Obtain the patch version id
 341                     patchVersion = Integer.parseInt(token.substring(patchIndex+1, endIndex));
 342                 }
 343             } catch (NumberFormatException e) {
 344                 System.out.println(versionError);
 345                 return 0;
 346             }
 347             return prversion * 100 + (patchVersion + charVersion);
 348         }
 349         else
 350         {
 351             //This is a milestone release, either a early access, alpha, beta, or RC
 352 
 353             // Obtain the version
 354             int mrversion;
 355             try {
 356                 mrversion = Integer.parseInt(token.substring(0, prIndex));
 357             } catch (NumberFormatException e) {
 358                 System.out.println(versionError);
 359                 return 0;
 360             }
 361 
 362             // Obtain the patch version string, including the milestone + version
 363             String prString = token.substring(prIndex + 1);
 364 
 365             // Milestone version
 366             String msVersion = "";
 367             int delta = 0;
 368 
 369             if (prString.indexOf("ea") != -1)
 370             {
 371                 msVersion = prString.substring(2);
 372                 delta = 50;
 373             }
 374             else if (prString.indexOf("alpha") != -1)
 375             {
 376                 msVersion = prString.substring(5);
 377                 delta = 40;
 378             }
 379             else if (prString.indexOf("beta") != -1)
 380             {
 381                 msVersion = prString.substring(4);
 382                 delta = 30;
 383             }
 384             else if (prString.indexOf("rc") != -1)
 385             {
 386                 msVersion = prString.substring(2);
 387                 delta = 20;
 388             }
 389 
 390             if (msVersion == null || msVersion.equals(""))
 391             {
 392                 // No version after the milestone, assume 0
 393                 return mrversion * 100 - delta ;
 394             }
 395             else
 396             {
 397                 // Convert the milestone version
 398                 try {
 399                     return mrversion * 100 - delta + Integer.parseInt(msVersion);
 400                 } catch (NumberFormatException e) {
 401                     System.out.println(versionError);
 402                     return 0;
 403                 }
 404             }
 405         }
 406     }
 407 }