    001    package com.hammurapi.reasoning.impl;
    002
    003    import java.lang.reflect.Field;
    004    import java.lang.reflect.InvocationTargetException;
    005    import java.lang.reflect.Method;
    006    import java.lang.reflect.Modifier;
    007    import java.util.HashMap;
    008    import java.util.Map;
    009    import java.util.logging.Level;
    010    import java.util.logging.Logger;
    011
    012    import com.hammurapi.convert.AtomicConverter;
    013    import com.hammurapi.convert.Converter;
    014    import com.hammurapi.reasoning.spi.Superseder;
    015    import com.hammurapi.util.Context;
    016
    017    public class BeanSupersederAtomicConverter implements AtomicConverter<Object, Superseder> {
    018            private static final Logger logger = Logger.getLogger(BeanSupersederAtomicConverter.class.getName());
    019
    020            @Override
    021            public Superseder convert(final Object source, Converter master, Context context, ClassLoader classLoader) {
    022                    return new Superseder() {
    023
    024                            @Override
    025                            public boolean supersedes(Object subFact) {
    026                                    if (source==subFact) {
    027                                            return false;
    028                                    }
    029
    030                                    if (source==null) {
    031                                            return false;
    032                                    }
    033
    034                                    if (subFact==null) {
    035                                            return false;
    036                                    }
    037
    038                                    if (subFact.getClass().isInstance(source) && !source.getClass().isInstance(subFact)) {
    039                                            try {
    040                                                    Map<String, Object> sourceData = extractData(source);
    041                                                    Map<String, Object> subFactData = extractData(subFact);
    042                                                    if (sourceData.keySet().containsAll(subFactData.keySet())) {
    043                                                            for (String key: subFactData.keySet()) {
    044                                                                    Object sourceValue = sourceData.get(key);
    045                                                                    Object subFactValue = subFactData.get(key);
    046                                                                    if (sourceValue==null) {
    047                                                                            if (subFactValue!=null) {
    048                                                                                    return false;
    049                                                                            }
    050                                                                    } else {
    051                                                                            if (subFactValue==null) {
    052                                                                                    return false;
    053                                                                            }
    054
    055                                                                            if (!sourceValue.equals(subFactValue)) {
    056                                                                                    return false;
    057                                                                            }
    058                                                                    }
    059                                                            }
    060                                                            return true;
    061                                                    }
    062                                            } catch (InvocationTargetException e) {
    063                                                    logger.log(Level.WARNING, "Data extraction failed: "+e, e);
    064                                                    return false;
    065                                            } catch (IllegalAccessException e) {
    066                                                    logger.log(Level.WARNING, "Data extraction failed: "+e, e);
    067                                                    return false;
    068                                            }
    069                                    }
    070                                    return false;
    071                            }
    072
    073                    };
    074            }
    075
    076            private static Map<String, Object> extractData(Object obj) throws IllegalAccessException, InvocationTargetException {
    077                    Map<String, Object> ret = new HashMap<String, Object>();
    078                    for (Method method: obj.getClass().getMethods()) {
    079                            if (method.getName().startsWith("get")
    080                                            && !Modifier.isStatic(method.getModifiers())
    081                                            && method.getParameterTypes().length==0
    082                                            && !Object.class.equals(method.getDeclaringClass())) {
    083                                    ret.put("method:"+method.getName(), method.invoke(obj));
    084                            }
    085                    }
    086
    087                    for (Field field: obj.getClass().getFields()) {
    088                            if (!Modifier.isStatic(field.getModifiers())) {
    089                                    ret.put("field:"+field.getName(), field.get(obj));
    090                            }
    091                    }
    092
    093                    return ret;
    094            }
    095
    096            @Override
    097            public Class<Object> getSourceType() {
    098                    return Object.class;
    099            }
    100
    101            @Override
    102            public Class<? extends Superseder> getTargetType() {
    103                    return Superseder.class;
    104            }
    105
    106    }