1package org.testng.internal;
2
3import java.lang.reflect.Modifier;
4import java.util.Iterator;
5import java.util.List;
6import java.util.Map;
7
8import org.testng.IInstanceInfo;
9import org.testng.ITestContext;
10import org.testng.ITestNGMethod;
11import org.testng.TestNGException;
12import org.testng.collections.Lists;
13import org.testng.collections.Maps;
14import org.testng.internal.annotations.IAnnotationFinder;
15import org.testng.xml.XmlTest;
16
17/**
18 * This class represents a method annotated with @Factory
19 *
20 * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
21 */
22public class FactoryMethod extends BaseTestMethod {
23  /**
24   *
25   */
26  private static final long serialVersionUID = -7329918821346197099L;
27  private Object m_instance = null;
28  private XmlTest m_xmlTest = null;
29  private ITestContext m_testContext = null;
30
31  public FactoryMethod(ConstructorOrMethod com,
32                       Object instance,
33                       XmlTest xmlTest,
34                       IAnnotationFinder annotationFinder,
35                       ITestContext testContext)
36  {
37    super(com.getName(), com, annotationFinder, instance);
38    Utils.checkInstanceOrStatic(instance, com.getMethod());
39    Utils.checkReturnType(com.getMethod(), Object[].class, IInstanceInfo[].class);
40    Class<?> declaringClass = com.getDeclaringClass();
41    if (instance != null && ! declaringClass.isAssignableFrom(instance.getClass())) {
42      throw new TestNGException("Mismatch between instance/method classes:"
43          + instance.getClass() + " " + declaringClass);
44    }
45    if (instance == null && com.getMethod() != null && !Modifier.isStatic(com.getMethod().getModifiers())) {
46      throw new TestNGException("An inner factory method MUST be static. But '" + com.getMethod().getName() + "' from '" + declaringClass.getName() + "' is not.");
47    }
48    if (com.getMethod() != null && !Modifier.isPublic(com.getMethod().getModifiers())) {
49      try {
50        com.getMethod().setAccessible(true);
51      } catch (SecurityException e) {
52        throw new TestNGException(e);
53      }
54    }
55
56    m_instance = instance;
57    m_xmlTest = xmlTest;
58    m_testContext = testContext;
59    NoOpTestClass tc = new NoOpTestClass();
60    tc.setTestClass(declaringClass);
61    m_testClass = tc;
62  }
63
64  private static void ppp(String s) {
65    System.out.println("[FactoryMethod] " + s);
66  }
67
68  public Object[] invoke() {
69    List<Object> result = Lists.newArrayList();
70
71    Map<String, String> allParameterNames = Maps.newHashMap();
72    Iterator<Object[]> parameterIterator =
73      Parameters.handleParameters(this,
74          allParameterNames,
75          m_instance,
76          new Parameters.MethodParameters(m_xmlTest.getAllParameters(),
77              findMethodParameters(m_xmlTest),
78              null, null, m_testContext,
79              null /* testResult */),
80          m_xmlTest.getSuite(),
81          m_annotationFinder,
82          null /* fedInstance */).parameters;
83
84    try {
85      while (parameterIterator.hasNext()) {
86        Object[] parameters = parameterIterator.next();
87        Object[] testInstances;
88        ConstructorOrMethod com = getConstructorOrMethod();
89        if (com.getMethod() != null) {
90          testInstances = (Object[]) getMethod().invoke(m_instance, parameters);
91          for (Object testInstance : testInstances) {
92            result.add(testInstance);
93          }
94        } else {
95          Object instance = com.getConstructor().newInstance(parameters);
96          result.add(instance);
97        }
98      }
99    }
100    catch (Throwable t) {
101      ConstructorOrMethod com = getConstructorOrMethod();
102      throw new TestNGException("The factory method "
103          + com.getDeclaringClass() + "." + com.getName()
104          + "() threw an exception", t);
105    }
106
107    return result.toArray(new Object[result.size()]);
108  }
109
110  @Override
111  public ITestNGMethod clone() {
112    throw new IllegalStateException("clone is not supported for FactoryMethod");
113  }
114}
115