com.bstek.dorado.data.config.definition.DataTypeDefinition.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.data.config.definition.DataTypeDefinition.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.config.definition;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.reflect.MethodUtils;

import com.bstek.dorado.annotation.ResourceInjection;
import com.bstek.dorado.common.Namable;
import com.bstek.dorado.config.definition.CreationContext;
import com.bstek.dorado.config.definition.Definition;
import com.bstek.dorado.config.definition.DefinitionUtils;
import com.bstek.dorado.config.definition.ObjectDefinition;
import com.bstek.dorado.core.Context;
import com.bstek.dorado.core.bean.Scope;
import com.bstek.dorado.core.el.ExpressionHandler;
import com.bstek.dorado.data.Constants;
import com.bstek.dorado.data.config.DataTypeName;
import com.bstek.dorado.data.config.xml.DataXmlConstants;
import com.bstek.dorado.data.resource.ModelResourceBundle;
import com.bstek.dorado.data.resource.ModelResourceManager;
import com.bstek.dorado.data.type.AggregationDataType;
import com.bstek.dorado.data.type.DataType;
import com.bstek.dorado.data.type.EntityDataType;
import com.bstek.dorado.data.type.RudeDataType;
import com.bstek.dorado.data.type.property.PropertyDef;
import com.bstek.dorado.util.CloneUtils;

/**
 * DataType?
 * 
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since Mar 8, 2008
 * @see com.bstek.dorado.data.type.DataType
 */
public class DataTypeDefinition extends ListenableObjectDefinition implements Namable {
    private static final String[] DEFAULT_PROPERTIES = new String[] { "caption", "label", "title" };
    private static final String SELF_AGGREGATION_DATA_TYPE_SCTION = '[' + PropertyDef.SELF_DATA_TYPE_NAME + ']';
    private static final String RESOURCE_RELATIVE_DEFINITION = "resourceRelativeDefinition";

    private String name;
    private String id;
    private Class<?> matchType;
    private Class<?> creationType;
    private boolean global;
    private Map<String, PropertyDefDefinition> propertyDefs;
    private boolean isAggregationType;

    private DataType cachedInstance;

    public DataTypeDefinition() {
        setScope(Scope.thread);
    }

    @Override
    public void setCacheCreatedObject(boolean cacheCreatedObject) {
        throw new UnsupportedOperationException();
    }

    public DataTypeDefinition(String name) {
        setName(name);
    }

    /**
     * DataType??
     */
    public String getName() {
        return name;
    }

    /**
     * DataType??
     */
    public void setName(String name) {
        this.name = name;
        if (StringUtils.isNotEmpty(name)) {
            if (StringUtils.isEmpty(getBeanId())) {
                setBeanId(Constants.SCOPE_DATA_TYPE_PREFIX + name);
            }

            DataTypeName dataTypeName = new DataTypeName(name);
            isAggregationType = (dataTypeName.getSubDataTypes().length == 1);
        }
    }

    public String getId() {
        return id;
    }

    void setId(String id) {
        this.id = id;
    }

    public boolean isAggregationType() {
        return isAggregationType;
    }

    /**
     * DataType?
     */
    public Class<?> getMatchType() {
        return matchType;
    }

    /**
     * DataType?
     */
    public void setMatchType(Class<?> matchType) {
        this.matchType = matchType;
    }

    /**
     * DataType??
     */
    public Class<?> getCreationType() {
        return creationType;
    }

    /**
     * DataType??
     */
    public void setCreationType(Class<?> creationType) {
        this.creationType = creationType;
    }

    public boolean isGlobal() {
        return global;
    }

    /**
     * DataType?
     */
    @Deprecated
    public void setGlobal(boolean global) {
        this.global = global;
    }

    /**
     * ?DataType
     * 
     * @param name
     *            ??
     * @param propertyDef
     *            ?
     */
    public void addPropertyDef(PropertyDefDefinition propertyDef) {
        if (propertyDefs == null) {
            propertyDefs = new LinkedHashMap<String, PropertyDefDefinition>();
        }
        propertyDefs.put(propertyDef.getName(), propertyDef);
    }

    @Deprecated
    public void addPropertyDef(String name, PropertyDefDefinition propertyDef) {
        if (propertyDefs == null) {
            propertyDefs = new LinkedHashMap<String, PropertyDefDefinition>();
        }
        propertyDefs.put(name, propertyDef);
    }

    /**
     * ???
     * 
     * @param name
     *            ??
     * @return 
     */
    public PropertyDefDefinition getPropertyDef(String name) {
        if (propertyDefs != null) {
            return propertyDefs.get(name);
        } else {
            return null;
        }
    }

    /**
     * DataTypeMap?<br>
     * Map???
     */
    public Map<String, PropertyDefDefinition> getPropertyDefs() {
        return propertyDefs;
    }

