package org.jbehave.eclipse.editor.step;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IMemberValuePair;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaModelException;
import org.jbehave.core.annotations.Alias;
import org.jbehave.core.annotations.Aliases;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
import org.jbehave.core.steps.PatternVariantBuilder;
import org.jbehave.core.steps.StepType;
import org.jbehave.eclipse.cache.container.Containers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class takes IMethod instances, analyzes their annotations for JBehave
* related bindings and, if matching, creates StepCandidates to extend the
* collecting container.
*/
public class MethodToStepCandidateReducer {
private static final Logger log = LoggerFactory
.getLogger(MethodToStepCandidateReducer.class);
/**
* The simple names of the handled annotations
*/
private static final List<String> HANDLED_ANNOTATION_NAMES;
static {
HANDLED_ANNOTATION_NAMES = Arrays.asList(Given.class.getSimpleName(),
When.class.getSimpleName(), Then.class.getSimpleName(),
Alias.class.getSimpleName(), Aliases.class.getSimpleName());
}
/**
* Constructor
*/
public MethodToStepCandidateReducer() {
}
/**
* This method checks the method and reports a step candidate if it
* represents one.
*
* @param method
* the method to analyze
* @param listener
* for collecting results
* @throws JavaModelException
* at problems extracting model information
*/
public void reduce(final IMethod method,
final StepCandidateReduceListener listener)
throws JavaModelException {
StepType stepType = StepType.GIVEN;
for (final IAnnotation annotation : method.getAnnotations()) {
final String fullQualifiedName = getFullQualifiedName(annotation);
IMemberValuePair[] annotationAttributes = annotation
.getMemberValuePairs();
Integer priority = Integer.valueOf(0);
boolean basicStep = false;
List<String> patterns = new ArrayList<String>();
if (Given.class.getName().equals(fullQualifiedName)) {
stepType = StepType.GIVEN;
basicStep = true;
} else if (When.class.getName().equals(fullQualifiedName)) {
stepType = StepType.WHEN;
basicStep = true;
} else if (Then.class.getName().equals(fullQualifiedName)) {
stepType = StepType.THEN;
basicStep = true;
}
if (basicStep) {
String stepPattern = getValue(annotationAttributes, "value");
priority = getValue(annotationAttributes, "priority");
patterns = extractPatternVariants(patterns, stepPattern);
} else if (Aliases.class.getName().equals(fullQualifiedName)) {
Object aliases = getValue(annotationAttributes, "values");
if (aliases instanceof Object[]) {
for (Object o : (Object[]) aliases) {
if (o instanceof String) {
patterns = extractPatternVariants(patterns,
(String) o);
}
}
}
} else if (Alias.class.getName().equals(fullQualifiedName)) {
String stepPattern = getValue(annotationAttributes, "value");
patterns = extractPatternVariants(patterns, stepPattern);
}
if (!patterns.isEmpty()) {
log.debug("Analysing method: " + Containers.pathOf(method)
+ " found: " + patterns);
for (String stepPattern : patterns) {
listener.add(method, stepType, stepPattern, priority);
}
}
}
}
private String getFullQualifiedName(IAnnotation annotation) {
String elementName = annotation.getElementName();
StringBuilder fullQualifiedName = new StringBuilder();
boolean isQualified = elementName.indexOf('.') >= 0;
if (!isQualified
&& (HANDLED_ANNOTATION_NAMES.indexOf(elementName) >= 0)) {
// TODO check import declaration matches org.jbehave...
fullQualifiedName.append("org.jbehave.core.annotations.");
}
fullQualifiedName.append(elementName);
return fullQualifiedName.toString();
}
private List<String> extractPatternVariants(List<String> patterns,
final String pattern) {
PatternVariantBuilder b = new PatternVariantBuilder(pattern);
for (String variant : b.allVariants()) {
patterns.add(variant);
}
return patterns;
}
@SuppressWarnings("unchecked")
public static <T> T getValue(IMemberValuePair[] memberValuePairs, String key) {
for (IMemberValuePair kv : memberValuePairs) {
if (kv.getMemberName().equalsIgnoreCase(key))
return (T) kv.getValue();
}
return null;
}
}