/*
* Copyright (c) 2012-2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.upgrade;
import java.io.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.services.util.AlertsLogger;
public class UpgradeImageDownloader {
private static final Logger _log = LoggerFactory.getLogger(UpgradeImageDownloader.class);
private static UpgradeManager _upgradeManager = null;
private static UpgradeImageDownloader _instance = null;
public static UpgradeImageDownloader getInstance(final UpgradeManager upgradeManager) {
synchronized (UpgradeImageDownloader.class) {
if (_instance == null) {
_instance = new UpgradeImageDownloader();
_upgradeManager = upgradeManager;
}
}
return _instance;
}
public void startBackgroundDownload(final String prefix, final File file, final InputStream in, final String url, String version) {
_log.info(prefix + "");
if (gcDownloads() > 0) {
_log.error(prefix + "There is a download in progress.");
tryClose(in);
return;
}
Future<DownloadTask> future = (Future<DownloadTask>) _executor.submit(new DownloadTask(prefix, file, in, url, version));
if (future == null) {
_log.error(prefix + "Failed!");
tryClose(in);
return;
}
_downloads.put(file.getPath(), future);
_log.info(prefix + "Download started.");
}
public void shutdownNow() {
for (String downloadPath : _downloads.keySet()) {
final Future<DownloadTask> f = _downloads.get(downloadPath);
if (!f.isDone()) {
f.cancel(true);
}
}
_executor.shutdownNow();
gcDownloads();
}
public boolean isDownloading() {
return gcDownloads() != 0;
}
private int gcDownloads() {
_log.info("gcDownloads():");
List<String> done = new ArrayList<String>();
for (String downloadPath : _downloads.keySet()) {
if (_downloads.get(downloadPath).isDone()) {
final File tmp = getTmpFile(new File(downloadPath));
if (tmp.exists()) {
tmp.delete();
if (tmp.exists()) {
_log.error("gcDownloads(): Failed to remove {}", tmp);
}
}
done.add(downloadPath);
}
}
for (String downloadPath : done) {
_downloads.remove(downloadPath);
}
final int inProgress = _downloads.size();
_log.info("gcDownloads(): {} downloads in progress", inProgress);
return inProgress;
}
private static File getTmpFile(File file) {
return new File(file + ".downloading");
}
private static void tryClose(final InputStream in) {
try {
if (in != null) {
in.close();
}
} catch (Exception e) {
;
}
}
private static void tryClose(final OutputStream out) {
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
;
}
}
public class DownloadTask implements Runnable {
private final String _prefix;
private final InputStream _in;
private final File _file;
private final String _url;
private final String _version;
public DownloadTask(final String prefix, final File file, final InputStream in, final String url, String version) {
_prefix = prefix;
_in = in;
_file = file;
_url = url;
_version = version;
}
@Override
public void run() {
_log.info(_prefix + "Background download.");
download();
if (_upgradeManager != null) {
_upgradeManager.wakeup();
}
}
private void download() {
if (_file.exists()) {
_file.delete();
if (_file.exists()) {
_log.error(_prefix + "Download failed. Can't remove " + _file);
return;
}
}
final File tmp = getTmpFile(_file);
if (tmp.exists()) {
tmp.delete();
if (tmp.exists()) {
_log.error(_prefix + "Download failed. Can't remove " + tmp);
return;
}
}
final File dir = tmp.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
if (!dir.exists()) {
_log.error(_prefix + "Download failed. Can't create directory " + dir);
return;
}
}
long start = System.currentTimeMillis();
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(tmp));
UpgradeImageCommon upgradeImage = new UpgradeImageCommon(_in, out, _log, _prefix, _upgradeManager, _version);
if (!upgradeImage.start()) {
AlertsLogger.getAlertsLogger().error(
MessageFormat.format("Unexpected error downloading image from url \"{0}\". See syssvc logs for details", _url));
return;
}
if (!tmp.renameTo(_file)) {
_log.error(_prefix + "Download failed. Can't rename to: " + tmp);
return;
} else if (!_file.exists()) {
_log.error(_prefix + "Download failed. No such file: " + _file);
return;
}
long end = System.currentTimeMillis();
_log.info(_prefix + "Download successful. Time cost: " + (end - start) / 1000 + " seconds.");
} catch (Exception e) {
_log.error(_prefix + "Download failed. " + e);
} finally {
tryClose(_in);
tryClose(out);
tmp.delete();
}
}
}
private UpgradeImageDownloader() {
}
private final Map<String, Future<DownloadTask>> _downloads = new ConcurrentHashMap<String, Future<DownloadTask>>();
private final ExecutorService _executor = Executors.newFixedThreadPool(1);
}