001package com.hammurapi.extract; 002 003import java.util.Map; 004import java.util.Set; 005 006import com.hammurapi.extract.ComparisonResult.Type; 007 008 009/** 010 * This predicate evaluates to true if argument is of a particular type. 011 * @author Pavel Vlasov. 012 * 013 * @param <T> 014 */ 015public class InstanceOfPredicate<T, C> implements Predicate<T, C>, Mappable<T,Boolean,C> { 016 017 private Class<?> instanceType; 018 private Extractor<T, Object, C> extractor; 019 020 @SuppressWarnings("unchecked") 021 public InstanceOfPredicate(Extractor<T, Object, C> extractor, Class<?> instanceType) { 022 this.extractor = extractor; 023 if (instanceType.isPrimitive()) { 024 if (boolean.class.equals(instanceType)) { 025 this.instanceType = (Class<? extends T>) Boolean.class; 026 } else if (char.class.equals(instanceType)) { 027 this.instanceType = (Class<? extends T>) Character.class; 028 } else if (byte.class.equals(instanceType)) { 029 this.instanceType = (Class<? extends T>) Byte.class; 030 } else if (short.class.equals(instanceType)) { 031 this.instanceType = (Class<? extends T>) Short.class; 032 } else if (int.class.equals(instanceType)) { 033 this.instanceType = (Class<? extends T>) Integer.class; 034 } else if (long.class.equals(instanceType)) { 035 this.instanceType = (Class<? extends T>) Long.class; 036 } else if (float.class.equals(instanceType)) { 037 this.instanceType = (Class<? extends T>) Float.class; 038 } else if (double.class.equals(instanceType)) { 039 this.instanceType = (Class<? extends T>) Double.class; 040 } else if (void.class.equals(instanceType)) { 041 this.instanceType = null; 042 } 043 } else { 044 this.instanceType = instanceType; 045 } 046 } 047 048 @SuppressWarnings("unchecked") 049 public ComparisonResult compareTo(Extractor<T, Boolean, C> otherPredicate) { 050 if (instanceType==null) { 051 return False.getInstance().compareTo((Extractor<Object, Boolean, Object>) otherPredicate); 052 } 053 054 if (otherPredicate instanceof InstanceOfPredicate) { 055 ComparisonResult ecr = extractor.compareTo(((InstanceOfPredicate<T, C>) otherPredicate).extractor); 056 if (ecr == null || ecr.getType()!=ComparisonResult.Type.EQUAL) { 057 return ComparisonResult.NOT_EQUAL_NM; 058 } 059 060 Class<?> otherInstanceType = ((InstanceOfPredicate<T, C>) otherPredicate).instanceType; 061 if (otherInstanceType.equals(instanceType)) { 062 return new ComparisonResult(Type.EQUAL, ecr.getIndexMap()); 063 } 064 if (instanceType.isAssignableFrom(otherInstanceType)) { 065 return new ComparisonResult(Type.LESS_RESTRICTIVE, ecr.getIndexMap()); 066 } 067 if (otherInstanceType.isAssignableFrom(instanceType)) { 068 return new ComparisonResult(Type.MORE_RESTRICTIVE, ecr.getIndexMap()); 069 } 070 071 // No multiple inheritance in Java - if both types are classes, then they 072 // are mutually exclusive - i.e. a instanceof String is opposite less restrictive than 073 // a instanceof Integer. 074 if (!instanceType.isInterface() && !otherInstanceType.isInterface()) { 075 return new ComparisonResult(Type.OPPOSITE_LESS_RESTRICTIVE, ecr.getIndexMap()); 076 } 077 078 } 079 080 // True is less restrictive than anything but self. 081 if (otherPredicate instanceof True) { 082 return ComparisonResult.MORE_RESTRICTIVE_NM; 083 } 084 085 // False is more restrictive than anything but self. 086 if (otherPredicate instanceof False) { 087 return ComparisonResult.LESS_RESTRICTIVE_NM; 088 } 089 090 if (otherPredicate instanceof FacadeExtractor) { 091 ComparisonResult cr = otherPredicate.compareTo(this); 092 if (cr==null) { 093 return cr; 094 } 095 switch (cr.getType()) { 096 case EQUAL: 097 case NOT_EQUAL: 098 case OPPOSITE: 099 return cr; 100 case LESS_RESTRICTIVE: 101 return new ComparisonResult(Type.MORE_RESTRICTIVE, ComparisonResult.inverse(cr.getIndexMap(), parameterIndices())); 102 case MORE_RESTRICTIVE: 103 return new ComparisonResult(Type.LESS_RESTRICTIVE, ComparisonResult.inverse(cr.getIndexMap(), parameterIndices())); 104 case OPPOSITE_LESS_RESTRICTIVE: 105 return new ComparisonResult(Type.OPPOSITE_LESS_RESTRICTIVE, ComparisonResult.inverse(cr.getIndexMap(), parameterIndices())); 106 case OPPOSITE_MORE_RESTRICTIVE: 107 return new ComparisonResult(Type.OPPOSITE_MORE_RESTRICTIVE, ComparisonResult.inverse(cr.getIndexMap(), parameterIndices())); 108 } 109 } 110 111 return ComparisonResult.NOT_EQUAL_NM; 112 } 113 114 @SuppressWarnings({ "unchecked", "rawtypes" }) 115 public Boolean extract(C context, Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache, T... obj) { 116 return instanceType==null ? false : instanceType.isInstance(extractor.extract(context, (Map) cache, obj)); 117 } 118 119 public Set<Integer> parameterIndices() { 120 return extractor.parameterIndices(); 121 } 122 123 public boolean isContextDependent() { 124 return false; 125 } 126 127 @Override 128 public String toString() { 129 return "InstanceOfPredicate [instanceType=" + instanceType + ", extractor=" + extractor + "]"; 130 } 131 132 @Override 133 public double getCost() { 134 return 0; 135 } 136 137 @Override 138 public Extractor<T, Boolean, C> map(int[] map) { 139 if (extractor instanceof Mappable) { 140 Extractor<T,Object,C> mapped = ((Mappable<T,Object,C>) extractor).map(map); 141 if (mapped!=null) { 142 return new InstanceOfPredicate<T, C>(mapped, instanceType); 143 } 144 } 145 return null; 146 } 147 148 /** 149 * @return Extractor which return value is checked for instanceof. 150 */ 151 public Extractor<T, Object, C> getExtractor() { 152 return extractor; 153 } 154 155 public Class<?> getInstanceType() { 156 return instanceType; 157 } 158}