BeanDiff.java

package sk.iway.iwcm.helpers;

import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.ArrayUtils;

import sk.iway.iwcm.DBPool;


/**
 *  BeanDiff.java
 *
 *  Compares 2 beans of equal classes, returning differences found in the process.
 *
 *@Title        webjet7
 *@Company      Interway s.r.o. (www.interway.sk)
 *@Copyright    Interway s.r.o. (c) 2001-2010
 *@author       $Author: marosurbanec $
 *@version      $Revision: 1.3 $
 *@created      Date: 29.3.2010 16:45:51
 *@modified     $Date: 2004/08/16 06:26:11 $
 */
public class BeanDiff
{

	private Object original;
	private Object actual;

	private static final String[] supportedClasses = {"String", "Double", "Integer", "Float", "Byte", "Boolean", "int", "double", "boolean", "float", "byte"};
	private List<String> whitelist;
	private List<String> blacklist;
	private boolean whitelistOn = false;
	private boolean blacklistOn = false;

	public Map<String, PropertyDiff> diff()
	{
		Map<String, PropertyDiff> changes = new HashMap<>();

		if (actual != null)
		{
			PropertyDescriptor[] descriptors;
			if (original != null)
				descriptors = PropertyUtils.getPropertyDescriptors(original.getClass());
			else
				descriptors = PropertyUtils.getPropertyDescriptors(actual.getClass());

			for (PropertyDescriptor descriptor : descriptors)
			{
				try{
					String property = descriptor.getName();
					if (whitelistOn && !whitelist.contains(property)) continue;
					if (blacklistOn && blacklist.contains(property)) continue;
					if (descriptor.getPropertyType() != null && !ArrayUtils.contains(supportedClasses, descriptor.getPropertyType().getSimpleName()))
						continue;

					Object originalValue = original != null ? PropertyUtils.getProperty(original, property) : null;
					Object newValue = PropertyUtils.getProperty(actual, property);
					if (originalValue == null && descriptor.getPropertyType() == String.class)
						originalValue = "";
					if (newValue == null && descriptor.getPropertyType() == String.class)
						newValue = "";
					if (originalValue == null) originalValue = "NULL";
					if (newValue == null) newValue = "NULL";

					if (!originalValue.equals(newValue) || original == null)
					{
						PropertyDiff diff = new PropertyDiff();
						diff.valueBefore = originalValue;
						diff.valueAfter = newValue;
						changes.put(property, diff);
					}

				}
				catch (Exception e) {/*in order to satisfy compiler*/}
			}
		}

		return changes;
	}

	public BeanDiff setOriginal(Object original)
	{
		this.original = original;
		return this;
	}

	public BeanDiff setNew(Object newBean)
	{
		this.actual = newBean;
		return this;
	}

	/**
	 * Nastavi novy objekt typu JPA a nahra aktualnu verziu z DB na porovnanie
	 * Nie je potrebne nasledne volat setOriginal
	 * @param actual
	 * @param id
	 * @return
	 */
	public BeanDiff setNewLoadJpaOriginal(Object actual, int id)
	{
		this.actual = actual;

		//ak je to JPA vieme ziskat original, musime mat ale novy EntityManager a nie ten z ThreadLocal, tam by sme totiz mohli vidiet uz zmeneny bean co je actual
		EntityManagerFactory factory = DBPool.getEntityManagerFactory("iwcm");
		EntityManager em = factory.createEntityManager();

		this.original = em.find(actual.getClass(), id);

		em.close();

		return this;
	}

	public BeanDiff whitelist(String... properties)
	{
		whitelistOn = true;
		whitelist = Arrays.asList(properties);
		return this;
	}

	public BeanDiff blacklist(String... properties)
	{
		blacklistOn = true;
		blacklist = Arrays.asList(properties);
		return this;
	}

	public boolean hasOriginal()
	{
		return original != null;
	}

}