com.bstek.dorado.data.entity.EntityUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.data.entity.EntityUtils.java

Source

/*
 * This file is part of Dorado 7.x (http://dorado7.bsdn.org).
 * 
 * Copyright (c) 2002-2012 BSTEK Corp. All rights reserved.
 * 
 * This file is dual-licensed under the AGPLv3 (http://www.gnu.org/licenses/agpl-3.0.html) 
 * and BSDN commercial (http://www.bsdn.org/licenses) licenses.
 * 
 * If you are unsure which license is appropriate for your use, please contact the sales department
 * at http://www.bstek.com/contact.
 */

package com.bstek.dorado.data.entity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.cglib.beans.BeanMap;

import org.aopalliance.intercept.MethodInterceptor;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.CollectionUtils;

import com.bstek.dorado.core.Context;
import com.bstek.dorado.core.el.Expression;
import com.bstek.dorado.data.provider.Page;
import com.bstek.dorado.data.type.AggregationDataType;
import com.bstek.dorado.data.type.CustomEntityDataType;
import com.bstek.dorado.data.type.DataType;
import com.bstek.dorado.data.type.EntityDataType;
import com.bstek.dorado.data.type.manager.DataTypeManager;
import com.bstek.dorado.data.variant.Record;
import com.bstek.dorado.data.variant.VariantConvertor;
import com.bstek.dorado.data.variant.VariantUtils;
import com.bstek.dorado.util.proxy.MethodInterceptorDispatcher;
import com.bstek.dorado.util.proxy.ProxyBeanUtils;

/**
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since 2010-12-20
 */
public abstract class EntityUtils {
    private static final Log logger = LogFactory.getLog(EntityUtils.class);

    private static DataTypeManager dataTypeManager;
    private static EntityProxyMethodInterceptorFactory methodInterceptorFactory;
    private static VariantConvertor variantConvertor;

