package distMaker.jre; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; import distMaker.DistUtils; import distMaker.digest.Digest; import distMaker.digest.DigestType; import distMaker.digest.DigestUtils; import distMaker.platform.PlatformUtils; import distMaker.utils.ParseUtils; import distMaker.utils.PlainVersion; import distMaker.utils.Version; import distMaker.utils.VersionUtils; import glum.gui.GuiUtil; import glum.io.IoUtil; import glum.net.Credential; import glum.net.NetUtil; import glum.task.PartialTask; import glum.task.Task; import glum.util.ThreadUtil; public class AppLauncherUtils { /** * Returns a list of all the available AppLauncher releases specified at:
* {@literal /launcher/appCatalog.txt} */ public static List getAvailableAppLauncherReleases(Task aTask, URL aUpdateSiteUrl, Credential aCredential) { List retList; URL catUrl; URLConnection connection; InputStream inStream; BufferedReader bufReader; DigestType digestType; String errMsg, strLine; errMsg = null; retList = new ArrayList<>(); catUrl = IoUtil.createURL(aUpdateSiteUrl.toString() + "/launcher/appCatalog.txt"); // Default to DigestType of MD5 digestType = DigestType.MD5; inStream = null; bufReader = null; try { // Read the contents of the file connection = catUrl.openConnection(); inStream = NetUtil.getInputStream(connection, aCredential); bufReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(inStream))); // Read the lines while (true) { strLine = bufReader.readLine(); // Bail once we are done if (strLine == null) break; // Ignore comments and empty lines if (strLine.isEmpty() == true || strLine.startsWith("#") == true) continue; String[] tokens; tokens = strLine.split(",", 5); if (tokens.length == 2 && tokens[0].equals("name") == true && tokens[1].equals("AppLauncher") == true) ; // Nothing to do - we just entered the "JRE" section // Logic to handle the 'exit' command else if (tokens.length >= 1 && tokens[0].equals("exit") == true) { // We support exit commands with 3 tokens. All others // we will just exit. if (tokens.length != 3) break; String targName = tokens[1]; String needVer = tokens[2]; if (ParseUtils.shouldExitLogic(targName, needVer) == true) break; } // Logic to handle the 'digest' command else if (tokens.length == 2 && tokens[0].equals("digest") == true) { DigestType tmpDigestType; tmpDigestType = DigestType.parse(tokens[1]); if (tmpDigestType == null) aTask.infoAppendln("Failed to locate DigestType for: " + tokens[1]); else digestType = tmpDigestType; } // Logic to handle the 'F' command: AppLauncher File else if (tokens.length == 5 && tokens[0].equals("F") == true) { String filename, digestStr, version; long fileLen; // Form the JreRelease digestStr = tokens[1]; fileLen = GuiUtil.readLong(tokens[2], -1); filename = tokens[3]; version = tokens[4]; Digest tmpDigest = new Digest(digestType, digestStr); retList.add(new AppLauncherRelease(version, filename, tmpDigest, fileLen)); } else { aTask.infoAppendln("Unreconized line: " + strLine); } } } catch(FileNotFoundException aExp) { errMsg = "Failed to locate resource: " + catUrl; } catch(IOException aExp) { errMsg = ThreadUtil.getStackTrace(aExp); } finally { IoUtil.forceClose(inStream); IoUtil.forceClose(bufReader); } // See if we are in a valid state if (errMsg != null) ; // Nothing to do, as an earlier error has occurred else if (retList.size() == 0) errMsg = "The catalog appears to be invalid."; // Bail if there were issues if (errMsg != null) { aTask.infoAppendln(errMsg); return null; } return retList; } /** * Utility method that checks to see if the AppLauncher will need be updated in order to support the specified JRE. *

* Returns false if the AppLauncher does NOT need be updated. Otherwise true will be returned and the version info * will be logged to the specified aTask. */ public static boolean isAppLauncherUpdateNeeded(Task aTask, JreRelease aJreRelease) { Version currVer, nMinVer, nMaxVer; // Bail if the installed version of AppLauncher is equal to or later than the required version currVer = DistUtils.getAppLauncherVersion(); nMinVer = aJreRelease.getAppLauncherMinVersion(); nMaxVer = aJreRelease.getAppLauncherMaxVersion(); if (VersionUtils.isInRange(currVer, nMinVer, nMaxVer) == true) return false; // Log the fact that we need to update our AppLauncher aTask.infoAppendln("Your current AppLauncher is not compatible with this release. It will need to be upgraded!"); aTask.infoAppendln("\tCurrent ver: " + currVer); if (nMinVer != PlainVersion.AbsMin) aTask.infoAppendln("\tMinimum ver: " + nMinVer); if (nMaxVer != PlainVersion.AbsMax) aTask.infoAppendln("\tMaximum ver: " + nMaxVer); aTask.infoAppendln(""); return true; } /** * Utility method that will return the AppLauncherRelease that satisfies the requirements as specified by the * JreRelease. *

* Returns null if no AppLauncherRelease is located that can satisfy the specified JreRelease. *

* Any issues that cropped up while searching for a valid AppLauncherRelease will be logged to the specified task, * aTask. *

* TODO: Remove the comments below *

* corresponding to the AppLauncher that we to the specified version required by this JRE. *

* Returns false on any failure. */ public static AppLauncherRelease updateAppLauncher(Task aTask, JreRelease aJreRelease, File aDestPath, URL updateSiteUrl, Credential aCredential) { // Locate the list of available AppLaunchers List availList; availList = AppLauncherUtils.getAvailableAppLauncherReleases(aTask, updateSiteUrl, aCredential); if (availList == null) { aTask.infoAppendln("The update site does not have any deployed AppLaunchers."); aTask.infoAppendln("Please contact the update site adminstartor."); return null; } if (availList.size() == 0) { aTask.infoAppendln("No AppLauncher releases found!"); aTask.infoAppendln("Please contact the update site adminstartor."); return null; } // Retrieve the AppLauncher that is compatible from the list Version nMinVer = aJreRelease.getAppLauncherMinVersion(); Version nMaxVer = aJreRelease.getAppLauncherMaxVersion(); AppLauncherRelease pickRelease = null; for (AppLauncherRelease aRelease : availList) { Version evalVer = aRelease.getVersion(); if (VersionUtils.isInRange(evalVer, nMinVer, nMaxVer) == false) continue; pickRelease = aRelease; break; } // Bail if no compatible release could be found if (pickRelease == null) { aTask.infoAppendln("No compatible AppLauncher releases have been deployed!"); aTask.infoAppendln("Please contact the update site adminstartor."); return null; } // Get stats on the release Version pickVer = pickRelease.getVersion(); long fileLen = pickRelease.getFileLen(); // Define the path to the launcher File launcherPath; if (PlatformUtils.getPlatform().equals("Apple") == true) launcherPath = new File(aDestPath.getParentFile(), "Java"); else launcherPath = new File(aDestPath.getParentFile(), "launcher"); // Download the AppLauncher Digest targDigest, testDigest; MessageDigest msgDigest; targDigest = pickRelease.getDigest(); msgDigest = DigestUtils.getDigest(targDigest.getType()); aTask.infoAppendln("Downloading AppLauncher... Version: " + pickVer); URL srcUrl = IoUtil.createURL(updateSiteUrl.toString() + "/launcher/appLauncher-" + pickVer + ".jar"); File dstFile = new File(launcherPath, pickRelease.getFileName()); int zios_2018Feb15; // TODO: Consider refactoring this code and making it cleaner... Task tmpTask = new PartialTask(aTask, aTask.getProgress(), 0.01); // Task tmpTask = new PartialTask(aTask, aTask.getProgress(), (tmpFileLen * 0.75) / (releaseSizeFull + 0.00)); // Task tmpTask = new SilentTask(); if (DistUtils.downloadFile(tmpTask, srcUrl, dstFile, aCredential, fileLen, msgDigest) == false) { aTask.infoAppendln("Failed to download updated AppLauncher."); aTask.infoAppendln("\tSource: " + srcUrl); aTask.infoAppendln("\tFile: " + dstFile + "\n"); return null; } // Validate that the AppLauncher was downloaded successfully testDigest = new Digest(targDigest.getType(), msgDigest.digest()); if (targDigest.equals(testDigest) == false) { aTask.infoAppendln("The download of the AppLauncher appears to be corrupted."); aTask.infoAppendln("\tFile: " + dstFile); aTask.infoAppendln("\t\tExpected " + targDigest.getDescr()); aTask.infoAppendln("\t\tReceived " + testDigest.getDescr() + "\n"); return null; } // Update the appLauncher.jar file File targFile = new File(launcherPath, "appLauncher.jar"); boolean isPass; // Back up the "original" targFile (only if a backup has not already already been made). In case // there are multiple updates we do not want to overwrite the "real" original boolean isOriginalBackedUp = false; File origFile = new File(launcherPath, "appLauncher.jar.orig"); if (origFile.exists() == false) { isPass = targFile.renameTo(origFile); if (isPass == false) { aTask.infoAppendln("Failed to rename: " + targFile + " to " + origFile); } else { isOriginalBackedUp = true; aTask.infoAppendln("Original file has been backed up."); aTask.infoAppendln("\t" + targFile + " ---> " + origFile); } } // Update the targFile with the newly downloaded file isPass = dstFile.renameTo(targFile); // targFile.renameTo(origFile); if (isPass == false) { aTask.infoAppendln("Failed to rename: " + dstFile + " to " + targFile); aTask.infoAppendln("Update is being aborted"); // We need to revert to the original backup if (isOriginalBackedUp == true) { isPass = origFile.renameTo(targFile); if (isPass == false) { aTask.infoAppendln("Failed to revert to the orginal AppLauncher."); aTask.infoAppendln("\t" + targFile); aTask.infoAppendln("Update has FAILED and left application in an invalid state.\n"); } } return null; } else { aTask.infoAppendln("Success updating AppLauncher... "); aTask.infoAppendln("\t" + dstFile + " ---> " + targFile + "\n"); } return pickRelease; } }