| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2007 IBM Corporation and others. |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // which accompanies this distribution, and is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // Contributors: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.library.edit.validation; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.epf.library.edit.util.TngUtil; |
| import org.eclipse.epf.uma.Activity; |
| import org.eclipse.epf.uma.CustomCategory; |
| import org.eclipse.epf.uma.Deliverable; |
| import org.eclipse.epf.uma.MethodElement; |
| import org.eclipse.epf.uma.MethodPlugin; |
| import org.eclipse.epf.uma.VariabilityElement; |
| import org.eclipse.epf.uma.VariabilityType; |
| import org.eclipse.epf.uma.util.AssociationHelper; |
| |
| /** |
| * This class handles plugin dependency info for circular dependency check |
| * |
| * @author Weiping Lu |
| * @since 1.2 |
| */ |
| public class PluginDepInfo { |
| |
| private PluginDependencyInfoMgr mgr; |
| private MethodPlugin plugin; |
| private HashMap parentMap; |
| private boolean complete = false; |
| private boolean debug = false; |
| |
| protected PluginDepInfo(PluginDependencyInfoMgr mgr, MethodPlugin plugin) { |
| this.mgr = mgr; |
| this.plugin = plugin; |
| } |
| |
| public boolean isComplete() { |
| return complete; |
| } |
| |
| public void build(boolean checkCircular) { |
| if (debug) { |
| System.out.println("LD> build: " + this); //$NON-NLS-1$ |
| } |
| buildInner(checkCircular); |
| } |
| |
| private void buildInner(boolean checkCircular) { |
| Object info = mgr.getProcessedInfo(getPlugin()); |
| if (info != null) { |
| if (info == this && complete) { |
| return; |
| } |
| throw new RuntimeException("Internal error in buildInner: " + info); //$NON-NLS-1$ |
| } |
| mgr.addToProcessed(this); |
| if (debug) { |
| System.out.println("LD> buildInner: " + this); //$NON-NLS-1$ |
| System.out.println(""); //$NON-NLS-1$ |
| } |
| buildInner_(checkCircular); |
| } |
| |
| private void buildInner_(boolean checkCircular) { |
| List parents = getPlugin().getBases(); |
| int sz = parents == null ? 0 : parents.size(); |
| if (sz == 0) { |
| complete = true; |
| return; |
| } |
| |
| parentMap = new HashMap(); |
| List processedParents = null; |
| for (int i = 0; i< sz; i++) { |
| MethodPlugin parentElem = (MethodPlugin) parents.get(i); |
| PluginDepInfo pinfo = (PluginDepInfo) mgr.getProcessedInfo(parentElem); |
| if (pinfo == null){ |
| pinfo = new PluginDepInfo(mgr, parentElem); |
| parentMap.put(parentElem.getGuid(), pinfo); |
| pinfo.buildInner(checkCircular); |
| } else { |
| parentMap.put(parentElem.getGuid(), pinfo); |
| if (checkCircular) { |
| if (processedParents == null) { |
| processedParents = new ArrayList(); |
| } |
| processedParents.add(pinfo); |
| } |
| } |
| } |
| complete = true; |
| |
| if (checkCircular && processedParents != null) { |
| for (int i=0; i<processedParents.size(); i++) { |
| reachableBy((PluginDepInfo) processedParents.get(i)); |
| } |
| } |
| } |
| |
| public boolean reachableBy(PluginDepInfo info) { |
| if (! (info instanceof PluginDepInfo)) { |
| throw new UnsupportedOperationException(); |
| } |
| if (debug) { |
| System.out.println("LD> Entry reachableBy: this -> " + this); //$NON-NLS-1$ |
| System.out.println("LD> Entry reachableBy: info -> " + info); //$NON-NLS-1$ |
| System.out.println(""); //$NON-NLS-1$ |
| } |
| return reachableBy((PluginDepInfo) info, new Stack(), new HashMap()); |
| } |
| |
| private boolean reachableBy(PluginDepInfo info, Stack stack, Map seen) { |
| stack.push(info); |
| if (debug) { |
| System.out.println("LD> reachableBy: this -> " + this); //$NON-NLS-1$ |
| System.out.println("LD> reachableBy: info -> " + info); //$NON-NLS-1$ |
| System.out.println(""); //$NON-NLS-1$ |
| } |
| boolean ret = reachableBy_(info, stack, seen); |
| stack.pop(); |
| return ret; |
| } |
| |
| private boolean reachableBy_(PluginDepInfo info, Stack stack, Map seen) { |
| Map testMap = info.parentMap; |
| if (testMap == null || testMap.isEmpty()) { |
| return false; |
| } |
| |
| if (testMap.containsKey(getPlugin().getGuid())) { |
| if (debug) { |
| System.out.println("LD> Contained in parentMap of: " + info); //$NON-NLS-1$ //$NON-NLS-1$ |
| } |
| stack.push(this); |
| mgr.logCircularDependency((Stack) stack.clone()); |
| stack.pop(); |
| return true; |
| } |
| |
| if (seen.containsKey(info.getPlugin().getGuid())) { |
| return false; |
| } |
| |
| |
| seen.put(info.getPlugin().getGuid(), info); |
| |
| for (Iterator it = testMap.values().iterator(); it.hasNext();) { |
| PluginDepInfo parentInfo = (PluginDepInfo) it.next(); |
| if (parentInfo.containedIn(stack)) { |
| if (debug) { |
| System.out.println("LD> containedIn stack: " + info); //$NON-NLS-1$ //$NON-NLS-1$ |
| } |
| stack.push(parentInfo); |
| mgr.logCircularDependency((Stack) stack.clone()); |
| stack.pop(); |
| return true; |
| } |
| if (reachableBy(parentInfo, stack, seen)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| public MethodPlugin getPlugin() { |
| return plugin; |
| } |
| |
| public String toString() { |
| return TngUtil.getLabelWithPath(plugin); |
| } |
| |
| //This would scale up for performance when infoList gets large |
| private boolean containedIn(List infoList) { |
| int sz = infoList == null ? 0 : infoList.size(); |
| if (sz == 0) { |
| return false; |
| } |
| String guid = getPlugin().getGuid(); |
| if (sz == 1) { |
| return guid.equals(((PluginDepInfo) infoList.get(0)).getPlugin().getGuid()); |
| } |
| Map listMap = new HashMap(); |
| for (int i=0; i<sz; i++) { |
| PluginDepInfo info = (PluginDepInfo) infoList.get(i); |
| listMap.put(info.getPlugin().getGuid(), info); |
| } |
| |
| return listMap.containsKey(guid); |
| } |
| |
| } |