/*
|
* 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 legal-notices/CDDLv1_0.txt
|
* or http://forgerock.org/license/CDDLv1.0.html.
|
* 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 legal-notices/CDDLv1_0.txt.
|
* 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-2014 ForgeRock AS.
|
*/
|
|
package org.opends.quicksetup.webstart;
|
import org.forgerock.i18n.LocalizableMessage;
|
|
import java.io.IOException;
|
import java.net.MalformedURLException;
|
import java.net.URL;
|
|
import org.forgerock.i18n.slf4j.LocalizedLogger;
|
|
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.*;
|
import static com.forgerock.opendj.util.OperatingSystem.isWindows;
|
import static com.forgerock.opendj.cli.Utils.getThrowableMsg;
|
|
/**
|
* 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 {
|
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
|
|
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 LocalizableMessage summary = null;
|
|
/**
|
* This enumeration contains the different Status on which
|
* the downloading 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), 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 LocalizableMessage 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(LocalizableMessage 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)
|
{
|
logger.error(LocalizableMessage.raw("Could not find service: "+
|
Utils.JNLP_SERVICE_NAME, e));
|
String setupFile;
|
if (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), 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];
|
}
|
|
}
|