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    }