1 43 44 package org.jfree.xml.generator; 45 46 import java.beans.BeanInfo ; 47 import java.beans.IndexedPropertyDescriptor ; 48 import java.beans.IntrospectionException ; 49 import java.beans.Introspector ; 50 import java.beans.PropertyDescriptor ; 51 import java.lang.reflect.Method ; 52 import java.lang.reflect.Modifier ; 53 import java.util.ArrayList ; 54 import java.util.Arrays ; 55 import java.util.Iterator ; 56 import java.util.Properties ; 57 58 import org.jfree.util.HashNMap; 59 import org.jfree.xml.generator.model.ClassDescription; 60 import org.jfree.xml.generator.model.DescriptionModel; 61 import org.jfree.xml.generator.model.MultiplexMappingInfo; 62 import org.jfree.xml.generator.model.PropertyInfo; 63 import org.jfree.xml.generator.model.PropertyType; 64 import org.jfree.xml.generator.model.TypeInfo; 65 import org.jfree.xml.util.BasicTypeSupport; 66 67 71 public final class ModelBuilder { 72 73 74 private static ModelBuilder instance; 75 76 81 public static ModelBuilder getInstance() { 82 if (instance == null) { 83 instance = new ModelBuilder(); 84 } 85 return instance; 86 } 87 88 89 private Properties handlerMapping; 90 91 94 private ModelBuilder() { 95 this.handlerMapping = new Properties (); 96 } 97 98 103 public void addAttributeHandlers(final Properties p) { 104 this.handlerMapping.putAll(p); 105 } 106 107 117 public DescriptionModel buildModel(final SourceCollector c, DescriptionModel model) { 118 119 Class [] classes = c.getClasses(); 120 121 if (model == null) { 122 model = new DescriptionModel(); 123 } 124 125 while (classes.length != 0) { 126 classes = fillModel(classes, model); 127 } 128 129 fillSuperClasses(model); 130 132 final Class [] baseClasses = findElementTypes(model); 135 136 final HashNMap classMap = new HashNMap(); 137 for (int i = 0; i < baseClasses.length; i++) { 138 139 final Class base = baseClasses[i]; 140 141 for (int j = 0; j < baseClasses.length; j++) { 142 143 final Class child = baseClasses[j]; 144 if (Modifier.isAbstract(child.getModifiers())) { 145 continue; 146 } 147 if (base.isAssignableFrom(child)) { 148 classMap.add(base, child); 149 } 150 } 151 } 152 153 final Iterator keys = classMap.keys(); 157 while (keys.hasNext()) { 158 final Class base = (Class ) keys.next(); 159 final Class [] childs = (Class []) classMap.toArray(base, new Class [0]); 160 if (childs.length < 2) { 161 continue; 162 } 163 164 boolean isNew = false; 165 MultiplexMappingInfo mmi = model.getMappingModel().lookupMultiplexMapping(base); 166 final ArrayList typeInfoList; 167 if (mmi == null) { 168 mmi = new MultiplexMappingInfo(base); 169 typeInfoList = new ArrayList (); 170 isNew = true; 171 } 172 else { 173 typeInfoList = new ArrayList (Arrays.asList(mmi.getChildClasses())); 174 } 175 176 for (int i = 0; i < childs.length; i++) { 177 final TypeInfo typeInfo = new TypeInfo(childs[i].getName(), childs[i]); 180 if (!typeInfoList.contains(typeInfo)) { 181 typeInfoList.add(typeInfo); 182 } 183 } 184 185 mmi.setChildClasses((TypeInfo[]) typeInfoList.toArray(new TypeInfo[0])); 186 if (isNew) { 187 model.getMappingModel().addMultiplexMapping(mmi); 188 } 189 } 190 191 return model; 196 } 197 198 private Class [] findElementTypes(final DescriptionModel model) { 199 final ArrayList baseClasses = new ArrayList (); 200 201 for (int i = 0; i < model.size(); i++) { 202 final ClassDescription cd = model.get(i); 203 if (!baseClasses.contains(cd.getObjectClass())) { 204 baseClasses.add(cd.getObjectClass()); 205 } 206 207 final PropertyInfo[] properties = cd.getProperties(); 208 for (int p = 0; p < properties.length; p++) { 209 if (!properties[p].getPropertyType().equals(PropertyType.ELEMENT)) { 212 continue; 213 } 214 final Class type = properties[p].getType(); 215 if (baseClasses.contains(type)) { 216 continue; 217 } 218 if (Modifier.isFinal(type.getModifiers())) { 220 continue; 221 } 222 baseClasses.add(type); 223 } 224 } 225 return (Class []) baseClasses.toArray(new Class [baseClasses.size()]); 226 } 227 228 235 private void fillSuperClasses(final DescriptionModel model) { 236 for (int i = 0; i < model.size(); i++) { 238 final ClassDescription cd = model.get(i); 239 final Class parent = cd.getObjectClass().getSuperclass(); 240 if (parent == null) { 241 continue; 242 } 243 final ClassDescription superCD = model.get(parent); 244 if (superCD != null) { 245 cd.setSuperClass(superCD.getObjectClass()); 246 } 247 } 248 } 249 250 258 private Class [] fillModel(final Class [] classes, final DescriptionModel model) { 259 final ArrayList superClasses = new ArrayList (); 263 for (int i = 0; i < classes.length; i++) { 264 265 Class superClass = classes[i].getSuperclass(); 266 if (superClass != null) { 267 if (!Object .class.equals(superClass) 268 && !contains(classes, superClass) 269 && !superClasses.contains(superClass)) { 270 superClasses.add(superClass); 271 } 272 } 273 else { 274 superClass = Object .class; 275 } 276 277 try { 278 final BeanInfo bi = Introspector.getBeanInfo(classes[i], superClass); 279 final ClassDescription parent = model.get(classes[i]); 280 final ClassDescription cd = createClassDescription(bi, parent); 281 if (cd != null) { 282 model.addClassDescription(cd); 283 } 284 } 285 catch (IntrospectionException ie) { 286 } 288 } 289 return (Class []) superClasses.toArray(new Class [0]); 290 } 291 292 300 private ClassDescription createClassDescription (final BeanInfo beanInfo, final ClassDescription parent) { 301 final PropertyDescriptor [] props = beanInfo.getPropertyDescriptors(); 302 final ArrayList properties = new ArrayList (); 303 for (int i = 0; i < props.length; i++) { 304 final PropertyDescriptor propertyDescriptor = props[i]; 305 PropertyInfo pi; 306 if (parent != null) { 307 pi = parent.getProperty(propertyDescriptor.getName()); 308 if (pi != null) { 309 properties.add(pi); 313 continue; 314 } 315 } 316 317 if (props[i] instanceof IndexedPropertyDescriptor ) { 318 } 326 else { 327 pi = createSimplePropertyInfo(props[i]); 328 if (pi != null) { 329 properties.add(pi); 330 } 331 } 332 } 333 334 final PropertyInfo[] propArray = (PropertyInfo[]) 335 properties.toArray(new PropertyInfo[properties.size()]); 336 337 final ClassDescription cd; 338 if (parent != null) { 339 cd = parent; 340 } 341 else { 342 cd = new ClassDescription(beanInfo.getBeanDescriptor().getBeanClass()); 343 cd.setDescription(beanInfo.getBeanDescriptor().getShortDescription()); 344 } 345 346 cd.setProperties(propArray); 347 return cd; 348 } 349 350 356 public static boolean isValidMethod(final Method method) { 357 if (method == null) { 358 return false; 359 } 360 if (!Modifier.isPublic(method.getModifiers())) { 361 return false; 362 } 363 return true; 364 } 365 366 373 public PropertyInfo createSimplePropertyInfo(final PropertyDescriptor pd) { 374 375 final boolean readMethod = isValidMethod(pd.getReadMethod()); 376 final boolean writeMethod = isValidMethod(pd.getWriteMethod()); 377 if (!writeMethod || !readMethod) { 378 return null; 380 } 381 382 final PropertyInfo pi = new PropertyInfo(pd.getName(), pd.getPropertyType()); 383 pi.setConstrained(pd.isConstrained()); 384 pi.setDescription(pd.getShortDescription()); 385 pi.setNullable(true); 386 pi.setPreserve(false); 387 pi.setReadMethodAvailable(readMethod); 388 pi.setWriteMethodAvailable(writeMethod); 389 pi.setXmlName(pd.getName()); 390 if (isAttributeProperty(pd.getPropertyType())) { 391 pi.setPropertyType(PropertyType.ATTRIBUTE); 392 pi.setXmlHandler(getHandlerClass(pd.getPropertyType())); 393 } 394 else { 395 pi.setPropertyType(PropertyType.ELEMENT); 396 } 397 return pi; 398 } 399 400 408 private boolean isAttributeProperty(final Class c) { 409 if (BasicTypeSupport.isBasicDataType(c)) { 410 return true; 411 } 412 return this.handlerMapping.containsKey(c.getName()); 413 } 414 415 422 private String getHandlerClass(final Class c) { 423 if (BasicTypeSupport.isBasicDataType(c)) { 424 final String handler = BasicTypeSupport.getHandlerClass(c); 425 if (handler != null) { 426 return handler; 427 } 428 } 429 return this.handlerMapping.getProperty(c.getName()); 430 } 431 432 440 private boolean contains(final Class [] cAll, final Class c) { 441 for (int i = 0; i < cAll.length; i++) { 442 if (cAll[i].equals(c)) { 443 return true; 444 } 445 } 446 return false; 447 } 448 449 450 } 478 | Popular Tags |