package org.jbehave.eclipse.editor.step;
import static fj.data.List.iterableList;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.jbehave.eclipse.Activator;
import org.jbehave.eclipse.JBehaveProject;
import org.jbehave.eclipse.editor.JDTUtils;
import org.jbehave.eclipse.util.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fj.Ord;
public class StepLocator {
private static Logger log = LoggerFactory.getLogger(StepLocator.class);
private JBehaveProject project;
public StepLocator(JBehaveProject project) {
this.project = project;
}
static boolean findCandidatesCheckStepType = true;
/**
* Finds the step candidates starting with a given text, ordered by their
* weight
*/
public Iterable<WeightedStep> findCandidatesStartingWith(final String step) {
log.debug("Finding candidates starting with <{}>", step);
try {
LocalizedStepSupport localizedStepSupport = project
.getLocalizedStepSupport();
final String searchedType = StepSupport.stepType(
localizedStepSupport, step);
final String stepWithoutKeyword = StepSupport.stepWithoutKeyword(
localizedStepSupport, step);
Visitor<StepCandidate, WeightedStep> findOne = new Visitor<StepCandidate, WeightedStep>() {
@Override
public void visit(StepCandidate candidate) {
boolean sameType = candidate.isTypeEqualTo(searchedType);
if (findCandidatesCheckStepType && !sameType) {
return;
}
if (StringUtils.isBlank(stepWithoutKeyword) && sameType) {
add(new WeightedStep(candidate, 0.1f));
return;
}
float weight = candidate.weightOf(stepWithoutKeyword);
if (weight > 0) {
add(new WeightedStep(candidate, weight));
} else {
// Activator.logInfo(">> Step (" + weight +
// ") rejected: " + candidate);
}
}
};
traverseSteps(findOne);
ConcurrentLinkedQueue<WeightedStep> elements = findOne
.getElementsFound();
log.debug("Candidates starting with <{}> found: #{}", step,
elements.size());
return elements;
} catch (JavaModelException e) {
log.error("Failed to find candidates for step <" + step + ">", e);
Activator.logError("Failed to find candidates for step <" + step
+ ">", e);
}
return null;
}
/**
* Returns the first {@link StepCandidate} found that match the step,
* ordered by priority. Be careful that there can be several other
* {@link StepCandidate}s that fulfill the step too.
*
* @param stepWithoutKeyword
* the step to match without keyword
* @return A StepCandidate
*/
public StepCandidate findFirstMatchingCandidate(
final String stepWithoutKeyword) {
log.debug("Finding the first step candidate matching <{}>",
stepWithoutKeyword);
try {
Visitor<StepCandidate, StepCandidate> matchingStepVisitor = new Visitor<StepCandidate, StepCandidate>() {
@Override
public void visit(StepCandidate candidate) {
boolean matches = candidate.matches(stepWithoutKeyword);
if (matches) {
add(candidate);
}
}
};
traverseSteps(matchingStepVisitor);
StepCandidate found = firstCandidateWithHighestPriority(matchingStepVisitor
.getElementsFound());
if (found == null) {
log.debug("No candidate found matching <{}>",
stepWithoutKeyword);
return null;
} else {
log.debug("First candidate matching <{}> found: <{}>",
stepWithoutKeyword, found.stepPattern);
return found;
}
} catch (JavaModelException e) {
log.error("Failed to find candidates for step <"
+ stepWithoutKeyword + ">", e);
Activator.logError("Failed to find candidates for step <"
+ stepWithoutKeyword + ">", e);
}
return null;
}
private StepCandidate firstCandidateWithHighestPriority(
Iterable<StepCandidate> candidates) {
fj.data.List<Integer> priorities = iterableList(candidates).map(
new TransformByPriority());
if (priorities.isEmpty()) {
return null;
}
final int maxPriority = priorities.maximum(Ord.intOrd);
fj.data.List<StepCandidate> candidatesByPriority = iterableList(
candidates).filter(new FilterByPriority(maxPriority));
return candidatesByPriority.head();
}
public IJavaElement findMethod(final String step) {
log.debug("Finding method for step <{}>", step);
StepCandidate stepCandidate = findFirstMatchingCandidate(step);
if (stepCandidate != null) {
log.debug("Method found for step <{}>: <{}>", step,
stepCandidate.method);
return stepCandidate.method;
} else {
log.debug("No method found for <{}>", step);
return null;
}
}
public IJavaElement findMethodByQualifiedName(final String qualifiedName) {
log.debug("Finding method using its qualified name <{}>", qualifiedName);
try {
Visitor<StepCandidate, StepCandidate> findOne = new Visitor<StepCandidate, StepCandidate>() {
@Override
public void visit(StepCandidate candidate) {
if (JDTUtils.formatQualifiedName(candidate.method).equals(
qualifiedName)) {
add(candidate);
done();
}
}
};
traverseSteps(findOne);
StepCandidate first = findOne.getFirst();
if (first == null) {
log.debug("No method found using its qualified name <{}>",
qualifiedName);
return null;
}
log.debug("Found method using its qualified name <{}>, got: {}",
qualifiedName, first.method);
return first.method;
} catch (JavaModelException e) {
Activator.logError("Failed to find candidates for method <"
+ qualifiedName + ">", e);
}
return null;
}
public void traverseSteps(Visitor<StepCandidate, ?> visitor)
throws JavaModelException {
log.debug("Traversing steps with: {}", visitor.getClass());
project.traverseSteps(visitor);
}
}