package org.korsakow.services.updater;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.dsrg.soenea.service.Registry;
import org.korsakow.ide.Application;
import org.korsakow.ide.Build;
import org.korsakow.ide.XPathHelper;
import org.korsakow.ide.lang.LanguageBundle;
import org.korsakow.ide.util.DomUtil;
import org.korsakow.ide.util.Platform;
import org.korsakow.ide.util.PreferencesManager;
import org.korsakow.ide.util.ShellExec;
import org.korsakow.ide.util.UIUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class Updater extends Thread
{
private static void setIncludeUsageStats(boolean set) {
PreferencesManager.getVersionIndependentPreferences().putBoolean("updater.include.usageData", set);
}
public static void main(String[] args) {
setIncludeUsageStats(true);
}
public static void checkAsynch()
{
Updater updater = new Updater();
updater.start();
}
private double availableRelease;
private String availableVersion = "";
private String message = "";
public Updater()
{
super(Updater.class.getCanonicalName());
super.setPriority(Thread.MIN_PRIORITY); // don't be an annoying background hog
}
public void startAsynchronousCheck()
{
start();
}
public void synchronousCheck() throws XPathExpressionException, IOException, SAXException, ParserConfigurationException
{
checkUpdate();
run();
}
private void checkUpdate() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException
{
String url;
try {
url = Registry.getProperty("updater.url");
} catch (Exception e) {
throw new IOException(e.getMessage()); // i hate leaking "exception"
}
HttpClient client = new HttpClient();
Map<String, Object> params = new HashMap<String, Object>();
params.put("version", Build.getVersion());
params.put("release", ""+Build.getRelease());
if (PreferencesManager.getVersionIndependentPreferences().getBoolean("updater.include.usageData", true)) {
params.put("uuid", Application.getUUID());
params.put("platform.arch", Platform.getArch().getCanonicalName());
params.put("platform.os", Platform.getOS().getCanonicalName());
params.put("platform.os.version", Platform.getOS().getVersion());
params.put("locale.country", LanguageBundle.getCurrentLocale().getCountry());
params.put("locale.language", LanguageBundle.getCurrentLocale().getLanguage());
}
List<NameValuePair> nvp = new ArrayList<NameValuePair>();
for (String key : params.keySet())
nvp.add(new NameValuePair(key, ""+params.get(key)));
GetMethod request = new GetMethod(url);
request.setQueryString(nvp.toArray(new NameValuePair[nvp.size()]));
LogFactory.getLog(getClass()).info(String.format("Checking for updates: %s", request.getURI()));
client.executeMethod(request);
String response = request.getResponseBodyAsString();
Document doc = DomUtil.parseXMLString(response);
availableRelease = XPathHelper.xpathAsDouble(doc, "/korsakow/release");
availableVersion = XPathHelper.xpathAsString(doc, "/korsakow/version");
message = XPathHelper.xpathAsString(doc, "/korsakow/message");
}
@Override
public void run()
{
try {
checkUpdate();
} catch (IOException e) {
// we don't notify on IO errors because a common case is when you're using the software without a connection or the site is
// down or something, don't bug the user about it.
// other errors like in the format of the XML are exception circumstance.
Logger.getLogger(Updater.class).error(e);
} catch (Exception e) {
UIUtil.runUITaskNow(new ErrorAction(LanguageBundle.getString("updater.error.title"), e));
}
if (availableRelease > Build.getRelease()) {
UIUtil.runUITaskNow(new AlertAction(LanguageBundle.getString("updater.newversion.title"), LanguageBundle.getString("updater.newversion.message", availableVersion, message)));
}
}
private static class AlertAction implements Runnable
{
private final String title;
private final String message;
public AlertAction(String title, String message)
{
this.title = title;
this.message = message;
}
public void run()
{
if (Application.getInstance().showOKCancelDialog(title, message)) {
try {
ShellExec.openUrl(Registry.getProperty("downloadpage"));
} catch (Exception e) {
Application.getInstance().showUnhandledErrorDialog(LanguageBundle.getString("general.errors.uncaughtexception.title"), e);
}
}
}
}
private static class ErrorAction implements Runnable
{
private final String title;
private final Throwable details;
public ErrorAction(String title, Throwable details)
{
this.title = title;
this.details = details;
}
public void run()
{
Application.getInstance().showUnhandledErrorDialog(title, details);
}
}
}