/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2013 ForgeRock AS. */ package org.opends.quicksetup.webstart; import org.opends.messages.Message; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import javax.jnlp.DownloadService; import javax.jnlp.DownloadServiceListener; import javax.jnlp.ServiceManager; import javax.jnlp.UnavailableServiceException; import org.opends.quicksetup.ApplicationException; import org.opends.quicksetup.Installation; import org.opends.quicksetup.ReturnCode; import org.opends.quicksetup.util.Utils; import org.opends.server.util.SetupUtils; import static org.opends.quicksetup.util.Utils.*; import static org.opends.messages.QuickSetupMessages.*; /** * This class is used to download the files that have been marked as lazy * in the QuickSetup.jnlp file. * * The global idea is to force the user to download just one jar file * (quicksetup.jar) to display the Web Start installer dialog. Then QuickSetup * will call this class and it will download the jar files. Until this class is * not finished the WebStartInstaller will be on the * ProgressStep.DOWNLOADING step. */ public class WebStartDownloader implements DownloadServiceListener { static private final Logger LOG = Logger.getLogger(WebStartDownloader.class.getName()); private ApplicationException ex; private boolean isFinished; private int downloadPercentage = 0; private int currentPercMin = 0; private int currentPercMax = 0; private int currentValidatingPercent = 0; private int currentUpgradingPercent = 0; private Status status = Status.DOWNLOADING; private Message summary = null; /** * This enumeration contains the different Status on which * the dowloading process of the jars can be. * */ public enum Status { /** * Downloading a jar file. */ DOWNLOADING, /** * Validating a jar file. */ VALIDATING, /** * Upgrading a jar file. */ UPGRADING } /** * Creates a default instance. */ public WebStartDownloader() { this.summary = INFO_DOWNLOADING.get(); } /** * Starts the downloading of the jar files. If forceDownload is set to * <CODE>true</CODE> the files will be re-downloaded even if they already * are on cache. * * This method does not block the thread that calls it. * * @param forceDownload used to ignore the case and force download. */ public void start(final boolean forceDownload) { isFinished = false; Thread t = new Thread(new Runnable() { public void run() { try { startDownload(forceDownload); } catch (ApplicationException ex) { WebStartDownloader.this.ex = ex; } catch (MalformedURLException mfe) { // This is a bug ex = new ApplicationException(ReturnCode.BUG, getThrowableMsg(INFO_BUG_MSG.get(),mfe), mfe); } catch (IOException ioe) { StringBuilder buf = new StringBuilder(); String[] jars = getJarUrls(); for (int i = 0; i < jars.length; i++) { if (i != 0) { buf.append(","); } buf.append(jars[i]); } ex = new ApplicationException( ReturnCode.DOWNLOAD_ERROR, getThrowableMsg( INFO_DOWNLOADING_ERROR.get(buf.toString()), ioe), ioe); } catch (Throwable t) { // This is a bug ex = new ApplicationException(ReturnCode.BUG, getThrowableMsg(INFO_BUG_MSG.get(), t), t); } } }); t.start(); } /** * Gets a summary message of the downloader's current progress. * @return String for showing the user progress */ public Message getSummary() { return this.summary; } /** * Sets a summary message of the downloader's current progress. * @param summary String for showing the user progress */ public void setSummary(Message summary) { this.summary = summary; } /** * Returns <CODE>true</CODE> if the install is finished and * <CODE>false</CODE> otherwise. * @return <CODE>true</CODE> if the install is finished and * <CODE>false</CODE> otherwise. */ public boolean isFinished() { return isFinished; } /** * Returns the Status of the current download process. * @return the current status of the download process. */ public Status getStatus() { return status; } /** * Returns the current download percentage. * @return the current download percentage. */ public int getDownloadPercentage() { return downloadPercentage; } /** * Returns the completed percentage for the file being currently validated. * @return the completed percentage for the file being currently validated. */ public int getCurrentValidatingPercentage() { return currentValidatingPercent; } /** * Returns the completed percentage for the file being currently upgraded. * @return the completed percentage for the file being currently upgraded. */ public int getCurrentUpgradingPercentage() { return currentUpgradingPercent; } /** * Starts synchronously the downloading on this thread. The thread calling * this method will be blocked. If forceDownload is set to * <CODE>true</CODE> the files will be re-downloaded even if they already * are on cache. * @param forceDownload used to ignore the case and force download. * @throws MalformedURLException if there is an error with the URLs that we * get from the property SetupUtils.LAZY_JAR_URLS * @throws IOException if a network problem occurs. * @throws ApplicationException if the download service is not available. */ private void startDownload(boolean forceDownload) throws IOException, ApplicationException { DownloadService ds; try { ds = (DownloadService) ServiceManager.lookup(Utils.JNLP_SERVICE_NAME); } catch (UnavailableServiceException e) { LOG.log(Level.SEVERE, "Could not find service: "+ Utils.JNLP_SERVICE_NAME, e); String setupFile; if (Utils.isWindows()) { setupFile = Installation.WINDOWS_SETUP_FILE_NAME; } else { setupFile = Installation.UNIX_SETUP_FILE_NAME; } throw new ApplicationException( ReturnCode.DOWNLOAD_ERROR, getThrowableMsg(INFO_DOWNLOADING_ERROR_NO_SERVICE_FOUND.get( Utils.JNLP_SERVICE_NAME, setupFile), e), e); } String[] urls = getJarUrls(); String[] versions = getJarVersions(); /* * Calculate the percentages that correspond to each file. * TODO ideally this should be done dynamically, but as this is just * to provide progress, updating this information from time to time can * be enough and does not complexify the build process. */ int[] percentageMax = new int[urls.length]; int[] ratios = new int[urls.length]; int totalRatios = 0; for (int i=0; i<percentageMax.length; i++) { int ratio; if (urls[i].endsWith("OpenDS.jar")) { ratio = 23; } else if (urls[i].endsWith("je.jar")) { ratio = 11; } else if (urls[i].endsWith("zipped.jar")) { ratio = 110; } else if (urls[i].endsWith("aspectjrt.jar")) { ratio = 10; } else { ratio = (100 / urls.length); } ratios[i] = ratio; totalRatios += ratio; } for (int i=0; i<percentageMax.length; i++) { int r = 0; for (int j=0; j<=i; j++) { r += ratios[j]; } percentageMax[i] = (100 * r)/totalRatios; } for (int i = 0; i < urls.length && (getException() == null); i++) { if (i == 0) { currentPercMin = 0; } else { currentPercMin = percentageMax[i-1]; } currentPercMax = percentageMax[i]; // determine if a particular resource is cached String sUrl = urls[i]; String version = versions[i]; URL url = new URL(sUrl); boolean cached = ds.isResourceCached(url, version); if (cached && forceDownload) { try { ds.removeResource(url, version); } catch (IOException ioe) { } cached = false; } if (!cached) { // if not in the cache load the resource into the cache ds.loadResource(url, version, this); } downloadPercentage = currentPercMax; } isFinished = true; } /** * Returns the ApplicationException that has occurred during the download or * <CODE>null</CODE> if no exception occurred. * @return the ApplicationException that has occurred during the download or * <CODE>null</CODE> if no exception occurred. */ public ApplicationException getException() { return ex; } /** * {@inheritDoc} */ public void downloadFailed(URL url, String version) { ex = new ApplicationException( ReturnCode.DOWNLOAD_ERROR, INFO_DOWNLOADING_ERROR.get(url.toString()), null); } /** * {@inheritDoc} */ public void progress(URL url, String version, long readSoFar, long total, int overallPercent) { if (overallPercent >= 0) { downloadPercentage = getPercentage(overallPercent); } status = Status.DOWNLOADING; } /** * {@inheritDoc} */ public void upgradingArchive(URL url, String version, int patchPercent, int overallPercent) { currentUpgradingPercent = overallPercent; status = Status.UPGRADING; } /** * {@inheritDoc} */ public void validating(URL url, String version, long entry, long total, int overallPercent) { if (total > 0) { currentValidatingPercent = (int)((100 * entry) / total); } else { currentValidatingPercent = 0; } status = Status.VALIDATING; } /** * Returns the jar files in a String[] from the System properties. * @return the jar files from the System properties. */ private String[] getJarUrls() { String jars = System.getProperty(SetupUtils.LAZY_JAR_URLS); return jars.split(" "); } /** * Returns the downloaded percentage based on how much of the current jar file * has been downloaded. * @param currentJarRatio the download ratio of the jar file that is being * currently downloaded. * @return the downloaded percentage based on how much of the current jar file * has been downloaded. */ private int getPercentage(int currentJarRatio) { return currentPercMin + (currentJarRatio * (currentPercMax - currentPercMin) / 100); } /** * Returns the java jar versions in a String[]. Currently just returns some * null strings. * @return the java jar versions in a String[]. */ private String[] getJarVersions() { return new String[getJarUrls().length]; } }