All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xwiki.extension.job.internal.UpgradePlanJob Maven / Gradle / Ivy

There is a newer version: 16.10.2
Show newest version
/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This 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 software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.extension.job.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.NavigableSet;
import java.util.TreeSet;

import javax.inject.Named;

import org.xwiki.component.annotation.Component;
import org.xwiki.extension.ExtensionId;
import org.xwiki.extension.InstallException;
import org.xwiki.extension.InstalledExtension;
import org.xwiki.extension.ResolveException;
import org.xwiki.extension.job.InstallRequest;
import org.xwiki.extension.job.plan.internal.DefaultExtensionPlanTree;
import org.xwiki.extension.repository.result.IterableResult;
import org.xwiki.extension.version.Version;
import org.xwiki.job.Request;

/**
 * Create an Extension upgrade plan.
 *
 * @version $Id: 0638211a245109e0059f2843073c33496e6b832d $
 * @since 4.1M1
 */
@Component
@Named(UpgradePlanJob.JOBTYPE)
public class UpgradePlanJob extends AbstractInstallPlanJob
{
    /**
     * The id of the job.
     */
    public static final String JOBTYPE = "upgradeplan";

    @Override
    public String getType()
    {
        return JOBTYPE;
    }

    @Override
    protected InstallRequest castRequest(Request request)
    {
        InstallRequest installRequest;
        if (request instanceof InstallRequest) {
            installRequest = (InstallRequest) request;
        } else {
            installRequest = new InstallRequest(request);
        }

        return installRequest;
    }

    /**
     * @param extension the extension currently installed
     * @param namespace the namespace where the extension is installed
     */
    protected void upgradeExtension(InstalledExtension extension, String namespace, boolean filterDependencies)
    {
        if (!getRequest().getExcludedExtensions().contains(extension.getId())
            && (!filterDependencies || !extension.isDependency(namespace))) {
            NavigableSet versions = getVersions(extension, namespace);

            // Useless to continue if the extension does not have any available version
            if (!versions.isEmpty()) {
                upgradeExtension(extension, namespace, versions.descendingSet());
            }
        }
    }

    private NavigableSet getVersions(InstalledExtension extension, String namespace)
    {
        NavigableSet versionList = new TreeSet<>();

        // Search local versions
        try {
            IterableResult versions =
                this.localExtensionRepository.resolveVersions(extension.getId().getId(), 0, -1);
            for (Version version : versions) {
                versionList.add(version);
            }
        } catch (ResolveException e) {
            this.logger.debug("Failed to resolve local versions for extension id [{}]", extension.getId().getId(), e);
        }

        // Search remote versions
        try {
            IterableResult versions = this.repositoryManager.resolveVersions(extension.getId().getId(), 0, -1);

            for (Version version : versions) {
                versionList.add(version);
            }
        } catch (ResolveException e) {
            this.logger.debug("Failed to resolve remote versions for extension id [{}]", extension.getId().getId(), e);
        }

        // Make sure the current version is included if the extension is invalid (it's possible this version does
        // not exist on any repository)
        if (!extension.isValid(namespace)) {
            versionList.add(extension.getId().getVersion());
        }

        return versionList;
    }

    protected void upgradeExtension(InstalledExtension extension, String namespace, Collection versionList)
    {
        for (Version version : versionList) {
            // Don't try to upgrade for lower versions but try to repair same version of the extension is invalid
            int compare = extension.getId().getVersion().compareTo(version);
            if (compare > 0 || (compare == 0 && extension.isValid(namespace))) {
                break;
            }

            // Only upgrade beta if the current is beta etc.
            if (extension.getId().getVersion().getType().ordinal() <= version.getType().ordinal()) {
                if (tryInstallExtension(new ExtensionId(extension.getId().getId(), version), namespace)) {
                    break;
                }
            }
        }
    }

