phex.update.UpdateCheckRunner.java Source code

Java tutorial

Introduction

Here is the source code for phex.update.UpdateCheckRunner.java

Source

/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2007 Phex Development Group
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 *  --- CVS Information ---
 *  $Id: UpdateCheckRunner.java 4365 2009-01-16 11:21:31Z gregork $
 */
package phex.update;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;

import org.apache.commons.lang.SystemUtils;
import org.apache.commons.lang.time.DateUtils;

import phex.common.Environment;
import phex.common.LongObj;
import phex.common.log.NLogger;
import phex.event.UpdateNotificationListener;
import phex.gui.common.GUIRegistry;
import phex.prefs.core.PhexCorePrefs;
import phex.prefs.core.StatisticPrefs;
import phex.prefs.core.UpdatePrefs;
import phex.servent.Servent;
import phex.share.SharedFilesService;
import phex.statistic.StatisticProvider;
import phex.statistic.StatisticProviderConstants;
import phex.statistic.StatisticsManager;
import phex.utils.IOUtil;
import phex.utils.VersionUtils;
import phex.xml.sax.DPhex;
import phex.xml.sax.DUpdateRequest;
import phex.xml.sax.DUpdateResponse;
import phex.xml.sax.XMLBuilder;
import phex.xml.sax.DUpdateResponse.VersionType;

/**
 * The UpdateCheckRunner handles regular update check against the phex website.
 * It is also used to collect Phex statistics to identify possible problem areas
 * with new versions.<br/>
 * Phex informations are transmitted in an XML structure, the update information
 * response is also returned in an XML structure.
 */
public class UpdateCheckRunner implements Runnable {
    // I2PMOD:
    // Since updates aren't signed, and to avoid leaking needless information
    // like the fact of using Phex instead of merely I2P, don't check for updates.
    // Emptying the URL here is merely a crude first part of disabling them.
    private static final String UPDATE_CHECK_URL = "http://";

    private Throwable updateCheckError;
    private UpdateNotificationListener listener;
    private String releaseVersion;
    private String betaVersion;
    private boolean isBetaInfoShown;

    public UpdateCheckRunner(UpdateNotificationListener updateListener, boolean showBetaInfo) {
        listener = updateListener;
        this.isBetaInfoShown = showBetaInfo;
    }

    /**
     * Trigger a automated background update check. This is the standard Phex
     * check done every week to display the update dialog or just collect Phex
     * statistics.
     * The call is not blocking.
     */
    public static void triggerAutoBackgroundCheck(final UpdateNotificationListener updateListener,
            final boolean showBetaInfo) {
        // I2PMOD:
        // For the I2P version, update checks are disabled for now.
        return;
        /*
        if ( UpdatePrefs.LastUpdateCheckTime.get().longValue() >
         System.currentTimeMillis() - DateUtils.MILLIS_PER_DAY * 7 )
        {
        NLogger.debug( UpdateCheckRunner.class, "No update check necessary." );
        return;
        }
        NLogger.debug( UpdateCheckRunner.class, "Triggering update check." );
        UpdateCheckRunner runner = new UpdateCheckRunner( updateListener, showBetaInfo );
        Environment.getInstance().executeOnThreadPool( runner, "UpdateCheckRunner" );
        */
    }

    public String getReleaseVersion() {
        return releaseVersion;
    }

    public String getBetaVersion() {
        return betaVersion;
    }

    /**
     * Returns a possible Throwable that could be thrown during the update check
     * or null if no error was caught.
     * @return a possible Throwable that could be thrown during the update check
     * or null if no error was caught.
     */
    public Throwable getUpdateCheckError() {
        return updateCheckError;
    }

    /**
     * @see java.lang.Runnable#run()
     */
    public void run() {
        // I2PMOD:
        // For the I2P version, update checks are disabled for now.
        return;
        /*
         try
        {            
        performUpdateCheck();
        }
        catch ( Throwable exp )
        {
        updateCheckError = exp;
        NLogger.warn( UpdateCheckRunner.class, exp, exp );
        }
        */
    }

