package tc.oc.pgm.filters.operator; import java.util.Optional; import tc.oc.commons.core.reflect.TypeParameterCache; import tc.oc.pgm.filters.Filter; import tc.oc.pgm.filters.FilterTypeException; import tc.oc.pgm.filters.matcher.WeakTypedFilter; import tc.oc.pgm.filters.query.IQuery; /** * A filter that transforms a query of type {@link Q} into some other query of type {@link R} * and passes it to a child filter. * * @see SingleFilterFunction which transforms the response, rather than the query */ public abstract class TransformedFilter<Q extends IQuery, R extends IQuery> extends Filter.Impl implements WeakTypedFilter<Q> { private static final TypeParameterCache<TransformedFilter, ? extends IQuery> R_CACHE = new TypeParameterCache<>(TransformedFilter.class, "R"); private final Class<R> innerQueryType = (Class<R>) R_CACHE.resolveRaw(getClass()); protected final @Inspect Filter filter; public TransformedFilter(Filter filter) { this.filter = filter; } @Override public boolean respondsTo(Class<? extends IQuery> queryType) { return queryType().isAssignableFrom(queryType) && filter.respondsTo(innerQueryType); } @Override public void assertRespondsTo(Class<? extends IQuery> queryType) throws FilterTypeException { if(!queryType().isAssignableFrom(queryType)) { throw new FilterTypeException(this, queryType); } filter.assertRespondsTo(innerQueryType); } @Override public QueryResponse queryTyped(Q query) { return transformQuery(query).map(filter::query) .orElse(QueryResponse.DENY); } /** * Return a transformed query, or empty to DENY */ protected abstract Optional<R> transformQuery(Q query); }