com.bstek.dorado.config.definition.Definition.java Source code

Java tutorial

Introduction

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

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;

import com.bstek.dorado.config.ConfigUtils;
import com.bstek.dorado.core.io.Resource;
import com.bstek.dorado.util.CloneUtils;

/**
 * ?
 * <p>
 * ???????????
 * </p>
 * 
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since Mar 7, 2008
 */
public abstract class Definition implements Cloneable {
    private static final Object[] EMPTY_ARGS = new Object[0];

    private Resource resource;
    private Resource[] dependentResources;

    private Map<String, Object> properties;
    private Map<String, Object> unmodifiableProperties;
    private List<Operation> initOperations;
    private List<Operation> unmodifiableInitOperations;

    /**
     * ?<br>
     * ?? ??null
     */
    public Resource getResource() {
        return resource;
    }

    /**
     * ?
     * 
     * @see #getResource()
     */
    public void setResource(Resource resource) {
        this.resource = resource;
    }

    /**
     * @return
     */
    public Resource[] getDependentResources() {
        return dependentResources;
    }

    /**
     * @param dependentResources
     */
    public void setDependentResources(Resource[] dependentResources) {
        this.dependentResources = dependentResources;
    }

    private Map<String, Object> getOrCreateProperties() {
        if (properties == null) {
            properties = new HashMap<String, Object>();
            unmodifiableProperties = Collections.unmodifiableMap(properties);
        }
        return properties;
    }

    /**
     * ??<br>
     * Map?Map??<br>
     * ??????:
     * <ul>
     * <li></li>
     * <li>EL?{@link com.bstek.dorado.core.el.Expression}</li>
     * <li>?{@link com.bstek.dorado.config.definition.Definition}
     * ????</li>
     * <li>?
     * {@link com.bstek.dorado.config.definition.DefinitionReference}
     * ????</li>
     * </ul>
     */
    @SuppressWarnings("unchecked")
    public Map<String, Object> getProperties() {
        return (unmodifiableProperties != null) ? unmodifiableProperties : Collections.EMPTY_MAP;
    }

    public Object getProperty(String property) {
        return (properties != null) ? properties.get(property) : null;
    }

    public void setProperty(String property, Object value) {
        getOrCreateProperties().put(property, value);
    }

    public Object removeProperty(String property) {
        return (properties != null) ? properties.remove(property) : null;
    }

    public void setProperties(Map<String, Object> properties) {
        getOrCreateProperties().putAll(properties);
    }

