fork download
  1. /* package whatever; // don't place package name! */
  2. //http://stackoverflow.com/questions/25523570/how-to-decouple-input-params-for-different-handlers-in-a-filter-chain
  3. import java.util.*;
  4. import java.lang.*;
  5. import java.io.*;
  6.  
  7. class FacetedFilter
  8. {
  9. interface IFilter {
  10. boolean apply(Context context);
  11. }
  12.  
  13. /** Unique identifier for context data **/
  14. public static class FacetKey<T> {
  15. private final Class<T> type;
  16. public FacetKey(Class<T> type) {
  17. assert type != null;
  18. this.type = type;
  19. }
  20.  
  21. /**No one should override equals of key **/
  22. @Override
  23. public final boolean equals(Object object) {
  24. return super.equals(object);
  25. }
  26. }
  27.  
  28. /** Holds typed data.
  29.   * Only key holder can access data adressed by that key.
  30.   **/
  31. public static class Context {
  32. private final Map<FacetKey, Object> data = new HashMap<>();
  33. public <T> T put(FacetKey<T> key, T datum) {
  34. return key.type.cast(data.put(key, datum));
  35. }
  36. public <T> T get(FacetKey<T> key){
  37. return key.type.cast(data.get(key));
  38. }
  39. }
  40.  
  41. /** Basic helper for typesafe filter implementation **/
  42. static abstract class TypedFilter<T> implements IFilter {
  43. public final FacetKey<T> key;
  44. public TypedFilter(FacetKey<T> key) {
  45. this.key = key;
  46. }
  47. @Override
  48. public final boolean apply(Context context) {
  49. return apply(context.get(key));
  50. }
  51. public abstract boolean apply(T datum);
  52. }
  53.  
  54. /** Type of data for first filter */
  55. static class DataA {
  56. int x = 5;
  57. }
  58.  
  59. /** First filter */
  60. static class FilterA extends TypedFilter<DataA> {
  61. /**Each filter has its own key, unknown to other filters.
  62.   * This can be made as hidden as needed to prevent key reuse.
  63.   **/
  64. public static final FacetKey<DataA> key = new FacetKey<>(DataA.class);
  65. public FilterA() {
  66. super(key);
  67. }
  68. @Override
  69. public boolean apply(DataA datum) {
  70. return datum.x == 6; // arbitrary predicate
  71. }
  72. }
  73.  
  74. static class DataB {
  75. String y = "";
  76. }
  77.  
  78.  
  79. static class FilterB extends TypedFilter<DataB> {
  80. /**Each filter has its own key, unknown to other filters.
  81.   * This can be made as hidden as needed to prevent key reuse.
  82.   **/
  83. public static final FacetKey<DataB> key = new FacetKey<>(DataB.class);
  84. public FilterB() {
  85. super(key);
  86. }
  87. @Override
  88. public boolean apply(DataB datum) {
  89. return datum.y != null; // another predicate
  90. }
  91. }
  92.  
  93.  
  94. static class FilterC extends TypedFilter<DataB> {
  95. //Data type is not unique, but key is.
  96. //This key won't let you access B filter data.
  97. public static final FacetKey<DataB> key = new FacetKey<>(DataB.class);
  98. public FilterC() {
  99. super(key);
  100. }
  101. @Override
  102. public boolean apply(DataB datum) {
  103. return java.util.Objects.equals(datum.y, "Hey!"); // another predicate
  104. }
  105. }
  106.  
  107. static void println(Object line) {
  108. System.out.println(""+line);
  109. }
  110.  
  111. public static void main (String[] args) throws java.lang.Exception
  112. {
  113. Context context = new Context();
  114. context.put(FilterA.key, new DataA());
  115. context.put(FilterB.key, new DataB());
  116. DataB c = new DataB();
  117. c.y = "Hey!";
  118. context.put(FilterC.key, c);
  119. println(new FilterA().apply(context));
  120. println(new FilterB().apply(context));
  121. println(new FilterC().apply(context));
  122. }
  123. }
Success #stdin #stdout 0.07s 380160KB
stdin
Standard input is empty
stdout
false
true
true