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

ars.database.spring.HibernateDatabaseConfiguration Maven / Gradle / Ivy

package ars.database.spring;

import java.util.Set;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Collections;
import java.lang.reflect.Modifier;

import org.hibernate.Hibernate;
import org.hibernate.type.Type;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.event.spi.MergeEventListener;
import org.hibernate.event.spi.EvictEventListener;
import org.hibernate.event.spi.FlushEventListener;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.event.spi.RefreshEventListener;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.ReplicateEventListener;
import org.hibernate.event.spi.DirtyCheckEventListener;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.FlushEntityEventListener;
import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.event.spi.InitializeCollectionEventListener;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.springframework.beans.BeansException;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.framework.Advised;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import ars.util.Beans;
import ars.util.Trees;
import ars.util.Strings;
import ars.util.ObjectAdapter;
import ars.util.Conditions.Or;
import ars.util.Conditions.Condition;
import ars.database.model.TreeModel;
import ars.database.hibernate.Hibernates;
import ars.database.hibernate.HibernateSimpleRepository;
import ars.database.repository.Repository;
import ars.database.repository.Repositories;
import ars.database.repository.DataConstraintException;
import ars.database.service.event.DeleteEvent;
import ars.database.service.event.InitEvent;
import ars.database.service.event.ServiceEvent;
import ars.database.service.event.ServiceListener;
import ars.database.spring.DatabaseConfiguration;
import ars.invoke.request.ParameterInvalidException;

/**
 * 基于Hibernate数据操作配置
 * 
 * @author yongqiangwu
 * 
 */
