1 /*
   2  * Copyright (c) 2008, 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 com.sun.servicetag;
  27 
  28 import java.util.Date;
  29 import java.io.IOException;
  30 import static com.sun.servicetag.RegistrationDocument.*;
  31 
  32 /**
  33  * A service tag is an XML-based data structure that identifies a product or
  34  * a component on a system. The service tag schema is defined by the
  35  * Service Tags Technology. The location of the DTD file is platform dependent.
  36  * On Solaris, see <tt>/usr/share/lib/xml/dtd/servicetag.dtd</tt>.
  37  * <p>
  38  * A valid {@code ServiceTag} instance must comply to the service tag schema
  39  * and contain the following fields:
  40  * <ul>
  41  *   <li>{@link #getInstanceURN <tt>instance_urn</tt>}</li>
  42  *   <li>{@link #getProductName <tt>product_name</tt>}</li>
  43  *   <li>{@link #getProductVersion <tt>product_version</tt>}</li>
  44  *   <li>{@link #getProductURN <tt>product_urn</tt>}</li>
  45  *   <li>{@link #getProductParent <tt>product_parent</tt>}</li>
  46  *   <li>{@link #getProductParentURN <tt>product_parent_urn</tt>}</li>
  47  *   <li>{@link #getProductDefinedInstanceID <tt>product_defined_inst_id</tt>}</li>
  48  *   <li>{@link #getProductVendor <tt>product_vendor</tt>}</li>
  49  *   <li>{@link #getPlatformArch <tt>platform_arch</tt>}</li>
  50  *   <li>{@link #getContainer <tt>container</tt>}</li>
  51  *   <li>{@link #getSource <tt>source</tt>}</li>
  52  *   <li>{@link #getInstallerUID <tt>installer_uid</tt>}</li>
  53  *   <li>{@link #getTimestamp <tt>timestamp</tt>}</li>
  54  * </ul>
  55  *
  56  * The <tt>instance_urn</tt> can be specified when a {@code ServiceTag}
  57  * object is created, or it can be generated when it is added to
  58  * a {@link RegistrationData} object, or {@link Registry
  59  * system service tag registry}. The <tt>installer_uid</tt> and
  60  * <tt>timestamp</tt> are set when a {@code ServiceTag} object
  61  * is added to a {@link RegistrationData} object, or {@link Registry
  62  * system service tag registry}.
  63  *
  64  * @see <a href="https://sunconnection.sun.com/FAQ/sc_faq.html">Service Tags FAQ</a>
  65  */
  66 public class ServiceTag {
  67 
  68     private String instanceURN;
  69     private String productName;
  70     private String productVersion;
  71     private String productURN;
  72     private String productParent;
  73     private String productParentURN;
  74     private String productDefinedInstanceID;
  75     private String productVendor;
  76     private String platformArch;
  77     private String container;
  78     private String source;
  79     private int installerUID;
  80     private Date timestamp;
  81 
  82     // Service Tag Field Lengths (defined in sthelper.h)
  83     // Since the constants defined in sthelper.h includes the null-terminated
  84     // character, so minus 1 from the sthelper.h defined values.
  85     private final int MAX_URN_LEN             = 256 - 1;
  86     private final int MAX_PRODUCT_NAME_LEN    = 256 - 1;
  87     private final int MAX_PRODUCT_VERSION_LEN = 64 - 1;
  88     private final int MAX_PRODUCT_PARENT_LEN  = 256 - 1;
  89     private final int MAX_PRODUCT_VENDOR_LEN  = 64 - 1;
  90     private final int MAX_PLATFORM_ARCH_LEN   = 64 - 1;
  91     private final int MAX_CONTAINER_LEN       = 64 - 1;
  92     private final int MAX_SOURCE_LEN          = 64 - 1;
  93 
  94     // private constructors
  95     private ServiceTag() {
  96     }
  97     // package private
  98     ServiceTag(String instanceURN,
  99                String productName,
 100                String productVersion,
 101                String productURN,
 102                String productParent,
 103                String productParentURN,
 104                String productDefinedInstanceID,
 105                String productVendor,
 106                String platformArch,
 107                String container,
 108                String source,
 109                int installerUID,
 110                Date timestamp) {
 111         setInstanceURN(instanceURN);
 112         setProductName(productName);
 113         setProductVersion(productVersion);
 114         setProductURN(productURN);
 115         setProductParentURN(productParentURN);
 116         setProductParent(productParent);
 117         setProductDefinedInstanceID(productDefinedInstanceID);
 118         setProductVendor(productVendor);
 119         setPlatformArch(platformArch);
 120         setContainer(container);
 121         setSource(source);
 122         setInstallerUID(installerUID);
 123         setTimestamp(timestamp);
 124     }
 125 
 126     /**
 127      * Creates a service tag object with no <tt>instance_urn</tt>.
 128      *
 129      * @param productName               the name of the product.
 130      * @param productVersion            the version of the product.
 131      * @param productURN                the uniform resource name of the product
 132      * @param productParent             the name of the product's parent.
 133      * @param productParentURN          the uniform resource name of the product's parent.
 134      * @param productDefinedInstanceID  the instance identifier.
 135      * @param productVendor             the vendor of the product.
 136      * @param platformArch              the operating system architecture.
 137      * @param container                 the container of the product.
 138      * @param source                    the source of the product.
 139      *
 140      * @throws IllegalArgumentException if any value of the input fields
 141      *    does not conform to the service tag XML schema.
 142      */
 143     public static ServiceTag newInstance(String productName,
 144                                          String productVersion,
 145                                          String productURN,
 146                                          String productParent,
 147                                          String productParentURN,
 148                                          String productDefinedInstanceID,
 149                                          String productVendor,
 150                                          String platformArch,
 151                                          String container,
 152                                          String source) {
 153           return new ServiceTag("", /* empty instance_urn */
 154                                 productName,
 155                                 productVersion,
 156                                 productURN,
 157                                 productParent,
 158                                 productParentURN,
 159                                 productDefinedInstanceID,
 160                                 productVendor,
 161                                 platformArch,
 162                                 container,
 163                                 source,
 164                                 -1,
 165                                 null);
 166     }
 167 
 168     /**
 169      * Creates a service tag object with a specified <tt>instance_urn</tt>.
 170      *
 171      * @param instanceURN               the uniform resource name of this instance.
 172      * @param productName               the name of the product.
 173      * @param productVersion            the version of the product.
 174      * @param productURN                the uniform resource name of the product
 175      * @param productParent             the name of the product's parent.
 176      * @param productParentURN          the uniform resource name of the product's parent.
 177      * @param productDefinedInstanceID  the instance identifier.
 178      * @param productVendor             the vendor of the product.
 179      * @param platformArch              the operating system architecture.
 180      * @param container                 the container of the product.
 181      * @param source                    the source of the product.
 182      *
 183      * @throws IllegalArgumentException if any value of the input fields
 184      *    does not conform to the service tag XML schema.
 185      */
 186     public static ServiceTag newInstance(String instanceURN,
 187                                          String productName,
 188                                          String productVersion,
 189                                          String productURN,
 190                                          String productParent,
 191                                          String productParentURN,
 192                                          String productDefinedInstanceID,
 193                                          String productVendor,
 194                                          String platformArch,
 195                                          String container,
 196                                          String source) {
 197           return new ServiceTag(instanceURN,
 198                                 productName,
 199                                 productVersion,
 200                                 productURN,
 201                                 productParent,
 202                                 productParentURN,
 203                                 productDefinedInstanceID,
 204                                 productVendor,
 205                                 platformArch,
 206                                 container,
 207                                 source,
 208                                 -1,
 209                                 null);
 210     }
 211 
 212     // Creates a copy of the ServiceTag instance
 213     // with instance_urn and timestamp initialized
 214     static ServiceTag newInstanceWithUrnTimestamp(ServiceTag st) {
 215         String instanceURN =
 216             (st.getInstanceURN().length() == 0 ? Util.generateURN() :
 217                                                  st.getInstanceURN());
 218         ServiceTag svcTag = new ServiceTag(instanceURN,
 219                                            st.getProductName(),
 220                                            st.getProductVersion(),
 221                                            st.getProductURN(),
 222                                            st.getProductParent(),
 223                                            st.getProductParentURN(),
 224                                            st.getProductDefinedInstanceID(),
 225                                            st.getProductVendor(),
 226                                            st.getPlatformArch(),
 227                                            st.getContainer(),
 228                                            st.getSource(),
 229                                            st.getInstallerUID(),
 230                                            new Date());
 231         return svcTag;
 232     }
 233 
 234     /**
 235      * Returns a uniform resource name (URN) in this format:
 236      * <blockquote>
 237      * "<tt>urn:st:<32-char {@link java.util.UUID uuid}></tt>"
 238      * </blockquote>
 239      * @return a URN.
 240      */
 241     public static String generateInstanceURN() {
 242         return Util.generateURN();
 243     }
 244 
 245     /**
 246      * Returns the uniform resource name of this service tag instance.
 247      *
 248      * @return  the <tt>instance_urn</tt> of this service tag.
 249      */
 250     public String getInstanceURN() {
 251         return instanceURN;
 252     }
 253 
 254     /**
 255      * Returns the name of the product.
 256      *
 257      * @return the product name.
 258      */
 259     public String getProductName() {
 260         return productName;
 261     }
 262 
 263     /**
 264      * Returns the version of the product.
 265      *
 266      * @return the product version.
 267      */
 268     public String getProductVersion() {
 269         return productVersion;
 270     }
 271 
 272     /**
 273      * Returns the uniform resource name of the product.
 274      *
 275      * @return the product URN.
 276      */
 277     public String getProductURN() {
 278         return productURN;
 279     }
 280 
 281     /**
 282      * Returns the uniform resource name of the product's parent.
 283      *
 284      * @return the product's parent URN.
 285      */
 286     public String getProductParentURN() {
 287         return productParentURN;
 288     }
 289 
 290     /**
 291      * Returns the name of the product's parent.
 292      *
 293      * @return the product's parent name.
 294      */
 295     public String getProductParent() {
 296         return productParent;
 297     }
 298 
 299     /**
 300      * Returns the identifier defined for this product instance.
 301      *
 302      * @return  the identifier defined for this product instance.
 303      */
 304     public String getProductDefinedInstanceID() {
 305         return productDefinedInstanceID;
 306     }
 307 
 308     /**
 309      * Returns the vendor of the product.
 310      *
 311      * @return the product vendor.
 312      */
 313     public String getProductVendor() {
 314         return productVendor;
 315     }
 316 
 317     /**
 318      * Returns the platform architecture on which the product
 319      * is running on.
 320      *
 321      * @return the platform architecture on which the product is running on.
 322      */
 323     public String getPlatformArch() {
 324         return platformArch;
 325     }
 326 
 327     /**
 328      * Returns the timestamp.  This timestamp is set when this service tag
 329      * is added to or updated in a {@code RegistrationData} object or
 330      * the system service tag registry.
 331      * This method may return {@code null}.
 332      *
 333      * @return timestamp when this service tag
 334      * is added to or updated in a {@code RegistrationData} object or
 335      * the system service tag registry, or {@code null}.
 336      */
 337     public Date getTimestamp() {
 338         if (timestamp != null) {
 339             return (Date) timestamp.clone();
 340         } else {
 341             return null;
 342         }
 343     }
 344 
 345 
 346     /**
 347      * Returns the container of the product.
 348      *
 349      * @return the container of the product.
 350      */
 351     public String getContainer() {
 352         return container;
 353     }
 354 
 355     /**
 356      * Returns the source of this service tag.
 357      *
 358      * @return  source of this service tag.
 359      */
 360     public String getSource() {
 361         return source;
 362     }
 363 
 364     /**
 365      * Returns the UID. The UID is set when this service tag
 366      * is added to or updated in the system service tag registry.
 367      * This is platform dependent whose default value is {@code -1}.
 368      * When this service tag is added to a {@code RegistrationData},
 369      * the UID is not set.
 370      *
 371      * @return the UID of whom this service tag
 372      * is added to or updated in the system service tag registry,
 373      * or {@code -1}.
 374      */
 375     public int getInstallerUID() {
 376         return installerUID;
 377     }
 378 
 379     // The following setter methods are used to validate the
 380     // input field when constructing a ServiceTag instance
 381 
 382     private void setInstanceURN(String instanceURN) {
 383         if (instanceURN == null) {
 384             throw new NullPointerException("Parameter instanceURN cannot be null");
 385         }
 386         if (instanceURN.length() > MAX_URN_LEN) {
 387             throw new IllegalArgumentException("instanceURN \"" + instanceURN +
 388                 "\" exceeds maximum length " + MAX_URN_LEN);
 389         }
 390         this.instanceURN = instanceURN;
 391     }
 392 
 393     private void setProductName(String productName) {
 394         if (productName == null) {
 395             throw new NullPointerException("Parameter productName cannot be null");
 396         }
 397         if (productName.length() == 0) {
 398             throw new IllegalArgumentException("product name cannot be empty");
 399         }
 400         if (productName.length() > MAX_PRODUCT_NAME_LEN) {
 401             throw new IllegalArgumentException("productName \"" + productName +
 402                 "\" exceeds maximum length " + MAX_PRODUCT_NAME_LEN);
 403         }
 404         this.productName = productName;
 405     }
 406 
 407     private void setProductVersion(String productVersion) {
 408         if (productVersion == null) {
 409             throw new NullPointerException("Parameter productVersion cannot be null");
 410         }
 411 
 412         if (productVersion.length() == 0) {
 413             throw new IllegalArgumentException("product version cannot be empty");
 414         }
 415         if (productVersion.length() > MAX_PRODUCT_VERSION_LEN) {
 416             throw new IllegalArgumentException("productVersion \"" +
 417                 productVersion + "\" exceeds maximum length " +
 418                 MAX_PRODUCT_VERSION_LEN);
 419         }
 420         this.productVersion = productVersion;
 421     }
 422 
 423     private void setProductURN(String productURN) {
 424         if (productURN == null) {
 425             throw new NullPointerException("Parameter productURN cannot be null");
 426         }
 427         if (productURN.length() == 0) {
 428             throw new IllegalArgumentException("product URN cannot be empty");
 429         }
 430         if (productURN.length() > MAX_URN_LEN) {
 431             throw new IllegalArgumentException("productURN \"" + productURN +
 432                 "\" exceeds maximum length " + MAX_URN_LEN);
 433         }
 434         this.productURN = productURN;
 435     }
 436 
 437     private void setProductParentURN(String productParentURN) {
 438         if (productParentURN == null) {
 439             throw new NullPointerException("Parameter productParentURN cannot be null");
 440         }
 441         // optional field - can be empty
 442         if (productParentURN.length() > MAX_URN_LEN) {
 443             throw new IllegalArgumentException("productParentURN \"" +
 444                 productParentURN + "\" exceeds maximum length " +
 445                 MAX_URN_LEN);
 446         }
 447         this.productParentURN = productParentURN;
 448     }
 449 
 450     private void setProductParent(String productParent) {
 451         if (productParent == null) {
 452             throw new NullPointerException("Parameter productParent cannot be null");
 453         }
 454         if (productParent.length() == 0) {
 455             throw new IllegalArgumentException("product parent cannot be empty");
 456         }
 457         if (productParent.length() > MAX_PRODUCT_PARENT_LEN) {
 458             throw new IllegalArgumentException("productParent \"" +
 459                 productParent + "\" exceeds maximum length " +
 460                 MAX_PRODUCT_PARENT_LEN);
 461         }
 462         this.productParent = productParent;
 463     }
 464 
 465     void setProductDefinedInstanceID(String productDefinedInstanceID) {
 466         if (productDefinedInstanceID == null) {
 467             throw new NullPointerException("Parameter productDefinedInstanceID cannot be null");
 468         }
 469         if (productDefinedInstanceID.length() > MAX_URN_LEN) {
 470             throw new IllegalArgumentException("productDefinedInstanceID \"" +
 471                 productDefinedInstanceID + "\" exceeds maximum length " +
 472                 MAX_URN_LEN);
 473         }
 474         // optional field - can be empty
 475         this.productDefinedInstanceID = productDefinedInstanceID;
 476     }
 477 
 478     private void setProductVendor(String productVendor) {
 479         if (productVendor == null) {
 480             throw new NullPointerException("Parameter productVendor cannot be null");
 481         }
 482         if (productVendor.length() == 0) {
 483             throw new IllegalArgumentException("product vendor cannot be empty");
 484         }
 485         if (productVendor.length() > MAX_PRODUCT_VENDOR_LEN) {
 486             throw new IllegalArgumentException("productVendor \"" +
 487                 productVendor + "\" exceeds maximum length " +
 488                 MAX_PRODUCT_VENDOR_LEN);
 489         }
 490         this.productVendor = productVendor;
 491     }
 492 
 493     private void setPlatformArch(String platformArch) {
 494         if (platformArch == null) {
 495             throw new NullPointerException("Parameter platformArch cannot be null");
 496         }
 497         if (platformArch.length() == 0) {
 498             throw new IllegalArgumentException("platform architecture cannot be empty");
 499         }
 500         if (platformArch.length() > MAX_PLATFORM_ARCH_LEN) {
 501             throw new IllegalArgumentException("platformArch \"" +
 502                 platformArch + "\" exceeds maximum length " +
 503                 MAX_PLATFORM_ARCH_LEN);
 504         }
 505         this.platformArch = platformArch;
 506     }
 507 
 508     private void setTimestamp(Date timestamp) {
 509         // can be null
 510         this.timestamp = timestamp;
 511     }
 512 
 513     private void setContainer(String container) {
 514         if (container == null) {
 515             throw new NullPointerException("Parameter container cannot be null");
 516         }
 517         if (container.length() == 0) {
 518             throw new IllegalArgumentException("container cannot be empty");
 519         }
 520         if (container.length() > MAX_CONTAINER_LEN) {
 521             throw new IllegalArgumentException("container \"" +
 522                 container + "\" exceeds maximum length " +
 523                 MAX_CONTAINER_LEN);
 524         }
 525         this.container = container;
 526     }
 527 
 528     private void setSource(String source) {
 529         if (source == null) {
 530             throw new NullPointerException("Parameter source cannot be null");
 531         }
 532         if (source.length() == 0) {
 533             throw new IllegalArgumentException("source cannot be empty");
 534         }
 535         if (source.length() > MAX_SOURCE_LEN) {
 536             throw new IllegalArgumentException("source \"" + source +
 537                 "\" exceeds maximum length " + MAX_SOURCE_LEN);
 538         }
 539         this.source = source;
 540     }
 541 
 542     private void setInstallerUID(int installerUID) {
 543         this.installerUID = installerUID;
 544     }
 545 
 546     /**
 547      * Compares this service tag to the specified object.
 548      * The result is {@code true} if and only if the argument is
 549      * not {@code null} and is a {@code ServiceTag} object whose
 550      * <tt>instance_urn</tt> is the same as the
 551      * <tt>instance_urn</tt> of this service tag.
 552      *
 553      * @return {@code true} if this service tag is the same as
 554      * the specified object.
 555      */
 556     @Override
 557     public boolean equals(Object obj) {
 558         if (obj == null || !(obj instanceof ServiceTag)) {
 559             return false;
 560         }
 561         ServiceTag st = (ServiceTag) obj;
 562         if (st == this) {
 563             return true;
 564         }
 565         return st.getInstanceURN().equals(getInstanceURN());
 566     }
 567 
 568     /**
 569      * Returns the hash code value for this service tag.
 570      * @return the hash code value for this service tag.
 571      */
 572     @Override
 573     public int hashCode() {
 574         int hash = 7;
 575         hash = 19 * hash + (this.instanceURN != null ? this.instanceURN.hashCode() : 0);
 576         return hash;
 577     }
 578 
 579     /**
 580      * Returns the string representation of this service tag.
 581      * The format is implementation specific.
 582      *
 583      * @return the string representation of this service tag.
 584      */
 585     public String toString() {
 586         StringBuilder sb = new StringBuilder();
 587         sb.append(ST_NODE_INSTANCE_URN).append("=").append(instanceURN).append("\n");
 588         sb.append(ST_NODE_PRODUCT_NAME).append("=").append(productName).append("\n");
 589         sb.append(ST_NODE_PRODUCT_VERSION).append("=").append(productVersion).append("\n");
 590         sb.append(ST_NODE_PRODUCT_URN).append("=").append(productURN).append("\n");
 591         sb.append(ST_NODE_PRODUCT_PARENT_URN).append("=").append(productParentURN).append("\n");
 592         sb.append(ST_NODE_PRODUCT_PARENT).append("=").append(productParent).append("\n");
 593         sb.append(ST_NODE_PRODUCT_DEFINED_INST_ID).append("=").append(productDefinedInstanceID).append("\n");
 594         sb.append(ST_NODE_PRODUCT_VENDOR).append("=").append(productVendor).append("\n");
 595         sb.append(ST_NODE_PLATFORM_ARCH).append("=").append(platformArch).append("\n");
 596         sb.append(ST_NODE_TIMESTAMP).append("=").append(Util.formatTimestamp(timestamp)).append("\n");
 597         sb.append(ST_NODE_CONTAINER).append("=").append(container).append("\n");
 598         sb.append(ST_NODE_SOURCE).append("=").append(source).append("\n");
 599         sb.append(ST_NODE_INSTALLER_UID).append("=").append(String.valueOf(installerUID)).append("\n");
 600         return sb.toString();
 601     }
 602 
 603 
 604     /**
 605      * Returns the {@link ServiceTag} instance for the running Java
 606      * platform. The {@link ServiceTag#setSource source} field
 607      * of the {@code ServiceTag} will be set to the given {@code source}.
 608      * This method will return {@code null} if there is no service tag
 609      * for the running Java platform.
 610      * <p>
 611      * This method is designed for Sun software that bundles the JDK
 612      * or the JRE to use. It is recommended that the {@code source}
 613      * string contains information about the bundling software
 614      * such as the name and the version of the software bundle,
 615      * for example,
 616      * <blockquote>
 617      * <tt>NetBeans IDE 6.0 with JDK 6 Update 5 Bundle</tt>
 618      * </blockquote>
 619      * in a NetBeans/JDK bundle.
 620      * <p>
 621      * At the first time to call this method the application
 622      * is required to have the write permission to the installed
 623      * directory of this running JDK or JRE instance.
 624      *
 625      * @param source the source that bundles the JDK or the JRE.
 626      * @return a {@code ServiceTag} object for the Java platform,
 627      *         or {@code null} if not supported.
 628      * @throws IOException if an error occurs in this operation.
 629      */
 630     public static ServiceTag getJavaServiceTag(String source) throws IOException {
 631         return Installer.getJavaServiceTag(source);
 632     }
 633 
 634 }