    private static VariantConvertor getVariantConvertor() {
        try {
            variantConvertor = VariantUtils.getVariantConvertor();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e, e);
        }
        return variantConvertor;
    }

    private EntityUtils() {
    }

    private static DataTypeManager getDataTypeManager() throws Exception {
        if (dataTypeManager == null) {
            Context context = Context.getCurrent();
            dataTypeManager = (DataTypeManager) context.getServiceBean("dataTypeManager");
        }
        return dataTypeManager;
    }

    private static EntityProxyMethodInterceptorFactory getMethodInterceptorFactory() throws Exception {
        if (methodInterceptorFactory == null) {
            Context context = Context.getCurrent();
            methodInterceptorFactory = (EntityProxyMethodInterceptorFactory) context
                    .getServiceBean("entityProxyMethodInterceptorFactory");
        }
        return methodInterceptorFactory;
    }

    /**
     * ???
     */
    public static boolean isSimpleValue(Object data) {
        boolean b = (data == null || data instanceof String || data.getClass().isPrimitive()
                || data instanceof Boolean || data instanceof Number || data.getClass().isEnum()
                || data instanceof Date || data instanceof Character);
        if (!b && data.getClass().isArray()) {
            b = isSimpleType(data.getClass().getComponentType());
        }
        return b;
    }

    /**
     * ???
     */
    public static boolean isSimpleType(Class<?> cl) {
        boolean b = (String.class.equals(cl) || cl.isPrimitive() || Boolean.class.equals(cl)
                || Number.class.isAssignableFrom(cl) || cl.isEnum() || Date.class.isAssignableFrom(cl)
                || Character.class.isAssignableFrom(cl));
        if (!b && cl.isArray()) {
            b = isSimpleType(cl.getComponentType());
        }
        return b;
    }

    public static EntityEnhancer getEntityEnhancer(Object entity) {
        if (entity instanceof EnhanceableEntity) {
            EnhanceableEntity enhanceableEntity = (EnhanceableEntity) entity;
            return enhanceableEntity.getEntityEnhancer();
        } else if (ProxyBeanUtils.isProxy(entity)) {
            MethodInterceptorDispatcher dispatcher = ProxyBeanUtils.getMethodInterceptorDispatcher(entity);
            if (dispatcher != null) {
                MethodInterceptor[] mis = dispatcher.getSubMethodInterceptors();
                for (MethodInterceptor mi : mis) {
                    if (mi instanceof EntityEnhancer) {
                        return (EntityEnhancer) mi;
                    }
                }
            }
        }
        return null;
    }

    public static boolean isEntity(Object entity) {
        if (entity.getClass().isPrimitive()) {
            return false;
        }
        return getEntityEnhancer(entity) != null;
    }

    private static void throwNotValidEntity() {
        throw new IllegalStateException("The object is not a valid dorado entity.");
    }

    private static DataType getDataType(Class<?> type) throws Exception {
        return getDataTypeManager().getDataType(type);
    }

    public static AggregationDataType getDataType(Collection<?> entities) {
        AggregationDataType dataType = null;
        if (entities instanceof EntityCollection<?>) {
            dataType = ((EntityCollection<?>) entities).getDataType();
        }
        return dataType;
    }

    public static EntityDataType getDataType(Object entity) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            return entityEnhancer.getDataType();
        } else {
            return null;
        }
    }

    public static EntityState getState(Object entity) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            return entityEnhancer.getState();
        } else {
            return EntityState.NONE;
        }
    }

    public static void setState(Object entity, EntityState state) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            entityEnhancer.setState(state);
        } else {
            throwNotValidEntity();
        }
    }

    public static boolean isDirty(Object entity) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            return entityEnhancer.getState() != EntityState.NONE;
        } else {
            return false;
        }
    }

    public static boolean isCascadeDirty(Object entity) throws Exception {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            if (entityEnhancer.getState() != EntityState.NONE) {
                return true;
            } else {
                try {
                    boolean isDirty;
                    for (String property : entityEnhancer.getPropertySet(entity, false)) {
                        Object value = entityEnhancer.readProperty(entity, property, true);
                        if (value != null) {
                            if (isEntity(value)) {
                                isDirty = isCascadeDirty(value);
                                if (isDirty) {
                                    return true;
                                }
                            } else if (value instanceof Collection<?>) {
                                for (Object e : (Collection<?>) value) {
                                    isDirty = isCascadeDirty(e);
                                    if (isDirty) {
                                        return true;
                                    }
                                }
                            } else if (value instanceof Page<?>) {
                                for (Object e : ((Page<?>) value).getEntities()) {
                                    isDirty = isCascadeDirty(e);
                                    if (isDirty) {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                    return false;
                } catch (Exception e) {
                    throw e;
                } catch (Throwable t) {
                    throw new IllegalStateException(t);
                }
            }
        } else {
            return false;
        }
    }

    public static <T> T newEntity(Class<? extends T> type) throws Exception {
        return (T) newEntity(type, null);
    }

    @SuppressWarnings("unchecked")
    public static <T> T newEntity(EntityDataType entityDataType) throws Exception {
        Class<?> creationType = entityDataType.getCreationType();
        if (creationType == null) {
            creationType = entityDataType.getMatchType();
        }
        if (creationType == null) {
            creationType = Record.class;
        }
        return (T) newEntity(creationType, entityDataType);
    }

    public static <T> T newEntity(Class<? extends T> type, EntityDataType entityDataType) throws Exception {
        T object = type.newInstance();
        T entity = toEntity(object, entityDataType);
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        entityEnhancer.setState(EntityState.NEW);
        return entity;
    }

    public static void deleteEntity(Object entity) throws Exception {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            entityEnhancer.setState(EntityState.DELETED);
        } else {
            throwNotValidEntity();
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T toEntity(Object object) throws Exception {
        return (T) toEntity(object, null);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T toEntity(Object object, DataType dataType) throws Exception {
        if (isSimpleValue(object)) {
            return (T) object;
        }

        // Expression
        if (object instanceof Expression) {
            object = ((Expression) object).evaluate();
        }

        Class<?> cl = object.getClass();
        if (object instanceof Collection) {
            Collection<?> entities = (Collection<?>) object;
            if (entities instanceof EntityCollection<?>) {
                DataType currentDataType = getDataType(entities);
                if (currentDataType != dataType && dataType != null) {
                    ((EntityCollection<?>) entities).setDataType((AggregationDataType) dataType);
                }
                return (T) object;
            }
        } else {
            EntityEnhancer entityEnhancer = getEntityEnhancer(object);
            if (entityEnhancer != null) {
                DataType currentDataType = entityEnhancer.getDataType();
                if (currentDataType != dataType && dataType != null) {
                    entityEnhancer.setDataType((EntityDataType) dataType);
                }
                return (T) object;
            }
        }

        boolean useProxy = true;
        if (dataType == null) {
            dataType = getDataType(cl);
        }

        if (dataType != null) {
            Class<?> matchType = dataType.getMatchType();
            if (matchType != null) {
                boolean matching = false;
                if (matchType.isPrimitive()) {
                    matching = ClassUtils.primitiveToWrapper(matchType).equals(cl);
                } else {
                    matching = matchType.isAssignableFrom(cl);
                }
                if (!matching) {
                    if (dataType instanceof EntityDataType) {
                        DataType realDataType = getDataType(cl);
                        if (realDataType instanceof EntityDataType) {
                            matching = true;
                            useProxy = false;
                        }
                    } else if (dataType instanceof AggregationDataType) {
                        DataType realDataType = getDataType(cl);
                        if (realDataType instanceof AggregationDataType) {
                            matching = true;
                        }
                    }

                    if (!matching) {
                        throw new IllegalArgumentException(
                                "Result type mismatch. expect [" + matchType + "] but [" + cl + "].");
                    }
                }
            }
        }

        if (object instanceof Collection) {
            // Collection???
            AggregationDataType AggregationDataType = (AggregationDataType) dataType;
            if (object instanceof List) {
                object = new EntityList((List) object, AggregationDataType);
            } else if (object instanceof Set) {
                object = new EntitySet((Set) object, AggregationDataType);
            } else {
                throw new IllegalArgumentException("Unsupported result type [" + cl.getName() + "].");
            }
        } else if (object.getClass().isArray()) {
            Class type = object.getClass();
            if (isSimpleType(type.getComponentType())) {
                return (T) object;
            } else {
                // ??java.util.List
                logger.warn("Dorado converted a " + object.getClass() + " to " + List.class + " automatically.");

                List list = CollectionUtils.arrayToList(object);
                object = new EntityList(list, (AggregationDataType) dataType);
            }
        } else {
            // TODO Entity????
            // Entity???
            EntityDataType entityDataType = (EntityDataType) dataType;
            if (!(entityDataType instanceof CustomEntityDataType)) {
                if (useProxy) {
                    // ????
                    if (object instanceof EnhanceableEntity) {
                        EnhanceableEntity enhanceableEntity = (EnhanceableEntity) object;
                        if (enhanceableEntity.getEntityEnhancer() == null) {
                            EntityEnhancer entityEnhancer;
                            if (object instanceof Map) {
                                entityEnhancer = new EnhanceableMapEntityEnhancer(entityDataType);
                            } else {
                                entityEnhancer = new EnhanceableBeanEntityEnhancer(entityDataType,
                                        object.getClass());
                            }
                            enhanceableEntity.setEntityEnhancer(entityEnhancer);
                        }
                        return (T) object;
                    } else {
                        MethodInterceptor[] mis = getMethodInterceptorFactory().createInterceptors(entityDataType,
                                object.getClass(), object);
                        object = ProxyBeanUtils.proxyBean(object, mis);
                    }
                } else {
                    // ????
                    Class<?> creationType = entityDataType.getCreationType();
                    if (creationType == null) {
                        creationType = entityDataType.getMatchType();
                    }

                    Map map;
                    if (object instanceof Map) {
                        map = (Map) object;
                    } else {
                        map = BeanMap.create(object);
                    }

                    if (creationType == null) {
                        Record record = new Record(map);
                        record.setEntityEnhancer(new EnhanceableMapEntityEnhancer(entityDataType));
                        object = record;
                    } else {
                        MethodInterceptor[] mis = getMethodInterceptorFactory().createInterceptors(entityDataType,
                                creationType, null);
                        object = ProxyBeanUtils.createBean(creationType, mis);
                        setValues(object, map);
                    }
                }
            } else {
                object = ((CustomEntityDataType) entityDataType).toMap(object);
            }
        }
        return (T) object;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T toPureData(Object entity) throws Exception {
        if (isSimpleValue(entity)) {
            return (T) entity;
        }

        // !isEntity(object)
        if (entity instanceof Collection) {
            List list = new ArrayList();
            for (Object e : (Collection) entity) {
                if (EntityUtils.getState(e) != EntityState.DELETED) {
                    list.add(toPureData(e));
                }
            }
            return (T) list;
        } else {
            T object;
            EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
            if (entityEnhancer != null) {
                Map newMap;
                Set<String> propertySet;

                if (entityEnhancer instanceof BeanEntityEnhancer) {
                    Class<?> beanType = ((BeanEntityEnhancer) entityEnhancer).getBeanType();
                    object = (T) beanType.newInstance();
                    newMap = BeanMap.create(object);
                    propertySet = entityEnhancer.getPropertySet(entity, false);
                } else {
                    newMap = new HashMap();
                    object = (T) newMap;
                    propertySet = entityEnhancer.getPropertySet(entity, true);
                }

                try {
                    for (String property : propertySet) {
                        Object value = entityEnhancer.readProperty(entity, property, false);
                        if (!isSimpleValue(value)) {
                            value = toPureData(value);
                        }
                        newMap.put(property, value);
                    }
                } catch (Exception e) {
                    throw e;
                } catch (Throwable t) {
                    throw new IllegalStateException(t);
                }
            } else {
                Map oldMap, newMap;
                if (entity instanceof Map) {
                    oldMap = (Map) entity;
                    newMap = new HashMap();
                    object = (T) newMap;
                } else {
                    oldMap = BeanMap.create(entity);
                    object = (T) entity.getClass().newInstance();
                    newMap = BeanMap.create(object);
                }
                newMap.putAll(oldMap);
            }
            return object;
        }
    }

    public static void markDeleted(Object entity) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            entityEnhancer.setState(EntityState.DELETED);
        } else {
            throwNotValidEntity();
        }
    }

    /**
     * ??<br>
     * ????{@link com.bstek.dorado.data.state.EntityState#NONE}
     * ???
     * 
     * @param entity
     *            ?
     */
    public static void resetEntity(Object entity) {
        resetEntity(entity, true);
    }

    public static void resetEntity(Object entity, boolean lockState) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            if (entityEnhancer.getState() != EntityState.DELETED) {
                entityEnhancer.setState(EntityState.NONE);
            }
            entityEnhancer.clearOldValues();
            if (lockState) {
                entityEnhancer.setStateLocked(true);
            }
        } else {
            throwNotValidEntity();
        }
    }

    /**
     * ??
     * 
     * @param entities
     *            ??
     * @see #resetEntity(Object)
     */
    public static void resetEntities(Collection<?> entities) {
        resetEntities(entities, true);
    }

    public static void resetEntities(Collection<?> entities, boolean lockState) {
        for (Object o : entities) {
            resetEntity(o, lockState);
        }
    }

    /**
     * ?
     * 
     * @param entities
     *            ??
     * @param filter
     *            ?
     * @return 
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Iterator getIterator(Collection entities, FilterType filterType) {
        return new EntityIterator(entities, filterType);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <E> Iterator<E> getIterator(Collection entities, FilterType filterType, Class<E> cl) {
        return new EntityIterator<E>(entities, filterType);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Iterable getIterable(Collection entities, FilterType filterType) {
        return new EntityIterator(entities, filterType);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static <E> Iterable<E> getIterable(Collection entities, FilterType filterType, Class<E> cl) {
        return new EntityIterator<E>(entities, filterType);
    }

    public static boolean isLoaded(Object entity, String property) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            return entityEnhancer.isLoaded(property);
        } else {
            throwNotValidEntity();
            return false;
        }
    }

    public static boolean loadIfNecessary(Object entity, String property) throws Exception {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            try {
                return entityEnhancer.loadIfNecessary(entity, property);
            } catch (Exception e) {
                throw e;
            } catch (Throwable e) {
                throw new IllegalStateException(e);
            }
        } else {
            throwNotValidEntity();
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    private static <T> T getValue(Object entity, String property, boolean ignoreInterceptors) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            try {
                return (T) entityEnhancer.readProperty(entity, property, ignoreInterceptors);
            } catch (Throwable e) {
                throw new IllegalStateException(e);
            }
        } else {
            throwNotValidEntity();
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T getValue(Object entity, String property) {
        return (T) getValue(entity, property, false);
    }

    public static String getString(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toString(value);
    }

    public static int getInt(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toInt(value);
    }

    public static long getLong(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toLong(value);
    }

    public static float getFloat(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toFloat(value);
    }

    public static double getDouble(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toDouble(value);
    }

    public static boolean getBoolean(Object entity, String property) {
        Object value = getValue(entity, property);
        return getVariantConvertor().toBoolean(value);
    }

    public static void setValue(Object entity, String property, Object value) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            try {
                entityEnhancer.writeProperty(entity, property, value);
            } catch (Throwable e) {
                throw new IllegalStateException(e);
            }
        } else {
            throwNotValidEntity();
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void setValues(Object entity, Map properties) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            try {
                for (Map.Entry entry : (Set<Map.Entry>) properties.entrySet()) {
                    Object property = entry.getKey();
                    if (property instanceof String) {
                        entityEnhancer.writeProperty(entity, (String) property, entry.getValue());
                    }
                }
            } catch (Throwable e) {
                throw new IllegalStateException(e);
            }
        } else {
            throwNotValidEntity();
        }
    }

    public static boolean hasOldValues(Object entity) {
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            return entityEnhancer.getOldValues() != null;
        } else {
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T getOldValue(Object entity, String property) {
        Object value = null;
        EntityEnhancer entityEnhancer = getEntityEnhancer(entity);
        if (entityEnhancer != null) {
            Map<String, Object> oldValues = entityEnhancer.getOldValues();
            if (oldValues != null) {
                if (oldValues.containsKey(property)) {
                    value = oldValues.get(property);
                } else {
                    value = getValue(entity, property);
                }
            } else {
                value = getValue(entity, property);
            }
        }
        return (T) value;
    }

    public static String getOldString(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toString(value);
    }

    public static int getOldInt(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toInt(value);
    }

    public static long getOldLong(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toLong(value);
    }

    public static float getOldFloat(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toFloat(value);
    }

    public static double getOldDouble(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toDouble(value);
    }

    public static boolean getOldBoolean(Object entity, String property) {
        Object value = getOldValue(entity, property);
        return getVariantConvertor().toBoolean(value);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void copyProperties(Object target, Object source) throws Exception {
        try {
            EntityEnhancer sourceEnhancer = getEntityEnhancer(source);
            EntityEnhancer targetEnhancer = getEntityEnhancer(target);

            Map targetMap = null;
            if (targetEnhancer == null) {
                if (target instanceof Map) {
                    targetMap = (Map) target;
                } else {
                    targetMap = BeanMap.create(target);
                }
            }

            if (sourceEnhancer != null) {
                for (String property : sourceEnhancer.getPropertySet(target, false)) {
                    Object value = sourceEnhancer.readProperty(source, property, false);
                    if (targetEnhancer != null) {
                        targetEnhancer.writeProperty(target, property, value);
                    } else {
                        targetMap.put(property, value);
                    }
                }
            } else if (targetEnhancer != null) {
                Map sourceMap;
                if (source instanceof Map) {
                    sourceMap = (Map) source;
                } else {
                    sourceMap = BeanMap.create(source);
                }

                for (Object property : sourceMap.keySet()) {
                    targetEnhancer.writeProperty(source, (String) property, sourceMap.get(property));
                }
            } else {
                BeanUtils.copyProperties(target, source);
            }
        } catch (Exception e) {
            throw e;
        } catch (Throwable t) {
            throw new IllegalStateException(t);
        }
    }

}