Java tutorial
/* * 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; } }