package com.anjlab.eclipse.tapestry5.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; import com.anjlab.eclipse.tapestry5.EclipseUtils; import com.anjlab.eclipse.tapestry5.TapestryModule; import com.anjlab.eclipse.tapestry5.TapestryService.Matcher; import com.anjlab.eclipse.tapestry5.TapestryUtils; public class DeclarationCapturingScope { public static class Declaration { public final String name; public final String className; public final ASTNode node; public Declaration(ASTNode node, String name, String className) { this.name = name; this.className = className; this.node = node; } } public static class InjectedDeclaration extends Declaration { public final IType type; public InjectedDeclaration(ASTNode node, String name, String className, IType type) { super(node, name, className); this.type = type; } public InjectedDeclaration(Declaration declaration, IType type) { this(declaration.node, declaration.name, declaration.className, type); } public Matcher createMatcher(final TapestryModule module) { final AtomicReference<String> serviceId = new AtomicReference<String>(); final List<String> markers = new ArrayList<String>(); node.accept(new ASTVisitor() { @Override public boolean visit(NormalAnnotation node) { if (TapestryUtils.isAnnotationEquals( node, TapestryUtils.ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_INJECT_SERVICE)) { List<?> values = node.values(); for (Object value : values) { if (value instanceof MemberValuePair) { MemberValuePair pair = (MemberValuePair) value; if ("value".equals(pair.getName().getIdentifier())) { serviceId.set( EclipseUtils.evalExpression( module.getEclipseProject(), pair.getValue())); } } else { serviceId.set( EclipseUtils.evalExpression( module.getEclipseProject(), value)); } } } return super.visit(node); } @Override public boolean visit(MarkerAnnotation node) { if (TapestryUtils.isAnnotationEquals( node, TapestryUtils.ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_INJECT)) { // @Inject is not a service marker return super.visit(node); } try { markers.add( EclipseUtils.resolveTypeName( module.getModuleClass(), node.getTypeName().getFullyQualifiedName())); } catch (JavaModelException e) { // Ignore } return super.visit(node); } }); AndMatcher matcher = new AndMatcher(); matcher.add(new ServiceIntfMatcher(className)); if (StringUtils.isNotEmpty(serviceId.get())) { matcher.add(new IdentityIdMatcher(serviceId.get())); } for (String marker : markers) { matcher.add(new MarkerMatcher(marker)); } return matcher; } public boolean isServiceInjection() { final AtomicBoolean foundSymbolAnnotation = new AtomicBoolean(false); node.accept(new ASTVisitor() { @Override public boolean visit(NormalAnnotation node) { if (TapestryUtils.isAnnotationEquals( node, TapestryUtils.ORG_APACHE_TAPESTRY5_IOC_ANNOTATIONS_SYMBOL)) { foundSymbolAnnotation.set(true); } return super.visit(node); } }); return !foundSymbolAnnotation.get(); } } private Stack<Map<String, Declaration>> scopes = new Stack<Map<String, Declaration>>(); public DeclarationCapturingScope() { enterScope(); } public void enterScope() { scopes.push(new HashMap<String, Declaration>()); } public void exitScope() { scopes.pop(); } public void add(Declaration declaration) { scopes.peek().put(declaration.name, declaration); } public Declaration findClosest(String name) { for (int i = scopes.size() - 1; i >= 0; i--) { Map<String, Declaration> scope = scopes.get(i); Declaration declaration = scope.get(name); if (declaration != null) { return declaration; } } return null; } }