/*
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.dsl.pointcuts.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.eclipse.dsl.pointcuts.AbstractPointcut;
import org.codehaus.groovy.eclipse.dsl.pointcuts.GroovyDSLDContext;
import org.codehaus.groovy.eclipse.dsl.pointcuts.IPointcut;
import org.codehaus.groovy.eclipse.dsl.pointcuts.PointcutVerificationException;
import org.eclipse.core.resources.IStorage;
/**
* An abstract pointcut that filters the value of {@link GroovyDSLDContext#getOuterPointcutBinding()}.
*
* You can think of the filter pointcut as taking a set of things from the outer pointcut, and
* either sending it to the inner pointcut, which will do its own filter, or performing a filter
* using its argument.
*
* @author andrew
* @created Feb 11, 2011
*/
public abstract class FilteringPointcut<T> extends AbstractPointcut {
private final Class<T> filterBy;
public FilteringPointcut(IStorage containerIdentifier, String pointcutName, Class<T> filterBy) {
super(containerIdentifier, pointcutName);
this.filterBy = filterBy;
}
@Override
public Collection<?> matches(GroovyDSLDContext pattern, Object toMatch) {
Collection<T> explodedList = explodeObject(toMatch);
if (explodedList != null && !explodedList.isEmpty()) {
Object first = getFirstArgument();
if (first instanceof IPointcut) {
// pass the exploded list to the inner pointcut and match on each element of the list
return matchOnPointcutArgument((IPointcut) first, pattern, explodedList);
} else {
Collection<?> filtered = filterResult(explodedList, pattern);
if (filtered != null) {
return filtered;
}
}
}
return null;
}
protected Collection<?> filterResult(Collection<T> results, GroovyDSLDContext context) {
Object o = getFirstArgument();
String firstArg = asString(o);
Collection<T> filtered = new ArrayList<T>(results.size());
for (T obj : results) {
T maybe = filterObject(obj, context, firstArg);
if (maybe != null) {
filtered.add(maybe);
}
}
return reduce(filtered);
}
protected String asString(Object o) {
if (o instanceof String) {
return (String) o;
} else if (o instanceof Class) {
return ((Class<?>) o).getName();
} else if (o instanceof ClassNode) {
return ((ClassNode) o).getName();
} else if (o instanceof ClassExpression) {
return ((ClassExpression) o).getType().getName();
}
return null;
}
protected Collection<T> reduce(Collection<T> filtered) {
if (filtered == null || filtered.size() == 0) {
return null;
} else {
return filtered;
}
}
/**
* Filters an individual object based on some criteria in the concrete query
*/
protected abstract T filterObject(T result, GroovyDSLDContext context, String firstArgAsString);
/**
* Converts element to a collection of the {@link #filterBy} type or returns null if no match.
*/
@SuppressWarnings("unchecked")
protected Collection<T> explodeObject(Object toMatch) {
if (toMatch instanceof Collection) {
Collection<T> objs = new ArrayList<T>();
for (Object obj : (Collection<?>) toMatch) {
if (filterBy.isInstance(obj)) {
objs.add((T) obj);
}
}
if (!objs.isEmpty()) {
return objs;
}
} else if (filterBy.isInstance(toMatch)) {
return Collections.singletonList((T) toMatch);
}
return null;
}
/**
* Expecting one argument that can either be a string or another pointcut
*/
@Override
public void verify() throws PointcutVerificationException {
super.verify();
String oneStringOrOnePointcutArg = oneStringOrOnePointcutOrOneClassArg();
if (oneStringOrOnePointcutArg != null) {
String hasNoArgs = hasNoArgs();
if (hasNoArgs != null) {
throw new PointcutVerificationException(
"This pointcut expects either no arguments or 1 String or 1 pointcut argument", this);
}
}
}
}