uk.org.taverna.commons.update.impl.UpdateManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.taverna.commons.update.impl.UpdateManagerImpl.java

Source

/*******************************************************************************
 * Copyright (C) 2013 The University of Manchester
 *
 *  Modifications to the initial code base are copyright of their
 *  respective authors, or their employers as appropriate.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser 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
 ******************************************************************************/
package uk.org.taverna.commons.update.impl;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.io.FileUtils;
import org.osgi.service.event.EventAdmin;

import uk.org.taverna.commons.download.DownloadException;
import uk.org.taverna.commons.download.DownloadManager;
import uk.org.taverna.commons.profile.xml.jaxb.ApplicationProfile;
import uk.org.taverna.commons.profile.xml.jaxb.BundleInfo;
import uk.org.taverna.commons.profile.xml.jaxb.UpdateSite;
import uk.org.taverna.commons.profile.xml.jaxb.Updates;
import uk.org.taverna.commons.update.UpdateException;
import uk.org.taverna.commons.update.UpdateManager;
import uk.org.taverna.commons.versions.xml.jaxb.Version;
import uk.org.taverna.commons.versions.xml.jaxb.Versions;
import uk.org.taverna.configuration.app.ApplicationConfiguration;

/**
 * Implementation of the Taverna Update Manager.
 *
 * @author David Withers
 */
public class UpdateManagerImpl implements UpdateManager {

    private static final String DIGEST_ALGORITHM = "MD5";

    private EventAdmin eventAdmin;

    private int checkIntervalSeconds;

    private ApplicationConfiguration applicationConfiguration;

    private DownloadManager downloadManager;

    private long lastCheckTime;
    private boolean updateAvailable;
    private Unmarshaller unmarshaller;

    private Versions applicationVersions;
    private Version latestVersion;

