package org.testng.internal; import org.testng.ITestNGMethod; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; /** * This class wraps access to beforeGroups and afterGroups methods, * since they are passed around the various invokers and potentially * modified in different threads. * * @author Cedric Beust * @author Alexandru Popescu * @since 5.3 (Mar 2, 2006) */ public class ConfigurationGroupMethods implements Serializable { /** Use serialVersionUID for interoperability. */ private final static long serialVersionUID= 1660798519864898480L; /** The list of beforeGroups methods keyed by the name of the group */ private final Map> m_beforeGroupsMethods; /** The list of afterGroups methods keyed by the name of the group */ private final Map> m_afterGroupsMethods; /** The list of all test methods */ private final ITestNGMethod[] m_allMethods; /**A map that returns the last method belonging to the given group */ private Map> m_afterGroupsMap= null; public ConfigurationGroupMethods(ITestNGMethod[] allMethods, Map> beforeGroupsMethods, Map> afterGroupsMethods) { m_allMethods= allMethods; m_beforeGroupsMethods= beforeGroupsMethods; m_afterGroupsMethods= afterGroupsMethods; } public Map> getBeforeGroupsMethods() { return m_beforeGroupsMethods; } public Map> getAfterGroupsMethods() { return m_afterGroupsMethods; } /** * @return true if the passed method is the last to run for the group. * This method is used to figure out when is the right time to invoke * afterGroups methods. */ public synchronized boolean isLastMethodForGroup(String group, ITestNGMethod method) { // If we have more invocation to do, this is not the last one yet int invocationCount= method.getCurrentInvocationCount(); if(invocationCount < (method.getInvocationCount() * method.getParameterInvocationCount())) { return false; } // Lazy initialization since we might never be called if(m_afterGroupsMap == null) { m_afterGroupsMap= initializeAfterGroupsMap(); } List methodsInGroup= m_afterGroupsMap.get(group); if(null == methodsInGroup || methodsInGroup.isEmpty()) { return false; } methodsInGroup.remove(method); // Note: == is not good enough here as we may work with ITestNGMethod clones return methodsInGroup.isEmpty(); } private synchronized Map> initializeAfterGroupsMap() { Map> result= Maps.newHashMap(); for(ITestNGMethod m : m_allMethods) { String[] groups= m.getGroups(); for(String g : groups) { List methodsInGroup= result.get(g); if(null == methodsInGroup) { methodsInGroup= Lists.newArrayList(); result.put(g, methodsInGroup); } methodsInGroup.add(m); } } return result; } public synchronized void removeBeforeMethod(String group, ITestNGMethod method) { List methods= m_beforeGroupsMethods.get(group); if(methods != null) { Object success= methods.remove(method); if(success == null) { log("Couldn't remove beforeGroups method " + method + " for group " + group); } } else { log("Couldn't find any beforeGroups method for group " + group); } } private void log(String string) { Utils.log("ConfigurationGroupMethods", 2, string); } synchronized public Map> getBeforeGroupsMap() { return m_beforeGroupsMethods; } synchronized public Map> getAfterGroupsMap() { return m_afterGroupsMethods; } synchronized public void removeBeforeGroups(String[] groups) { for(String group : groups) { // log("Removing before group " + group); m_beforeGroupsMethods.remove(group); } } synchronized public void removeAfterGroups(Collection groups) { for(String group : groups) { // log("Removing before group " + group); m_afterGroupsMethods.remove(group); } } }