/**
   * Check that the extension is properly reported to be installed in the given namespace.
   *
   * @param installedExtension the local extension to check
   * @param namespace the namespace where it has been installed
   */
  private void checkInstallStatus(InstalledExtension installedExtension, String namespace) {
    // check extension status
    Assert.assertNotNull(installedExtension);
    Assert.assertNotNull(installedExtension.getFile());
    Assert.assertTrue(new File(installedExtension.getFile().getAbsolutePath()).exists());
    Assert.assertTrue(installedExtension.isInstalled(namespace));
    if (namespace != null) {
      Assert.assertFalse(installedExtension.isInstalled(null));
    }

    // check repository status
    Assert.assertNotNull(
        this.installedExtensionRepository.getInstalledExtension(
            installedExtension.getId().getId(), namespace));
    if (namespace != null) {
      Assert.assertNull(
          this.installedExtensionRepository.getInstalledExtension(
              installedExtension.getId().getId(), null));
    }
  }
  private ExtensionDependency checkInstalledExtension(
      InstalledExtension installedExtension,
      ExtensionDependency extensionDependency,
      VersionConstraint versionConstraint,
      String namespace,
      List<ModifableExtensionPlanNode> parentBranch)
      throws InstallException {
    ExtensionDependency targetDependency = extensionDependency;

    if (installedExtension != null) {
      // Check if already installed version is compatible
      if (installedExtension.isValid(namespace)
          && versionConstraint.isCompatible(installedExtension.getId().getVersion())) {
        if (getRequest().isVerbose()) {
          this.logger.debug(
              "There is already an installed extension [{}] covering extension dependency [{}]",
              installedExtension.getId(),
              extensionDependency);
        }

        ModifableExtensionPlanNode node =
            new ModifableExtensionPlanNode(extensionDependency, versionConstraint);
        node.setAction(
            new DefaultExtensionPlanAction(
                installedExtension,
                null,
                Action.NONE,
                namespace,
                installedExtension.isDependency(namespace)));

        addExtensionNode(node);
        parentBranch.add(node);

        return null;
      }

      // If not compatible with it, try to merge dependencies constraint of all backward
      // dependencies to find a
      // new compatible version for this extension
      VersionConstraint mergedVersionContraint;
      try {
        if (installedExtension.isInstalled(null)) {
          Map<String, Collection<InstalledExtension>> backwardDependencies =
              this.installedExtensionRepository.getBackwardDependencies(installedExtension.getId());

          mergedVersionContraint =
              mergeVersionConstraints(
                  backwardDependencies.get(null), extensionDependency.getId(), versionConstraint);
          if (namespace != null) {
            mergedVersionContraint =
                mergeVersionConstraints(
                    backwardDependencies.get(namespace),
                    extensionDependency.getId(),
                    mergedVersionContraint);
          }
        } else {
          Collection<InstalledExtension> backwardDependencies =
              this.installedExtensionRepository.getBackwardDependencies(
                  installedExtension.getId().getId(), namespace);

          mergedVersionContraint =
              mergeVersionConstraints(
                  backwardDependencies, extensionDependency.getId(), versionConstraint);
        }
      } catch (IncompatibleVersionConstraintException e) {
        throw new InstallException(
            "Provided depency is incompatible with already installed extensions", e);
      } catch (ResolveException e) {
        throw new InstallException("Failed to resolve backward dependencies", e);
      }

      if (mergedVersionContraint != versionConstraint) {
        targetDependency =
            new DefaultExtensionDependency(extensionDependency, mergedVersionContraint);
      }
    }

    return targetDependency;
  }
  protected InstalledExtension checkAlreadyInstalledExtension(
      String id, Version version, String namespace) throws ResolveException, InstallException {
    InstalledExtension installedExtension =
        this.installedExtensionRepository.getInstalledExtension(id, namespace);
    if (installedExtension != null) {
      if (getRequest().isVerbose()) {
        this.logger.debug(
            "Found already installed extension with id [{}]. Checking compatibility...", id);
      }

      if (version == null) {
        throw new InstallException(
            String.format("The extension with id [%s] is already installed", id));
      }

      int versionDiff = version.compareTo(installedExtension.getId().getVersion());

      if (versionDiff == 0) {
        throw new InstallException(
            String.format("The extension [%s-%s] is already installed", id, version));
      } else {
        // Change version
        InstalledExtension previousExtension = installedExtension;

        // Make sure the new version is compatible with old version backward dependencies
        if (installedExtension.isInstalled(null)) {
          Map<String, Collection<InstalledExtension>> backwardDependencies =
              this.installedExtensionRepository.getBackwardDependencies(installedExtension.getId());

          if (!isCompatible(backwardDependencies.get(null), id, version)) {
            throw new InstallException(
                String.format(
                    "The extension [%s-%s] is not compatible with previous version ([%s]) backward dependencies",
                    id, version, installedExtension.getId()));
          }

          if (namespace != null) {
            if (!isCompatible(backwardDependencies.get(namespace), id, version)) {
              throw new InstallException(
                  String.format(
                      "The extension [%s-%s] is not compatible with previous version ([%s]) backward dependencies on namespace [%s]",
                      id, version, installedExtension.getId(), namespace));
            }
          }
        } else {
          Collection<InstalledExtension> backwardDependencies =
              this.installedExtensionRepository.getBackwardDependencies(
                  installedExtension.getId().getId(), namespace);

          if (!isCompatible(backwardDependencies, id, version)) {
            throw new InstallException(
                String.format(
                    "The extension [%s-%s] is not compatible with previous version ([%s]) backward dependencies on namespace [%s]",
                    id, version, installedExtension.getId(), namespace));
          }
        }

        return previousExtension;
      }
    }

    return null;
  }