Java tutorial
/** * Copyright (c) 2007-2008 by Carlos Gmez Montiel <iberck@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * his program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.metamorfosis.model; import java.lang.reflect.Field; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.beanutils.LazyDynaBean; import org.apache.commons.beanutils.LazyDynaClass; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Esta clase modela cuatro principios bsicos. * * 1. Se le pueden inyectar propiedades a la clase * 2. Se le pueden inyectar propiedades a los fields * 3. Tiene un objeto metaClass el cual contiene una lista de propiedades * originales e inyectadas. * 4. Las propiedades originales e inyectadas sern accesibles por medio de * instance.get('propertyName') * * @author iberck */ public abstract class AbstractJMetaClass extends LazyDynaBean implements MetaClass { private static final Log log = LogFactory.getLog(AbstractJMetaClass.class); private String className; private MetaClassObject metaClass; private Object source; protected AbstractJMetaClass(Object instance) { this.source = instance; } protected AbstractJMetaClass(String className) { this.className = className; } public MetaClassObject getMetaClass() { return metaClass; } private static Object instantiateClass(String className) throws MetaClassException { try { return Class.forName(className).newInstance(); } catch (Exception ex) { throw new MetaClassException("Error al instanciar la clase '" + className + "'", ex); } } /** * Borra dinamicamente la propiedad * @param name Property name */ private void removeProperty(String propertyName) { ((LazyDynaClass) getDynaClass()).remove(propertyName); } private void replaceProperty(String propertyName, Object newPropertyValue) { try { removeProperty(propertyName); PropertyUtils.setNestedProperty(this, propertyName, newPropertyValue); } catch (Exception ex) { } } protected void copySourceProperties() { if (className != null) { source = instantiateClass(className); } try { // copia todas las propiedades del objeto original // y las pone al servicio con get('originalPropertyName') PropertyUtils.copyProperties(this, source); } catch (Exception ex) { throw new MetaClassException("Error al crear el metapojo", ex); } } @Override public void injectClassProperty(String propName, Object propValue) throws MetaClassException { try { // Pone la propiedad al servicio con get('injectedPropertyName') PropertyUtils.setNestedProperty(this, propName, propValue); } catch (Exception ex) { throw new MetaClassException("Error al inyectar la propiedad '[" + propName + ", " + propValue + "']", ex); } } @Override public void injectFieldProperty(String fieldName, String propertyName, Object propertyValue) { try { // 1.validar que exista el field y obtenerlo Object fieldObj = PropertyUtils.getNestedProperty(this, fieldName); // 2. MetaClass // datos del objeto original (copySource) JMetaClass metaField = new JMetaClass(fieldObj); Map<String, Object> metaFieldClassProperties = new HashMap(); // datos inyectados (propertyName:propertyValue) metaFieldClassProperties.put(propertyName, propertyValue); metaField.setInjectedClassProperties(metaFieldClassProperties); // datos del metaClassProperty (name, type) HashMap propertiesHash = getMetaClass().getPropertiesHash(); MetaClassProperty metaClassProperty = new MetaClassProperty(); metaClassProperty.setName(fieldName); metaClassProperty.setType(this.getClass()); PropertyUtils.copyProperties(metaField, metaClassProperty); metaField.initialize(); // 3. reemplazar propiedad original con el metaField replaceProperty(fieldName, metaField); // accesible por medio de get propertiesHash.put(fieldName, metaField); // accesible por medio de metaclass.properties } catch (Exception ex) { throw new MetaClassException( "No existe el field '" + fieldName + "' " + "dentro de la clase '" + source + "'", ex); } } /** * Pone las propiedades existentes dentro del objeto * * metaClass.properties */ protected void createMetaClass() { this.metaClass = new MetaClassObject(); HashMap propertiesHash = new HashMap(); // obtener las propiedades inyectadas y meterlas en un hash DynaProperty[] dynaProperties = getDynaClass().getDynaProperties(); for (DynaProperty dynaProperty : dynaProperties) { if (!dynaProperty.getName().equals("class")) { MetaClassProperty mcProperty = new MetaClassProperty(); mcProperty.setName(dynaProperty.getName()); mcProperty.setType(dynaProperty.getType()); propertiesHash.put(mcProperty.getName(), mcProperty); } } // obtener las propiedades del source, si existiera en el hash se // reemplazara para tener el type correcto ya que los dynaProperties // no tienen el type original. Field[] declaredFields = source.getClass().getDeclaredFields(); for (Field field : declaredFields) { MetaClassProperty mcProperty = new MetaClassProperty(); mcProperty.setName(field.getName()); mcProperty.setType(field.getType()); propertiesHash.put(mcProperty.getName(), mcProperty); } // crear el objeto metaClass this.metaClass.setPropertiesHash(propertiesHash); } public class MetaClassObject { private HashMap propertiesHash; public Collection getProperties() { return propertiesHash.values(); } public HashMap getPropertiesHash() { return propertiesHash; } public void setPropertiesHash(HashMap propertiesHash) { this.propertiesHash = propertiesHash; } } public class MetaClassProperty { private String name; private Class type; public String getName() { return name; } public void setName(String name) { this.name = name; } public Class getType() { return type; } public void setType(Class type) { this.type = type; } } /** * Se utiliza para cuando se obtenga inyectado un objeto de tipo JMetaClass * de tal forma que al obtener su valor obtenga el de su objeto original.toString() * * instance.get('gMetaClassInstance') * * @return */ @Override public String toString() { return source != null ? source.toString() : super.toString(); } }