1 /* 2 * Copyright (c) 2008, 2011, 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.io.*; 29 import java.util.HashSet; 30 import java.util.Locale; 31 import java.util.Properties; 32 import java.util.Set; 33 import java.util.List; 34 import java.util.ArrayList; 35 import static com.sun.servicetag.Util.*; 36 37 /** 38 * Service Tag Installer for Java SE. 39 */ 40 public class Installer { 41 // System properties for testing 42 private static String SVCTAG_DIR_PATH = 43 "servicetag.dir.path"; 44 private static String SVCTAG_ENABLE_REGISTRATION = 45 "servicetag.registration.enabled"; 46 private final static String ORACLE = "Oracle"; 47 private final static String SUN = "Sun Microsystems"; 48 private final static String REGISTRATION_XML = "registration.xml"; 49 private final static String SERVICE_TAG_FILE = "servicetag"; 50 private final static String REGISTRATION_HTML_NAME = "register"; 51 52 private final static Locale[] knownSupportedLocales = 53 new Locale[] { Locale.ENGLISH, 54 Locale.JAPANESE, 55 Locale.SIMPLIFIED_CHINESE}; 56 57 private final static String javaHome = System.getProperty("java.home"); 58 private static File svcTagDir; 59 private static File serviceTagFile; 60 private static File regXmlFile; 61 private static RegistrationData registration; 62 private static boolean supportRegistration; 63 private static String registerHtmlParent; 64 private static Set<Locale> supportedLocales = new HashSet<>(); 65 private static Properties svcTagProps = null; 66 private static String[] jreArchs = null; 67 static { 68 String dir = System.getProperty(SVCTAG_DIR_PATH); 69 if (dir == null) { 70 svcTagDir = new File(getJrePath(), "lib" + File.separator + SERVICE_TAG_FILE); 71 } else { 72 svcTagDir = new File(dir); 73 } 74 serviceTagFile = new File(svcTagDir, SERVICE_TAG_FILE); 75 regXmlFile = new File(svcTagDir, REGISTRATION_XML); 76 if (System.getProperty(SVCTAG_ENABLE_REGISTRATION) == null) { 77 supportRegistration = isJdk(); 78 } else { 79 supportRegistration = true; 80 } 81 } 82 83 private Installer() { 84 } 85 86 // Implementation of ServiceTag.getJavaServiceTag(String) method 87 static ServiceTag getJavaServiceTag(String source) throws IOException { 88 String vendor = System.getProperty("java.vendor", ""); 89 if (!vendor.startsWith(SUN) && !vendor.startsWith(ORACLE)) { 90 // Products bundling this implementation may run on 91 // Mac OS which is not a Sun/Oracle JDK 92 return null; 93 } 94 boolean cleanup = false; 95 try { 96 // Check if we have the swordfish entries for this JRE version 97 if (loadServiceTagProps() == null) { 98 return null; 99 } 100 101 ServiceTag st = getJavaServiceTag(); 102 // Check if the service tag created by this bundle owner 103 if (st != null && st.getSource().equals(source)) { 104 // Install the system service tag if supported 105 // stclient may be installed after the service tag creation 106 if (Registry.isSupported()) { 107 installSystemServiceTag(); 108 } 109 return st; 110 } 111 112 // in case any exception thrown during the cleanup 113 cleanup = true; 114 115 // re-create a new one for this bundle owner 116 // first delete the registration data 117 deleteRegistrationData(); 118 cleanup = false; 119 120 // create service tag and generate new register.html pages 121 return createServiceTag(source); 122 } finally { 123 if (cleanup) { 124 if (regXmlFile.exists()) { 125 regXmlFile.delete(); 126 } 127 if (serviceTagFile.exists()) { 128 serviceTagFile.delete(); 129 } 130 } 131 } 132 } 133 134 /** 135 * Returns the Java SE registration data located in 136 * the <JRE>/lib/servicetag/registration.xml by default. 137 * 138 * @throws IllegalArgumentException if the registration data 139 * is of invalid format. 140 */ 141 private static synchronized RegistrationData getRegistrationData() 142 throws IOException { 143 if (registration != null) { 144 return registration; 145 } 146 if (regXmlFile.exists()) { 147 try (BufferedInputStream in = 148 new BufferedInputStream(new FileInputStream(regXmlFile))) 149 { 150 registration = RegistrationData.loadFromXML(in); 151 } catch (IllegalArgumentException ex) { 152 System.err.println("Error: Bad registration data \"" + 153 regXmlFile + "\":" + ex.getMessage()); 154 throw ex; 155 } 156 } else { 157 registration = new RegistrationData(); 158 } 159 return registration; 160 } 161 162 /** 163 * Write the registration data to the registration.xml file. 164 * 165 * The offline registration page has to be regenerated with 166 * the new registration data. 167 * 168 * @throws java.io.IOException 169 */ 170 private static synchronized void writeRegistrationXml() 171 throws IOException { 172 if (!svcTagDir.exists()) { 173 // This check is for NetBeans or other products that 174 // bundles this com.sun.servicetag implementation for 175 // pre-6u5 release. 176 if (!svcTagDir.mkdir()) { 177 throw new IOException("Failed to create directory: " + svcTagDir); 178 } 179 } 180 181 // regenerate the new offline registration page 182 deleteRegistrationHtmlPage(); 183 getRegistrationHtmlPage(); 184 185 try (BufferedOutputStream out = 186 new BufferedOutputStream(new FileOutputStream(regXmlFile))) 187 { 188 getRegistrationData().storeToXML(out); 189 } catch (IllegalArgumentException ex) { 190 System.err.println("Error: Bad registration data \"" + 191 regXmlFile + "\":" + ex.getMessage()); 192 throw ex; 193 } 194 } 195 196 /** 197 * Returns the instance urn(s) stored in the servicetag file 198 * or empty set if file not exists. 199 */ 200 private static Set<String> getInstalledURNs() throws IOException { 201 Set<String> urnSet = new HashSet<>(); 202 if (serviceTagFile.exists()) { 203 try (BufferedReader in = new BufferedReader(new FileReader(serviceTagFile))) { 204 String urn; 205 while ((urn = in.readLine()) != null) { 206 urn = urn.trim(); 207 if (urn.length() > 0) { 208 urnSet.add(urn); 209 } 210 } 211 } 212 } 213 return urnSet; 214 } 215 216 /** 217 * Return the Java SE service tag(s) if it exists. 218 * Typically only one Java SE service tag but it could have two for 219 * Solaris 32-bit and 64-bit on the same install directory. 220 * 221 * @return the service tag(s) for Java SE 222 */ 223 private static ServiceTag[] getJavaServiceTagArray() throws IOException { 224 RegistrationData regData = getRegistrationData(); 225 Set<ServiceTag> svcTags = regData.getServiceTags(); 226 Set<ServiceTag> result = new HashSet<>(); 227 228 Properties props = loadServiceTagProps(); 229 String jdkUrn = props.getProperty("servicetag.jdk.urn"); 230 String jreUrn = props.getProperty("servicetag.jre.urn"); 231 for (ServiceTag st : svcTags) { 232 if (st.getProductURN().equals(jdkUrn) || 233 st.getProductURN().equals(jreUrn)) { 234 result.add(st); 235 } 236 } 237 return result.toArray(new ServiceTag[0]); 238 } 239 240 /** 241 * Returns the Java SE service tag for this running platform; 242 * or null if not exist. 243 * This method will return the 64-bit service tag if the JDK 244 * supports both 32-bit and 64-bit if already created. 245 */ 246 private static ServiceTag getJavaServiceTag() throws IOException { 247 String definedId = getProductDefinedId(); 248 for (ServiceTag st : getJavaServiceTagArray()) { 249 if (st.getProductDefinedInstanceID().equals(definedId)) { 250 return st; 251 } 252 } 253 return null; 254 } 255 256 /** 257 * Create a service tag for Java SE and install in the system 258 * service tag registry if supported. 259 * 260 * A registration data <JRE>/lib/servicetag/registration.xml 261 * will be created to storeToXML the XML entry for Java SE service tag. 262 * If the system supports service tags, this method will install 263 * the Java SE service tag in the system service tag registry and 264 * its <tt>instance_urn</tt> will be stored to <JRE>/lib/servicetag/servicetag. 265 * 266 * If <JRE>/lib/servicetag/registration.xml exists but is not installed 267 * in the system service tag registry (i.e. servicetag doesn't exist), 268 * this method will install it as described above. 269 * 270 * If the system supports service tag, stclient will be used 271 * to create the Java SE service tag. 272 * 273 * A Solaris 32-bit and 64-bit JDK will be installed in the same 274 * directory but the registration.xml will have 2 service tags. 275 * The servicetag file will also contain 2 instance_urns for that case. 276 */ 277 private static ServiceTag createServiceTag(String svcTagSource) 278 throws IOException { 279 // determine if a new service tag is needed to be created 280 ServiceTag newSvcTag = null; 281 if (getJavaServiceTag() == null) { 282 newSvcTag = newServiceTag(svcTagSource); 283 } 284 285 // Add the new service tag in the registration data 286 if (newSvcTag != null) { 287 RegistrationData regData = getRegistrationData(); 288 289 // Add the service tag to the registration data in JDK/JRE 290 newSvcTag = regData.addServiceTag(newSvcTag); 291 292 // add if there is a service tag for the OS 293 ServiceTag osTag = SolarisServiceTag.getServiceTag(); 294 if (osTag != null && regData.getServiceTag(osTag.getInstanceURN()) == null) { 295 regData.addServiceTag(osTag); 296 } 297 // write to the registration.xml 298 writeRegistrationXml(); 299 } 300 301 // Install the system service tag if supported 302 if (Registry.isSupported()) { 303 installSystemServiceTag(); 304 } 305 return newSvcTag; 306 } 307 308 private static void installSystemServiceTag() throws IOException { 309 // only install the service tag in the registry if 310 // it has permission to write the servicetag file. 311 if ((!serviceTagFile.exists() && !svcTagDir.canWrite()) || 312 (serviceTagFile.exists() && !serviceTagFile.canWrite())) { 313 return; 314 } 315 316 Set<String> urns = getInstalledURNs(); 317 ServiceTag[] javaSvcTags = getJavaServiceTagArray(); 318 if (urns.size() < javaSvcTags.length) { 319 for (ServiceTag st : javaSvcTags) { 320 // Add the service tag in the system service tag registry 321 // if not installed 322 String instanceURN = st.getInstanceURN(); 323 if (!urns.contains(instanceURN)) { 324 Registry.getSystemRegistry().addServiceTag(st); 325 } 326 } 327 } 328 writeInstalledUrns(); 329 } 330 331 private static ServiceTag newServiceTag(String svcTagSource) throws IOException { 332 Properties props = loadServiceTagProps(); 333 334 // Determine the product URN and name 335 String productURN; 336 String productName; 337 338 if (isJdk()) { 339 // <HOME>/jre exists which implies it's a JDK 340 productURN = props.getProperty("servicetag.jdk.urn"); 341 productName = props.getProperty("servicetag.jdk.name"); 342 } else { 343 // Otherwise, it's a JRE 344 productURN = props.getProperty("servicetag.jre.urn"); 345 productName = props.getProperty("servicetag.jre.name"); 346 } 347 348 return ServiceTag.newInstance(ServiceTag.generateInstanceURN(), 349 productName, 350 System.getProperty("java.version"), 351 productURN, 352 props.getProperty("servicetag.parent.name"), 353 props.getProperty("servicetag.parent.urn"), 354 getProductDefinedId(), 355 System.getProperty("java.vendor"), 356 System.getProperty("os.arch"), 357 getZoneName(), 358 svcTagSource); 359 } 360 361 /** 362 * Delete the registration data, the offline registration pages and 363 * the service tags in the system service tag registry if installed. 364 * 365 * The registration.xml and servicetag file will be removed. 366 */ 367 private static synchronized void deleteRegistrationData() 368 throws IOException { 369 try { 370 // delete the offline registration page 371 deleteRegistrationHtmlPage(); 372 373 // Remove the service tag from the system ST registry if exists 374 Set<String> urns = getInstalledURNs(); 375 if (urns.size() > 0 && Registry.isSupported()) { 376 for (String u : urns) { 377 Registry.getSystemRegistry().removeServiceTag(u); 378 } 379 } 380 registration = null; 381 } finally { 382 // Delete the registration.xml and servicetag files if exists 383 if (regXmlFile.exists()) { 384 if (!regXmlFile.delete()) { 385 throw new IOException("Failed to delete " + regXmlFile); 386 } 387 } 388 if (serviceTagFile.exists()) { 389 if (!serviceTagFile.delete()) { 390 throw new IOException("Failed to delete " + serviceTagFile); 391 } 392 } 393 } 394 } 395 396 /** 397 * Updates the registration data to contain one single service tag 398 * for the running Java runtime. 399 */ 400 private static synchronized void updateRegistrationData(String svcTagSource) 401 throws IOException { 402 RegistrationData regData = getRegistrationData(); 403 ServiceTag curSvcTag = newServiceTag(svcTagSource); 404 405 ServiceTag[] javaSvcTags = getJavaServiceTagArray(); 406 Set<String> urns = getInstalledURNs(); 407 for (ServiceTag st : javaSvcTags) { 408 if (!st.getProductDefinedInstanceID().equals(curSvcTag.getProductDefinedInstanceID())) { 409 String instanceURN = st.getInstanceURN(); 410 regData.removeServiceTag(instanceURN); 411 412 // remove it from the system service tag registry if exists 413 if (urns.contains(instanceURN) && Registry.isSupported()) { 414 Registry.getSystemRegistry().removeServiceTag(instanceURN); 415 } 416 } 417 } 418 writeRegistrationXml(); 419 writeInstalledUrns(); 420 } 421 422 private static void writeInstalledUrns() throws IOException { 423 // if the Registry is not supported, 424 // remove the servicetag file 425 if (!Registry.isSupported() && serviceTagFile.exists()) { 426 serviceTagFile.delete(); 427 return; 428 } 429 430 try (PrintWriter out = new PrintWriter(serviceTagFile)) { 431 ServiceTag[] javaSvcTags = getJavaServiceTagArray(); 432 for (ServiceTag st : javaSvcTags) { 433 // Write the instance_run to the servicetag file 434 String instanceURN = st.getInstanceURN(); 435 out.println(instanceURN); 436 } 437 } 438 } 439 440 /** 441 * Load the properties for generating Java SE service tags. 442 * 443 * @param version Version of Java SE 444 */ 445 private static synchronized Properties loadServiceTagProps() throws IOException { 446 if (svcTagProps != null) { 447 return svcTagProps; 448 } 449 450 // For Java SE 8 and later releases, JDK and JRE both use 451 // the same product number. The sworRDFish metadata were 452 // for legacy Sun part number. 453 String filename = "/com/sun/servicetag/resources/javase_servicetag.properties"; 454 try (InputStream in = Installer.class.getResourceAsStream(filename)) { 455 svcTagProps = new Properties(); 456 svcTagProps.load(in); 457 } 458 return svcTagProps; 459 } 460 461 /** 462 * Returns the product defined instance ID for Java SE. 463 * It is a list of comma-separated name/value pairs: 464 * "id=<full-version> <arch> [<arch>]*" 465 * "dir=<java.home system property value>" 466 * 467 * where <full-version> is the full version string of the JRE, 468 * <arch> is the architecture that the runtime supports 469 * (i.e. "sparc", "sparcv9", "i386", "amd64" (ISA list)) 470 * 471 * For Solaris, it can be dual mode that can support both 472 * 32-bit and 64-bit. the "id" will be set to 473 * "1.6.0_03-b02 sparc sparcv9" 474 * 475 * The "dir" property is included in the service tag to enable 476 * the Service Tag software to determine if a service tag for 477 * Java SE is invalid and perform appropriate service tag 478 * cleanup if necessary. See RFE# 6574781 Service Tags Enhancement. 479 * 480 */ 481 private static String getProductDefinedId() { 482 StringBuilder definedId = new StringBuilder(); 483 definedId.append("id="); 484 definedId.append(System.getProperty("java.runtime.version")); 485 486 String[] archs = getJreArchs(); 487 for (String name : archs) { 488 definedId.append(" " + name); 489 } 490 491 String location = ",dir=" + javaHome; 492 if ((definedId.length() + location.length()) < 256) { 493 definedId.append(",dir="); 494 definedId.append(javaHome); 495 } else { 496 // if it exceeds the limit, we will not include the location 497 if (isVerbose()) { 498 System.err.println("Warning: Product defined instance ID exceeds the field limit:"); 499 } 500 } 501 502 return definedId.toString(); 503 } 504 505 /** 506 * Returns the architectures that the runtime supports 507 * (i.e. "sparc", "sparcv9", "i386", "amd64" (ISA list)) 508 * The directory name where libjava.so is located. 509 * 510 * On Windows, returns the "os.arch" system property value. 511 */ 512 private synchronized static String[] getJreArchs() { 513 if (jreArchs != null) { 514 return jreArchs; 515 } 516 517 Set<String> archs = new HashSet<>(); 518 519 String os = System.getProperty("os.name"); 520 if (os.equals("SunOS") || os.equals("Linux")) { 521 // Traverse the directories under <JRE>/lib. 522 // If <JRE>/lib/<arch>/libjava.so exists, add <arch> 523 // to the product defined ID 524 File dir = new File(getJrePath() + File.separator + "lib"); 525 if (dir.isDirectory()) { 526 String[] children = dir.list(); 527 for (String name : children) { 528 File f = new File(dir, name + File.separator + "libjava.so"); 529 if (f.exists()) { 530 archs.add(name); 531 } 532 } 533 } 534 } else { 535 // Windows - append the os.arch 536 archs.add(System.getProperty("os.arch")); 537 } 538 jreArchs = archs.toArray(new String[0]); 539 return jreArchs; 540 } 541 542 /** 543 * Return the zonename if zone is supported; otherwise, return 544 * "global". 545 */ 546 private static String getZoneName() throws IOException { 547 String zonename = "global"; 548 549 String command = "/usr/bin/zonename"; 550 File f = new File(command); 551 // com.sun.servicetag package has to be compiled with JDK 5 as well 552 // JDK 5 doesn't support the File.canExecute() method. 553 // Risk not checking isExecute() for the zonename command is very low. 554 if (f.exists()) { 555 ProcessBuilder pb = new ProcessBuilder(command); 556 Process p = pb.start(); 557 String output = commandOutput(p); 558 if (p.exitValue() == 0) { 559 zonename = output.trim(); 560 } 561 562 } 563 return zonename; 564 } 565 566 private synchronized static String getRegisterHtmlParent() throws IOException { 567 if (registerHtmlParent == null) { 568 File htmlDir; // register.html is put under the JDK directory 569 if (getJrePath().endsWith(File.separator + "jre")) { 570 htmlDir = new File(getJrePath(), ".."); 571 } else { 572 // j2se non-image build 573 htmlDir = new File(getJrePath()); 574 } 575 576 // initialize the supported locales 577 initSupportedLocales(htmlDir); 578 579 // Determine the location of the offline registration page 580 String path = System.getProperty(SVCTAG_DIR_PATH); 581 if (path == null) { 582 // Default is <JDK>/register.html 583 registerHtmlParent = htmlDir.getCanonicalPath(); 584 } else { 585 File f = new File(path); 586 registerHtmlParent = f.getCanonicalPath(); 587 if (!f.isDirectory()) { 588 throw new InternalError("Path " + path + " set in \"" + 589 SVCTAG_DIR_PATH + "\" property is not a directory"); 590 } 591 } 592 } 593 return registerHtmlParent; 594 } 595 596 /** 597 * Returns the File object of the offline registration page localized 598 * for the default locale in the JDK directory. 599 */ 600 static synchronized File getRegistrationHtmlPage() throws IOException { 601 if (!supportRegistration) { 602 // No register.html page generated if JRE 603 return null; 604 } 605 606 String parent = getRegisterHtmlParent(); 607 608 // check if the offline registration page is already generated 609 File f = new File(parent, REGISTRATION_HTML_NAME + ".html"); 610 if (!f.exists()) { 611 // Generate the localized version of the offline registration Page 612 generateRegisterHtml(parent); 613 } 614 615 String name = REGISTRATION_HTML_NAME; 616 Locale locale = getDefaultLocale(); 617 if (!locale.equals(Locale.ENGLISH) && supportedLocales.contains(locale)) { 618 // if the locale is not English and is supported by JDK 619 // set to the appropriate offline registration page; 620 // otherwise,set to register.html. 621 name = REGISTRATION_HTML_NAME + "_" + locale.toString(); 622 } 623 File htmlFile = new File(parent, name + ".html"); 624 if (isVerbose()) { 625 System.out.print("Offline registration page: " + htmlFile); 626 System.out.println((htmlFile.exists() ? 627 "" : " not exist. Use register.html")); 628 } 629 if (htmlFile.exists()) { 630 return htmlFile; 631 } else { 632 return new File(parent, 633 REGISTRATION_HTML_NAME + ".html"); 634 } 635 } 636 637 private static Locale getDefaultLocale() { 638 List<Locale> candidateLocales = getCandidateLocales(Locale.getDefault()); 639 for (Locale l : candidateLocales) { 640 if (supportedLocales.contains(l)) { 641 return l; 642 } 643 } 644 return Locale.getDefault(); 645 } 646 647 private static List<Locale> getCandidateLocales(Locale locale) { 648 String language = locale.getLanguage(); 649 String country = locale.getCountry(); 650 String variant = locale.getVariant(); 651 652 List<Locale> locales = new ArrayList<>(3); 653 if (variant.length() > 0) { 654 locales.add(locale); 655 } 656 if (country.length() > 0) { 657 locales.add((locales.isEmpty()) ? 658 locale : new Locale(language, country, "")); 659 } 660 if (language.length() > 0) { 661 locales.add((locales.isEmpty()) ? 662 locale : new Locale(language, "", "")); 663 } 664 return locales; 665 } 666 667 // Remove the offline registration pages 668 private static void deleteRegistrationHtmlPage() throws IOException { 669 String parent = getRegisterHtmlParent(); 670 if (parent == null) { 671 return; 672 } 673 674 for (Locale locale : supportedLocales) { 675 String name = REGISTRATION_HTML_NAME; 676 if (!locale.equals(Locale.ENGLISH)) { 677 name += "_" + locale.toString(); 678 } 679 File f = new File(parent, name + ".html"); 680 if (f.exists()) { 681 if (!f.delete()) { 682 throw new IOException("Failed to delete " + f); 683 } 684 } 685 } 686 } 687 688 private static void initSupportedLocales(File jdkDir) { 689 if (supportedLocales.isEmpty()) { 690 // initialize with the known supported locales 691 for (Locale l : knownSupportedLocales) { 692 supportedLocales.add(l); 693 } 694 } 695 696 // Determine unknown supported locales if any 697 // by finding the localized version of README.html 698 // This prepares if a new locale in JDK is supported in 699 // e.g. in the OpenSource world 700 FilenameFilter ff = new FilenameFilter() { 701 public boolean accept(File dir, String name) { 702 String fname = name.toLowerCase(); 703 if (fname.startsWith("readme") && fname.endsWith(".html")) { 704 return true; 705 } 706 return false; 707 } 708 }; 709 710 String[] readmes = jdkDir.list(ff); 711 for (String name : readmes) { 712 String basename = name.substring(0, name.length() - ".html".length()); 713 String[] ss = basename.split("_"); 714 switch (ss.length) { 715 case 1: 716 // English version 717 break; 718 case 2: 719 supportedLocales.add(new Locale(ss[1])); 720 break; 721 case 3: 722 supportedLocales.add(new Locale(ss[1], ss[2])); 723 break; 724 default: 725 // ignore 726 break; 727 } 728 } 729 if (isVerbose()) { 730 System.out.println("Supported locales: "); 731 for (Locale l : supportedLocales) { 732 System.out.println(l); 733 } 734 } 735 } 736 737 private static final String JDK_HEADER_PNG_KEY = "@@JDK_HEADER_PNG@@"; 738 private static final String JDK_VERSION_KEY = "@@JDK_VERSION@@"; 739 private static final String REGISTRATION_URL_KEY = "@@REGISTRATION_URL@@"; 740 private static final String REGISTRATION_PAYLOAD_KEY = "@@REGISTRATION_PAYLOAD@@"; 741 742 @SuppressWarnings("unchecked") 743 private static void generateRegisterHtml(String parent) throws IOException { 744 int version = Util.getJdkVersion(); 745 int update = Util.getUpdateVersion(); 746 String jdkVersion = "Version " + version; 747 if (update > 0) { 748 // product name is not translated 749 jdkVersion += " Update " + update; 750 } 751 RegistrationData regData = getRegistrationData(); 752 // Make sure it uses the canonical path before getting the URI. 753 File img = new File(svcTagDir.getCanonicalPath(), "jdk_header.png"); 754 String headerImageSrc = img.toURI().toString(); 755 756 // Format the registration data in one single line 757 StringBuilder payload = new StringBuilder(); 758 String xml = regData.toString().replaceAll("\"", "%22"); 759 try (BufferedReader reader = new BufferedReader(new StringReader(xml))) { 760 String line = null; 761 while ((line = reader.readLine()) != null) { 762 payload.append(line.trim()); 763 } 764 } 765 766 String resourceFilename = "/com/sun/servicetag/resources/register"; 767 for (Locale locale : supportedLocales) { 768 String name = REGISTRATION_HTML_NAME; 769 String resource = resourceFilename; 770 if (!locale.equals(Locale.ENGLISH)) { 771 name += "_" + locale.toString(); 772 resource += "_" + locale.toString(); 773 } 774 File f = new File(parent, name + ".html"); 775 InputStream in = null; 776 BufferedReader br = null; 777 PrintWriter pw = null; 778 String registerURL = SunConnection. 779 getRegistrationURL(regData.getRegistrationURN(), 780 locale, 781 String.valueOf(version)).toString(); 782 try { 783 in = Installer.class.getResourceAsStream(resource + ".html"); 784 if (in == null) { 785 // if the resource file is missing 786 if (isVerbose()) { 787 System.out.println("Missing resouce file: " + resource + ".html"); 788 } 789 continue; 790 } 791 if (isVerbose()) { 792 System.out.println("Generating " + f + " from " + resource + ".html"); 793 } 794 795 try { 796 br = new BufferedReader(new InputStreamReader(in, "UTF-8")); 797 pw = new PrintWriter(f, "UTF-8"); 798 String line = null; 799 while ((line = br.readLine()) != null) { 800 String output = line; 801 if (line.contains(JDK_VERSION_KEY)) { 802 output = line.replace(JDK_VERSION_KEY, jdkVersion); 803 } else if (line.contains(JDK_HEADER_PNG_KEY)) { 804 output = line.replace(JDK_HEADER_PNG_KEY, headerImageSrc); 805 } else if (line.contains(REGISTRATION_URL_KEY)) { 806 output = line.replace(REGISTRATION_URL_KEY, registerURL); 807 } else if (line.contains(REGISTRATION_PAYLOAD_KEY)) { 808 output = line.replace(REGISTRATION_PAYLOAD_KEY, payload.toString()); 809 } 810 pw.println(output); 811 } 812 f.setReadOnly(); 813 pw.flush(); 814 } finally { 815 // It's safe for this finally block to have two close statements 816 // consecutively as PrintWriter.close doesn't throw IOException. 817 if (pw != null) { 818 pw.close(); 819 } 820 if (br!= null) { 821 br.close(); 822 } 823 } 824 } finally { 825 if (in != null) { 826 in.close(); 827 } 828 } 829 } 830 } 831 832 private static final int MAX_SOURCE_LEN = 63; 833 834 /** 835 * A utility class to create a service tag for Java SE. 836 * <p> 837 * <b>Usage:</b><br> 838 * <blockquote><tt> 839 * <JAVA_HOME>/bin/java com.sun.servicetag.Installer 840 * </tt></blockquote> 841 * <p> 842 */ 843 public static void main(String[] args) { 844 String source = "Manual "; 845 String runtimeName = System.getProperty("java.runtime.name"); 846 if (runtimeName.startsWith("OpenJDK")) { 847 source = "OpenJDK "; 848 } 849 source += System.getProperty("java.runtime.version"); 850 if (source.length() > MAX_SOURCE_LEN) { 851 source = source.substring(0, MAX_SOURCE_LEN); 852 } 853 854 // Parse the options (arguments starting with "-" ) 855 boolean delete = false; 856 boolean update = false; 857 boolean register = false; 858 int count = 0; 859 while (count < args.length) { 860 String arg = args[count]; 861 if (arg.trim().length() == 0) { 862 // skip empty arguments 863 count++; 864 continue; 865 } 866 867 if (arg.equals("-source")) { 868 source = args[++count]; 869 } else if (arg.equals("-delete")) { 870 delete = true; 871 } else if (arg.equals("-register")) { 872 register = true; 873 } else { 874 usage(); 875 return; 876 } 877 count++; 878 } 879 try { 880 if (delete) { 881 deleteRegistrationData(); 882 } else { 883 ServiceTag[] javaSvcTags = getJavaServiceTagArray(); 884 String[] archs = getJreArchs(); 885 if (javaSvcTags.length > archs.length) { 886 // 64-bit has been uninstalled 887 // so remove the service tag 888 updateRegistrationData(source); 889 } else { 890 // create the service tag 891 createServiceTag(source); 892 } 893 } 894 895 if (register) { 896 // Registration is only supported by JDK 897 // For testing purpose, override with a "servicetag.enable.registration" property 898 899 RegistrationData regData = getRegistrationData(); 900 if (supportRegistration && !regData.getServiceTags().isEmpty()) { 901 SunConnection.register(regData, 902 getDefaultLocale(), 903 String.valueOf(Util.getJdkVersion())); 904 } 905 } 906 System.exit(0); 907 } catch (IOException e) { 908 System.err.println("I/O Error: " + e.getMessage()); 909 if (isVerbose()) { 910 e.printStackTrace(); 911 } 912 } catch (IllegalArgumentException ex) { 913 if (isVerbose()) { 914 ex.printStackTrace(); 915 } 916 } catch (Exception e) { 917 System.err.println("Error: " + e.getMessage()); 918 if (isVerbose()) { 919 e.printStackTrace(); 920 } 921 } 922 System.exit(1); 923 } 924 925 private static void usage() { 926 System.out.println("Usage:"); 927 System.out.print(" " + Installer.class.getName()); 928 System.out.println(" [-delete|-source <source>|-register]"); 929 System.out.println(" to create a service tag for the Java platform"); 930 System.out.println(""); 931 System.out.println("Internal Options:"); 932 System.out.println(" -source: to specify the source of the service tag to be created"); 933 System.out.println(" -delete: to delete the service tag "); 934 System.out.println(" -register: to register the JDK"); 935 System.out.println(" -help: to print this help message"); 936 } 937 }