/* package whatever; // don't place package name! */
//http://stackoverflow.com/questions/25523570/how-to-decouple-input-params-for-different-handlers-in-a-filter-chain
import java.util.*;
import java.lang.*;
import java.io.*;
class FacetedFilter
{
interface IFilter {
}
/** Unique identifier for context data **/
public static class FacetKey<T> {
private final Class<T> type;
public FacetKey(Class<T> type) {
assert type != null;
this.type = type;
}
/**No one should override equals of key **/
@Override
public final boolean equals
(Object object
) { return super.equals(object);
}
}
/** Holds typed data.
* Only key holder can access data adressed by that key.
**/
private final Map<FacetKey, Object> data = new HashMap<>();
public <T> T put(FacetKey<T> key, T datum) {
return key.type.cast(data.put(key, datum));
}
public <T> T get(FacetKey<T> key){
return key.type.cast(data.get(key));
}
}
/** Basic helper for typesafe filter implementation **/
static abstract class TypedFilter<T> implements IFilter {
public final FacetKey<T> key;
public TypedFilter(FacetKey<T> key) {
this.key = key;
}
@Override
public final boolean apply
(Context context
) { return apply(context.get(key));
}
public abstract boolean apply(T datum);
}
/** Type of data for first filter */
static class DataA {
int x = 5;
}
/** First filter */
static class FilterA extends TypedFilter<DataA> {
/**Each filter has its own key, unknown to other filters.
* This can be made as hidden as needed to prevent key reuse.
**/
public static final FacetKey<DataA> key = new FacetKey<>(DataA.class);
public FilterA() {
super(key);
}
@Override
public boolean apply(DataA datum) {
return datum.x == 6; // arbitrary predicate
}
}
static class DataB {
}
static class FilterB extends TypedFilter<DataB> {
/**Each filter has its own key, unknown to other filters.
* This can be made as hidden as needed to prevent key reuse.
**/
public static final FacetKey<DataB> key = new FacetKey<>(DataB.class);
public FilterB() {
super(key);
}
@Override
public boolean apply(DataB datum) {
return datum.y != null; // another predicate
}
}
static class FilterC extends TypedFilter<DataB> {
//Data type is not unique, but key is.
//This key won't let you access B filter data.
public static final FacetKey<DataB> key = new FacetKey<>(DataB.class);
public FilterC() {
super(key);
}
@Override
public boolean apply(DataB datum) {
return java.util.Objects.equals(datum.y, "Hey!"); // another predicate
}
}
static void println
(Object line
) { }
{
context.put(FilterA.key, new DataA());
context.put(FilterB.key, new DataB());
DataB c = new DataB();
c.y = "Hey!";
context.put(FilterC.key, c);
println(new FilterA().apply(context));
println(new FilterB().apply(context));
println(new FilterC().apply(context));
}
}