public class HibernateDatabaseConfiguration extends DatabaseConfiguration
		implements ObjectAdapter, ServiceListener {
	private static Map, List> VALIDATE_MODEL_PROPERTY_MAPPING = new HashMap, List>(); // 数据模型/属性映射
	private static Map, Map, List>> VALIDATE_MODEL_RELATE_MAPPING = new HashMap, Map, List>>(); // 数据模型关联属性映射

	private String validate; // 数据验证模型

	public String getValidate() {
		return validate;
	}

	public void setValidate(String validate) {
		this.validate = validate;
	}

	/**
	 * 对象实体属性值有效性验证
	 * 
	 * @param event
	 *            初始化事件对象
	 */
	protected void validation(InitEvent event) {
		Object entity = event.getEntity();
		Class model = event.getService().getModel();
		while (true) {
			Class superclass = model.getSuperclass();
			if (superclass != Object.class && !Modifier.isAbstract(superclass.getModifiers())
					&& VALIDATE_MODEL_PROPERTY_MAPPING.containsKey(superclass)) {
				model = superclass;
				continue;
			}
			break;
		}
		Repository repository = Repositories.getRepository(model);
		List properties = VALIDATE_MODEL_PROPERTY_MAPPING.get(model);
		if (properties == null) {
			throw new RuntimeException("Unknown model:" + model.getName());
		}

		List uniques = new LinkedList();
		for (Property property : properties) {
			String name = property.getName();
			Object value = Beans.getValue(entity, name);
			Iterator columnIterator = property.getColumnIterator();
			if (columnIterator.hasNext()) {
				Column column = (Column) columnIterator.next();
				if (!column.isNullable() && Beans.isEmpty(value)) {
					throw new ParameterInvalidException(name, "required");
				} else if (column.isUnique() && !Beans.isEmpty(value)) {
					uniques.add(new Condition(name, value));
				}
			}
			if (entity instanceof TreeModel && name.equals("parent") && Trees.isLoop((TreeModel) entity)) {
				throw new ParameterInvalidException(name, "dead cycle");
			}
		}
		if (!uniques.isEmpty()) {
			Object id = Beans.getValue(entity, repository.getPrimary());
			Object exist = repository.query().ne(repository.getPrimary(), id)
					.condition(new Or(uniques.toArray(new Condition[0]))).single();
			if (exist != null) {
				for (Condition condition : uniques) {
					if (Beans.isEqual(Beans.getValue(exist, condition.getKey()), condition.getValue())) {
						throw new ParameterInvalidException(condition.getKey(), "exist");
					}
				}
			}
		}
	}

	/**
	 * 对象实体删除验证
	 * 
	 * @param event
	 *            删除事件对象
	 */
	protected void validation(DeleteEvent event) {
		Object entity = event.getEntity();
		Class model = event.getService().getModel();
		Map, List> relates = VALIDATE_MODEL_RELATE_MAPPING.get(model);
		if (relates != null && !relates.isEmpty()) {
			for (Entry, List> entry : relates.entrySet()) {
				Class foreignKeyClass = entry.getKey();
				Repository repository = Repositories.getRepository(foreignKeyClass);
				for (Property property : entry.getValue()) {
					if (TreeModel.class.isAssignableFrom(model) && model == foreignKeyClass
							&& property.getName().equals("parent")) {
						continue;
					}
					Object relate = repository.query().eq(property.getName(), entity).paging(1, 1).single();
					if (relate != null) {
						String message = new StringBuilder(event.getSource().format(foreignKeyClass.getName()))
								.append('[').append(relate.toString()).append(']').toString();
						throw new DataConstraintException(message);
					}
				}
			}
		}
	}

	/**
	 * 绑定持久化会话工厂实例
	 * 
	 * @param applicationContext
	 *            Spring上下文对象
	 */
	@SuppressWarnings("rawtypes")
	protected void bindSessionFactory(ApplicationContext applicationContext) {
		Collection sessionFactories = applicationContext.getBeansOfType(SessionFactory.class).values();
		Map, SessionFactory> modelSessionFactoryMappings = new HashMap, SessionFactory>();
		for (SessionFactory sessionFactory : sessionFactories) {
			Collection classMetadatas = sessionFactory.getAllClassMetadata().values();
			for (ClassMetadata classMetadata : classMetadatas) {
				modelSessionFactoryMappings.put(classMetadata.getMappedClass(), sessionFactory);
			}
		}

		// 绑定数据持久化对象会话工厂实例
		Map repositories = applicationContext.getBeansOfType(Repository.class);
		for (Entry entry : repositories.entrySet()) {
			Repository repository = entry.getValue();
			if (AopUtils.isAopProxy(repository)) {
				try {
					repository = (Repository) ((Advised) repository).getTargetSource().getTarget();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			if (!(repository instanceof HibernateSimpleRepository)) {
				continue;
			}
			Class model = repository.getModel();
			SessionFactory sessionFactory = modelSessionFactoryMappings.get(model);
			if (sessionFactory == null) {
				throw new RuntimeException("No matching session factory:" + model);
			}
			((HibernateSimpleRepository) repository).setSessionFactory(sessionFactory);
		}
	}

	/**
	 * 绑定数据验证属性
	 * 
	 * @param applicationContext
	 *            Spring上下文对象
	 */
	protected void bindValidateProperty(ApplicationContext applicationContext) {
		Collection sessionFactoryBeans = applicationContext
				.getBeansOfType(LocalSessionFactoryBean.class).values();
		for (LocalSessionFactoryBean bean : sessionFactoryBeans) {
			SessionFactory sessionFactory = bean.getObject();
			Configuration configuration = bean.getConfiguration();
			Iterator persistentIterator = configuration.getClassMappings();
			while (persistentIterator.hasNext()) {
				PersistentClass persistent = persistentIterator.next();
				Class mappedClass = persistent.getMappedClass();
				if (this.validate != null && !Strings.matches(mappedClass.getName(), this.validate)) {
					continue;
				}
				List mappedProperties = VALIDATE_MODEL_PROPERTY_MAPPING.get(mappedClass);
				if (mappedProperties == null) {
					mappedProperties = new LinkedList();
					VALIDATE_MODEL_PROPERTY_MAPPING.put(mappedClass, mappedProperties);
				}
				Iterator propertyIterator = persistent.getPropertyIterator();
				while (propertyIterator.hasNext()) {
					Property property = (Property) propertyIterator.next();
					String name = property.getName();
					if (TreeModel.class.isAssignableFrom(mappedClass) && (name.equals("key") || name.equals("level")
							|| name.equals("leaf") || name.equals("parent") || name.equals("children"))) {
						continue;
					}
					mappedProperties.add(property);
					Type type = property.getType();
					Class foreignKeyClass = Hibernates.getPropertyTypeClass(sessionFactory, type);
					if (this.validate != null && !Strings.matches(foreignKeyClass.getName(), this.validate)) {
						continue;
					}
					if (type.isEntityType() || type.isCollectionType()) {
						Map, List> relates = VALIDATE_MODEL_RELATE_MAPPING.get(foreignKeyClass);
						if (relates == null) {
							relates = new HashMap, List>();
							VALIDATE_MODEL_RELATE_MAPPING.put(foreignKeyClass, relates);
						}
						List properties = relates.get(mappedClass);
						if (properties == null) {
							properties = new LinkedList();
							relates.put(mappedClass, properties);
						}
						properties.add(property);
					}
				}
			}

			persistentIterator = configuration.getClassMappings();
			while (persistentIterator.hasNext()) {
				PersistentClass persistent = persistentIterator.next();
				Class mappedClass = persistent.getMappedClass();
				Map, List> relates = VALIDATE_MODEL_RELATE_MAPPING.get(mappedClass);
				if (relates == null) {
					continue;
				}
				Class superclass = mappedClass.getSuperclass();
				while (superclass != Object.class && !Modifier.isAbstract(superclass.getModifiers())) {
					Map, List> superrelates = VALIDATE_MODEL_RELATE_MAPPING.get(superclass);
					if (superrelates == null) {
						break;
					}
					for (Entry, List> entry : relates.entrySet()) {
						Class key = entry.getKey();
						List properties = superrelates.get(key);
						if (properties == null) {
							properties = new LinkedList();
							superrelates.put(key, properties);
						}
						for (Property property : entry.getValue()) {
							if (!properties.contains(property)) {
								properties.add(property);
							}
						}
					}
					for (Entry, List> entry : superrelates.entrySet()) {
						Class key = entry.getKey();
						List properties = relates.get(key);
						if (properties == null) {
							properties = new LinkedList();
							relates.put(key, properties);
						}
						for (Property property : entry.getValue()) {
							if (!properties.contains(property)) {
								properties.add(property);
							}
						}
					}
					superclass = superclass.getSuperclass();
				}
			}
		}
	}

	/**
	 * 注册事件监听器
	 * 
	 * @param applicationContext
	 *            Spring上下文对象
	 */
	protected void registerEventListener(ApplicationContext applicationContext) {
		Collection sessionFactories = applicationContext.getBeansOfType(SessionFactory.class).values();
		for (SessionFactory sessionFactory : sessionFactories) {
			EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry()
					.getService(EventListenerRegistry.class);

			Map loadEventListeners = applicationContext
					.getBeansOfType(LoadEventListener.class);
			if (!loadEventListeners.isEmpty()) {
				registry.appendListeners(EventType.LOAD, loadEventListeners.values().toArray(new LoadEventListener[0]));
			}

			Map lockEventListeners = applicationContext
					.getBeansOfType(LockEventListener.class);
			if (!lockEventListeners.isEmpty()) {
				registry.appendListeners(EventType.LOCK, lockEventListeners.values().toArray(new LockEventListener[0]));
			}

			Map mergeEventListeners = applicationContext
					.getBeansOfType(MergeEventListener.class);
			if (!mergeEventListeners.isEmpty()) {
				registry.appendListeners(EventType.MERGE,
						mergeEventListeners.values().toArray(new MergeEventListener[0]));
			}

			Map evictEventListeners = applicationContext
					.getBeansOfType(EvictEventListener.class);
			if (!evictEventListeners.isEmpty()) {
				registry.appendListeners(EventType.EVICT,
						evictEventListeners.values().toArray(new EvictEventListener[0]));
			}

			Map flushEventListeners = applicationContext
					.getBeansOfType(FlushEventListener.class);
			if (!flushEventListeners.isEmpty()) {
				registry.appendListeners(EventType.FLUSH,
						flushEventListeners.values().toArray(new FlushEventListener[0]));
			}

			Map deleteEventListeners = applicationContext
					.getBeansOfType(DeleteEventListener.class);
			if (!deleteEventListeners.isEmpty()) {
				registry.appendListeners(EventType.DELETE,
						deleteEventListeners.values().toArray(new DeleteEventListener[0]));
			}

			Map persistEventListeners = applicationContext
					.getBeansOfType(PersistEventListener.class);
			if (!persistEventListeners.isEmpty()) {
				registry.appendListeners(EventType.PERSIST,
						persistEventListeners.values().toArray(new PersistEventListener[0]));
			}

			Map refreshEventListeners = applicationContext
					.getBeansOfType(RefreshEventListener.class);
			if (!refreshEventListeners.isEmpty()) {
				registry.appendListeners(EventType.REFRESH,
						refreshEventListeners.values().toArray(new RefreshEventListener[0]));
			}

			Map preLoadEventListeners = applicationContext
					.getBeansOfType(PreLoadEventListener.class);
			if (!preLoadEventListeners.isEmpty()) {
				registry.appendListeners(EventType.PRE_LOAD,
						preLoadEventListeners.values().toArray(new PreLoadEventListener[0]));
			}

			Map postLoadEventListeners = applicationContext
					.getBeansOfType(PostLoadEventListener.class);
			if (!postLoadEventListeners.isEmpty()) {
				registry.appendListeners(EventType.POST_LOAD,
						postLoadEventListeners.values().toArray(new PostLoadEventListener[0]));
			}

			Map autoFlushEventListeners = applicationContext
					.getBeansOfType(AutoFlushEventListener.class);
			if (!autoFlushEventListeners.isEmpty()) {
				registry.appendListeners(EventType.AUTO_FLUSH,
						autoFlushEventListeners.values().toArray(new AutoFlushEventListener[0]));
			}

			Map preUpdateEventListeners = applicationContext
					.getBeansOfType(PreUpdateEventListener.class);
			if (!preUpdateEventListeners.isEmpty()) {
				registry.appendListeners(EventType.PRE_UPDATE,
						preUpdateEventListeners.values().toArray(new PreUpdateEventListener[0]));
			}

			Map preDeleteEventListeners = applicationContext
					.getBeansOfType(PreDeleteEventListener.class);
			if (!preDeleteEventListeners.isEmpty()) {
				registry.appendListeners(EventType.PRE_DELETE,
						preDeleteEventListeners.values().toArray(new PreDeleteEventListener[0]));
			}

			Map preInsertEventListeners = applicationContext
					.getBeansOfType(PreInsertEventListener.class);
			if (!preInsertEventListeners.isEmpty()) {
				registry.appendListeners(EventType.PRE_INSERT,
						preInsertEventListeners.values().toArray(new PreInsertEventListener[0]));
			}

			Map replicateEventListeners = applicationContext
					.getBeansOfType(ReplicateEventListener.class);
			if (!replicateEventListeners.isEmpty()) {
				registry.appendListeners(EventType.REPLICATE,
						replicateEventListeners.values().toArray(new ReplicateEventListener[0]));
			}

			Map dirtyCheckEventListeners = applicationContext
					.getBeansOfType(DirtyCheckEventListener.class);
			if (!dirtyCheckEventListeners.isEmpty()) {
				registry.appendListeners(EventType.DIRTY_CHECK,
						dirtyCheckEventListeners.values().toArray(new DirtyCheckEventListener[0]));
			}

			Map postUpdateEventListeners = applicationContext
					.getBeansOfType(PostUpdateEventListener.class);
			if (!postUpdateEventListeners.isEmpty()) {
				registry.appendListeners(EventType.POST_UPDATE,
						postUpdateEventListeners.values().toArray(new PostUpdateEventListener[0]));
			}

			Map postDeleteEventListeners = applicationContext
					.getBeansOfType(PostDeleteEventListener.class);
			if (!postDeleteEventListeners.isEmpty()) {
				registry.appendListeners(EventType.POST_DELETE,
						postDeleteEventListeners.values().toArray(new PostDeleteEventListener[0]));
			}

			Map postInsertEventListeners = applicationContext
					.getBeansOfType(PostInsertEventListener.class);
			if (!postInsertEventListeners.isEmpty()) {
				registry.appendListeners(EventType.POST_INSERT,
						postInsertEventListeners.values().toArray(new PostInsertEventListener[0]));
			}

			Map flushEntityEventListeners = applicationContext
					.getBeansOfType(FlushEntityEventListener.class);
			if (!flushEntityEventListeners.isEmpty()) {
				registry.appendListeners(EventType.FLUSH_ENTITY,
						flushEntityEventListeners.values().toArray(new FlushEntityEventListener[0]));
			}

			Map saveOrUpdateEventListeners = applicationContext
					.getBeansOfType(SaveOrUpdateEventListener.class);
			if (!saveOrUpdateEventListeners.isEmpty()) {
				registry.appendListeners(EventType.SAVE_UPDATE,
						saveOrUpdateEventListeners.values().toArray(new SaveOrUpdateEventListener[0]));
			}

			Map initializeCollectionEventListeners = applicationContext
					.getBeansOfType(InitializeCollectionEventListener.class);
			if (!initializeCollectionEventListeners.isEmpty()) {
				registry.appendListeners(EventType.INIT_COLLECTION,
						initializeCollectionEventListeners.values().toArray(new InitializeCollectionEventListener[0]));
			}
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		super.setApplicationContext(applicationContext);
		this.bindSessionFactory(applicationContext);
		this.bindValidateProperty(applicationContext);
		this.registerEventListener(applicationContext);
	}

	@Override
	public Object adaption(Object object) {
		if (Hibernate.isInitialized(object)) {
			return object;
		} else if (object instanceof Map) {
			return Collections.emptyMap();
		} else if (object instanceof Set) {
			return Collections.emptySet();
		} else if (object instanceof List) {
			return Collections.emptyList();
		}
		return null;
	}

	@Override
	public void onServiceEvent(ServiceEvent event) {
		Class model = event.getService().getModel();
		if (this.validate == null || Strings.matches(model.getName(), this.validate)) {
			if (event instanceof InitEvent) {
				this.validation((InitEvent) event);
			} else if (event instanceof DeleteEvent) {
				this.validation((DeleteEvent) event);
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy