@Override public Extension resolve(ExtensionDependency extensionDependency) throws ResolveException { return resolve( new ExtensionId( extensionDependency.getId(), new DefaultVersion(extensionDependency.getVersionConstraint().getValue()))); }
/** * Extract extension with the provided id from the provided extension. * * @param extension the extension * @param dependencyId the id of the dependency * @return the extension dependency or null if none has been found */ private ExtensionDependency getDependency(Extension extension, String dependencyId) { for (ExtensionDependency dependency : extension.getDependencies()) { if (dependency.getId().equals(dependencyId)) { return dependency; } } return null; }
/** * Install provided extension dependency. * * @param extensionDependency the extension dependency to install * @param namespace the namespace where to install the extension * @param parentBranch the children of the parent {@link DefaultExtensionPlanNode} * @throws InstallException error when trying to install provided extension */ private void installExtensionDependency( ExtensionDependency extensionDependency, String namespace, List<ModifableExtensionPlanNode> parentBranch) throws InstallException { if (getRequest().isVerbose()) { if (namespace != null) { this.logger.info( LOG_RESOLVEDEPENDENCY_NAMESPACE, "Resolving extension dependency [{}] on namespace [{}]", extensionDependency, namespace); } else { this.logger.info( LOG_RESOLVEDEPENDENCY, "Resolving extension dependency [{}] on all namespaces", extensionDependency); } } VersionConstraint versionConstraint = extensionDependency.getVersionConstraint(); // Make sure the dependency is not already a core extension if (checkCoreExtension(extensionDependency, parentBranch)) { // Already exists and added to the tree by #checkCoreExtension return; } // Make sure the dependency is not already in the current plan versionConstraint = checkExistingPlanNode(extensionDependency, namespace, parentBranch, versionConstraint); if (versionConstraint == null) { // Already exists and added to the tree by #checkExistingPlan return; } // Check installed extensions InstalledExtension previousExtension = this.installedExtensionRepository.getInstalledExtension( extensionDependency.getId(), namespace); ExtensionDependency targetDependency = checkInstalledExtension( previousExtension, extensionDependency, versionConstraint, namespace, parentBranch); if (targetDependency == null) { // Already exists and added to the tree by #checkInstalledExtension return; } // Not found locally, search it remotely ModifableExtensionPlanNode node = installExtension(previousExtension, targetDependency, true, namespace); node.versionConstraint = versionConstraint; addExtensionNode(node); parentBranch.add(node); }
/** * Check if provided id/version is compatible with provided extensions dependencies constraints. */ private boolean isCompatible( Collection<? extends Extension> extensions, String id, Version version) { if (extensions != null) { for (Extension extension : extensions) { for (ExtensionDependency dependency : extension.getDependencies()) { if (dependency.getId().equals(id)) { if (!dependency.getVersionConstraint().isCompatible(version)) { return false; } } } } } return true; }
private boolean checkCoreExtension( ExtensionDependency extensionDependency, List<ModifableExtensionPlanNode> parentBranch) throws InstallException { CoreExtension coreExtension = this.coreExtensionRepository.getCoreExtension(extensionDependency.getId()); if (coreExtension != null) { if (!extensionDependency .getVersionConstraint() .isCompatible(coreExtension.getId().getVersion())) { throw new InstallException( "Dependency [" + extensionDependency + "] is not compatible with core extension [" + coreExtension + "]"); } else { if (getRequest().isVerbose()) { this.logger.debug( "There is already a core extension [{}] covering extension dependency [{}]", coreExtension.getId(), extensionDependency); } ModifableExtensionPlanNode node = new ModifableExtensionPlanNode( extensionDependency, extensionDependency.getVersionConstraint()); node.setAction( new DefaultExtensionPlanAction(coreExtension, null, Action.NONE, null, true)); parentBranch.add(node); return true; } } return false; }
/** * @param extensions the extensions containing the dependencies for which to merge the constraints * @param dependencyId the id of the dependency * @param previousMergedVersionContraint if not null it's merged with the provided extension * dependencies version constraints * @return the merged version constraint * @throws IncompatibleVersionConstraintException the provided version constraint is compatible * with the provided version constraint */ private VersionConstraint mergeVersionConstraints( Collection<? extends Extension> extensions, String dependencyId, VersionConstraint previousMergedVersionContraint) throws IncompatibleVersionConstraintException { VersionConstraint mergedVersionContraint = previousMergedVersionContraint; if (extensions != null) { for (Extension extension : extensions) { ExtensionDependency dependency = getDependency(extension, dependencyId); if (dependency != null) { if (mergedVersionContraint == null) { mergedVersionContraint = dependency.getVersionConstraint(); } else { mergedVersionContraint = mergedVersionContraint.merge(dependency.getVersionConstraint()); } } } } return mergedVersionContraint; }
private VersionConstraint checkExistingPlanNode( ExtensionDependency extensionDependency, String namespace, List<ModifableExtensionPlanNode> parentBranch, VersionConstraint previousVersionConstraint) throws InstallException { VersionConstraint versionConstraint = previousVersionConstraint; ModifableExtensionPlanNode existingNode = getExtensionNode(extensionDependency.getId(), namespace); if (existingNode != null) { if (versionConstraint.isCompatible( existingNode.getAction().getExtension().getId().getVersion())) { ModifableExtensionPlanNode node = new ModifableExtensionPlanNode(extensionDependency, existingNode); addExtensionNode(node); parentBranch.add(node); return null; } else { if (existingNode.versionConstraint != null) { try { versionConstraint = versionConstraint.merge(existingNode.versionConstraint); } catch (IncompatibleVersionConstraintException e) { throw new InstallException( "Dependency [" + extensionDependency + "] is incompatible with current containt [" + existingNode.versionConstraint + "]", e); } } else { throw new InstallException( "Dependency [" + extensionDependency + "] incompatible with extension [" + existingNode.getAction().getExtension() + "]"); } } } return versionConstraint; }
private void guess( Map<String, DefaultCoreExtension> extensions, DefaultCoreExtensionRepository repository) { Set<ExtensionDependency> dependencies = new HashSet<ExtensionDependency>(); for (DefaultCoreExtension coreExtension : extensions.values()) { for (ExtensionDependency dependency : coreExtension.getDependencies()) { dependencies.add(dependency); } } // Normalize and guess Map<String, Object[]> fileNames = new HashMap<String, Object[]>(); Map<String, Object[]> guessedArtefacts = new HashMap<String, Object[]>(); Set<URL> urls = ClasspathHelper.forClassLoader(); for (URL url : urls) { try { String path = url.toURI().getPath(); String filename = path.substring(path.lastIndexOf('/') + 1); String type = null; int extIndex = filename.lastIndexOf('.'); if (extIndex != -1) { type = filename.substring(extIndex + 1); filename = filename.substring(0, extIndex); } int index; if (!filename.endsWith(SNAPSHOTSUFFIX)) { index = filename.lastIndexOf('-'); } else { index = filename.lastIndexOf('-', filename.length() - SNAPSHOTSUFFIX.length()); } if (index != -1) { fileNames.put(filename, new Object[] {url}); String artefactname = filename.substring(0, index); String version = filename.substring(index + 1); guessedArtefacts.put(artefactname, new Object[] {version, url, type}); } } catch (Exception e) { this.logger.warn("Failed to parse resource name [" + url + "]", e); } } // Try to resolve version no easy to find from the pom.xml try { for (DefaultCoreExtension coreExtension : extensions.values()) { String artifactId = getArtifactId(coreExtension); Object[] artefact = guessedArtefacts.get(artifactId); if (artefact != null) { if (coreExtension.getId().getVersion().getValue().charAt(0) == '$') { coreExtension.setId( new ExtensionId(coreExtension.getId().getId(), (String) artefact[0])); coreExtension.setGuessed(true); } if (coreExtension.getType().charAt(0) == '$') { coreExtension.setType((String) artefact[2]); coreExtension.setGuessed(true); } } } // Add dependencies that does not provide proper pom.xml resource and can't be found in the // classpath for (ExtensionDependency extensionDependency : dependencies) { Dependency dependency = (Dependency) extensionDependency.getProperty(MavenCoreExtensionDependency.PKEY_MAVEN_DEPENDENCY); if (dependency == null) { dependency = toDependency( extensionDependency.getId(), extensionDependency.getVersionConstraint().getValue(), null); } String dependencyId = dependency.getGroupId() + ':' + dependency.getArtifactId(); DefaultCoreExtension coreExtension = extensions.get(dependencyId); if (coreExtension == null) { String dependencyFileName = dependency.getArtifactId() + '-' + dependency.getVersion(); if (dependency.getClassifier() != null) { dependencyFileName += '-' + dependency.getClassifier(); dependencyId += ':' + dependency.getClassifier(); } Object[] filenameArtifact = fileNames.get(dependencyFileName); Object[] guessedArtefact = guessedArtefacts.get(dependency.getArtifactId()); if (filenameArtifact != null) { coreExtension = new DefaultCoreExtension( repository, (URL) filenameArtifact[0], new ExtensionId(dependencyId, dependency.getVersion()), packagingToType(dependency.getType())); coreExtension.setGuessed(true); } else if (guessedArtefact != null) { coreExtension = new DefaultCoreExtension( repository, (URL) guessedArtefact[1], new ExtensionId(dependencyId, (String) guessedArtefact[0]), packagingToType(dependency.getType())); coreExtension.setGuessed(true); } if (coreExtension != null) { extensions.put(dependencyId, coreExtension); } } } } catch (Exception e) { this.logger.warn("Failed to guess extra information about some extensions", e); } }
/** * @param previousExtension the previous installed version of the extension to install * @param extension the new extension to install * @param dependency indicate if the extension is installed as a dependency * @param namespace the namespace where to install the extension * @return the install plan node for the provided extension * @param initialDependency the initial dependency used to resolve the extension * @throws InstallException error when trying to install provided extension */ private ModifableExtensionPlanNode installExtension( InstalledExtension previousExtension, Extension extension, boolean dependency, String namespace, ExtensionDependency initialDependency) throws InstallException, ResolveException { // Is feature core extension for (String feature : extension.getFeatures()) { if (this.coreExtensionRepository.exists(feature)) { throw new InstallException( String.format("There is already a core extension with the id [%s]", feature)); } } // Find all previous version of the extension Set<InstalledExtension> previousExtensions = new LinkedHashSet<InstalledExtension>(); if (previousExtension != null) { previousExtensions.add(previousExtension); } if (!extension.getFeatures().isEmpty()) { for (String feature : extension.getFeatures()) { InstalledExtension installedExtension = checkAlreadyInstalledExtension(feature, extension.getId().getVersion(), namespace); if (installedExtension != null) { previousExtensions.add(installedExtension); } } } ExtensionHandler extensionHandler; // Is type supported ? try { extensionHandler = this.componentManager.getInstance(ExtensionHandler.class, extension.getType()); } catch (ComponentLookupException e) { throw new InstallException(String.format("Unsupported type [%s]", extension.getType()), e); } // Is installing the extension allowed ? extensionHandler.checkInstall(extension, namespace, getRequest()); // Check dependencies Collection<? extends ExtensionDependency> dependencies = extension.getDependencies(); notifyPushLevelProgress(dependencies.size() + 1); try { List<ModifableExtensionPlanNode> children = null; if (!dependencies.isEmpty()) { children = new ArrayList<ModifableExtensionPlanNode>(); for (ExtensionDependency dependencyDependency : extension.getDependencies()) { installExtensionDependency(dependencyDependency, namespace, children); notifyStepPropress(); } } ModifableExtensionPlanNode node = initialDependency != null ? new ModifableExtensionPlanNode( initialDependency, initialDependency.getVersionConstraint()) : new ModifableExtensionPlanNode(); node.setChildren(children); Action action; if (!previousExtensions.isEmpty()) { if (previousExtensions .iterator() .next() .getId() .getVersion() .compareTo(extension.getId().getVersion()) > 0) { action = Action.DOWNGRADE; } else { action = Action.UPGRADE; } } else { action = Action.INSTALL; } node.setAction( new DefaultExtensionPlanAction( extension, previousExtensions, action, namespace, dependency)); return node; } finally { notifyPopLevelProgress(); } }
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; }