com.autobizlogic.abl.hibernate.HibernateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.autobizlogic.abl.hibernate.HibernateUtil.java

Source

package com.autobizlogic.abl.hibernate;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map;

import javassist.util.proxy.ProxyFactory;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.EntityPersister;

import com.autobizlogic.abl.data.PersistentBean;
import com.autobizlogic.abl.data.hibernate.HibPersistentBeanFactory;
import com.autobizlogic.abl.metadata.MetaEntity;
import com.autobizlogic.abl.metadata.MetaModel;
import com.autobizlogic.abl.metadata.MetaModelFactory;
import com.autobizlogic.abl.metadata.MetaRole;
import com.autobizlogic.abl.util.BeanMap;

/**
 * General-purpose utility methods for Hibernate.
 */
public class HibernateUtil {

    /**
     * Given two persistent beans, which may or may not be proxies, determine whether they refer
     * to the same persistent object. In other words, are they of the same class, and do they
     * have the same primary key?
     * If both beans are null, this will return true.
     */
    public static boolean beansHaveSamePK(Object bean1, Object bean2, Session session) {

        if (bean1 == null && bean2 == null)
            return true;

        if (bean1 == null && bean2 != null)
            return false;

        if (bean1 != null && bean2 == null)
            return false;

        if (bean1 == bean2)
            return true;

        String bean1ClassName = getEntityNameForObject(bean1);
        String bean2ClassName = getEntityNameForObject(bean2);
        if (!bean1ClassName.equals(bean2ClassName))
            return false;

        SessionFactory sf = session.getSessionFactory();
        ClassMetadata meta = sf.getClassMetadata(bean1ClassName);
        if (meta == null)
            throw new RuntimeException("Unable to get Hibernate metadata for: " + bean1ClassName);
        Object pk1 = meta.getIdentifier(bean1, (SessionImplementor) session);
        Object pk2 = meta.getIdentifier(bean2, (SessionImplementor) session);
        if (pk1 == null || pk2 == null)
            return false;
        return pk1.equals(pk2);
    }

    /**
     * Given an object, find its first superclass that is not a Javassist proxy class.
     * @param bean An instance of an object, normally a persistent bean
     * @return The name of the lowest class that is not a proxy class
     */
    public static String getEntityNameForObject(Object bean) {
        return getEntityClassForBean(bean).getName();
    }

    /**
     * Given a persistent bean, return the "real" class for it, namely the first
     * superclass that is not a Javassist proxy class.
     */
    public static Class<?> getEntityClassForBean(Object bean) {
        return getEntityClassForClass(bean.getClass());
    }

    /**
     * Given a persistent class, return the "real" class for it, namely the first
     * superclass that is not a Javassist proxy class.
     */
    public static Class<?> getEntityClassForClass(Class<?> cls) {
        while (ProxyFactory.isProxyClass(cls)) {
            cls = cls.getSuperclass();
        }
        return cls;
    }

    /**
     * Get the value of the identifier for the given entity, whatever its type (Pojo or Map).
     * @param entity The entity
     * @param persister The entity's persister
     * @return The identifier for the entity
     */
    public static Serializable getPrimaryKeyForEntity(Object entity, EntityPersister persister) {

        String entityName = persister.getEntityName();
        MetaModel metaModel = MetaModelFactory.getHibernateMetaModel(persister.getFactory());
        MetaEntity metaEntity = metaModel.getMetaEntity(entityName);
        String pkName = metaEntity.getIdentifierName();
        if (entity instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> map = (Map<String, Object>) entity;
            return (Serializable) map.get(pkName);
        }
        BeanMap beanMap = new BeanMap(entity);
        return (Serializable) beanMap.get(pkName);
    }