    private void performUpdateCheck() {
        URL url;
        DPhex dPhex;
        try {
            url = new URL(UPDATE_CHECK_URL);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setUseCaches(false);
            connection.setRequestProperty("User-Agent", Environment.getPhexVendor());
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");

            OutputStream outStream = connection.getOutputStream();
            byte[] data = buildXMLUpdateRequest();
            if (data == null) {
                throw new IOException("Missing XML update data");
            }
            outStream.write(data);
            if (NLogger.isDebugEnabled(UpdateCheckRunner.class)) {
                NLogger.debug(UpdateCheckRunner.class, new String(data));
            }

            // dont need to buffer stream already done by Properties.load()
            InputStream inStream = connection.getInputStream();
            if (NLogger.isDebugEnabled(UpdateCheckRunner.class)) {
                byte[] respData = IOUtil.toByteArray(inStream);
                NLogger.debug(UpdateCheckRunner.class, new String(respData));
                inStream = new ByteArrayInputStream(respData);
            }
            dPhex = XMLBuilder.readDPhexFromStream(inStream);
        } catch (MalformedURLException exp) {
            updateCheckError = exp;
            NLogger.warn(UpdateCheckRunner.class, exp, exp);
            assert false;
            throw new RuntimeException();
        } catch (UnknownHostException exp) {
            // can't find way to host
            // this maybe means we have no internet connection
            updateCheckError = exp;
            NLogger.warn(UpdateCheckRunner.class, exp, exp);
            return;
        } catch (SocketException exp) {
            // can't connect... maybe a proxy is in the way...
            updateCheckError = exp;
            NLogger.warn(UpdateCheckRunner.class, exp, exp);
            return;
        } catch (IOException exp) {
            updateCheckError = exp;
            NLogger.warn(UpdateCheckRunner.class, exp, exp);
            return;
        }

        UpdatePrefs.LastUpdateCheckTime.set(Long.valueOf(System.currentTimeMillis()));

        DUpdateResponse response = dPhex.getUpdateResponse();
        List<VersionType> versionList = response.getVersionList();
        VersionType latestReleaseVersion = null;
        VersionType latestBetaVersion = null;

        for (VersionType currentVersion : versionList) {
            if (currentVersion.isBeta()) {
                if (latestBetaVersion == null
                        || VersionUtils.compare(currentVersion.getId(), latestBetaVersion.getId()) > 0) {
                    latestBetaVersion = currentVersion;
                }
            } else {
                if (latestReleaseVersion == null
                        || VersionUtils.compare(currentVersion.getId(), latestReleaseVersion.getId()) > 0) {
                    latestReleaseVersion = currentVersion;
                }
            }
        }

        betaVersion = "0";
        releaseVersion = "0";
        if (latestBetaVersion != null) {
            betaVersion = latestBetaVersion.getId();
        }
        if (latestReleaseVersion != null) {
            releaseVersion = latestReleaseVersion.getId();
        }

        int releaseCompare = 0;
        int betaCompare = 0;
        betaCompare = VersionUtils.compare(betaVersion, VersionUtils.getFullProgramVersion());
        releaseCompare = VersionUtils.compare(releaseVersion, VersionUtils.getFullProgramVersion());

        if (releaseCompare <= 0 && betaCompare <= 0) {
            PhexCorePrefs.save(false);
            return;
        }

        betaCompare = VersionUtils.compare(betaVersion, UpdatePrefs.LastBetaUpdateCheckVersion.get());
        releaseCompare = VersionUtils.compare(releaseVersion, UpdatePrefs.LastUpdateCheckVersion.get());

        int verDiff = VersionUtils.compare(betaVersion, releaseVersion);

        boolean triggerUpdateNotification = false;
        if (releaseCompare > 0) {
            UpdatePrefs.LastUpdateCheckVersion.set(releaseVersion);
            triggerUpdateNotification = true;
        }
        if (betaCompare > 0) {
            UpdatePrefs.LastBetaUpdateCheckVersion.set(betaVersion);
            triggerUpdateNotification = true;
        }

        if (verDiff > 0) {
            // reset release version since beta is more up-to-date
            releaseVersion = null;
        } else {
            // reset beta version since release is the one to go.
            betaVersion = null;
        }

        PhexCorePrefs.save(false);
        if (triggerUpdateNotification) {
            fireUpdateNotification();
        }
    }

