/*******************************************************************************
* Copyright (c) 2007, 2010 Spring IDE Developers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.aop.ui.matcher.internal;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.search.ui.ISearchQuery;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.text.Match;
import org.springframework.ide.eclipse.aop.core.internal.model.AopReference;
import org.springframework.ide.eclipse.aop.core.internal.model.builder.AspectDefinitionMatcher;
import org.springframework.ide.eclipse.aop.core.model.IAopReference;
import org.springframework.ide.eclipse.aop.core.model.IAspectDefinition;
import org.springframework.ide.eclipse.aop.core.model.IAopReference.ADVICE_TYPE;
import org.springframework.ide.eclipse.aop.ui.matcher.PointcutMatcherPlugin;
import org.springframework.ide.eclipse.beans.core.internal.model.BeansModelUtils;
import org.springframework.ide.eclipse.beans.core.model.IBean;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.core.MessageUtils;
import org.springframework.ide.eclipse.core.java.ClassUtils;
import org.springframework.ide.eclipse.core.java.IProjectClassLoaderSupport;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springframework.ide.eclipse.core.model.IModelElement;
import org.springframework.ide.eclipse.core.model.IModelElementVisitor;
import org.springframework.util.Assert;
/**
* {@link ISearchQuery} implementation matches pointcut expression on {@link IBeansConfig}s that are contained in the
* given scope.
* @author Christian Dupuis
* @since 2.0.2
*/
public class PointcutMatchQuery implements ISearchQuery {
private static class PointcutDefinition implements IAspectDefinition {
private final boolean isProxyTargetClass;
private final String expression;
public PointcutDefinition(boolean isProxyTargetClass, String expression) {
this.isProxyTargetClass = isProxyTargetClass;
this.expression = expression;
}
public Method getAdviceMethod() {
return null;
}
public String getAdviceMethodName() {
return null;
}
public String[] getAdviceMethodParameterTypes() {
return null;
}
public String[] getArgNames() {
return null;
}
public String getAspectClassName() {
return null;
}
public int getAspectEndLineNumber() {
return 0;
}
public String getAspectName() {
return null;
}
public int getAspectStartLineNumber() {
return 0;
}
public String getPointcutExpression() {
return expression;
}
public IResource getResource() {
return null;
}
public String getReturning() {
return null;
}
public String getThrowing() {
return null;
}
public ADVICE_TYPE getType() {
return null;
}
public boolean isProxyTargetClass() {
return isProxyTargetClass;
}
public void setResource(IResource file) {
}
}
private PointcutMatcherScope scope;
private String expression;
private ISearchResult result;
private boolean isProxyTragetClass;
public PointcutMatchQuery(PointcutMatcherScope scope, String pattern, boolean isProxyTragetClass) {
Assert.notNull(scope);
this.scope = scope;
this.expression = pattern;
this.isProxyTragetClass = isProxyTragetClass;
}
public boolean canRerun() {
return true;
}
public boolean canRunInBackground() {
return true;
}
private IProjectClassLoaderSupport getClassLoaderSupport(IProject project) {
return JdtUtils.getProjectClassLoaderSupport(project, null);
}
public String getExpression() {
return expression;
}
public String getLabel() {
return PointcutMatcherMessages.MatcherQuery_label;
}
private Set<IAopReference> getMatches(Set<IBean> beans, IAspectDefinition definition,
AspectDefinitionMatcher matcher) {
Set<IAopReference> references = new HashSet<IAopReference>();
for (IBean bean : beans) {
IProject project = bean.getElementResource().getProject();
if (!bean.isInfrastructure()) {
String className = BeansModelUtils.getBeanClass(bean, null);
try {
Class<?> targetClass = ClassUtils.loadClass(className);
Set<IMethod> matchingMethods = matcher.matches(targetClass, bean, definition, project);
for (IMethod method : matchingMethods) {
IAopReference ref = new AopReference(definition.getType(), null, -1, method, JdtUtils
.getLineNumber(method), definition, bean.getElementResource(), bean);
references.add(ref);
}
}
catch (Throwable e) {
}
}
}
return references;
}
public PointcutMatcherScope getScope() {
return scope;
}
public final ISearchResult getSearchResult() {
if (result == null) {
result = new PointcutMatcherResult(this);
}
return result;
}
public final IStatus run(final IProgressMonitor monitor) {
final PointcutMatcherResult result = (PointcutMatcherResult) getSearchResult();
result.removeAll();
final IAspectDefinition definition = new PointcutDefinition(isProxyTragetClass, expression);
for (final IModelElement element : scope.getModelElements()) {
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
final IModelElementVisitor visitor = new IModelElementVisitor() {
public boolean visit(final IModelElement element, IProgressMonitor monitor) {
if (element instanceof IBeansConfig) {
final IBeansConfig config = (IBeansConfig) element;
monitor.beginTask("Matching pointcut in file ["
+ config.getElementResource().getProjectRelativePath().toString() + "]", 100);
IProject project = config.getElementResource().getProject();
try {
// get beans before messing around with the class
// loader
final Set<IBean> beans = BeansModelUtils.getBeans(config);
getClassLoaderSupport(project).executeCallback(
new IProjectClassLoaderSupport.IProjectClassLoaderAwareCallback() {
public void doWithActiveProjectClassLoader() throws Throwable {
for (IAopReference reference : getMatches(beans, definition,
new AspectDefinitionMatcher())) {
Match match = new Match(reference, Match.UNIT_LINE, -1, -1);
result.addMatch(match);
}
}
});
}
catch (Throwable e) {
}
return false;
}
return true;
}
};
element.accept(visitor, monitor);
}
Object[] args = new Object[] { new Integer(result.getMatchCount()) };
String message = MessageUtils.format(PointcutMatcherMessages.MatcherQuery_status, args);
return new Status(IStatus.OK, PointcutMatcherPlugin.PLUGIN_ID, 0, message, null);
}
}