diff --git a/modules/core/src/main/java/org/jpos/util/BeanDiff.java b/modules/core/src/main/java/org/jpos/util/BeanDiff.java
new file mode 100644
index 0000000000..7a1cec6187
--- /dev/null
+++ b/modules/core/src/main/java/org/jpos/util/BeanDiff.java
@@ -0,0 +1,311 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2015 Alejandro P. Revilla
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.util;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Andres Alcarraz
+ * @author Alejandro Revilla
+ */
+public class BeanDiff {
+ public static String LINESEP = "
";
+
+ /**
+ * should update diff info?
+ */
+ private boolean dirty = false;
+
+ /**
+ * first bean to compare
+ */
+ private Object b1;
+
+ /**
+ * second bean to compare
+ */
+ private Object b2;
+
+ /**
+ * list of object diferences.
+ * it has entries for different elements only.
+ */
+ private List differences;
+
+ /**
+ * properties to check, if null all properties will get compared
+ */
+ private String[] properties;
+
+ private static Map classInfo = new Hashtable();
+
+ private String[] actualProperties;
+
+ public BeanDiff () {
+ super();
+ }
+
+ public BeanDiff (Object b1, Object b2) {
+ super();
+ setB1 (b1);
+ setB2 (b2);
+ }
+ public BeanDiff (Object b1, Object b2, String[] props) {
+ this (b1, b2);
+ setProperties (props);
+ }
+ protected boolean isDirty() {
+ return dirty;
+ }
+ protected void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ if (dirty)
+ setDifferences (null);
+ }
+
+ public Object getB1() {
+ return b1;
+ }
+
+ public void setB1(Object b1) {
+ setDirty (true);
+ this.b1 = b1;
+ }
+
+ public Object getB2() {
+ return b2;
+ }
+
+ public void setB2(Object b2) {
+ setDirty (true);
+ this.b2 = b2;
+ }
+
+ protected static ClassInfo getClassInfo (String className)
+ throws IntrospectionException
+ {
+ try {
+ return getClassInfo(Class.forName(className));
+ } catch (ClassNotFoundException e) {
+ return null;
+ //FIXME see what to do here
+ //throw new DiffException("Managed class does not exists", e);
+ }
+ }
+
+ protected static ClassInfo getClassInfo(Class c)
+ throws IntrospectionException
+ {
+ ClassInfo ret = (ClassInfo)classInfo.get(c.getName());
+ if(ret == null)
+ classInfo.put(c.getName(), ret = new ClassInfo(c));
+ return ret;
+ }
+
+ protected static class ClassInfo {
+ protected Class c;
+ protected BeanInfo info;
+ protected Map properties = new Hashtable();
+ public ClassInfo(String className)
+ throws ClassNotFoundException, IntrospectionException
+ {
+ try {
+ c = Class.forName(className);
+ init();
+ } catch (ClassNotFoundException e){
+ // This should never happen as instances of this class
+ // should already exist in the current classloader.
+ }
+ }
+ public ClassInfo (Class c) throws IntrospectionException {
+ this.c = c;
+ init();
+ }
+ protected final void init() throws IntrospectionException {
+ info = Introspector.getBeanInfo(c);
+ PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+ for (int i=0; iprops array.
+ * @param props desired properties
+ */
+ public Map getProperties(String[] props){
+ if (props == null)
+ return getProperties();
+ Map ret = new LinkedHashMap();
+ for(int i = 0; i < props.length; i++){
+ ret.put(props[i], properties.get(props[i]));
+ }
+ return ret;
+ }
+
+ public Object getValue(Object bean, String prop) {
+ try{
+ PropertyDescriptor descriptor = getPropertyDescriptor(prop);
+ return descriptor.getReadMethod().invoke(bean);
+ } catch (InvocationTargetException e){
+ } catch (IllegalAccessException e){
+ }
+ return "{error}";
+ }
+ }
+ /**
+ * Hook method to let a subclass change the way the values are compared
+ * @param i index of the property being compared in de order
+ * given by the properties attribute.
+ */
+ protected boolean equals (int i, Object v1, Object v2){
+ if (v1 instanceof Comparable && v2 != null)
+ return ((Comparable)v1).compareTo(v2) == 0;
+ else if (v1 != null)
+ return v1.equals(v2);
+ else
+ return v2 == null;
+ }
+ /**
+ * intersects two collections the first parameter will hold the
+ * result.
+ */
+ protected static void intersect (Collection col1, Collection col2){
+ Collection col1_col2 = new LinkedList (col1); //clone col1
+ col1_col2.removeAll (col2); //
+ col1.removeAll (col1_col2); //remve all elements of col1 that are not in col2
+ }
+ protected void updateActualProperties(ClassInfo info1, ClassInfo info2){
+ String[] actualProperties = getProperties();
+ List res;
+ if (actualProperties != null) {
+ res = new LinkedList(Arrays.asList(actualProperties));
+ intersect(res, new LinkedList(info1.getProperties().keySet()));
+ } else {
+ res = new LinkedList(info1.getProperties().keySet());
+ }
+ intersect(res, info2.getProperties().keySet());
+ setActualProperties((String [])res.toArray(new String[] {}));
+ }
+ protected void updateDiffInfo()
+ throws IntrospectionException
+ {
+ if (!isDirty())
+ return;
+ setDirty(false);
+ List differences = new ArrayList();
+ setDifferences(differences);
+ Object b1 = getB1(), b2 = getB2();
+ ClassInfo bean1Props = getClassInfo(b1.getClass());
+ ClassInfo bean2Props = getClassInfo(b2.getClass());
+ updateActualProperties(bean1Props, bean2Props);
+ String[] props = getActualProperties();
+
+ for (int i = 0; i < props.length; i++){
+ Object v1 = bean1Props.getValue(b1, props[i]);
+ Object v2 = bean2Props.getValue(b2, props[i]);
+ if (!equals(i, v1, v2))
+ differences.add(new DiffEntry(this, props[i], v1, v2));
+ }
+ }
+ public List getDifferences()
+ throws IntrospectionException
+ {
+ updateDiffInfo();
+ return differences;
+ }
+ protected void setDifferences(List differences) {
+ this.differences = differences;
+ }
+
+ public String toString() {
+ try {
+ updateDiffInfo();
+ Iterator iter = getDifferences().iterator();
+ StringBuilder sb = new StringBuilder();
+ while (iter.hasNext()) {
+ DiffEntry de = (DiffEntry) iter.next();
+ if (sb.length() > 0)
+ sb.append (LINESEP);
+ sb.append (de.toString());
+ }
+ return sb.toString();
+ } catch (IntrospectionException e) {
+ return e.getMessage();
+ }
+ }
+
+ /**
+ * @return properties that are effectively being checked, these are the intersection
+ * of properties
, properties of bean 1 and properties of bean 2
+ */
+ public String[] getActualProperties()
+ throws IntrospectionException
+ {
+ updateDiffInfo();
+ return actualProperties;
+ }
+ protected void setActualProperties(String[] actualProperties){
+ this.actualProperties = actualProperties;
+ }
+ public String[] getProperties() {
+ return properties;
+ }
+ public void setProperties(String[] properties) {
+ setDirty(true);
+ this.properties = properties;
+ }
+
+}
diff --git a/modules/core/src/main/java/org/jpos/util/DiffEntry.java b/modules/core/src/main/java/org/jpos/util/DiffEntry.java
new file mode 100644
index 0000000000..176dc9ea9c
--- /dev/null
+++ b/modules/core/src/main/java/org/jpos/util/DiffEntry.java
@@ -0,0 +1,80 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2015 Alejandro P. Revilla
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.util;
+
+/**
+ *
+ * @author Andres Alcarraz
+ */
+public class DiffEntry {
+ private String property;
+ private Object value1;
+ private Object value2;
+ private BeanDiff beanDiff;
+
+ public DiffEntry() {
+ super();
+ }
+ public DiffEntry (BeanDiff beanDiff, String prop,
+ Object value1, Object value2) {
+ super ();
+ setBeanDiff(beanDiff);
+ setProperty(prop);
+ setValue1(value1);
+ setValue2(value2);
+ }
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append ('-');
+ sb.append (getProperty());
+ sb.append (':');
+ sb.append (getValue1());
+ sb.append (BeanDiff.LINESEP);
+ sb.append ('+');
+ sb.append (getProperty());
+ sb.append (':');
+ sb.append (getValue2());
+ return sb.toString();
+ }
+ public String getProperty() {
+ return property;
+ }
+ public void setProperty (String property) {
+ this.property = property;
+ }
+ public Object getValue1 () {
+ return value1;
+ }
+ public void setValue1 (Object value1) {
+ this.value1 = value1;
+ }
+ public Object getValue2 () {
+ return value2;
+ }
+ public void setValue2 (Object value2) {
+ this.value2 = value2;
+ }
+ public BeanDiff getBeanDiff() {
+ return beanDiff;
+ }
+ public void setBeanDiff (BeanDiff beanDiff) {
+ this.beanDiff = beanDiff;
+ }
+}
+