    private void fireUpdateNotification() {
        listener.updateNotification(this);
    }

    private byte[] buildXMLUpdateRequest() {
        Servent servent = Servent.getInstance();
        try {
            DPhex dPhex = new DPhex();
            DUpdateRequest dRequest = new DUpdateRequest();
            dPhex.setUpdateRequest(dRequest);

            // I2PFIXME:
            // Some details over here might be undesirable to transmit,
            // even when in future we might be able to check for signed updates
            // and do it over eepproxy.
            dRequest.setCurrentVersion(VersionUtils.getFullProgramVersion());
            dRequest.setStartupCount(StatisticPrefs.TotalStartupCounter.get().intValue());
            dRequest.setLafUsed(GUIRegistry.getInstance().getUsedLAFClass());
            dRequest.setJavaVersion(System.getProperty("java.version"));
            dRequest.setOperatingSystem(SystemUtils.OS_NAME);

            dRequest.setHostid(servent.getServentGuid().toHexString());
            dRequest.setShowBetaInfo(isBetaInfoShown);
            dRequest.setLastInfoId(UpdatePrefs.LastShownUpdateInfoId.get().intValue());

            String lastCheckVersion;
            if (VersionUtils.compare(UpdatePrefs.LastUpdateCheckVersion.get(),
                    UpdatePrefs.LastBetaUpdateCheckVersion.get()) > 0) {
                lastCheckVersion = UpdatePrefs.LastUpdateCheckVersion.get();
            } else {
                lastCheckVersion = UpdatePrefs.LastBetaUpdateCheckVersion.get();
            }
            dRequest.setLastCheckVersion(lastCheckVersion);

            StatisticsManager statMgr = servent.getStatisticsService();

            StatisticProvider uptimeProvider = statMgr.getStatisticProvider(StatisticsManager.UPTIME_PROVIDER);
            dRequest.setAvgUptime(((LongObj) uptimeProvider.getAverageValue()).value);

            StatisticProvider dailyUptimeProvider = statMgr
                    .getStatisticProvider(StatisticsManager.DAILY_UPTIME_PROVIDER);
            dRequest.setDailyAvgUptime(((Integer) dailyUptimeProvider.getValue()).intValue());

            StatisticProvider downloadProvider = statMgr
                    .getStatisticProvider(StatisticProviderConstants.TOTAL_DOWNLOAD_COUNT_PROVIDER);
            dRequest.setDownloadCount((int) ((LongObj) downloadProvider.getValue()).value);

            StatisticProvider uploadProvider = statMgr
                    .getStatisticProvider(StatisticProviderConstants.TOTAL_UPLOAD_COUNT_PROVIDER);
            dRequest.setUploadCount((int) ((LongObj) uploadProvider.getValue()).value);

            SharedFilesService sharedFilesService = Servent.getInstance().getSharedFilesService();
            dRequest.setSharedFiles(sharedFilesService.getFileCount());
            dRequest.setSharedSize(sharedFilesService.getTotalFileSizeInKb());

            dRequest.setErrorLog(getErrorLogFileTail());

            return phex.xml.sax.XMLBuilder.serializeToBytes(dPhex);
        } catch (IOException exp) {
            NLogger.error(UpdateCheckRunner.class, exp, exp);
            return null;
        }
    }

    private String getErrorLogFileTail() {
        try {
            File logFile = Environment.getInstance().getPhexConfigFile("phex.error.log");
            if (!logFile.exists()) {
                return null;
            }
            RandomAccessFile raf = new RandomAccessFile(logFile, "r");
            long pos = Math.max(raf.length() - 10 * 1024, 0);
            raf.seek(pos);
            byte[] buffer = new byte[(int) Math.min(10 * 1024, raf.length())];
            int lenRead = raf.read(buffer);
            return new String(buffer, 0, lenRead);
        } catch (IOException exp) {
            NLogger.error(UpdateCheckRunner.class, exp, exp);
            return exp.toString();
        }
    }
}