1 20 21 package org.jdesktop.jdic.packager.impl; 22 23 import java.io.IOException ; 24 import java.io.File ; 25 import java.io.FileInputStream ; 26 import java.io.FileOutputStream ; 27 import java.util.TreeMap ; 28 import java.util.ArrayList ; 29 30 34 public class MsiPackageGenerator implements PackageGenerator { 35 38 private static final String SYS_JAR_FILE_NAME = "packager.jar"; 39 42 private static final String JNLP_FILES_JAR_NAME = "JnlpFiles.jar"; 43 46 private static final String MSI_SUPPORT_FILES_HIERARCHY_PATH = 47 "org/jdesktop/jdic/packager/impl/files/"; 48 51 private static final String MAKECAB_EXE_PATH = 52 "Samples\\sysmgmt\\msi\\Patching\\makecab.exe"; 53 56 private static final String MSIDB_EXE_PATH = 57 "bin\\msidb.exe"; 58 61 private static final String SYS_BOOTSTRAPPER_FILE_PATH = 62 MSI_SUPPORT_FILES_HIERARCHY_PATH + "bootstrapper.exe"; 63 66 private static final String CUSTOM_DLL_FILE_NAME = "custom.dll"; 67 70 private static final String LOCALIZED_WELCOME_MSG_FILE_NAME = 71 "WelcomeMsg.idt"; 72 75 public static final String LOCALIZED_WELCOME_MSG_TABLE_NAME = 76 "WelcomeMsg"; 77 80 private static final String PANEL_JPG_FILE_NAME = "panel.jpg"; 81 84 private static final String BANNER_JPG_FILE_NAME = "banner.jpg"; 85 88 private static final String JAVA_HOME_DIR_PROPERTY = "java.home"; 89 92 private static final String SYS_CLASS_PATH = "java.class.path"; 93 96 private static final String AUTHOR_INFO = "http://jdic.dev.java.net"; 97 100 private static final int VI_CONTROL_TEXT = 10; 101 104 private static final int VI_CONTROLEVENT_ARGUMENT = 4; 105 108 private static final int VI_CONTROLEVENT_EVENT = 3; 109 112 private static final int VI_PROPERTY_VALUE = 2; 113 116 private static final int PID_REVISION_NUMBER = 9; 117 120 private static final int PID_AUTHOR = 4; 121 124 private static String packagerJarFilePath = null; 125 126 130 public MsiPackageGenerator() { 131 } 132 133 138 private static void getPackagerJarFilePath() throws IOException { 139 String sysClassPath = System.getProperty(SYS_CLASS_PATH); 140 int fileNameIndex = sysClassPath.indexOf(SYS_JAR_FILE_NAME); 141 int filePathIndex = -1; 142 int i = fileNameIndex; 143 char indexChar; 144 while (i > 0) { 145 i--; 146 indexChar = sysClassPath.charAt(i); 147 if ((indexChar == ';') || (i == 0)) { 148 filePathIndex = i; 149 break; 150 } 151 } 152 if (filePathIndex > 0) { 153 packagerJarFilePath = 154 sysClassPath.substring( 155 filePathIndex + 1, 156 fileNameIndex + SYS_JAR_FILE_NAME.length()); 157 } else if (filePathIndex == 0) { 158 packagerJarFilePath = 159 sysClassPath.substring( 160 filePathIndex, 161 fileNameIndex + SYS_JAR_FILE_NAME.length()); 162 } else { 163 throw new IOException ( 164 "Could not locate " 165 + SYS_JAR_FILE_NAME 166 + " in system CLASSPATH setting!"); 167 } 168 } 169 170 177 private static void adjustMsiLicenseFields( 178 String msiFilePath, 179 JnlpPackageInfo pkgInfo, 180 int localeIndex) throws IOException { 181 TreeMap treeMap = new TreeMap (); 182 File licenseFile; 183 FileInputStream fis; 184 if (pkgInfo.getShowLicense()) { 186 try { 187 String realLicenseInfo = new String (); 188 realLicenseInfo += 189 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deftab720{\\fonttbl{\\f0\\" 190 + "froman\\fprq2 Times New Roman;}}{\\colortbl\\red0\\green0\\" 191 + "blue0;} \\deflang1033\\horzdoc{\\*\\fchars }{\\*\\lchars }\\" 192 + "pard\\plain\\f0\\fs20"; 193 194 licenseFile = new File ( 196 pkgInfo.getLicenseDirPath() 197 + File.separator 198 + JnlpConstants.LOCALES[localeIndex] 199 + ".txt"); 200 201 if (!licenseFile.exists()) { 202 licenseFile = 203 new File ( 204 pkgInfo.getLicenseDirPath() 205 + File.separator 206 + JnlpConstants.LOCALES[JnlpConstants.LOCALE_EN] 207 + ".txt"); 208 } 209 210 fis = new FileInputStream (licenseFile); 211 int fLen = (int) licenseFile.length(); 212 byte[] bits = new byte[fLen]; 213 fis.read(bits, 0, fLen); 214 fis.close(); 215 216 realLicenseInfo += new String (bits); 217 realLicenseInfo += "\\par }"; 218 treeMap.clear(); 219 treeMap.put("AgreementText", realLicenseInfo); 220 WinMsiUtility.winMsiSetProperty( 221 msiFilePath, 222 "Control", 223 "Control", 224 VI_CONTROL_TEXT, 225 false, 226 treeMap); 227 } catch (IOException e) { 228 throw new IOException ( 229 "License Agreement: Modify Control Table failed: " 230 + "Set MSI LicenseAgreement field property failed!"); 231 } 232 233 try { 234 treeMap.clear(); 235 treeMap.put("AfterWelcomeDlg", "LicenseAgreementDlg"); 236 WinMsiUtility.winMsiSetProperty( 237 msiFilePath, 238 "ControlEvent", 239 "Argument", 240 VI_CONTROLEVENT_ARGUMENT, 241 false, 242 treeMap); 243 } catch (IOException e) { 244 throw new IOException ( 245 "License Agreement: Modify ControlEvent Table failed: " 246 + "Insert License Agreement dialog failed!"); 247 } 248 } else { 249 try { 250 treeMap.clear(); 251 treeMap.put("AfterWelcomeDlg", "EndDialog"); 252 WinMsiUtility.winMsiSetProperty( 253 msiFilePath, 254 "ControlEvent", 255 "Argument", 256 VI_CONTROLEVENT_EVENT, 257 false, 258 treeMap); 259 } catch (IOException e) { 260 throw new IOException ( 261 "No License Agreement: Modify ControlEvent Table failed: " 262 + "AfterWelcomeDlg/EndDialog"); 263 } 264 265 try { 266 treeMap.clear(); 267 treeMap.put("AfterWelcomeDlg", "Return"); 268 WinMsiUtility.winMsiSetProperty( 269 msiFilePath, 270 "ControlEvent", 271 "Argument", 272 VI_CONTROLEVENT_ARGUMENT, 273 false, 274 treeMap); 275 } catch (IOException e) { 276 throw new IOException ( 277 "No License Agreement: Modify ControlEvent Table failed: " 278 + "AfterWelcomeDlg/Return"); 279 } 280 } 281 String welcomeMsg = WinMsiUtility.getWelcomeMsg( 284 msiFilePath, 285 JnlpConstants.LOCALES[localeIndex], 286 pkgInfo.getShowLicense()); 287 try { 288 treeMap.clear(); 289 treeMap.put("SunButton", "[ButtonText_Next]"); 290 treeMap.put( 292 "WelcomeDescription", 293 welcomeMsg); 294 WinMsiUtility.winMsiSetProperty( 295 msiFilePath, 296 "Control", 297 "Text", 298 VI_CONTROL_TEXT, 299 false, 300 treeMap); 301 } catch (IOException e) { 302 throw new IOException ( 303 "Handling Agreement: Modify Control Table failed: Next " 304 + "Button/WelcomeDescription"); 305 } 306 } 307 308 314 private static void customizeNonLocalizedMsiFields(String msiFilePath, 315 JnlpPackageInfo pkgInfo) throws IOException { 316 TreeMap treeMap = new TreeMap (); 317 String uuidProduct = "{" + WinMsiUtility.genUUID() + "}"; 319 String uuidUpgrade = "{" + WinMsiUtility.genUUID() + "}"; 320 321 try { 323 treeMap.clear(); 324 treeMap.put("ARPCONTACT", AUTHOR_INFO); 325 treeMap.put("ARPHELPLINK", AUTHOR_INFO); 326 treeMap.put("ARPURLINFOABOUT", AUTHOR_INFO); 327 treeMap.put("ARPURLUPDATEINFO", AUTHOR_INFO); 328 treeMap.put( 329 "ARPCOMMENTS", 330 "Generated by JDIC Project"); 331 332 treeMap.put("ProductCode", uuidProduct); 333 treeMap.put("UpgradeCode", uuidUpgrade); 334 treeMap.put( 336 "ProductVersion", 337 pkgInfo.getVersion() + 338 "." + 339 pkgInfo.getRelease()); 340 treeMap.put("JnlpFileName", pkgInfo.getJnlpFileName()); 341 treeMap.put("UninstallInfo", pkgInfo.getJnlpFileHref()); 342 343 treeMap.put( 344 "Shortcut", 345 pkgInfo.getShortcutEnabled() ? "1" : "0"); 346 treeMap.put( 347 "Association", 348 pkgInfo.getAssociationEnabled() ? "1" : "0"); 349 350 treeMap.put( 351 "CacheType", 352 pkgInfo.getSystemCacheEnabled() ? "system" : "user"); 353 354 WinMsiUtility.winMsiSetProperty( 355 msiFilePath, 356 "Property", 357 "Property", 358 VI_PROPERTY_VALUE, 359 false, 360 treeMap); 361 } catch (IOException e) { 362 throw new IOException ("Set MSI field property failed!"); 363 } 364 365 try { 367 WinMsiUtility.setSummaryInfoProperty(msiFilePath, 368 PID_REVISION_NUMBER, 369 uuidProduct); 370 WinMsiUtility.setSummaryInfoProperty(msiFilePath, 371 PID_AUTHOR, 372 AUTHOR_INFO); 373 } catch (IOException e) { 374 throw new IOException ("Set MSI summary information stream failed!"); 375 } 376 377 String [] names = new String [] {"Name", "Data"}; 378 String [] properties = new String [] {"String", "Stream"}; 379 String [] values = new String [2]; 380 try { 381 String customDLLFilePath = 383 pkgInfo.getUniqueTmpDirPath() + CUSTOM_DLL_FILE_NAME; 384 WinUtility.extractFileFromJarFile( 385 packagerJarFilePath, 386 MSI_SUPPORT_FILES_HIERARCHY_PATH + CUSTOM_DLL_FILE_NAME, 387 customDLLFilePath); 388 values[0] = "CustomDLL"; 389 values[1] = customDLLFilePath; 390 WinMsiUtility.addBinaryRecord( 391 msiFilePath, 392 "Binary", 393 names, 394 properties, 395 values); 396 } catch (IOException e) { 397 throw new IOException ("Binary: insert CustomDLL field failed!"); 398 } 399 400 try { 401 String tempJarFilePath = pkgInfo.getUniqueTmpDirPath() 403 + JNLP_FILES_JAR_NAME; 404 WinUtility.jarJnlpFiles(tempJarFilePath, pkgInfo); 405 values[0] = "JarPack"; 406 values[1] = tempJarFilePath; 407 WinMsiUtility.addBinaryRecord( 408 msiFilePath, 409 "Binary", 410 names, 411 properties, 412 values); 413 } catch (IOException e) { 414 throw new IOException ("Binary: insert JarPack field failed!"); 415 } 416 417 treeMap.clear(); 418 try { 419 String bannerJpgFilePath = 421 pkgInfo.getUniqueTmpDirPath() + BANNER_JPG_FILE_NAME; 422 if (pkgInfo.getBannerJpgFilePath() != null) { 423 bannerJpgFilePath = pkgInfo.getBannerJpgFilePath(); 424 } else { 425 WinUtility.extractFileFromJarFile( 426 packagerJarFilePath, 427 MSI_SUPPORT_FILES_HIERARCHY_PATH + BANNER_JPG_FILE_NAME, 428 bannerJpgFilePath); 429 } 430 treeMap.put("bannrbmp", bannerJpgFilePath); 431 } catch (IOException e) { 432 throw new IOException ("Binary: pre insert bannrbmp field failed!"); 433 } 434 435 try { 436 String panelJpgFilePath = pkgInfo.getUniqueTmpDirPath() 438 + PANEL_JPG_FILE_NAME; 439 if (pkgInfo.getPanelJpgFilePath() != null) { 440 panelJpgFilePath = pkgInfo.getPanelJpgFilePath(); 441 } else { 442 WinUtility.extractFileFromJarFile( 443 packagerJarFilePath, 444 MSI_SUPPORT_FILES_HIERARCHY_PATH + PANEL_JPG_FILE_NAME, 445 panelJpgFilePath); 446 } 447 treeMap.put("dlgbmp", panelJpgFilePath); 448 } catch (IOException e) { 449 throw new IOException ("Binary: pre insert dlgbmp field failed!"); 450 } 451 452 try { 453 WinMsiUtility.winMsiSetProperty( 454 msiFilePath, 455 "Binary", 456 "Name", 457 2, 458 true, 459 treeMap); 460 } catch (IOException e) { 461 throw new IOException ( 462 "Binary: insert bannrbmp and dlgbmp field failed!"); 463 } 464 } 465 466 472 private static void createTemplateMsiFile(String msiFilePath, 473 JnlpPackageInfo pkgInfo) throws IOException { 474 ArrayList sqlStrings = new ArrayList (); 476 sqlStrings.add("CREATE TABLE Directory (Directory CHAR(72) NOT NULL, " 478 + "Directory_Parent CHAR(72), DefaultDir CHAR(255) NOT " 479 + "NULL LOCALIZABLE PRIMARY KEY Directory)"); 480 sqlStrings.add("INSERT INTO Directory (Directory, Directory_Parent, " 481 + "DefaultDir) VALUES ('TARGETDIR', '', 'SourceDir')"); 482 sqlStrings.add("INSERT INTO Directory (Directory, Directory_Parent, " 483 + "DefaultDir) VALUES ('ProgramFilesFolder', " 484 + "'TARGETDIR', '.:PROGRA~1|program files')"); 485 sqlStrings.add("INSERT INTO Directory (Directory, Directory_Parent, " 486 + "DefaultDir) VALUES ('INSTALLDIR', 'TempFolder', " 487 + "'.')"); 488 sqlStrings.add("INSERT INTO Directory (Directory, Directory_Parent, " 489 + "DefaultDir) VALUES ('TempFolder', 'TARGETDIR', " 490 + "'.:Temp')"); 491 sqlStrings.add("CREATE TABLE Component (Component CHAR(72) NOT NULL, " 493 + "ComponentId CHAR(38), Directory_ CHAR(72) NOT NULL, " 494 + "Attributes INT NOT NULL, Condition CHAR(255), " 495 + "KeyPath CHAR(72) PRIMARY KEY Component)"); 496 sqlStrings.add("INSERT INTO Component (Component, ComponentId, " 497 + "Directory_, Attributes, Condition, KeyPath) VALUES " 498 + "('AllOtherFiles', " 499 + "'{31CCF52F-FCB3-4239-9D82-05CDA204867A}', " 500 + "'INSTALLDIR', 8, '', '')"); 501 sqlStrings.add("CREATE TABLE File (File CHAR(72) NOT NULL, Component_ " 503 + "CHAR(72) NOT NULL, FileName CHAR(255) NOT NULL " 504 + "LOCALIZABLE, FileSize LONG NOT NULL, " 505 + "Version CHAR(72), Language CHAR(20), Attributes INT, " 506 + "Sequence INT NOT NULL PRIMARY KEY File)"); 507 sqlStrings.add("INSERT INTO File (File, Component_, FileName, " 508 + "FileSize, Version, Language, Attributes, Sequence) " 509 + "VALUES ('place.txt', 'AllOtherFiles', 'place.txt', " 510 + "18, '', '', 16384, 1)"); 511 sqlStrings.add("CREATE TABLE Media (DiskId INT NOT NULL, LastSequence " 513 + "INT NOT NULL, DiskPrompt CHAR(64) LOCALIZABLE, " 514 + "Cabinet CHAR(255), VolumeLabel CHAR(32), Source " 515 + "CHAR(72) PRIMARY KEY DiskId)"); 516 sqlStrings.add("INSERT INTO Media (DiskId, LastSequence, DiskPrompt, " 517 + "Cabinet, VolumeLabel, Source) VALUES (1, 1, '', " 518 + "'#Data1.cab', '', '')"); 519 sqlStrings.add("CREATE TABLE Feature (Feature CHAR(38) NOT NULL, " 521 + "Feature_Parent CHAR(38), Title CHAR(64) LOCALIZABLE, " 522 + "Description CHAR(255) LOCALIZABLE, Display INT, " 523 + "Level INT NOT NULL, Directory_ CHAR(72), Attributes " 524 + "INT NOT NULL PRIMARY KEY Feature)"); 525 sqlStrings.add("INSERT INTO Feature (Feature, Feature_Parent, Title, " 526 + "Description, Display, Level, Directory_ , " 527 + "Attributes) VALUES ('NewFeature1', '', " 528 + "'NewFeature1', '', 2, 1, 'INSTALLDIR', 0)"); 529 sqlStrings.add("CREATE TABLE FeatureComponents (Feature_ CHAR(38) NOT " 531 + "NULL, Component_ CHAR(72) NOT NULL PRIMARY KEY " 532 + "Feature_, Component_)"); 533 sqlStrings.add("INSERT INTO FeatureComponents (Feature_, Component_) " 534 + "VALUES ('NewFeature1', 'AllOtherFiles')"); 535 sqlStrings.add("CREATE TABLE CustomAction(Action CHAR(72) NOT NULL, " 537 + "Type INT NOT NULL, Source CHAR(72), Target CHAR(255) " 538 + "PRIMARY KEY Action)"); 539 sqlStrings.add("INSERT INTO CustomAction (Action,Type,Source,Target) " 540 + "VALUES ('CustomInstallAction', 1, 'CustomDLL', " 541 + "'InstallAction')"); 542 sqlStrings.add("INSERT INTO CustomAction (Action,Type,Source,Target) " 543 + "VALUES ('CustomUninstallAction', 1, 'CustomDLL', " 544 + "'UninstallAction')"); 545 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 547 + "('Manufacturer','" + AUTHOR_INFO + "')"); 548 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 549 + "('ProductCode', " 550 + "'{3D11E9FC-142F-4945-8010-861EAA24850F}')"); 551 sqlStrings.add("INSERT INTO Property (Property,Value) " 552 + "VALUES ('ProductName','Default')"); 553 sqlStrings.add("INSERT INTO Property (Property,Value) " 554 + "VALUES ('ProductVersion','1.00.0000')"); 555 sqlStrings.add("INSERT INTO Property (Property,Value) " 556 + "VALUES ('UpgradeCode', " 557 + "'{20AC1669-B481-4CAD-82AF-2CD00005F304}')"); 558 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 559 + "('JnlpFileName','ok')"); 560 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 561 + "('UninstallInfo','ok')"); 562 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 563 + "('Locale','en')"); 564 sqlStrings.add("UPDATE Property SET Value='" + AUTHOR_INFO 565 + "' where Property='ARPHELPLINK'"); 566 sqlStrings.add("UPDATE Property SET Value='" + AUTHOR_INFO 567 + "' where Property='ComponentDownload'"); 568 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 569 + "('ARPCONTACT','" + AUTHOR_INFO + "')"); 570 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 571 + "('ARPURLINFOABOUT','" + AUTHOR_INFO + "')"); 572 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 573 + "('ARPURLUPDATEINFO','" + AUTHOR_INFO + "')"); 574 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 575 + "('ARPCOMMENTS','Generated by JDIC Project')"); 576 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 577 + "('Shortcut','yes')"); 578 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 579 + "('Association','yes')"); 580 sqlStrings.add("INSERT INTO Property (Property,Value) VALUES " 581 + "('CacheType','user')"); 582 583 sqlStrings.add("INSERT INTO InstallExecuteSequence (Action, Condition, " 585 + "Sequence) VALUES ('CustomInstallAction', " 586 + "'NOT Installed', 6650)"); 587 sqlStrings.add("INSERT INTO InstallExecuteSequence (Action, Condition, " 588 + "Sequence) VALUES ('CustomUninstallAction', " 589 + "'Installed', 6651)"); 590 sqlStrings.add("UPDATE Dialog SET Control_Cancel='RemoveButton' where " 592 + "Dialog='MaintenanceTypeDlg'"); 593 sqlStrings.add("UPDATE Control SET Attributes=0 where " 595 + "Dialog_='MaintenanceTypeDlg' and " 596 + "Control='ChangeLabel'"); 597 sqlStrings.add("UPDATE Control SET Attributes=5767168 where " 598 + "Dialog_='MaintenannceTypeDlg' and " 599 + "Control='ChangeButton'"); 600 sqlStrings.add("UPDATE Control SET Attributes=0 where " 601 + "Dialog_='MaintenanceTypeDlg' and " 602 + "Control='ChangeText'"); 603 sqlStrings.add("UPDATE Control SET Attributes=0 where " 604 + "Dialog_='MaintenanceTypeDlg' and " 605 + "Control='RepairLabel'"); 606 sqlStrings.add("UPDATE Control SET Attributes=5767168 where " 607 + "Dialog_='MaintenanceTypeDlg' and " 608 + "Control='RepairButton'"); 609 sqlStrings.add("UPDATE Control SET Attributes=0 where " 610 + "Dialog_='MaintenanceTypeDlg' and " 611 + "Control='RepairText'"); 612 sqlStrings.add("UPDATE Control SET Y=65 where " 613 + "Dialog_='MaintenanceTypeDlg' and " 614 + "Control='RemoveButton'"); 615 sqlStrings.add("UPDATE Control SET Y=65 where " 616 + "Dialog_='MaintenanceTypeDlg' and " 617 + "Control='RemoveLabel'"); 618 sqlStrings.add("UPDATE Control SET Y=78 where " 619 + "Dialog_='MaintenanceTypeDlg' and " 620 + "Control='RemoveText'"); 621 sqlStrings.add("UPDATE Control SET Y=78 where " 622 + "Dialog_='MaintenanceTypeDlg' and " 623 + "Control='RemoveText'"); 624 sqlStrings.add("UPDATE Control SET " 625 + "Text='[DlgTitleFont]Remove installation' where " 626 + "Dialog_='MaintenanceTypeDlg' and Control='Title'"); 627 sqlStrings.add("UPDATE Control SET Attributes=196608 where " 628 + "Dialog_='MaintenanceTypeDlg' and " 629 + "Control='Description'"); 630 sqlStrings.add("UPDATE Control SET Text='The [Wizard] is ready to " 631 + "begin the installation' where " 632 + "Dialog_='VerifyReadyDlg' and Control='Description'"); 633 sqlStrings.add("UPDATE Control SET Text='Click Install to begin the " 634 + "installation. Click Cancel to exit the wizard.' " 635 + "where Dialog_='VerifyReadyDlg' and Control='Text'"); 636 sqlStrings.add("UPDATE Control SET Text='The [Wizard] will allow you to" 637 + "remove [ProductName] from your computer. Click Next " 638 + "to continue or Cancel to exit the [Wizard].' where " 639 + "Dialog_='MaintenanceWelcomeDlg' and " 640 + "Control='Description'"); 641 sqlStrings.add("UPDATE Control SET Text='Click Remove to remove " 642 + "[ProductName] from your computer. Click Cancel to " 643 + "exit the wizard.' where Dialog_='VerifyRemoveDlg' " 644 + "and Control='Text'"); 645 sqlStrings.add("UPDATE Control SET Text='{\\DlgFontBold8}Remove " 646 + "[ProductName]' where Dialog_='VerifyRemoveDlg' " 647 + "and Control='Title'"); 648 sqlStrings.add("UPDATE Control SET Text='SunButton' where " 649 + "Dialog_='WelcomeDlg' and Control='Next'"); 650 sqlStrings.add("UPDATE Control SET Text='WelcomeDescription' where " 651 + "Dialog_='WelcomeDlg' and Control='Description'"); 652 sqlStrings.add("UPDATE Control SET Text='[ButtonText_Remove]' where " 653 + "Dialog_='MaintenanceWelcomeDlg' and Control='Next'"); 654 sqlStrings.add("UPDATE Control SET Text='The [Wizard] will allow you " 655 + "to remove [ProductName] from your computer. Click " 656 + "Remove to continue or Cancel to exit the [Wizard].' " 657 + "where Dialog_='MaintenanceWelcomeDlg' and " 658 + "Control='Description'"); 659 sqlStrings.add("DELETE FROM ControlEvent where Dialog_='WelcomeDlg' " 661 + "and Control_='Next'"); 662 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 663 + "Argument, Condition) VALUES ('WelcomeDlg', 'Next', " 664 + "'NewDialog', 'AfterWelcomeDlg', 1)"); 665 sqlStrings.add("DELETE from ControlEvent where " 666 + "Dialog_='LicenseAgreementDlg' and Control_='Next' " 667 + "and Event='NewDialog'"); 668 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_,Event, " 669 + "Argument, Condition, Ordering) VALUES " 670 + "('LicenseAgreementDlg', 'Next', 'EndDialog', " 671 + "'Return', 'IAgree = \"Yes\"', 1)"); 672 sqlStrings.add("DELETE FROM ControlEvent where " 673 + "Dialog_='MaintenanceWelcomeDlg' and Control_='Next'"); 674 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 675 + "Argument, Condition, Ordering) VALUES " 676 + "('MaintenanceWelcomeDlg', 'Next', '[InstallMode]', " 677 + "'Remove', '1', 1)"); 678 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 679 + "Argument, Condition, Ordering) VALUES " 680 + "('MaintenanceWelcomeDlg', 'Next', '[Progress1]', " 681 + "'Removing', '1', 2)"); 682 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 683 + "Argument, Condition, Ordering) VALUES " 684 + "('MaintenanceWelcomeDlg', 'Next', '[Progress2]', " 685 + "'removes', '1', 3)"); 686 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 687 + "Argument, Condition, Ordering) VALUES " 688 + "('MaintenanceWelcomeDlg', 'Next', 'SpawnWaitDialog', " 689 + "'WaitForCostingDlg', 'CostingComplete = 1', 4)"); 690 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 691 + "Argument, Condition, Ordering) VALUES " 692 + "('MaintenanceWelcomeDlg', 'Next', 'Remove', " 693 + "'All', '1', 5)"); 694 sqlStrings.add("INSERT INTO ControlEvent (Dialog_, Control_, Event, " 695 + "Argument, Condition, Ordering) VALUES " 696 + "('MaintenanceWelcomeDlg', 'Next', 'EndDialog', " 697 + "'Return', '1', 6)"); 698 WinMsiUtility.runSql(msiFilePath, sqlStrings); 699 700 File tempTxtFile = new File (pkgInfo.getUniqueTmpDirPath() 702 + "place.txt"); 703 FileOutputStream fis = new FileOutputStream (tempTxtFile); 704 String contentString = new String (AUTHOR_INFO); 705 byte[] bits = contentString.getBytes(); 706 fis.write(bits, 0, contentString.length()); 707 fis.close(); 708 709 String makecabFullPath = pkgInfo.getMSSDKDirPath() + MAKECAB_EXE_PATH; 712 String msidbFullPath = pkgInfo.getMSSDKDirPath() + MSIDB_EXE_PATH; 713 File temFile = new File (makecabFullPath); 714 if (!temFile.exists()) { 715 throw new IOException ("Can not locate makecab.exe at" + 716 makecabFullPath); 717 } 718 temFile = new File (msidbFullPath); 719 if (!temFile.exists()) { 720 throw new IOException ( 721 "Can not locate msidb.exe at" + 722 msidbFullPath); 723 } 724 String tempCabFilePath = pkgInfo.getUniqueTmpDirPath() + "Data1.cab"; 725 Process proc = Runtime.getRuntime().exec( 726 "\"" + makecabFullPath + "\" " + tempTxtFile.toString() 727 + " " + tempCabFilePath); 728 try { 729 proc.waitFor(); 730 } catch (InterruptedException e) { 731 throw new IOException (e.getMessage()); 732 } 733 proc = Runtime.getRuntime().exec( 734 "\"" + msidbFullPath + "\" -d " + msiFilePath + 735 " -a " + tempCabFilePath); 736 try { 737 proc.waitFor(); 738 } catch (InterruptedException e) { 739 throw new IOException (e.getMessage()); 740 } 741 742 String tempWelcomeMsgFilePath = pkgInfo.getUniqueTmpDirPath() 744 + LOCALIZED_WELCOME_MSG_FILE_NAME; 745 String sysWelcomeMsgFilePath = MSI_SUPPORT_FILES_HIERARCHY_PATH 746 + LOCALIZED_WELCOME_MSG_FILE_NAME; 747 WinUtility.extractFileFromJarFile( 748 packagerJarFilePath, 749 sysWelcomeMsgFilePath, 750 tempWelcomeMsgFilePath); 751 WinMsiUtility.importTableFromFile( 752 msiFilePath, 753 pkgInfo.getUniqueTmpDirPath(), 754 LOCALIZED_WELCOME_MSG_FILE_NAME); 755 } 756 757 763 public final void generatePackage(JnlpPackageInfo pkgInfo) 764 throws IOException { 765 getPackagerJarFilePath(); 767 769 String enMsiFilePath = pkgInfo.getUniqueTmpDirPath() + "en.msi"; 771 String rawMsiFilePath = pkgInfo.getRawMsiFilePath(); 772 FileOperUtility.copyLocalFile(rawMsiFilePath, enMsiFilePath); 773 774 createTemplateMsiFile(enMsiFilePath, pkgInfo); 776 customizeNonLocalizedMsiFields(enMsiFilePath, pkgInfo); 777 putProductNameIntoMsi(enMsiFilePath, pkgInfo, JnlpConstants.LOCALE_EN); 779 adjustMsiLicenseFields(enMsiFilePath, pkgInfo, JnlpConstants.LOCALE_EN); 781 782 if (pkgInfo.getLocalizationEnabled()) { 784 for (int i = 1; i < JnlpConstants.LOCALES.length; i++) { 786 String localizedMsiFilePath = 788 pkgInfo.getUniqueTmpDirPath() 789 + JnlpConstants.LOCALES[i] 790 + ".msi"; 791 FileOperUtility.copyLocalFile(enMsiFilePath, 792 localizedMsiFilePath); 793 794 importLocalizedTables(localizedMsiFilePath, pkgInfo, i); 796 797 putProductNameIntoMsi(localizedMsiFilePath, pkgInfo, i); 799 800 adjustMsiLicenseFields(localizedMsiFilePath, pkgInfo, i); 803 } 804 } 805 generateBootStrapper(pkgInfo); 806 } 807 808 816 public final void importLocalizedTables(String localizedMsiFilePath, 817 JnlpPackageInfo pkgInfo, 818 int localeIndex) throws IOException { 819 ArrayList sqlStrings = new ArrayList (); 820 sqlStrings.add("DROP TABLE ActionText"); 823 sqlStrings.add("DROP TABLE Error"); 824 sqlStrings.add("DROP TABLE Control"); 825 sqlStrings.add("DROP TABLE ControlEvent"); 826 827 WinMsiUtility.runSql(localizedMsiFilePath, sqlStrings); 828 829 String localizedControlTableFileName = 831 "Control." + JnlpConstants.LOCALES_SUFFIX[localeIndex]; 832 String localizedControlTableFilePath = 833 pkgInfo.getUniqueTmpDirPath() + localizedControlTableFileName; 834 String localizedControlEventTableFileName = 835 "ControlEvent." + JnlpConstants.LOCALES_SUFFIX[localeIndex]; 836 String localizedControlEventTableFilePath = 837 pkgInfo.getUniqueTmpDirPath() 838 + localizedControlEventTableFileName; 839 840 WinUtility.extractFileFromJarFile( 841 packagerJarFilePath, 842 MSI_SUPPORT_FILES_HIERARCHY_PATH + localizedControlTableFileName, 843 localizedControlTableFilePath); 844 845 WinUtility.extractFileFromJarFile( 846 packagerJarFilePath, 847 MSI_SUPPORT_FILES_HIERARCHY_PATH 848 + localizedControlEventTableFileName, 849 localizedControlEventTableFilePath); 850 851 WinMsiUtility.importTableFromFile( 853 localizedMsiFilePath, 854 pkgInfo.getUniqueTmpDirPath(), 855 "ActionTe." + JnlpConstants.LOCALES_SUFFIX[localeIndex]); 856 857 WinMsiUtility.importTableFromFile( 859 localizedMsiFilePath, 860 pkgInfo.getUniqueTmpDirPath(), 861 "Error" + JnlpConstants.LOCALES_SUFFIX[localeIndex]); 862 863 WinMsiUtility.importTableFromFile( 865 localizedMsiFilePath, 866 pkgInfo.getUniqueTmpDirPath(), 867 localizedControlTableFileName); 868 869 WinMsiUtility.importTableFromFile( 871 localizedMsiFilePath, 872 pkgInfo.getUniqueTmpDirPath(), 873 localizedControlEventTableFileName); 874 875 } 876 877 885 public final void putProductNameIntoMsi(String localizedMsiFilePath, 886 JnlpPackageInfo pkgInfo, 887 int localeIndex) 888 throws IOException { 889 TreeMap treeMap = new TreeMap (); 890 try { 891 treeMap.clear(); 892 treeMap.put( 893 "ProductName", 894 pkgInfo.getLocalizedJnlpInfo( 895 JnlpConstants.LOCALES[localeIndex], 896 JnlpConstants.JNLP_FIELD_TITLE)); 897 treeMap.put("Locale", JnlpConstants.LOCALES[localeIndex]); 898 WinMsiUtility.winMsiSetProperty( 899 localizedMsiFilePath, 900 "Property", 901 "Property", 902 2, 903 false, 904 treeMap); 905 } catch (IOException e) { 906 throw new IOException ( 907 "Property Table: Modify ProductName field failed!"); 908 } 909 } 910 911 919 public final void generateBootStrapper(JnlpPackageInfo pkgInfo) 920 throws IOException { 921 String enMsiFilePath = 925 pkgInfo.getUniqueTmpDirPath() 926 + JnlpConstants.LOCALES[JnlpConstants.LOCALE_EN] 927 + ".msi"; 928 929 if (pkgInfo.getLocalizationEnabled()) { 932 String localizedMsiFilePath; 935 String targetMstFilePath; 936 for (int i = 1; i < JnlpConstants.LOCALES.length; i++) { 937 localizedMsiFilePath = 938 pkgInfo.getUniqueTmpDirPath() 939 + JnlpConstants.LOCALES[i] 940 + ".msi"; 941 targetMstFilePath = 942 pkgInfo.getUniqueTmpDirPath() 943 + JnlpConstants.LOCALES[i] 944 + ".mst"; 945 WinMsiUtility.generateTransform( 946 enMsiFilePath, 947 localizedMsiFilePath, 948 targetMstFilePath); 949 } 950 951 String newFieldName; 955 for (int i = 1; i < JnlpConstants.LOCALES.length; i++) { 956 targetMstFilePath = 957 pkgInfo.getUniqueTmpDirPath() 958 + JnlpConstants.LOCALES[i] 959 + ".mst"; 960 newFieldName = "cust_" + JnlpConstants.LOCALES[i]; 961 WinMsiUtility.incorporateMST( 962 enMsiFilePath, 963 targetMstFilePath, 964 newFieldName); 965 } 966 } 967 968 String tempBootStrapperFilePath = 970 pkgInfo.getUniqueTmpDirPath() + pkgInfo.getPackageName() + ".exe"; 971 WinUtility.extractFileFromJarFile( 972 packagerJarFilePath, 973 SYS_BOOTSTRAPPER_FILE_PATH, 974 tempBootStrapperFilePath); 975 976 String exeUUID = WinMsiUtility.genUUID(); 980 WinUtility.updateResourceString( 981 tempBootStrapperFilePath, 982 exeUUID, 983 WinUtility.STRING_RES_UUID_ID); 984 985 WinUtility.updateResourceData( 987 tempBootStrapperFilePath, 988 enMsiFilePath, 989 WinUtility.BIN_RES_ID); 990 991 String localizationFlag; 993 if (pkgInfo.getLocalizationEnabled()) { 994 localizationFlag = "localization supported"; 995 } else { 996 localizationFlag = "no localization support"; 997 } 998 WinUtility.updateResourceString( 999 tempBootStrapperFilePath, 1000 localizationFlag, 1001 WinUtility.STRING_RES_LOCALIZATION_FLAG_ID); 1002 1003 String targetBootStrapperFilePath = 1005 pkgInfo.getOutputDirPath() + pkgInfo.getPackageName() + ".exe"; 1006 FileOperUtility.copyLocalFile(tempBootStrapperFilePath, 1007 targetBootStrapperFilePath); 1008 File targetFile = new File (targetBootStrapperFilePath); 1010 if (targetFile.exists()) { 1011 System.out.println("\nSuccess: The bootstrapper MSI file has been" + 1012 " generated at: \n" + targetBootStrapperFilePath + "\n"); 1013 } 1014 1015 File tempDir = new File (pkgInfo.getUniqueTmpDirPath()); 1017 FileOperUtility.deleteDirTree(tempDir); 1018 } 1019} 1020 | Popular Tags |