/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2012 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.extension.dependency; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * A extension dependency path result found when trying to resolve an install/update. * @author acostescu */ public class DependencyPath implements Serializable { /** true if this is a dependency path for an uninstall operation (in which case only installSequence and libChoices are meaningful), * and false if it's an install/replace path (in which case all members are meaningful) */ public final boolean uninstall; /** The list of extension/version nodes in this valid install/replace dependency path. It is not used for uninstall. */ public final transient ExtensionNode[] extensionPath; /** Any lib choices that must be made on this dependency path. Each lib choice is a list of conflicting/non-conflicting lib declarations with the same lib id but other versions. Can be null. */ public final LibChoice[] libChoices; public final InstallStep[] installSequence; /** * Creates a new INSTALL/REPLACE extension dependency path result. * @param extensionPath the list of extension/version nodes in this valid dependency path. * @param libChoices any lib choices found on this dependency path. A list of more then one conflicting/non-conflicting lib declarations with the same lib id that are affected by the INSTALL/REPLACE. Can be null. */ public DependencyPath(ExtensionNode[] extensionPath, LibChoice[] libChoices) { uninstall = false; this.extensionPath = extensionPath; this.libChoices = libChoices; ArrayList<InstallStep> installSeq = new ArrayList<InstallStep>(extensionPath.length * 2); computeInstallDep(extensionPath[0], installSeq); // at this time, all ExtensionNode children members are usable (valid search tree) installSequence = installSeq.toArray(new InstallStep[installSeq.size()]); } /** * Creates a new UNINSTALL extension dependency path result. * @param extensionPath the list of installed extensions that depend on the extension to be uninstalled. * @param libChoices the uninstall operation might have deleted some libs that extensions remaining installed might still need. In * this case, one of the remaining installed versions of that lib needs to be activated instead. Can be null. */ public DependencyPath(InstallStep[] uninstallSequence, LibChoice[] libChoices) { uninstall = true; installSequence = uninstallSequence; this.libChoices = libChoices; extensionPath = null; } protected void computeInstallDep(ExtensionNode node, List<InstallStep> installSeq) { if (node.resolveType != ExtensionNode.SIMPLE_DEPENDENCY_RESOLVE) { // recurse through reverse broken dependencies for uninstall for (ExtensionNode n : node.brokenDepChildren) { computeInverseBrokenDepUninstall(n, installSeq); } installSeq.add(new InstallStep(InstallStep.UNINSTALL, node)); } for (ExtensionNode n : node.depChildren) { computeInstallDep(n, installSeq); } installSeq.add(new InstallStep(InstallStep.INSTALL, node)); if (node.resolveType != ExtensionNode.SIMPLE_DEPENDENCY_RESOLVE) { for (ExtensionNode n : node.brokenDepChildren) { computeInverseBrokenDepInstall(n, installSeq); } } } protected void computeInverseBrokenDepUninstall(ExtensionNode node, List<InstallStep> installSeq) { for (ExtensionNode n : node.brokenDepChildren) { computeInverseBrokenDepUninstall(n, installSeq); } installSeq.add(new InstallStep(InstallStep.UNINSTALL, node)); } protected void computeInverseBrokenDepInstall(ExtensionNode node, List<InstallStep> installSeq) { for (ExtensionNode n : node.depChildren) { computeInstallDep(n, installSeq); } installSeq.add(new InstallStep(InstallStep.INSTALL, node)); for (ExtensionNode n : node.brokenDepChildren) { computeInverseBrokenDepInstall(n, installSeq); } } @Override @SuppressWarnings("nls") public String toString() { if (uninstall) { return "{ U OP, " + Arrays.asList(installSequence) + ", LIB Choices: " + (libChoices == null ? null : Arrays.asList(libChoices)) + "}"; } else { return "{ I/R OP, " + Arrays.asList(extensionPath) + ", LIB Choices: " + (libChoices == null ? null : Arrays.asList(libChoices)) + "}"; } } }