    /**
     * ?
     * 
     * @param object
     *            ?
     * @param properties
     *            ?
     * @param context
     *            
     * @throws Exception
     */
    protected void initProperties(Object object, Map<String, Object> properties, CreationContext context)
            throws Exception {
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            String property = entry.getKey();
            Object value = entry.getValue();
            try {
                setObjectProperty(object, property, value, context);
            } catch (Exception e) {
                throw new IllegalArgumentException(
                        "Error occured while writing [" + value + "] into property [" + property + "]", e);
            }
        }
    }

    /**
     * ?
     * 
     * @param object
     *            ?
     * @param property
     *            ??
     * @param value
     *            @see {@link #getProperties()}
     * @param context
     *            
     * @throws Exception
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected void setObjectProperty(Object object, String property, Object value, CreationContext context)
            throws Exception {
        if (object instanceof Map) {
            value = DefinitionUtils.getRealValue(value, context);
            if (value instanceof DefinitionSupportedList && ((DefinitionSupportedList) value).hasDefinitions()) {
                List collection = new ArrayList();
                for (Object element : (Collection) value) {
                    Object realElement = DefinitionUtils.getRealValue(element, context);
                    if (realElement != ConfigUtils.IGNORE_VALUE) {
                        collection.add(realElement);
                    }
                }
                value = collection;
            }
            if (value != ConfigUtils.IGNORE_VALUE) {
                ((Map) object).put(property, value);
            }
        } else {
            PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(object, property);
            if (propertyDescriptor != null) {
                Method readMethod = propertyDescriptor.getReadMethod();
                Method writeMethod = propertyDescriptor.getWriteMethod();

                Class<?> propertyType = propertyDescriptor.getPropertyType();
                if (writeMethod != null) {
                    Class<?> oldImpl = context.getDefaultImpl();
                    try {
                        context.setDefaultImpl(propertyType);
                        value = DefinitionUtils.getRealValue(value, context);
                    } finally {
                        context.setDefaultImpl(oldImpl);
                    }
                    if (!propertyType.equals(String.class) && value instanceof String) {
                        if (propertyType.isEnum()) {
                            value = Enum.valueOf((Class) propertyType, (String) value);
                        } else if (StringUtils.isBlank((String) value)) {
                            value = null;
                        }
                    } else if (value instanceof DefinitionSupportedList
                            && ((DefinitionSupportedList) value).hasDefinitions()) {
                        List collection = new ArrayList();
                        for (Object element : (Collection) value) {
                            Object realElement = DefinitionUtils.getRealValue(element, context);
                            if (realElement != ConfigUtils.IGNORE_VALUE) {
                                collection.add(realElement);
                            }
                        }
                        value = collection;
                    }
                    if (value != ConfigUtils.IGNORE_VALUE) {
                        writeMethod.invoke(object, new Object[] { ConvertUtils.convert(value, propertyType) });
                    }
                } else if (readMethod != null && Collection.class.isAssignableFrom(propertyType)) {
                    Collection collection = (Collection) readMethod.invoke(object, EMPTY_ARGS);
                    if (collection != null) {
                        if (value instanceof DefinitionSupportedList
                                && ((DefinitionSupportedList) value).hasDefinitions()) {
                            for (Object element : (Collection) value) {
                                Object realElement = DefinitionUtils.getRealValue(element, context);
                                if (realElement != ConfigUtils.IGNORE_VALUE) {
                                    collection.add(realElement);
                                }
                            }
                        } else {
                            collection.addAll((Collection) value);
                        }
                    }
                } else {
                    throw new NoSuchMethodException(
                            "Property [" + property + "] of [" + object + "] is not writable.");
                }
            } else {
                throw new NoSuchMethodException("Property [" + property + "] not found in [" + object + "].");
            }
        }
    }

    /**
     * ???
     * 
     * @param operation
     *            ??
     */
    public void addInitOperation(Operation operation) {
        if (initOperations == null) {
            initOperations = new ArrayList<Operation>();
            unmodifiableInitOperations = Collections.unmodifiableList(initOperations);
        }
        initOperations.add(operation);
    }

    /**
     * ??
     * 
     * @see #addInitOperation(Operation)
     */
    @SuppressWarnings("unchecked")
    public List<Operation> getInitOperations() {
        return (unmodifiableInitOperations != null) ? unmodifiableInitOperations : Collections.EMPTY_LIST;
    }

    /**
     * ??
     * 
     * @param object
     *            ?
     * @param operations
     *            ???
     * @param context
     *            
     * @throws Exception
     */
    protected void executeInitOperations(Object object, List<Operation> operations, CreationContext context)
            throws Exception {
        if (operations != null) {
            for (Operation operation : operations) {
                operation.execute(object, context);
            }
        }
    }

    protected abstract Object doCreate(CreationContext context, Object[] constuctorArgs) throws Exception;

    /**
     * ??
     * 
     * @param context
     *            
     * @return 
     * @throws Exception
     */
    public final Object create(CreationContext context) throws Exception {
        Object object = doCreate(context, null);
        if (object != null && object instanceof DefinitionPostProcessor) {
            ((DefinitionPostProcessor) object).onInit();
        }
        return object;
    }

    /**
     * ??
     * 
     * @param context
     *            
     * @param constructorArgs
     *            ?
     * @return 
     * @throws Exception
     */
    public final Object create(CreationContext context, Object[] constructorArgs) throws Exception {
        Object object = doCreate(context, constructorArgs);
        if (object != null && object instanceof DefinitionPostProcessor) {
            ((DefinitionPostProcessor) object).onInit();
        }
        return object;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Definition definition = (Definition) super.clone();
        if (properties != null) {
            definition.properties = CloneUtils.clone(properties);
            definition.unmodifiableProperties = Collections.unmodifiableMap(definition.properties);
        }
        if (initOperations != null) {
            definition.initOperations = CloneUtils.clone(initOperations);
            definition.unmodifiableInitOperations = Collections
                    .unmodifiableList(definition.unmodifiableInitOperations);
        }
        return definition;
    }

}