    /**
     * Given a persistent bean, get (if available) the values originally loaded from the database
     * when the object was read.
     * @param bean The persistent bean (must be Pojo)
     * @param session The current Hibernate session
     * @return Null if the object is not known by Hibernate, otherwise an ObjectState with the original
     * values.
     */
    public static PersistentBean getOldStateForObject(Object bean, Session session) {

        if (!session.contains(bean))
            return null;

        Serializable pk = session.getIdentifier(bean);

        Class<?> beanClass = getEntityClassForBean(bean);
        String beanClassName = beanClass.getName();
        EntityPersister persister = HibernateSessionUtil.getEntityPersister(session, beanClassName, bean);
        Object[] cachedValues = persister.getDatabaseSnapshot(pk, (SessionImplementor) session);

        return HibPersistentBeanFactory.createPersistentBeanCopyFromState(cachedValues, bean, persister, session);
    }

    /**
     * This gets called when an inconsistent relationship is detected.
     * An inconsistent relationship is one where the two sides of the relationship do not agree.
     * For instance, if customer1.getPurchaseOrders().contains(po1) is true, but po1.getCustomer()
     * is not customer1.
     * @param backParent The parent obtained from the child
     * @param parent The parent which contains the child
     * @param childObject Self-explanatory
     * @param roleToChild The role from the parent to the child
     */
    public static void failInconsistentRelationship(Object backParent, PersistentBean parent,
            PersistentBean childObject, MetaRole roleToChild) {

        // A common source of problems is people forgetting to implement equals and hashCode.
        String msg = "Child object " + childObject + " points to a parent object " + backParent + " through role "
                + roleToChild.getOtherMetaRole().getRoleName() + ", but it is also contained by parent " + parent
                + " through role " + roleToChild.getRoleName()
                + ". When setting a relationship, it must be set at both ends, otherwise the logic "
                + "cannot execute properly.";
        if (objectLacksOwnEquals(childObject))
            msg += " A common cause for this is forgetting to implement equals() and hashCode() in your "
                    + "Hibernate beans. See https://community.jboss.org/wiki/EqualsAndHashCode for details.";
        throw new RuntimeException(msg);
    }

    /**
     * This gets called when an inconsistent relationship is detected.
     * An inconsistent relationship is one where the two sides of the relationship do not agree.
     * For instance, if customer1.getPurchaseOrders().contains(po1) is true, but po1.getCustomer()
     * is not customer1.
     * @param parent The parent which does not contains the child
     * @param childObject Self-explanatory
     * @param roleToChild The role from the parent to the child
     */
    public static void failInconsistentRelationship(Object parent, PersistentBean childObject,
            MetaRole roleToChild) {
        // A common source of problems is people forgetting to implement equals and hashCode.      
        String msg = "Child object " + childObject + " points to a parent object " + parent + " through role "
                + roleToChild.getOtherMetaRole().getRoleName() + ", but that parent does not contain the child "
                + "through role " + roleToChild.getRoleName()
                + ". When setting a relationship, it must be set at both ends, otherwise the logic "
                + "cannot execute properly.";
        if (objectLacksOwnEquals(childObject))
            msg += " A common cause for this is forgetting to implement equals() and hashCode() in your "
                    + "Hibernate beans. See https://community.jboss.org/wiki/EqualsAndHashCode for details.";
        throw new RuntimeException(msg);
    }

    /**
     * Determine whether the given object lacks its own implementation of equals(). This will return true
     * if the object does not somehow override java.lang.Object's equals.
     * @param bean Any PersistentBean
     */
    private static boolean objectLacksOwnEquals(PersistentBean bean) {
        if (bean == null)
            return false;
        if (!bean.isPojo())
            return false;
        Class<?> cls = bean.getBean().getClass();
        try {
            Method equalsMethod = cls.getMethod("equals", Object.class);
            if ("java.lang.Object".equals(equalsMethod.getDeclaringClass().getName()))
                return true;
        } catch (Exception ex) {
            // Ignore -- we can't deal with this right now
        }
        return false;
    }
}

/*
 * The contents of this file are subject to the Automated Business Logic Public License Version 1.0 (the "License"),
 * which is derived from the Mozilla Public License version 1.1. You may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at http://www.automatedbusinesslogic.com/license/public-license
 *
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, 
 * either express or implied. See the License for the specific language governing rights and limitations under the License.
 */