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

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.data.entity.BeanEntityEnhancer.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.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

import net.sf.cglib.beans.BeanMap;

import org.apache.commons.beanutils.PropertyUtils;

import com.bstek.dorado.data.type.EntityDataType;

public abstract class BeanEntityEnhancer extends EntityEnhancer {
    private static Set<Class<?>> cachedTypes = Collections.synchronizedSet(new HashSet<Class<?>>());
    private static Map<Class<?>, Map<String, Boolean>> propertiesCache = new Hashtable<Class<?>, Map<String, Boolean>>();
    private static Map<Class<?>, Map<Method, String>> readMethodsCache = new Hashtable<Class<?>, Map<Method, String>>();
    private static Map<Class<?>, Map<Method, String>> writeMethodsCache = new Hashtable<Class<?>, Map<Method, String>>();

    private Class<?> beanType;
    private Object entity;
    private BeanMap beanMap;
    protected Map<String, Boolean> properties;
    protected Map<Method, String> readMethods;
    protected Map<Method, String> writeMethods;

    public BeanEntityEnhancer(EntityDataType dataType, Class<?> beanType) throws Exception {
        super(dataType);
        this.beanType = beanType;
        buildReflectionCahce();
    }

    public Class<?> getBeanType() {
        return beanType;
    }

    protected synchronized void buildReflectionCahce() throws Exception {
        synchronized (cachedTypes) {
            if (!cachedTypes.contains(beanType)) {
                cachedTypes.add(beanType);

                Map<String, Boolean> properties = new Hashtable<String, Boolean>();
                Map<Method, String> readMethods = new Hashtable<Method, String>();
                Map<Method, String> writeMethods = new Hashtable<Method, String>();
                PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(beanType);
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    String property = propertyDescriptor.getName();
                    if (propertyDescriptor.getReadMethod() == null) {
                        continue;
                    }

                    properties.put(property, Boolean.valueOf(propertyDescriptor.getWriteMethod() != null));

                    Method readMethod = propertyDescriptor.getReadMethod();
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    if (readMethod != null) {
                        if (readMethod.getDeclaringClass() != beanType) {
                            readMethod = beanType.getMethod(readMethod.getName(), readMethod.getParameterTypes());
                        }
                        readMethods.put(readMethod, property);
                    }
                    if (writeMethod != null) {
                        if (writeMethod.getDeclaringClass() != beanType) {
                            writeMethod = beanType.getMethod(writeMethod.getName(),
                                    writeMethod.getParameterTypes());
                        }
                        writeMethods.put(writeMethod, property);
                    }
                }
                propertiesCache.put(beanType, properties);
                readMethodsCache.put(beanType, readMethods);
                writeMethodsCache.put(beanType, writeMethods);
                this.properties = properties;
                this.readMethods = readMethods;
                this.writeMethods = writeMethods;
            } else {
                this.properties = propertiesCache.get(beanType);
                this.readMethods = readMethodsCache.get(beanType);
                this.writeMethods = writeMethodsCache.get(beanType);
            }
        }
    }

    @Override
    protected Set<String> doGetPropertySet(Object entity, boolean excludeExProperties) {
        Map<String, Object> exProperties = getExProperties(false);
        if (excludeExProperties || exProperties == null || exProperties.isEmpty()) {
            return properties.keySet();
        } else {
            Set<String> propertySet = new HashSet<String>(properties.keySet());
            propertySet.addAll(exProperties.keySet());
            return propertySet;
        }
    }

    protected BeanMap getBeanMap(Object entity) {
        if (entity == this.entity && beanMap != null) {
            return beanMap;
        }

        this.entity = entity;
        beanMap = BeanMap.create(entity);
        return beanMap;
    }

    @Override
    protected Object internalReadProperty(Object entity, String property) throws Exception {
        return getBeanMap(entity).get(property);
    }

    @Override
    protected void internalWriteProperty(Object entity, String property, Object value) throws Exception {
        BeanMap beanMap = getBeanMap(entity);
        Class<?> propertyType = beanMap.getPropertyType(property);
        if (!propertyType.isInstance(value)) {
            value = tryConvertValue(propertyType, value);
        }
        PropertyUtils.setSimpleProperty(entity, property, value);
    }

    protected Object tryConvertValue(Class<?> propertyType, Object value) {
        if (java.util.Date.class.isAssignableFrom(propertyType) && value instanceof java.util.Date) {
            long time = ((java.util.Date) value).getTime();
            if (java.sql.Date.class.isAssignableFrom(propertyType)) {
                value = new java.sql.Date(time);
            } else if (java.sql.Time.class.isAssignableFrom(propertyType)) {
                value = new java.sql.Time(time);
            } else if (java.sql.Timestamp.class.isAssignableFrom(propertyType)) {
                value = new java.sql.Timestamp(time);
            }
        }
        return value;
    }

    @Override
    public Object readProperty(Object entity, String property, boolean ignoreInterceptors) throws Throwable {
        boolean isExProp = !properties.containsKey(property);
        Object result = internalReadProperty(entity, property, isExProp);
        if (ignoreInterceptors) {
            return result;
        } else {
            return interceptReadMethod(entity, property, result, isExProp);
        }
    }

    @Override
    public void writeProperty(Object entity, String property, Object value) throws Throwable {
        Boolean writable = properties.get(property);
        boolean isExProp = !(writable != null && writable.booleanValue());
        if (interceptWriteMethod(entity, property, value, isExProp)) {
            internalWriteProperty(entity, property, value, isExProp);
        }
    }

}