    @Override
    protected Object doCreate(CreationContext context, Object[] constructorArgs) throws Exception {
        if (global) {
            DataType dataType = cachedInstance;
            if (dataType != null) {
                return dataType;
            }

            dataType = (DataType) super.doCreate(context, constructorArgs);
            if (!(dataType instanceof EntityDataType || dataType instanceof AggregationDataType)) {
                cachedInstance = dataType;
            }
            return dataType;
        } else {
            return super.doCreate(context, constructorArgs);
        }
    }

    protected ExpressionHandler getExpressionHandler(Context doradoContext) throws Exception {
        return (ExpressionHandler) doradoContext.getServiceBean("expressionHandler");
    }

    private void injectResourceStrings(DataTypeDefinition dataTypeDefinition, EntityDataType dataType)
            throws Exception {
        Context doradoContext = Context.getCurrent();
        ModelResourceManager modelResourceManager = (ModelResourceManager) doradoContext
                .getServiceBean("modelResourceManager");
        ModelResourceBundle bundle = (ModelResourceBundle) modelResourceManager.getBundle(dataTypeDefinition);
        if (bundle == null) {
            return;
        }

        Properties strings = bundle.getSubProperties(dataTypeDefinition.getName());
        if (strings == null) {
            return;
        }

        for (Map.Entry<Object, Object> entry : strings.entrySet()) {
            injectResourceString(dataType, (String) entry.getKey(), (String) entry.getValue());
        }
    }

