1 19 20 package com.sslexplorer.agent.client.util; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InputStreamReader ; 28 import java.io.StringReader ; 29 import java.lang.reflect.Method ; 30 import java.net.URL ; 31 import java.net.URLConnection ; 32 import java.text.MessageFormat ; 33 import java.util.Enumeration ; 34 import java.util.Hashtable ; 35 import java.util.Vector ; 36 import java.util.zip.Adler32 ; 37 import java.util.zip.CheckedInputStream ; 38 39 import com.sslexplorer.agent.client.util.types.DefaultAgentApplicationType; 40 import com.sslexplorer.agent.client.util.types.ExecutableApplicationType; 41 import com.sslexplorer.agent.client.util.types.HtmlApplicationType; 42 import com.sslexplorer.agent.client.util.types.JavaApplicationType; 43 44 58 public abstract class AbstractApplicationLauncher { 59 60 static Vector EMPTY_VECTOR = new Vector (); 61 File installDir; 62 File sharedDir; 63 String typeName; 64 65 String name; 66 String ticket; 67 68 70 protected String applicationStoreProtocol; 71 protected String applicationStoreHost; 72 protected String applicationStoreUser; 73 protected int applicationStorePort; 74 protected ApplicationLauncherEvents events; 75 protected Hashtable parameters; 76 77 79 private long totalBytesToDownload = 0; 80 private Vector filesToDownload = new Vector (); 81 private Hashtable sharedFilesToDowload = new Hashtable (); 82 private Hashtable descriptorParams = new Hashtable (); 83 private boolean debug = false; 84 private String localProxyURL; 85 private ApplicationType type; 86 private Hashtable replacements = new Hashtable (); 87 private Vector transformations = new Vector (); 88 private boolean hasPrepared = false; 89 private File cacheDir; 90 private String smallIcon, largeIcon; 91 92 104 public AbstractApplicationLauncher(File cacheDir, String applicationStoreProtocol, String applicationStoreUser, String applicationStoreHost, 105 int applicationStorePort, Hashtable parameters, ApplicationLauncherEvents events) { 106 this.cacheDir = cacheDir; 107 this.applicationStoreProtocol = applicationStoreProtocol; 108 this.applicationStoreHost = applicationStoreHost; 109 this.applicationStoreUser = applicationStoreUser; 110 this.applicationStorePort = applicationStorePort; 111 this.parameters = parameters; 112 this.events = events; 113 } 114 115 121 public void setLocalProxyURL(String localProxyURL) { 122 this.localProxyURL = localProxyURL; 123 } 124 125 130 public void setDebug(boolean debug) { 131 this.debug = debug; 132 } 133 134 139 public ApplicationType getApplicationType() { 140 return type; 141 } 142 143 148 public void prepare() throws IOException { 149 150 hasPrepared = true; 151 152 if (events != null) 153 events.debug(Messages.getString("ApplicationLauncher.checkingParameters")); 155 if (debug) { 157 parameters.put("debug", "true"); } 159 160 ticket = (String ) parameters.get("ticket"); if (events != null && ticket!=null) 162 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.storingTicket"), new Object [] { ticket })); 164 XMLElement element = new XMLElement(); 165 166 168 events.debug(Messages.getString("ApplicationLauncher.gettingDescriptorStream")); InputStreamReader reader = new InputStreamReader (getApplicationDescriptor()); 170 events.debug(Messages.getString("ApplicationLauncher.readingDescriptorStream")); char[] cbuf = new char[65536]; 172 StringBuffer xml = new StringBuffer (); 173 int read = 0; 174 while (read != -1) { 175 read = reader.read(cbuf,0,cbuf.length); 176 if(read != -1) { 177 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.readBlock"), new Object [] { String.valueOf(read) })); xml.append(cbuf,0,read); 179 } 180 } 181 try { 182 events.debug(Messages.getString("ApplicationLauncher.parsingDescriptor")); element.parseFromReader(new StringReader (xml.toString())); 184 events.debug(Messages.getString("ApplicationLauncher.parsedDescriptor")); } 186 catch(XMLParseException xmlpe) { 187 if (events != null) { 188 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.failedToParseXML"), new Object [] { xmlpe.getMessage() } ) ); events.debug(xml.toString()); 190 } 191 throw xmlpe; 192 } 193 194 195 events.debug("[XML] [" + xml.toString() + "]"); 196 197 if (events != null) 198 events.debug(Messages.getString("ApplicationLauncher.receivedResponseFromServer")); 200 if (!element.getName().equals("application") && !element.getName().equals("error") && !element.getName().equals("extension")) { throw new IOException (Messages.getString("ApplicationLauncher.urlDoesNotPointToApplicationDescriptor")); } else if (element.getName().equals("error")) { throw new IOException (element.getContent()); 205 } 206 207 name = (String ) element.getAttribute("extension"); if (name == null) { 209 name = (String ) element.getAttribute("application"); } 211 212 typeName = (String ) element.getAttribute("type"); smallIcon = (String ) element.getAttribute("smallIcon"); largeIcon = (String ) element.getAttribute("largeIcon"); 216 try { 217 type = ApplicationTypeManager.getInstance().createType(typeName); 218 } catch (Throwable t) { 219 t.printStackTrace(); 220 throw new IOException (MessageFormat.format(Messages.getString("ApplicationLauncher.failedToLoadApplicationDescriptor"), new Object [] { typeName + " " + t.getMessage() })); } 222 223 if (events != null) 224 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.applicationNameIs"), new Object [] { name, type.getClass().getName() })); 226 if (events != null) { 227 events.processingDescriptor(); 228 } 229 230 if (events != null) 231 events.debug(Messages.getString("ApplicationLauncher.creatingInstallFolder")); 233 236 if (events != null) 237 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.userHomeIs"), new Object [] { cacheDir.getAbsolutePath() })); 239 installDir = new File (cacheDir, "applications" + File.separator + name); 241 sharedDir = new File (cacheDir, "shared"); 243 if (!installDir.exists()) { 244 installDir.mkdirs(); 245 } 246 247 if (!sharedDir.exists()) { 248 sharedDir.mkdirs(); 249 } 250 251 if (events != null) 252 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.installingTo"), new Object [] { installDir.getAbsolutePath() })); 254 Enumeration e = element.enumerateChildren(); 255 256 while (e.hasMoreElements()) { 257 XMLElement el = (XMLElement) e.nextElement(); 258 259 if (el.getName().equalsIgnoreCase("files")) { processFiles(el); 261 } else if (el.getName().equalsIgnoreCase("tunnel")) { createTunnel(el); 265 } else if (el.getName().equalsIgnoreCase("parameter")) { addParameter(el); 267 } else if (el.getName().equalsIgnoreCase("messages")) { } else if (el.getName().equalsIgnoreCase("description")) { } else if (el.getName().equalsIgnoreCase("replacements")) { FileReplacement replacement = new FileReplacement(installDir); 274 replacement.processReplacementXML(el, this); 275 replacements.put(replacement.getId(), replacement); 276 } else if (processLauncherElement(el)) { 277 continue; 280 } else if (el.getName().equalsIgnoreCase("transform")) { ParameterTransformation trans = new ParameterTransformation(el, this); 282 transformations.addElement(trans); 283 } else { 284 type.prepare(this, events, el); 285 } 286 } 287 } 288 289 public void download() throws IOException { 290 291 downloadFiles(); 292 293 if (events != null) 294 events.debug(Messages.getString("ApplicationLauncher.applyingParameterTransformations")); 296 for (Enumeration ep = transformations.elements(); ep.hasMoreElements();) { 297 ParameterTransformation trans = (ParameterTransformation) ep.nextElement(); 298 trans.processTransformation(); 299 } 300 301 if (events != null) 302 events.debug(Messages.getString("ApplicationLauncher.creatingReplacements")); 304 for (Enumeration ep = replacements.elements(); ep.hasMoreElements();) { 305 FileReplacement replacement = (FileReplacement) ep.nextElement(); 306 replacement.createReplacementsFile(this); 307 } 308 309 if (events != null) 310 events.debug(Messages.getString("ApplicationLauncher.replacementsCreatedPreparationComplete")); } 312 313 318 public String getSmallIcon() { 319 return smallIcon; 320 } 321 322 327 public String getLargeIcon() { 328 return largeIcon; 329 } 330 331 338 protected abstract InputStream getApplicationDescriptor() throws IOException ; 339 340 protected boolean processLauncherElement(XMLElement e) { 341 return false; 342 } 343 344 349 public String getName() { 350 return name; 351 } 352 353 358 public File getInstallDir() { 359 return installDir; 360 } 361 362 365 public void start() throws IOException { 366 download(); 367 type.start(); 368 } 369 370 377 public void addParameter(String parameter, String value) { 378 379 if (events != null) { 380 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.addingParameter"), new Object [] { parameter, value })); } 382 383 descriptorParams.put(parameter, value); 384 } 385 386 392 public void processFiles(XMLElement element) throws IOException { 393 processFiles(element, null); 394 } 395 396 403 public void processFiles(XMLElement element, String app) throws IOException { 404 405 Enumeration en = element.enumerateChildren(); 406 XMLElement e; 407 408 while (en.hasMoreElements()) { 409 e = (XMLElement) en.nextElement(); 410 if (e.getName().equalsIgnoreCase("file")) { if(checkCondition(type, e, parameters)) { 412 addFile(e, app); 413 } 414 } else if (e.getName().equalsIgnoreCase("if")) { if (checkCondition(type, e, parameters)) { 416 processFiles(e, app); 417 } 418 419 } else 420 throw new IOException (MessageFormat.format(Messages.getString("ApplicationLauncher.invalidElementInFiles"), new Object [] { e.getName() })); } 422 423 } 424 425 436 public static boolean checkCondition(ApplicationType type, XMLElement el, Hashtable params) throws IOException , IllegalArgumentException { 437 String jre = (String ) el.getAttribute("jre"); String os = (String ) el.getAttribute("os"); String osVersion = (String ) el.getAttribute("osversion"); String arch = (String ) el.getAttribute("arch"); String parameter = (String ) el.getAttribute("parameter"); String string = (String ) el.getAttribute("string"); if(jre != null) { 444 if(!Utils.isSupportedJRE(jre)) { 445 return false; 446 } 447 } 448 if(os != null) { 449 if(!Utils.isSupportedPlatform(os)) { 450 return false; 451 } 452 } 453 if(osVersion != null) { 454 if(!Utils.isSupportedOSVersion(osVersion)) { 455 return false; 456 } 457 } 458 if(arch != null) { 459 if(!Utils.isSupportedArch(arch)) { 460 return false; 461 } 462 } 463 if (parameter != null) { 464 if(params == null) { 465 throw new IOException (Messages.getString("ApplicationLauncher.noParametersToTestAgainst")); } 467 String requiredValue = (String ) el.getAttribute("value"); boolean not = "true".equalsIgnoreCase(((String ) el.getAttribute("not"))); 470 String paramValue = (String ) params.get(parameter); 472 473 if ((!not && !requiredValue.equalsIgnoreCase(paramValue)) || (not && requiredValue.equalsIgnoreCase(paramValue))) { 474 return false; 475 } 476 } 477 if(string != null) { 478 String requiredValue = (String ) el.getAttribute("value"); boolean not = "true".equalsIgnoreCase(((String ) el.getAttribute("not"))); 481 if ((!not && !requiredValue.equalsIgnoreCase(string)) || (not && requiredValue.equalsIgnoreCase(string))) { 482 return false; 483 } 484 } 485 return true; 486 } 487 488 494 public Hashtable getDescriptorParams() { 495 return descriptorParams; 496 } 497 498 505 public File addShared(XMLElement e) throws IOException { 506 return addShared(e, null); 507 } 508 509 517 public File addShared(XMLElement e, String app) throws IOException { 518 return addFile(e, app, true); 519 520 } 521 522 530 public File addFile(XMLElement e, String app) throws IOException { 531 return addFile(e, app, false); 532 } 533 534 543 File addFile(XMLElement e, String app, boolean shared) throws IOException { 544 545 boolean executable = "true".equals(e.getStringAttribute("exec", "false")); 546 boolean readOnly = "true".equals(e.getStringAttribute("readOnly", "false")); 547 String targetDirName = e.getStringAttribute("targetDir"); 548 549 550 554 String name = e.getStringAttribute("name", ""); 555 if(name.equals("")) { 556 name = Utils.trimmedBothOrBlank(e.getContent()); 557 } 558 name = name.replace('/', File.separatorChar); 559 560 File targetDir = installDir; 562 File entry = new File (installDir, name); 563 if(!Utils.isNullOrTrimmedBlank(targetDirName)) { 564 if(shared) { 565 throw new IOException ("Cannot specify target directory for shared files."); 566 } 567 targetDir = new File (installDir, targetDirName); 568 String filename = name; 569 int idx = name.lastIndexOf(File.separatorChar); 570 if(idx != -1) { 571 filename = filename.substring(idx + 1); 572 } 573 entry = new File (targetDir, filename); 574 if (events != null) { 575 events.debug("Alternative target directory of " + targetDirName + " (" + targetDir.getAbsolutePath() + ") provided. Target is " + entry.getAbsolutePath()); 576 } 577 } 578 579 DownloadableFile df = new DownloadableFile(name, app, executable, readOnly, entry, 0); 580 long size = 0; 581 try { 582 size = Long.parseLong((String ) e.getAttribute("size")); } 584 catch(NumberFormatException nfe) { 585 throw new IOException (MessageFormat.format(Messages.getString("ApplicationLauncher.invalidSize"), new Object [] { name })); 587 } 588 589 if (events != null) { 590 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.addingFile"), new Object [] { entry.getAbsolutePath(), new Long (size) } ) ); } 592 593 if (e.getAttribute("checksum") == null || e.getAttribute("size") == null) { throw new IOException (MessageFormat.format(Messages.getString("ApplicationLauncher.expectedChecksumAndSize"), new Object [] { name })); } 596 df.setChecksum(Long.parseLong((String ) e.getAttribute("checksum"))); 597 if (entry.exists()) { 598 599 602 long currentChecksum = generateChecksum(entry); 603 604 if (events != null) { 605 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.fileExistsCurrentChecksum"), new Object [] { new Long (currentChecksum), new Long (df.getChecksum()) })); } 607 608 if (currentChecksum != df.getChecksum() || entry.length() != size) { 609 if (events != null) { 610 events.debug(Messages.getString("ApplicationLauncher.checksumMismatchDownloading")); } 612 613 if(shared) 614 sharedFilesToDowload.put(name, df); 615 else 616 filesToDownload.addElement(df); 617 618 totalBytesToDownload += entry.length(); 619 } 620 } else { 621 if (events != null) { 622 events.debug(Messages.getString("ApplicationLauncher.fileDoesntExistDownloading")); } 624 625 if(shared) 627 sharedFilesToDowload.put(name, df); 628 else 629 filesToDownload.addElement(df); 630 totalBytesToDownload += size; 631 } 632 633 Enumeration ae = e.enumerateChildren(); 635 while (ae.hasMoreElements()) { 636 XMLElement el = (XMLElement) ae.nextElement(); 637 if(el.getName().equals("alias")) { 638 df.addAlias(Utils.trimmedBothOrBlank(el.getContent())); 639 } 640 } 641 642 return entry; 643 } 644 645 660 public long downloadFile(File basedir, String app, String filename, File target, long bytesSoFar, boolean executable, boolean readOnly, Vector aliases, long checksum) throws IOException { 661 662 666 if (events != null) 667 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.downloading"), new Object [] { filename, target.getAbsolutePath() })); 669 File f = new File (target.getParent()); 670 f.mkdirs(); 671 672 if (events != null) 673 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.creating"), new Object [] { target.getAbsolutePath() })); 675 target.delete(); 676 FileOutputStream out = new FileOutputStream (target); 677 InputStream in = getDownloadFile(app, ticket, filename); 678 byte[] buf = new byte[16384]; 679 int read; 680 while ((read = in.read(buf)) > -1) { 681 out.write(buf, 0, read); 682 bytesSoFar += read; 683 684 if (events != null) 685 events.progressedDownload(bytesSoFar); 686 } 687 if (events != null) 688 events.debug(Messages.getString("ApplicationLauncher.finishingDownloadFile")); 690 in.close(); 691 out.close(); 692 693 if(executable) { 694 try { 695 if (events != null) 696 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.makingExecutable"), new Object [] { target.getPath() } ) ); Utils.makeExecutable(target); 698 } 699 catch(IOException ioe) { 700 if (events != null) 701 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.failedToMakeExecutable"), new Object [] { target.getPath(), ioe.getMessage() } ) ); } 703 } 704 705 long newChecksum = generateChecksum(target); 706 if(newChecksum != checksum) { 707 events.debug("WARNING. File " + target.getPath() + " does not match expected checksum. Checksum is " + newChecksum + ", should be " + checksum); 708 } 709 710 if(readOnly) { 711 try { 712 if (events != null) 713 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.makingReadOnly"), new Object [] { target.getPath() } ) ); Utils.makeReadOnly(target); 715 } 716 catch(IOException ioe) { 717 if (events != null) 718 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.failedToMakeReadOnly"), new Object [] { target.getPath(), ioe.getMessage() } ) ); } 720 } 721 722 if(aliases != null && aliases.size() >0) { 723 for(Enumeration e = aliases.elements(); e.hasMoreElements(); ) { 724 String alias = (String )e.nextElement(); 725 File aliasTarget = new File (basedir, alias); 727 if(events != null) { 728 events.debug("Copying " + target.getPath() + " to " + aliasTarget.getPath()); 729 } 730 Utils.copyFile(target, aliasTarget); 731 } 732 } 733 734 return bytesSoFar; 735 736 } 737 738 744 public String getApplicationStoreHost() { 745 return applicationStoreHost; 746 } 747 748 754 public int getApplicationStorePort() { 755 return applicationStorePort; 756 } 757 758 764 public String getApplicationStoreProtocol() { 765 return applicationStoreProtocol; 766 } 767 768 770 786 public String replaceTokens(String str) { 787 str = replaceAllTokens(str, "${client:installDir}", installDir.getAbsolutePath()); str = replaceAllTokens(str, "${sslexplorer:user}", applicationStoreUser == null ? "" : applicationStoreUser); str = replaceAllTokens(str, "${sslexplorer:host}", applicationStoreHost == null ? "" : applicationStoreHost); str = replaceAllTokens(str, "${sslexplorer:port}", applicationStorePort == -1 ? "" : String.valueOf(applicationStorePort)); str = replaceAllTokens(str, "${sslexplorer:protocol}", applicationStoreProtocol == null ? "" : applicationStoreProtocol); str = replaceAllTokens(str, "${client:localProxyURL}", localProxyURL == null ? "" : localProxyURL); for (Enumeration e = descriptorParams.keys(); e.hasMoreElements();) { 794 String key = (String ) e.nextElement(); 795 String val = (String ) descriptorParams.get(key); 796 str = replaceAllTokens(str, "${param:" + key + "}", val); } 798 return str; 799 } 800 801 public InputStream getDownloadFile(String name, String ticket, String filename) throws IOException { 802 URL file = new URL (applicationStoreProtocol, applicationStoreHost, applicationStorePort, "/getApplicationFile.do" + "?name=" + name + "&ticket=" + ticket + "&file=" + filename); if (events != null) 805 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.requestApplicationUsing"), new Object [] { file.toExternalForm() })); 807 URLConnection con = file.openConnection(); 808 con.setUseCaches(false); 809 810 try { 811 Method m = con.getClass().getMethod("setConnectTimeout", new Class [] { int.class }); if (events != null) { 813 events.debug(Messages.getString("ApplicationLauncher.runtime5")); } 815 m.invoke(con, new Object [] { new Integer (20000) }); 816 m = con.getClass().getMethod("setReadTimeout", new Class [] { int.class }); m.invoke(con, new Object [] { new Integer (20000) }); 818 } catch (Throwable t) { 819 } 820 821 return con.getInputStream(); 822 } 823 824 832 public static String replaceAllTokens(String source, String token, String value) { 833 if(token.equals(value)) { 835 return source; 836 } 837 838 int idx; 839 840 do { 841 idx = source.indexOf(token); 842 843 if (idx > -1) { 844 source = source.substring(0, idx) + value 845 + ((source.length() - idx <= token.length()) ? "" : source.substring(idx + token.length())); } 847 848 } while (idx > -1); 849 850 return source; 851 } 852 853 854 private void addParameter(XMLElement e) throws IOException { 855 String parameter = (String ) e.getAttribute("name"); String value = (String ) e.getAttribute("value"); if (events != null) { 858 events.debug(MessageFormat.format(Messages.getString("ApplicationLauncher.addingParameter"), new Object [] { parameter, value })); } 860 861 descriptorParams.put(parameter, value); 862 } 863 864 protected void createTunnel(XMLElement e) throws IOException { 865 throw new IOException (Messages.getString("ApplicationLauncher.tunnelRequiredButNoEventHandler")); } 867 868 private long generateChecksum(File f) throws IOException { 869 870 Adler32 alder = new Adler32 (); 871 CheckedInputStream in = new CheckedInputStream (new FileInputStream (f), alder); 872 try { 873 byte[] buf = new byte[4096]; 874 int read = 0; 875 while ((read = in.read(buf)) > -1) 876 ; 877 878 alder = (Adler32 ) in.getChecksum(); 879 880 return alder.getValue(); 881 } finally { 882 in.close(); 883 } 884 } 885 886 private void downloadFiles() throws IOException { 887 888 if (events != null) 889 events.debug(Messages.getString("ApplicationLauncher.downloadingFiles")); 891 if (events != null) 892 events.startDownload(totalBytesToDownload); 893 894 long bytesSoFar = 0; 895 896 DownloadableFile df; 897 for (int i = 0; i < filesToDownload.size(); i++) { 898 df = (DownloadableFile) filesToDownload.elementAt(i); 899 bytesSoFar = downloadFile(installDir, 900 (df.getApplicationName() == null ? name : df.getApplicationName()), 901 df.getName(), 902 df.getTarget(), 903 bytesSoFar, 904 df.isExecutable(), 905 df.isReadOnly(), 906 df.getAliases(), 907 df.getChecksum()); 908 } 909 910 for (Enumeration e = sharedFilesToDowload.keys(); e.hasMoreElements();) { 911 String name = (String ) e.nextElement(); 912 df = (DownloadableFile) sharedFilesToDowload.get(name); 913 bytesSoFar = downloadFile(sharedDir, 914 (df.getApplicationName() == null ? name : df.getApplicationName()), 915 df.getName(), 916 df.getTarget(), 917 bytesSoFar, 918 df.isExecutable(), 919 df.isReadOnly(), 920 df.getAliases(), 921 df.getChecksum()); 922 } 923 924 if (events != null) 925 events.completedDownload(); 926 927 if (events != null) 928 events.debug(Messages.getString("ApplicationLauncher.completedDownloadingFiles")); } 930 931 public Vector getTunnels() { 932 return EMPTY_VECTOR; 933 } 934 935 public void processErrorMessage(String text) { 936 events.error(text); 937 } 938 } | Popular Tags |