//------------------------------------------------------------------------------ // 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.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.epf.common.utils.ProfilingUtil; import org.eclipse.epf.library.edit.LibraryEditPlugin; import org.eclipse.epf.library.edit.LibraryEditResources; import org.eclipse.epf.library.edit.util.TngUtil; import org.eclipse.epf.uma.MethodElement; import org.eclipse.epf.uma.MethodLibrary; import org.eclipse.epf.uma.MethodPlugin; /** * This class manages circular dependency info for plugins. * * @author Weiping Lu * @since 1.2 */ public class PluginDependencyInfoMgr { private static boolean profiling = false; private static boolean debug = false; private MethodLibrary lib; private Map processed; private List circularList; public PluginDependencyInfoMgr(MethodLibrary lib) { this.lib = lib; } public void logCircularDependency(Stack trace) { if (circularList == null) { circularList = new ArrayList(); } circularList.addAll(trace); } private List getAndClearCircularList() { List ret = circularList; circularList = null; return ret; } private void log(String msg) { LibraryEditPlugin.INSTANCE.log(msg); } private PluginDepInfo registerPlugin(MethodPlugin plugin, boolean checkCircular) { PluginDepInfo info = getProcessedInfo(plugin); if (info == null) { info = new PluginDepInfo(this, plugin); } if (! info.isComplete()) { info.build(checkCircular); } return info; } public IStatus checkCircularDependnecy(MethodPlugin plugin) { if (debug) { System.out.println("LD> plugin: " + TngUtil.getLabelWithPath(plugin)); //$NON-NLS-1$ } PluginDepInfo info = registerPlugin(plugin, true); List cirList = getAndClearCircularList(); boolean loop = cirList != null && !cirList.isEmpty(); if (loop) { log("Error> Circular dependency detected: "); //$NON-NLS-1$ for (int i=0; i<cirList.size(); i++) { PluginDepInfo loopInfo = (PluginDepInfo) cirList.get(i); MethodElement elem = loopInfo.getPlugin(); log("Error> " + i + ": " + TngUtil.getLabelWithPath(elem));//$NON-NLS-1$ //$NON-NLS-2$ } log(""); //$NON-NLS-1$ return new ValidationStatus(IStatus.ERROR, 0, genErrorMsg(cirList), plugin, null); } return Status.OK_STATUS; } private String genErrorMsg(List cirList) { String msg = LibraryEditResources.variability_element_circular_loop_error_msg; for (int i=0; i<cirList.size(); i++) { PluginDepInfo loopInfo = (PluginDepInfo) cirList.get(i); MethodElement elem = loopInfo.getPlugin(); if (i > 0) { msg += ": "; //$NON-NLS-1$ } msg += TngUtil.getLabelWithPath(elem); } return msg; } protected boolean processed(MethodPlugin plugin) { return processed != null && processed.containsKey(plugin.getGuid()); } protected PluginDepInfo getProcessedInfo(MethodPlugin plugin) { return processed == null ? null : (PluginDepInfo) processed.get(plugin.getGuid()); } protected void addToProcessed(PluginDepInfo info) { if (processed == null) { processed = new HashMap(); } processed.put(info.getPlugin().getGuid(), info); } /* * Check circular dependency among the plugins of the library. */ public CheckResult checkCircularDependnecy(Tracer tracer, boolean accumErrors) { if (tracer == null) { tracer = new Tracer() { public void trace(String line) {} }; } long usedMem0 = 0; Runtime rt = Runtime.getRuntime(); if (profiling) { for (Iterator it = lib.eAllContents(); it.hasNext();) { it.next(); } ProfilingUtil.fullGC(); usedMem0 = rt.totalMemory() - rt.freeMemory(); } CheckResult result = checkCircularDependnecy_(tracer, accumErrors); if (profiling) { ProfilingUtil.fullGC(); System.out.println("LD> usedMem0: " + usedMem0/1000 + " k bytes"); //$NON-NLS-1$ //$NON-NLS-2$ long usedMem1 = rt.totalMemory() - rt.freeMemory(); System.out.println("LD> usedMem1: " + usedMem1/1000 + " k bytes"); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println("LD> diffMem: " + (usedMem1 - usedMem0)/1000 + " k bytes"); //$NON-NLS-1$ //$NON-NLS-2$ } return result; } private CheckResult checkCircularDependnecy_(Tracer tracer, boolean accumErrors) { CheckResult result = new CheckResult(); List plugins = lib.getMethodPlugins(); for (Iterator it = plugins.iterator(); it.hasNext();) { MethodPlugin plugin = (MethodPlugin) it.next(); PluginDepInfo info = registerPlugin(plugin, true); List cirList = getAndClearCircularList(); boolean loop = cirList != null && !cirList.isEmpty(); if (loop) { tracer.trace("Error> Circular dependency detected: "); //$NON-NLS-1$ for (int i=0; i<cirList.size(); i++) { PluginDepInfo loopInfo = (PluginDepInfo) cirList.get(i); MethodElement elem = loopInfo.getPlugin(); tracer.trace("Error> " + i + ": " + TngUtil.getLabelWithPath(elem));//$NON-NLS-1$ //$NON-NLS-2$ } result.circularList.add(cirList); if (! accumErrors) { return result; } } } return result; } public static class CheckResult { public List circularList = new ArrayList(); public int getErrorCount() { return circularList.size(); } } }