    protected void injectResourceString(EntityDataType dataType, String key, String resourceString)
            throws Exception {
        Object object = dataType;
        ResourceInjection resourceInjection = object.getClass().getAnnotation(ResourceInjection.class);

        String[] sections = StringUtils.split(key, ".");
        int len = sections.length;
        for (int i = 0; i < len; i++) {
            String section = sections[i];
            boolean isObject = section.charAt(0) == '#';

            if (isObject) {
                section = section.substring(1);

                if (resourceInjection == null) {
                    throwInvalidResourceKey(key);
                }
                String methodName = resourceInjection.subObjectMethod();
                if (StringUtils.isEmpty(methodName)) {
                    throwInvalidResourceKey(key);
                }
                object = MethodUtils.invokeExactMethod(object, methodName, new String[] { section });
                if (object == null) {
                    break;
                }
                resourceInjection = object.getClass().getAnnotation(ResourceInjection.class);

                if (i == len - 1) {
                    String[] defaultProperties;
                    if (resourceInjection == null) {
                        defaultProperties = DEFAULT_PROPERTIES;
                    } else {
                        defaultProperties = resourceInjection.defaultProperty();
                    }

                    boolean found = false;
                    for (String property : defaultProperties) {
                        if (PropertyUtils.isWriteable(object, property)) {
                            // if (PropertyUtils.getSimpleProperty(object,
                            // property) == null) {
                            PropertyUtils.setSimpleProperty(object, property, resourceString);
                            // }
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        throwInvalidResourceKey(key);
                    }
                }
            } else {
                if (i == len - 1) {
                    if (PropertyUtils.getSimpleProperty(object, section) == null) {
                        PropertyUtils.setSimpleProperty(object, section, resourceString);
                    }
                } else {
                    object = PropertyUtils.getSimpleProperty(object, section);
                }
            }
        }
    }

    private void throwInvalidResourceKey(String key) {
        throw new IllegalArgumentException("Invalid resource key \"" + key + "\".");
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void doInitObject(Object object, CreationInfo creationInfo, CreationContext context)
            throws Exception {
        Context doradoContext = Context.getCurrent();
        ExpressionHandler expressionHandler = getExpressionHandler(doradoContext);
        JexlContext jexlContext = expressionHandler.getJexlContext();

        Definition resourceRelativeDefinition = (Definition) jexlContext.get(RESOURCE_RELATIVE_DEFINITION);
        jexlContext.set(RESOURCE_RELATIVE_DEFINITION, this);
        try {
            DataType dataType = (DataType) object;

            RudeDataType rudeDataType = (RudeDataType) dataType;
            rudeDataType.setName(name);
            if (StringUtils.isNotEmpty(id)) {
                rudeDataType.setId(id);
            }

            Class<?> matchType = (Class<?>) creationInfo.getUserData("matchType");
            if (matchType != null && !Object.class.equals(matchType)) {
                rudeDataType.setMatchType(matchType);
            }

            Class<?> creationType = (Class<?>) creationInfo.getUserData("creationType");
            if (creationType != null) {
                rudeDataType.setCreationType(creationType);
            }

            Map<String, PropertyDefDefinition> propertyDefs = (Map<String, PropertyDefDefinition>) creationInfo
                    .getUserData("propertyDefs");
            if (propertyDefs != null && !propertyDefs.isEmpty()) {
                if (dataType instanceof EntityDataType) {
                    EntityDataType entityDataType = (EntityDataType) dataType;
                    for (PropertyDefDefinition definition : propertyDefs.values()) {
                        Object tempDataType = definition.getProperty(DataXmlConstants.ATTRIBUTE_DATA_TYPE);
                        if (tempDataType != null && tempDataType instanceof DataTypeDefinitionReference) {
                            DataTypeDefinitionReference dataTypeRef = (DataTypeDefinitionReference) tempDataType;
                            String nameRef = dataTypeRef.getName();
                            if (nameRef.equals(PropertyDef.SELF_DATA_TYPE_NAME)) {
                                dataTypeRef.setName(name);
                            } else if (nameRef.indexOf(SELF_AGGREGATION_DATA_TYPE_SCTION) >= 0) {
                                nameRef = nameRef.replace(SELF_AGGREGATION_DATA_TYPE_SCTION, '[' + name + ']');
                                dataTypeRef.setName(nameRef);
                            }
                        }

                        jexlContext.set(RESOURCE_RELATIVE_DEFINITION, definition);
                        PropertyDef propertyDef = (PropertyDef) DefinitionUtils.getRealValue(definition, context);
                        entityDataType.addPropertyDef(propertyDef);
                        jexlContext.set(RESOURCE_RELATIVE_DEFINITION, this);
                    }
                } else {
                    throw new IllegalArgumentException("Can not add PropertyDef for DataType [" + name + "].");
                }
            }

            super.doInitObject(dataType, creationInfo, context);

            if (dataType instanceof EntityDataType) {
                EntityDataType entityDataType = ((EntityDataType) dataType);
                if (entityDataType.isAutoCreatePropertyDefs()) {
                    entityDataType.createPropertyDefs();
                }

                Definition[] parents = creationInfo.getParents().toArray(new Definition[0]);
                for (int i = parents.length - 1; i >= 0; i--) {
                    Definition parent = parents[i];
                    if (parent instanceof DataTypeDefinition) {
                        DataTypeDefinition parentDataType = (DataTypeDefinition) parent;
                        if (!parentDataType.isGlobal() || parentDataType.isAggregationType()) {
                            continue;
                        }

                        if (dataType instanceof EntityDataType) {
                            injectResourceStrings(parentDataType, entityDataType);
                        }
                    }
                }

                if (isGlobal() && !isAggregationType()) {
                    injectResourceStrings(this, entityDataType);
                }
            }
        } finally {
            jexlContext.set(RESOURCE_RELATIVE_DEFINITION, resourceRelativeDefinition);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void initCreationInfo(CreationInfo creationInfo, ObjectDefinition definition,
            boolean processConstrInfos) throws Exception {
        super.initCreationInfo(creationInfo, definition, processConstrInfos);
        DataTypeDefinition dataTypeDefinition = (DataTypeDefinition) definition;

        if (processConstrInfos) {
            // process MatchType and CreationType
            Class<?> matchType = dataTypeDefinition.getMatchType();
            if (matchType != null) {
                creationInfo.setUserData("matchType", matchType);
            }
            Class<?> creationType = dataTypeDefinition.getCreationType();
            if (creationType != null) {
                creationInfo.setUserData("creationType", creationType);
            }
        }

        // process PropertyDefs
        if (isAggregationType) {
            return;
        }

        Map<String, ObjectDefinition> allPropertyDefs = (Map<String, ObjectDefinition>) creationInfo
                .getUserData("propertyDefs");
        if (allPropertyDefs == null) {
            allPropertyDefs = new LinkedHashMap<String, ObjectDefinition>();
            creationInfo.setUserData("propertyDefs", allPropertyDefs);
        }

        Map<String, PropertyDefDefinition> propertyDefs = dataTypeDefinition.getPropertyDefs();
        if (propertyDefs != null) {
            for (Map.Entry<String, PropertyDefDefinition> entry : propertyDefs.entrySet()) {
                String name = entry.getKey();
                PropertyDefDefinition propertyDef = entry.getValue();

                ObjectDefinition parentProperty = allPropertyDefs.get(name);
                if (parentProperty != null) {
                    propertyDef = CloneUtils.clone(propertyDef);
                    Definition[] originParents = propertyDef.getParents();
                    Definition[] parents;
                    if (originParents == null) {
                        parents = new Definition[] { parentProperty };
                    } else {
                        parents = new Definition[originParents.length + 1];
                        parents[0] = parentProperty;
                        System.arraycopy(originParents, 0, parents, 1, originParents.length);
                    }
                    propertyDef.setParents(parents);
                }
                allPropertyDefs.put(name, propertyDef);
            }
        }
    }

    @Override
    protected void setObjectProperty(Object object, String property, Object value, CreationContext context)
            throws Exception {
        try {
            super.setObjectProperty(object, property, value, context);
        } catch (NoSuchMethodException e) {
            if (DataXmlConstants.ATTRIBUTE_ELEMENT_DATA_TYPE.equals(property)
                    && !(object instanceof EntityDataType)) {
                // do nothing
            } else {
                throw e;
            }
        }
    }

}