    /**
     * Try to install the provided extension and update the plan if it's working.
     *
     * @param extensionId the extension version to install
     * @param namespace the namespace where to install the extension
     * @return true if the installation would succeed, false otherwise
     */
    protected boolean tryInstallExtension(ExtensionId extensionId, String namespace)
    {
        DefaultExtensionPlanTree currentTree = this.extensionTree.clone();

        try {
            installExtension(extensionId, namespace, currentTree);

            setExtensionTree(currentTree);

            return true;
        } catch (InstallException e) {
            this.logger.debug("Can't install extension [{}] on namespace [{}].", extensionId, namespace, e);
        }

        return false;
    }

    protected void upgrade(String namespace, Collection installedExtensions,
        boolean filterDependencies)
    {
        this.progressManager.pushLevelProgress(installedExtensions.size(), this);

        try {
            for (InstalledExtension installedExtension : installedExtensions) {
                this.progressManager.startStep(this);

                if (namespace == null || !installedExtension.isInstalled(null)) {
                    upgradeExtension(installedExtension, namespace, filterDependencies);
                }
            }
        } finally {
            this.progressManager.popLevelProgress(this);
        }
    }

    protected void upgrade(Collection installedExtensions, boolean filterDependencies)
    {
        this.progressManager.pushLevelProgress(installedExtensions.size(), this);

        try {
            for (InstalledExtension installedExtension : installedExtensions) {
                this.progressManager.startStep(this);

                if (installedExtension.getNamespaces() == null) {
                    upgradeExtension(installedExtension, null, filterDependencies);
                } else {
                    this.progressManager.pushLevelProgress(installedExtension.getNamespaces().size(), this);

                    try {
                        for (String namespace : installedExtension.getNamespaces()) {
                            this.progressManager.startStep(this);

                            upgradeExtension(installedExtension, namespace, filterDependencies);
                        }
                    } finally {
                        this.progressManager.popLevelProgress(this);
                    }
                }
            }
        } finally {
            this.progressManager.popLevelProgress(this);
        }
    }

    protected Collection getInstalledExtensions(String namespace)
    {
        Collection requestExtensions = getRequest().getExtensions();

        Collection installedExtensions;

        if (requestExtensions != null && !requestExtensions.isEmpty()) {
            installedExtensions = new ArrayList<>(requestExtensions.size());

            for (ExtensionId requestExtension : requestExtensions) {
                InstalledExtension installedExtension =
                    this.installedExtensionRepository.getInstalledExtension(requestExtension);
                if (installedExtension.isInstalled(namespace)) {
                    installedExtensions.add(installedExtension);
                }
            }
        } else {
            installedExtensions = this.installedExtensionRepository.getInstalledExtensions(namespace);
        }

        return installedExtensions;
    }

    protected Collection getInstalledExtensions()
    {
        Collection requestExtensions = getRequest().getExtensions();

        Collection installedExtensions;

        if (requestExtensions != null && !requestExtensions.isEmpty()) {
            installedExtensions = new ArrayList<>(requestExtensions.size());

            for (ExtensionId requestExtension : requestExtensions) {
                InstalledExtension installedExtension =
                    this.installedExtensionRepository.getInstalledExtension(requestExtension);
                installedExtensions.add(installedExtension);
            }
        } else {
            installedExtensions = this.installedExtensionRepository.getInstalledExtensions();
        }

        return installedExtensions;
    }

    @Override
    protected void runInternal() throws Exception
    {
        Collection namespaces = getRequest().getNamespaces();
        Collection requestExtensions = getRequest().getExtensions();
        boolean filterDependencies = requestExtensions == null || requestExtensions.isEmpty();

        if (namespaces == null) {
            Collection installedExtensions = getInstalledExtensions();

            upgrade(installedExtensions, filterDependencies);
        } else {
            this.progressManager.pushLevelProgress(namespaces.size(), this);

            try {
                for (String namespace : namespaces) {
                    this.progressManager.startStep(this);

                    upgrade(namespace, getInstalledExtensions(namespace), filterDependencies);
                }
            } finally {
                this.progressManager.popLevelProgress(this);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy