private ModifableExtensionPlanNode installExtension(Extension sourceExtension, Extension rewrittenExtension,
        boolean dependency, String namespace, ExtensionDependency initialDependency,
        Map<String, ExtensionDependency> managedDependencies, Set<String> parents) throws InstallException,
        ResolveException, IncompatibleVersionConstraintException, UninstallException, NamespaceNotAllowedException
    {
        boolean allowed = isNamespaceAllowed(rewrittenExtension, namespace);

        // Check if the namespace is compatible with the Extension
        if (!allowed) {
            if (namespace != null) {
                if (getRequest().isRootModificationsAllowed()) {
                    // Try to install it on root namespace
                    return installExtension(sourceExtension, rewrittenExtension, dependency, null, initialDependency,
                        managedDependencies, parents);
                }
            }

            // Extension is not allowed on target namespace
            throw new NamespaceNotAllowedException(
                String.format("Extension [%s] is not allowed on namespace [%s]. Allowed namespaces are: %s",
                    rewrittenExtension.getId(), namespace, rewrittenExtension.getAllowedNamespaces()));
        }

        // Check if the extension is already in the install plan
        checkExistingPlanNodeExtension(rewrittenExtension, namespace);

        // Check if the extension matches a root extension
        if (namespace != null) {
            // Check if the extension already exist on root, throw exception if not allowed
            if (checkRootExtension(rewrittenExtension)) {
                // Restart install on root
                return installExtension(sourceExtension, rewrittenExtension, dependency, null, initialDependency,
                    managedDependencies, parents);
            }
        }

        // Check if the extension is already installed
        Extension installedExtension = checkInstalledExtension(rewrittenExtension, namespace);
        if (installedExtension != rewrittenExtension) {
            sourceExtension = installedExtension;

            // Rewrite the extension
            if (getRequest().getRewriter() != null) {
                rewrittenExtension = getRequest().getRewriter().rewrite(installedExtension);
            } else {
                rewrittenExtension = installedExtension;
            }
        }

        // Check if the extension is a core extension
        checkCoreExtension(rewrittenExtension);

        // Find out what need to be upgraded and uninstalled

        this.progressManager.pushLevelProgress(5, this);

        try {
            this.progressManager.startStep(this);

            // Is installing the extension supported/allowed ?
            checkTypeInstall(rewrittenExtension, namespace);

            this.progressManager.endStep(this);

            this.progressManager.startStep(this);

            // Find all existing versions of the extension
            Set<InstalledExtension> previousExtensions = getReplacedInstalledExtensions(rewrittenExtension, namespace);

            this.progressManager.endStep(this);

            this.progressManager.startStep(this);

            // Mark replaced extensions as uninstalled
            for (InstalledExtension previousExtension : new ArrayList<>(previousExtensions)) {
                if (!previousExtension.isInstalled(namespace)
                    || !previousExtension.getId().getId().equals(rewrittenExtension.getId().getId())) {
                    if (namespace == null && previousExtension.getNamespaces() != null) {
                        for (String previousNamespace : previousExtension.getNamespaces()) {
                            uninstallExtension(previousExtension, previousNamespace, this.extensionTree, false);
                            previousExtensions.remove(previousExtension);
                        }
                    } else {
                        uninstallExtension(previousExtension, namespace, this.extensionTree, false);
                    }
                }
            }

            this.progressManager.endStep(this);

            this.progressManager.startStep(this);

            // Check dependencies
            Collection<? extends ExtensionDependency> dependencies = rewrittenExtension.getDependencies();

            List<ModifableExtensionPlanNode> children = null;
            if (!dependencies.isEmpty()) {
                parents = ExtensionUtils.append(parents, rewrittenExtension.getId().getId());

                this.progressManager.pushLevelProgress(dependencies.size() + 1, this);

                try {
                    children = new ArrayList<>();
                    for (ExtensionDependency extensionDependency : dependencies) {
                        this.progressManager.startStep(this);

                        if (parents.contains(extensionDependency.getId())) {
                            // In case of cross dependency just ignore it
                            continue;
                        }

                        // Replace with managed dependency if any
                        extensionDependency =
                            ExtensionUtils.getDependency(extensionDependency, managedDependencies, rewrittenExtension);

                        // Try installing recommended version (if any)
                        boolean valid = false;
                        ExtensionDependency recommendedDependency = ExtensionUtils
                            .getRecommendedDependency(extensionDependency, this.configuration, this.factory);
                        if (recommendedDependency != null) {
                            valid = installOptionalExtensionDependency(recommendedDependency, namespace, children,
                                ExtensionUtils.append(managedDependencies, rewrittenExtension), parents);
                        }

                        // If recommended version is invalid, try the one provided by the extension
                        if (!valid) {
                            installExtensionDependency(extensionDependency, namespace, children,
                                ExtensionUtils.append(managedDependencies, rewrittenExtension), parents);
                        }

                        this.progressManager.endStep(this);
                    }
                } finally {
                    this.progressManager.popLevelProgress(this);
                }
            }

            this.progressManager.endStep(this);

            this.progressManager.startStep(this);

            ModifableExtensionPlanNode node = initialDependency != null
                ? new ModifableExtensionPlanNode(initialDependency, initialDependency.getVersionConstraint())
                : new ModifableExtensionPlanNode();

            node.setChildren(children);

            Action action;
            if (!previousExtensions.isEmpty()) {
                if (rewrittenExtension.compareTo(previousExtensions.iterator().next()) < 0) {
                    action = Action.DOWNGRADE;
                } else {
                    action = Action.UPGRADE;
                }
            } else if (rewrittenExtension instanceof InstalledExtension) {
                action = Action.REPAIR;
            } else {
                action = Action.INSTALL;
            }

            node.setAction(new DefaultExtensionPlanAction(sourceExtension, rewrittenExtension, previousExtensions,
                action, namespace, dependency));

            return node;
        } finally {
            this.progressManager.popLevelProgress(this);
        }
    }
private ModifableExtensionPlanNode installExtension ( Extension sourceExtension , Extension rewrittenExtension , boolean dependency , String namespace , ExtensionDependency initialDependency , Map < String , ExtensionDependency > managedDependencies , Set < String > parents ) throws InstallException , ResolveException , IncompatibleVersionConstraintException , UninstallException , NamespaceNotAllowedException { boolean allowed = isNamespaceAllowed ( rewrittenExtension , namespace ) ; if ( ! allowed ) { if ( namespace != null ) { if ( getRequest ( ) . isRootModificationsAllowed ( ) ) { return installExtension ( sourceExtension , rewrittenExtension , dependency , null , initialDependency , managedDependencies , parents ) ; } } throw new NamespaceNotAllowedException ( String . format ( "Extension [%s] is not allowed on namespace [%s]. Allowed namespaces are: %s" , rewrittenExtension . getId ( ) , namespace , rewrittenExtension . getAllowedNamespaces ( ) ) ) ; } checkExistingPlanNodeExtension ( rewrittenExtension , namespace ) ; if ( namespace != null ) { if ( checkRootExtension ( rewrittenExtension ) ) { return installExtension ( sourceExtension , rewrittenExtension , dependency , null , initialDependency , managedDependencies , parents ) ; } } Extension installedExtension = checkInstalledExtension ( rewrittenExtension , namespace ) ; if ( installedExtension != rewrittenExtension ) { sourceExtension = installedExtension ; if ( getRequest ( ) . getRewriter ( ) != null ) { rewrittenExtension = getRequest ( ) . getRewriter ( ) . rewrite ( installedExtension ) ; } else { rewrittenExtension = installedExtension ; } } checkCoreExtension ( rewrittenExtension ) ; this . progressManager . pushLevelProgress ( 5 , this ) ; try { this . progressManager . startStep ( this ) ; checkTypeInstall ( rewrittenExtension , namespace ) ; this . progressManager . endStep ( this ) ; this . progressManager . startStep ( this ) ; Set < InstalledExtension > previousExtensions = getReplacedInstalledExtensions ( rewrittenExtension , namespace ) ; this . progressManager . endStep ( this ) ; this . progressManager . startStep ( this ) ; for ( InstalledExtension previousExtension : new ArrayList < > ( previousExtensions ) ) { if ( ! previousExtension . isInstalled ( namespace ) || ! previousExtension . getId ( ) . getId ( ) . equals ( rewrittenExtension . getId ( ) . getId ( ) ) ) { if ( namespace == null && previousExtension . getNamespaces ( ) != null ) { for ( String previousNamespace : previousExtension . getNamespaces ( ) ) { uninstallExtension ( previousExtension , previousNamespace , this . extensionTree , false ) ; previousExtensions . remove ( previousExtension ) ; } } else { uninstallExtension ( previousExtension , namespace , this . extensionTree , false ) ; } } } this . progressManager . endStep ( this ) ; this . progressManager . startStep ( this ) ; Collection < ? extends ExtensionDependency > dependencies = rewrittenExtension . getDependencies ( ) ; List < ModifableExtensionPlanNode > children = null ; if ( ! dependencies . isEmpty ( ) ) { parents = ExtensionUtils . append ( parents , rewrittenExtension . getId ( ) . getId ( ) ) ; this . progressManager . pushLevelProgress ( dependencies . size ( ) + 1 , this ) ; try { children = new ArrayList < > ( ) ; for ( ExtensionDependency extensionDependency : dependencies ) { this . progressManager . startStep ( this ) ; if ( parents . contains ( extensionDependency . getId ( ) ) ) { continue ; } extensionDependency = ExtensionUtils . getDependency ( extensionDependency , managedDependencies , rewrittenExtension ) ; boolean valid = false ; ExtensionDependency recommendedDependency = ExtensionUtils . getRecommendedDependency ( extensionDependency , this . configuration , this . factory ) ; if ( recommendedDependency != null ) { valid = installOptionalExtensionDependency ( recommendedDependency , namespace , children , ExtensionUtils . append ( managedDependencies , rewrittenExtension ) , parents ) ; } if ( ! valid ) { installExtensionDependency ( extensionDependency , namespace , children , ExtensionUtils . append ( managedDependencies , rewrittenExtension ) , parents ) ; } this . progressManager . endStep ( this ) ; } } finally { this . progressManager . popLevelProgress ( this ) ; } } this . progressManager . endStep ( this ) ; this . progressManager . startStep ( this ) ; ModifableExtensionPlanNode node = initialDependency != null ? new ModifableExtensionPlanNode ( initialDependency , initialDependency . getVersionConstraint ( ) ) : new ModifableExtensionPlanNode ( ) ; node . setChildren ( children ) ; Action action ; if ( ! previousExtensions . isEmpty ( ) ) { if ( rewrittenExtension . compareTo ( previousExtensions . iterator ( ) . next ( ) ) < 0 ) { action = Action . DOWNGRADE ; } else { action = Action . UPGRADE ; } } else if ( rewrittenExtension instanceof InstalledExtension ) { action = Action . REPAIR ; } else { action = Action . INSTALL ; } node . setAction ( new DefaultExtensionPlanAction ( sourceExtension , rewrittenExtension , previousExtensions , action , namespace , dependency ) ) ; return node ; } finally { this . progressManager . popLevelProgress ( this ) ; } }
@param sourceExtension the new extension to install
@param rewrittenExtension the rewritten version of the passed extension
@param dependency indicate if the extension is installed as a dependency
@param namespace the namespace where to install the extension
@param initialDependency the initial dependency used to resolve the extension
@param managedDependencies the managed dependencies
@param parents the parents extensions (which triggered this extension install)
@return the install plan node for the provided extension
@throws InstallException error when trying to install provided extension
@throws IncompatibleVersionConstraintException
@throws UninstallException
@throws NamespaceNotAllowedException when passed namespace is not compatible with the passed extension