    public UpdateManagerImpl() throws UpdateException {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(UpdateSite.class, ApplicationProfile.class);
            unmarshaller = jaxbContext.createUnmarshaller();
        } catch (JAXBException e) {
            throw new UpdateException("Error creating JAXBContext", e);
        }
    }

    @Override
    public boolean checkForUpdates() throws UpdateException {
        ApplicationProfile applicationProfile = applicationConfiguration.getApplicationProfile();
        String version = applicationProfile.getVersion();
        Updates updates = applicationProfile.getUpdates();

        URL updatesURL;
        try {
            URI updateSiteURI = new URI(updates.getUpdateSite());
            updatesURL = updateSiteURI.resolve(updates.getUpdatesFile()).toURL();
        } catch (MalformedURLException e) {
            throw new UpdateException(
                    String.format("Update site URL (%s) is not a valid URL", updates.getUpdateSite()), e);
        } catch (URISyntaxException e) {
            throw new UpdateException(
                    String.format("Update site URL (%s) is not a valid URL", updates.getUpdateSite()), e);
        }
        File updateDirectory = new File(applicationConfiguration.getApplicationHomeDir(), "updates");
        updateDirectory.mkdirs();
        File updatesFile = new File(updateDirectory, updates.getUpdatesFile());
        try {
            downloadManager.download(updatesURL, updatesFile, DIGEST_ALGORITHM);
        } catch (DownloadException e) {
            throw new UpdateException(String.format("Error downloading %1$s", updatesURL), e);
        }

        try {
            UpdateSite updateSite = (UpdateSite) unmarshaller.unmarshal(updatesFile);
            applicationVersions = updateSite.getVersions();
            latestVersion = applicationVersions.getLatestVersion();
            updateAvailable = isHigherVersion(latestVersion.getVersion(), version);
        } catch (JAXBException e) {
            throw new UpdateException(String.format("Error reading %s", updatesFile.getName()), e);
        }
        lastCheckTime = System.currentTimeMillis();
        return updateAvailable;
    }

    @Override
    public boolean update() throws UpdateException {
        if (updateAvailable) {
            ApplicationProfile applicationProfile = applicationConfiguration.getApplicationProfile();
            Updates updates = applicationProfile.getUpdates();
            URL profileURL;
            try {
                URI updateSiteURI = new URI(updates.getUpdateSite());
                profileURL = updateSiteURI.resolve(latestVersion.getFile()).toURL();
            } catch (MalformedURLException e) {
                throw new UpdateException(
                        String.format("Application profile URL (%s) is not a valid URL", latestVersion.getFile()),
                        e);
            } catch (URISyntaxException e) {
                throw new UpdateException(
                        String.format("Update site URL (%s) is not a valid URL", updates.getUpdateSite()), e);
            }

            File updateDirectory = new File(applicationConfiguration.getApplicationHomeDir(), "updates");
            updateDirectory.mkdirs();
            File latestProfileFile = new File(updateDirectory,
                    "ApplicationProfile-" + latestVersion.getVersion() + ".xml");
            try {
                downloadManager.download(profileURL, latestProfileFile, DIGEST_ALGORITHM);
            } catch (DownloadException e) {
                throw new UpdateException(String.format("Error downloading %1$s", profileURL), e);
            }

            ApplicationProfile latestProfile;
            try {
                latestProfile = (ApplicationProfile) unmarshaller.unmarshal(latestProfileFile);
            } catch (JAXBException e) {
                throw new UpdateException(String.format("Error reading %s", latestProfileFile.getName()), e);
            }

            Set<BundleInfo> requiredBundles = getRequiredBundles(applicationConfiguration.getApplicationProfile(),
                    latestProfile);
            downloadBundles(latestProfile, requiredBundles,
                    new File(applicationConfiguration.getStartupDir(), "lib"));
            File applicationProfileFile = new File(applicationConfiguration.getStartupDir(),
                    "ApplicationProfile.xml");
            try {
                FileUtils.copyFile(latestProfileFile, applicationProfileFile);
            } catch (IOException e) {
                throw new UpdateException(String.format("Error copying %1$s to %2$s", latestProfileFile.getName(),
                        applicationProfileFile.getName()), e);
            }
            //         eventAdmin.postEvent(new Event("UpdateManagerEvent", new HashMap()));
            updateAvailable = false;
            return true;
        }
        return false;
    }

    /**
     * @param requiredBundles
     * @param file
     * @throws UpdateException
     */
    private void downloadBundles(ApplicationProfile profile, Set<BundleInfo> requiredBundles, File file)
            throws UpdateException {
        Updates updates = profile.getUpdates();
        String updateSite = updates.getUpdateSite();
        String libDirectory = updates.getLibDirectory();
        if (!libDirectory.endsWith("/")) {
            libDirectory = libDirectory + "/";
        }

        URI updateLibDirectory;
        try {
            updateLibDirectory = new URI(updateSite).resolve(libDirectory);
        } catch (URISyntaxException e) {
            throw new UpdateException(
                    String.format("Update site URL (%s) is not a valid URL", updates.getUpdateSite()), e);
        }
        for (BundleInfo bundle : requiredBundles) {
            URL bundleURL;
            URI bundleURI = updateLibDirectory.resolve(bundle.getFileName());
            try {
                bundleURL = bundleURI.toURL();
            } catch (MalformedURLException e) {
                throw new UpdateException(String.format("Bundle URL (%s) is not a valid URL", bundleURI), e);
            }
            File bundleDestination = new File(file, bundle.getFileName());
            try {
                downloadManager.download(bundleURL, new File(file, bundle.getFileName()), DIGEST_ALGORITHM);
            } catch (DownloadException e) {
                throw new UpdateException(
                        String.format("Error downloading %1$s to %2$s", bundleURL, bundleDestination), e);
            }
        }
    }

    /**
     * Returns the new bundles required for the new application profile.
     *
     * @param currentProfile
     * @param newProfile
     * @return the new bundles required for the new application profile
     */
    private Set<BundleInfo> getRequiredBundles(ApplicationProfile currentProfile, ApplicationProfile newProfile) {
        Set<BundleInfo> requiredBundles = new HashSet<BundleInfo>();
        Map<String, BundleInfo> currentBundles = new HashMap<String, BundleInfo>();
        for (BundleInfo bundle : currentProfile.getBundle()) {
            currentBundles.put(bundle.getSymbolicName(), bundle);
        }
        for (BundleInfo bundle : newProfile.getBundle()) {
            if (currentBundles.containsKey(bundle.getSymbolicName())) {
                BundleInfo currentBundle = currentBundles.get(bundle.getSymbolicName());
                if (!bundle.getVersion().equals(currentBundle.getVersion())) {
                    requiredBundles.add(bundle);
                }
            } else {
                requiredBundles.add(bundle);
            }
        }
        return requiredBundles;
    }

    private boolean isHigherVersion(String version1, String version2) {
        org.osgi.framework.Version semanticVersion1 = org.osgi.framework.Version.parseVersion(version1);
        org.osgi.framework.Version semanticVersion2 = org.osgi.framework.Version.parseVersion(version2);
        return semanticVersion1.compareTo(semanticVersion2) > 0;
    }

    public void setEventAdmin(EventAdmin eventAdmin) {
        this.eventAdmin = eventAdmin;
    }

    public void setCheckIntervalSeconds(int checkIntervalSeconds) {
        this.checkIntervalSeconds = checkIntervalSeconds;
    }

    public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
        this.applicationConfiguration = applicationConfiguration;
    }

    public void setDownloadManager(DownloadManager downloadManager) {
        this.downloadManager = downloadManager;
    }

}