    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}