/**
* *****************************************************************************
*
* Copyright (c) 2012 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Winston Prakash
*
*****************************************************************************
*/
package org.eclipse.hudson.plugins;
import hudson.ProxyConfiguration;
import hudson.Util;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.CountingInputStream;
import org.eclipse.hudson.plugins.UpdateSiteManager.AvailablePluginInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Background Job to install or update a Job
*
* @author Winston Prakash
*/
public final class PluginInstallationJob implements Runnable {
private Logger logger = LoggerFactory.getLogger(PluginInstallationJob.class);
private final AvailablePluginInfo plugin;
private File pluginsDir;
private boolean success;
private String errorMsg;
private ProxyConfiguration proxyConfig;
public PluginInstallationJob(AvailablePluginInfo plugin, File dir, ProxyConfiguration proxyConfig) {
this.plugin = plugin;
pluginsDir = dir;
this.proxyConfig = proxyConfig;
}
public String getName() {
return plugin.getDisplayName();
}
@Override
public void run() {
URL src;
try {
logger.info("Installing the plugin " + getName());
src = getDownloadURL();
File dst = getDestination();
File tmp = download(src);
replace(dst, tmp);
logger.info(getName() + " installation successful");
} catch (Exception exc) {
logger.error(getName() + " installation unsuccessful", exc);
success = false;
errorMsg = getStackTrace(exc);
return;
} catch (Error err) {
logger.error(getName() + " installation unsuccessful", err);
success = false;
errorMsg = getStackTrace(err);
return;
}
success = true;
}
@Override
public String toString() {
return super.toString() + "[plugin=" + plugin.getDisplayName() + "]";
}
public boolean getStatus() {
return success;
}
public String getErrorMsg() {
return errorMsg;
}
public static String getStackTrace(Throwable throwable) {
Writer result = new StringWriter();
PrintWriter printWriter = new PrintWriter(result);
throwable.printStackTrace(printWriter);
return result.toString();
}
private File download(URL src) throws IOException {
URLConnection con;
if ((proxyConfig != null) && (proxyConfig.name != null)) {
con = proxyConfig.openUrl(src);
} else {
con = src.openConnection();
}
int total = con.getContentLength();
CountingInputStream in = new CountingInputStream(con.getInputStream());
byte[] buf = new byte[8192];
int len;
File dst = getDestination();
File tmp = new File(dst.getPath() + ".tmp");
OutputStream out = new FileOutputStream(tmp);
try {
while ((len = in.read(buf)) >= 0) {
out.write(buf, 0, len);
//job.status = job.new Installing(total == -1 ? -1 : in.getCount() * 100 / total);
}
} catch (IOException e) {
throw new IOException("Failed to load " + src + " to " + tmp, e);
} finally {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(in);
}
if (total != -1 && total != tmp.length()) {
throw new IOException("Inconsistent file length: expected " + total + " but only got " + tmp.length());
}
return tmp;
}
/**
* Called when the download is completed to overwrite the old file with the
* new file.
*/
private void replace(File dst, File src) throws IOException {
File bak = Util.changeExtension(dst, ".bak");
bak.delete();
dst.renameTo(bak);
dst.delete(); // any failure up to here is no big deal
if (!src.renameTo(dst)) {
throw new IOException("Failed to rename " + src + " to " + dst);
}
}
private URL getDownloadURL() throws MalformedURLException {
return new URL(plugin.getDownloadUrl());
}
private File getDestination() {
return new File(pluginsDir, plugin.getName() + ".hpi");
}
}