/******************************************************************************* * Copyright (c) 2007 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.smooks.configuration.editors.javabean12; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.jboss.tools.smooks.configuration.editors.IXMLStructuredObject; import org.jboss.tools.smooks.configuration.editors.utils.JavaPropertyUtils; /** * @author Dart Peng * */ public class JavaBeanModel implements IXMLStructuredObject, Cloneable { private boolean flat = false; private boolean expaned = false; private Properties extendProperties = new Properties(); protected PropertyChangeSupport support = new PropertyChangeSupport(this); private String beanClassString = null; public void setBeanClassString(String beanClassString) { this.beanClassString = beanClassString; } private Object waring = null; private Object error = null; private String name = ""; //$NON-NLS-1$ private Class typeRef = null; private boolean many = false; private boolean collection = false; private boolean isPrimitive = false; private boolean hasGenericType = false; private Class<? extends Object> beanClass = null; private JavaBeanModel parent = null; public Class getBeanClass() { return beanClass; } private Class parentClass = null; // private boolean isRoot = false; private boolean isRootClassModel = false; /** * @return the isRootClassModel */ public boolean isRootClassModel() { return isRootClassModel || getParent() == null; } public boolean isFlat() { return flat; } public void setFlat(boolean flat) { this.flat = flat; } /** * @param isRootClassModel * the isRootClassModel to set */ public void setRootClassModel(boolean isRootClassModel) { this.isRootClassModel = isRootClassModel; } public void addNodePropetyChangeListener(PropertyChangeListener listener) { PropertyChangeListener[] array = support.getPropertyChangeListeners(); for (int i = 0; i < array.length; i++) { if (listener == array[i]) return; } support.addPropertyChangeListener(listener); } public void removeNodePropetyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } public void cleanAllNodePropertyChangeListeners() { PropertyChangeListener[] ps = support.getPropertyChangeListeners(); for (int i = 0; i < ps.length; i++) { PropertyChangeListener p = ps[i]; support.removePropertyChangeListener(p); } } // /** // * @return the isRoot // */ // public boolean isRoot() { // return isRoot; // } public String getBeanClassString() { if (beanClassString != null && beanClassString.length() != 0) { return this.beanClassString; } Class clazz = this.getBeanClass(); if (clazz == null) return "<null>"; //$NON-NLS-1$ if (clazz.isArray()) { String s = clazz.getComponentType().getName(); return s + "[]"; //$NON-NLS-1$ } // if(this.isList()){ // String cs = "<"+System.currentTimeMillis()+">"; // Class componentClazz = this.getComponentClass(); // if(componentClazz != null){ // cs = "<" + componentClazz.getName() +">"; // } // return clazz.getName() + cs; // } return clazz.getName(); } public String getBeanClassStringWithList() { String s = getBeanClassString(); if (this.isList()) { Class genericType = getGenericType(); if (genericType != null) s += "<" + genericType.getName() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ } return s; } /** * @param isRoot * the isRoot to set */ // public void setRoot(boolean isRoot) {ois private boolean isList = false; private Class componentClass = null; private boolean lazyLoadProperties = true; public boolean isList() { if (beanClass == null) return false; if (Collection.class.isAssignableFrom(beanClass)) { if (this.propertyDescriptor != null) { Method rmethod = propertyDescriptor.getReadMethod(); if (rmethod != null) { Type returnType = rmethod.getGenericReturnType(); if (returnType instanceof ParameterizedType) { Type gtype = ((ParameterizedType) returnType).getActualTypeArguments()[0]; if(gtype instanceof Class){ Class beanType = (Class) gtype; componentClass = beanType; setGenericType(true); } if(gtype instanceof WildcardType){ Type[] upperBounds = ((WildcardType)gtype).getUpperBounds(); Type[] lowerBounds = ((WildcardType)gtype).getLowerBounds(); if(upperBounds.length != 0){ componentClass = (Class<?>) upperBounds[0]; setGenericType(true); } if(lowerBounds.length != 0){ componentClass = (Class<?>) lowerBounds[0]; setGenericType(true); } } } } } setList(true); } return isList; } public void setList(boolean isList) { this.isList = isList; } private PropertyDescriptor propertyDescriptor; public PropertyDescriptor getPropertyDescriptor() { return propertyDescriptor; } public void setPropertyDescriptor(PropertyDescriptor propertyDescriptor) { this.propertyDescriptor = propertyDescriptor; } JavaBeanModel(Class beanClass, String beanName, PropertyDescriptor propertyDescriptor, Class parentClass, boolean lazyLoadProperties) { this.lazyLoadProperties = lazyLoadProperties; this.beanClass = toConcreteImpl(beanClass); this.name = beanName; if (beanClass == null) return; if (this.name == null) { this.name = beanClass.getSimpleName(); } if (propertyDescriptor == null) setRootClassModel(true); this.propertyDescriptor = propertyDescriptor; Class beanType = beanClass; if (beanClass.isArray()) { beanType = beanClass.getComponentType(); setMany(true); componentClass = beanType; } if (Collection.class.isAssignableFrom(beanClass)) { if (this.propertyDescriptor != null) { Method rmethod = propertyDescriptor.getReadMethod(); if (rmethod != null) { Type returnType = rmethod.getGenericReturnType(); if (returnType instanceof ParameterizedType) { Type gtype = ((ParameterizedType) returnType).getActualTypeArguments()[0]; if (gtype instanceof Class) { beanType = (Class) gtype; componentClass = beanType; } } } } setList(true); } if (beanType.isPrimitive() || JavaBeanModelFactory.isPrimitiveObject(beanType)) { this.parentClass = parentClass; if (!isArray() && !isList()) setPrimitive(true); return; } this.parentClass = parentClass; if (!lazyLoadProperties) this.getProperties(); } JavaBeanModel(Class beanClass, String beanName, PropertyDescriptor propertyDescriptor) { this(beanClass, beanName, propertyDescriptor, null, true); } public JavaBeanModel(Class beanClass) { this(beanClass, null, null, null, true); } public JavaBeanModel(Class beanClass, String name) { this(beanClass, name, null, null, true); } JavaBeanModel(Class<?> beanClass, boolean lazyLoadProperties) { this(beanClass, null, null, null, lazyLoadProperties); } private Class<? extends Object> toConcreteImpl(Class declaredType) { // Intentionally not doing an isAssignableFrom test... want to know is it the // the exact class... if(declaredType == List.class) { return ArrayList.class; } else if(declaredType == Set.class) { return LinkedHashSet.class; } else if(declaredType == Collection.class) { return ArrayList.class; } else if(declaredType == Map.class) { return LinkedHashMap.class; } return declaredType; } public boolean isPrimitive() { Class<?> beanType = getBeanClass(); if (beanType == null) return false; if (beanType.isPrimitive() || JavaBeanModelFactory.isPrimitiveObject(beanType)) { if (!isArray() && !isList()) setPrimitive(true); } return isPrimitive; } public void setPrimitive(boolean isPrimitive) { this.isPrimitive = isPrimitive; } public boolean isArray() { if (beanClass == null) return false; if (beanClass.isArray()) { Class beanType = beanClass.getComponentType(); setMany(true); componentClass = beanType; setGenericType(true); } return many; } public Class getGenericType() { return componentClass; } public void setMany(boolean many) { this.many = many; } // public boolean isCollection() { // return collection; // } // // public void setCollection(boolean collection) { // this.collection = collection; // } // public Class getTypeRef() { // return typeRef; // } // // public void setTypeRef(Class typeRef) { // this.typeRef = typeRef; // } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addProperty(JavaBeanModel property) { if (properties != null) { properties.add(property); property.setParent(this); } } protected void createArrayChildren(Class<Object> clazz, String name, PropertyDescriptor pd, Class<? extends Object> parentClass, boolean lazyLoad) { JavaBeanModel proxyModel = newChildJavaBean(clazz, name, pd, parentClass, lazyLoad); addProperty(proxyModel); } protected void createListChildren(Class<Object> clazz, String name, PropertyDescriptor pd, Class<? extends Object> parentClass, boolean lazyLoad) { JavaBeanModel proxyModel = newChildJavaBean(clazz, name, pd, parentClass, lazyLoad); addProperty(proxyModel); } private List properties; /** * @return the expaned */ public boolean isExpaned() { return expaned; } public List getProperties() { expaned = true; JavaBeanModel parent = this.getParent(); if (parent != null) { if (parent.isFlat()) return Collections.emptyList(); } if (properties == null) { properties = new ArrayList(); if (isPrimitive()) return properties; Class beanType = beanClass; if (isArray() || isList()) { if (componentClass != null) { createArrayChildren(componentClass, componentClass.getSimpleName(), null, beanClass, this.lazyLoadProperties); beanType = componentClass; } else { createListChildren(Object.class, "object", null, beanClass, this.lazyLoadProperties); //$NON-NLS-1$ beanType = componentClass; } return properties; } if (beanType == null) return Collections.EMPTY_LIST; PropertyDescriptor[] pds = JavaPropertyUtils.getPropertyDescriptor(beanType); for (int i = 0; i < pds.length; i++) { PropertyDescriptor pd = pds[i]; if ("class".equals(pd.getName())) //$NON-NLS-1$ continue; if (pd.getPropertyType() == null) continue; if (Collection.class.isAssignableFrom(pd.getPropertyType())) { Method rmethod = pd.getReadMethod(); if (rmethod != null) { Type returnType = rmethod.getGenericReturnType(); if (returnType instanceof ParameterizedType) { Type[] types = ((ParameterizedType) returnType).getActualTypeArguments(); if (types == null || types.length == 0) { continue; } } else { continue; } } } JavaBeanModel jbm = newChildJavaBean(pd.getPropertyType(), pd.getName(), pd, beanClass, this.lazyLoadProperties); addProperty(jbm); } } return properties; } protected JavaBeanModel newChildJavaBean(Class clazz, String name, PropertyDescriptor pd, Class parentClass, boolean lazyLoading) { return new JavaBeanModel(clazz, name, pd, parentClass, lazyLoading); } public void setProperties(List properties) { this.properties = properties; } public boolean propertiesHasBeenLoaded() { return properties != null; } /** * @return the parent */ public JavaBeanModel getParent() { return parent; } /** * @param parent * the parent to set */ public void setParent(JavaBeanModel parent) { this.parent = parent; } public Object getWarning() { return waring; } public void setWarning(Object waring) { this.waring = waring; } public Object getError() { return error; } public void setError(Object error) { this.error = error; } public JavaBeanModel getRootParent() { JavaBeanModel parent = this.getParent(); if (parent == null) return this; JavaBeanModel temp = parent; while (temp != null) { parent = temp; temp = temp.getParent(); } return parent; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { StringBuffer buffer = new StringBuffer("JavaName : " + name); //$NON-NLS-1$ if (beanClass != null) buffer.append("BeanClass : " + this.beanClass.getName()); //$NON-NLS-1$ if (this.properties != null) { buffer.append("\n"); //$NON-NLS-1$ for (Iterator<?> iterator = properties.iterator(); iterator.hasNext();) { JavaBeanModel child = (JavaBeanModel) iterator.next(); buffer.append("\t"); //$NON-NLS-1$ buffer.append(child.toString()); buffer.append("\n"); //$NON-NLS-1$ } } return buffer.toString(); } public String getSelectorString() { if (parent == null) { return getBeanClassString(); } if (parent.getClass() == JavaBeanList.class) { return getBeanClassString(); } if (parent.isArray() || parent.isList()) { return getBeanClassString(); } return getName(); } public boolean hasGenericType() { return hasGenericType; } public void setGenericType(boolean hasGenericType) { this.hasGenericType = hasGenericType; } public boolean isAttribute() { return false; } public List<IXMLStructuredObject> getChildren() { List ps = getProperties(); if (ps != null) { return ps; } return null; } public Object getID() { Class<?> clazz = getBeanClass(); if(Collection.class.isAssignableFrom(clazz)){ return getBeanClassString() + getName(); } return getBeanClass(); } public String getNodeName() { return getSelectorString(); } public boolean isRootNode() { // TODO Auto-generated method stub return false; } public void setComponentClass(Class clazz) { componentClass = clazz; } public Class getComponentClass() { return componentClass; } public void addExtendProperty(String name, String value) { extendProperties.setProperty(name, value); } public String getExtendProperty(String name) { return extendProperties.getProperty(name); } public Object clone() { if (isList()) { JavaBeanModel model = JavaBeanModelFactory.getJavaBeanModelWithLazyLoad(ArrayList.class); model.setComponentClass(componentClass); return model; } return JavaBeanModelFactory.getJavaBeanModelWithLazyLoad(this.getBeanClass()); } }