All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.archinnov.achilles.entity.operations.ThriftEntityMerger Maven / Gradle / Ivy

package info.archinnov.achilles.entity.operations;

import static info.archinnov.achilles.entity.metadata.PropertyType.*;
import static javax.persistence.CascadeType.*;
import info.archinnov.achilles.context.AchillesPersistenceContext;
import info.archinnov.achilles.context.ThriftPersistenceContext;
import info.archinnov.achilles.entity.metadata.EntityMeta;
import info.archinnov.achilles.entity.metadata.JoinProperties;
import info.archinnov.achilles.entity.metadata.PropertyMeta;
import info.archinnov.achilles.entity.metadata.PropertyType;
import info.archinnov.achilles.proxy.AchillesEntityInterceptor;
import info.archinnov.achilles.proxy.AchillesMethodInvoker;
import info.archinnov.achilles.validation.Validator;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.CascadeType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Sets;

/**
 * ThriftEntityMerger
 * 
 * @author DuyHai DOAN
 * 
 */
public class ThriftEntityMerger implements AchillesEntityMerger
{
	private static final Logger log = LoggerFactory.getLogger(ThriftEntityMerger.class);

	private ThriftEntityPersister persister = new ThriftEntityPersister();
	private AchillesMethodInvoker invoker = new AchillesMethodInvoker();
	private AchillesEntityProxifier proxifier = new ThriftEntityProxifier();
	private Set multiValueTypes = Sets.newHashSet(LIST, LAZY_LIST, SET, LAZY_SET,
			MAP, LAZY_MAP);

	@Override
	public  T mergeEntity(AchillesPersistenceContext context, T entity)
	{
		log.debug("Merging entity of class {} with primary key {}", context
				.getEntityClass()
				.getCanonicalName(), context.getPrimaryKey());

		ThriftPersistenceContext thriftContext = (ThriftPersistenceContext) context;
		EntityMeta entityMeta = context.getEntityMeta();

		Validator.validateNotNull(entity, "Proxy object should not be null");
		Validator.validateNotNull(entityMeta, "entityMeta should not be null");

		T proxy;
		if (proxifier.isProxy(entity))
		{
			log.debug("Checking for dirty fields before merging");

			T realObject = proxifier.getRealObject(entity);
			AchillesEntityInterceptor interceptor = proxifier.getInterceptor(entity);
			Map> dirtyMap = interceptor.getDirtyMap();

			if (dirtyMap.size() > 0)
			{
				for (Entry> entry : dirtyMap.entrySet())
				{
					PropertyMeta propertyMeta = entry.getValue();
					if (multiValueTypes.contains(propertyMeta.type()))
					{
						log.debug("Removing dirty collection/map {} before merging",
								propertyMeta.getPropertyName());
						persister.removePropertyBatch(thriftContext, propertyMeta);
					}
					persister.persistProperty(context, propertyMeta);
				}
			}

			dirtyMap.clear();

			for (Entry> entry : entityMeta.getPropertyMetas().entrySet())
			{
				PropertyMeta propertyMeta = entry.getValue();
				if (propertyMeta.isJoin())
				{
					Set cascadeTypes = propertyMeta
							.getJoinProperties()
							.getCascadeTypes();
					if (cascadeTypes.contains(MERGE) || cascadeTypes.contains(ALL))
					{
						log.debug("Cascade-merging join property {}",
								propertyMeta.getPropertyName());

						switch (propertyMeta.type())
						{
							case JOIN_SIMPLE:
								mergeJoinProperty(thriftContext, realObject, propertyMeta);
								break;
							case JOIN_LIST:
								mergeJoinListProperty(thriftContext, realObject, propertyMeta);
								break;
							case JOIN_SET:
								mergeJoinSetProperty(thriftContext, realObject, propertyMeta);
								break;
							case JOIN_MAP:
								mergeJoinMapProperty(thriftContext, realObject, propertyMeta);
								break;
							default:
								break;
						}
					}
				}
			}
			interceptor.setContext(thriftContext);
			interceptor.setTarget(realObject);
			proxy = entity;
		}
		else
		{
			log.debug("Persisting transient entity");

			if (!context.isWideRow())
			{
				this.persister.persist(context);
			}

			proxy = proxifier.buildProxy(entity, context);
		}

		return proxy;
	}

	private  void mergeJoinProperty(ThriftPersistenceContext context, T entity,
			PropertyMeta propertyMeta)
	{

		JoinProperties joinProperties = propertyMeta.getJoinProperties();
		Object joinEntity = invoker.getValueFromField(entity, propertyMeta.getGetter());

		if (joinEntity != null)
		{
			log.debug("Merging join entity {} ", joinEntity);
			Object mergedEntity = mergeEntity(
					context.newPersistenceContext(joinProperties.getEntityMeta(), joinEntity),
					joinEntity);
			invoker.setValueToField(entity, propertyMeta.getSetter(), mergedEntity);
		}
	}

	private void mergeJoinListProperty(ThriftPersistenceContext context, Object entity,
			PropertyMeta propertyMeta)
	{
		JoinProperties joinProperties = propertyMeta.getJoinProperties();
		List joinEntities = (List) invoker
				.getValueFromField(entity, propertyMeta.getGetter());
		List mergedEntities = new ArrayList();
		mergeCollectionOfJoinEntities(context, joinProperties, joinEntities, mergedEntities);
		invoker.setValueToField(entity, propertyMeta.getSetter(), mergedEntities);
	}

	private void mergeJoinSetProperty(ThriftPersistenceContext context, Object entity,
			PropertyMeta propertyMeta)
	{
		JoinProperties joinProperties = propertyMeta.getJoinProperties();
		Set joinEntities = (Set) invoker.getValueFromField(entity, propertyMeta.getGetter());
		Set mergedEntities = new HashSet();
		mergeCollectionOfJoinEntities(context, joinProperties, joinEntities, mergedEntities);
		invoker.setValueToField(entity, propertyMeta.getSetter(), mergedEntities);
	}

	private void mergeCollectionOfJoinEntities(ThriftPersistenceContext context,
			JoinProperties joinProperties, Collection joinEntities,
			Collection mergedEntities)
	{
		if (joinEntities != null)
		{
			log.debug("Merging join collection of entity {} ", joinEntities);
			for (Object joinEntity : joinEntities)
			{
				Object mergedEntity = mergeEntity(
						context.newPersistenceContext(joinProperties.getEntityMeta(), joinEntity),
						joinEntity);
				mergedEntities.add(mergedEntity);
			}
		}
	}

	private void mergeJoinMapProperty(ThriftPersistenceContext context, Object entity,
			PropertyMeta propertyMeta)
	{
		JoinProperties joinProperties = propertyMeta.getJoinProperties();
		Map joinEntitiesMap = (Map) invoker.getValueFromField(entity,
				propertyMeta.getGetter());
		Map mergedEntitiesMap = new HashMap();
		if (joinEntitiesMap != null)
		{
			log.debug("Merging join map of entity {} ", joinEntitiesMap);
			for (Entry joinEntityEntry : joinEntitiesMap.entrySet())
			{
				Object mergedEntity = this.mergeEntity(context.newPersistenceContext(
						joinProperties.getEntityMeta(), joinEntityEntry.getValue()),
						joinEntityEntry.getValue());
				mergedEntitiesMap.put(joinEntityEntry.getKey(), mergedEntity);
			}
		}
		invoker.setValueToField(entity, propertyMeta.getSetter(), mergedEntitiesMap);
	}

	public void setPersister(ThriftEntityPersister persister)
	{
		this.persister = persister;
	}
}