1 16 package org.apache.commons.betwixt.io; 17 18 import java.util.HashMap ; 19 import java.util.List ; 20 import java.util.Map ; 21 22 import org.apache.commons.betwixt.AttributeDescriptor; 23 import org.apache.commons.betwixt.ElementDescriptor; 24 import org.apache.commons.betwixt.XMLBeanInfo; 25 import org.apache.commons.betwixt.XMLIntrospector; 26 import org.apache.commons.betwixt.digester.XMLIntrospectorHelper; 27 import org.apache.commons.betwixt.expression.Context; 28 import org.apache.commons.betwixt.expression.MethodUpdater; 29 import org.apache.commons.betwixt.expression.Updater; 30 import org.apache.commons.digester.Rule; 31 import org.apache.commons.digester.Rules; 32 import org.apache.commons.logging.Log; 33 import org.apache.commons.logging.LogFactory; 34 import org.xml.sax.Attributes ; 35 36 44 public class BeanCreateRule extends Rule { 45 46 47 private static Log log = LogFactory.getLog( BeanCreateRule.class ); 48 49 53 public static void setLog(Log aLog) { 54 log = aLog; 55 } 56 57 58 private ElementDescriptor descriptor; 59 60 private Context context; 61 62 private boolean addedChildren; 63 64 private boolean createdBean; 65 66 private Class beanClass; 67 68 private String pathPrefix; 69 70 private boolean matchIDs = true; 71 72 private String classNameAttribute = "className"; 73 74 81 public BeanCreateRule( 82 ElementDescriptor descriptor, 83 Class beanClass, 84 String pathPrefix ) { 85 this( descriptor, beanClass, pathPrefix, true ); 86 } 87 88 96 public BeanCreateRule( 97 ElementDescriptor descriptor, 98 Class beanClass, 99 String pathPrefix, 100 boolean matchIDs ) { 101 this( 102 descriptor, 103 beanClass, 104 new Context(), 105 pathPrefix, 106 matchIDs); 107 } 108 109 115 public BeanCreateRule( ElementDescriptor descriptor, Class beanClass ) { 116 this( descriptor, beanClass, true ); 117 } 118 119 126 public BeanCreateRule( ElementDescriptor descriptor, Class beanClass, boolean matchIDs ) { 127 this( descriptor, beanClass, descriptor.getQualifiedName() + "/" , matchIDs ); 128 } 129 130 137 public BeanCreateRule( 138 ElementDescriptor descriptor, 139 Context context, 140 String pathPrefix ) { 141 this( descriptor, context, pathPrefix, true ); 142 } 143 144 152 public BeanCreateRule( 153 ElementDescriptor descriptor, 154 Context context, 155 String pathPrefix, 156 boolean matchIDs ) { 157 this( 158 descriptor, 159 descriptor.getSingularPropertyType(), 160 context, 161 pathPrefix, 162 matchIDs ); 163 } 164 165 174 private BeanCreateRule( 175 ElementDescriptor descriptor, 176 Class beanClass, 177 Context context, 178 String pathPrefix, 179 boolean matchIDs ) { 180 this.descriptor = descriptor; 181 this.context = context; 182 this.beanClass = beanClass; 183 this.pathPrefix = pathPrefix; 184 this.matchIDs = matchIDs; 185 if (log.isTraceEnabled()) { 186 log.trace("Created bean create rule"); 187 log.trace("Descriptor=" + descriptor); 188 log.trace("Class=" + beanClass); 189 log.trace("Path prefix=" + pathPrefix); 190 } 191 } 192 193 194 195 198 203 public void begin(Attributes attributes) { 204 log.debug( "Called with descriptor: " + descriptor 205 + " propertyType: " + descriptor.getPropertyType() ); 206 207 if (log.isTraceEnabled()) { 208 int attributesLength = attributes.getLength(); 209 if (attributesLength > 0) { 210 log.trace("Attributes:"); 211 } 212 for (int i=0, size=attributesLength; i<size; i++) { 213 log.trace("Local:" + attributes.getLocalName(i)); 214 log.trace("URI:" + attributes.getURI(i)); 215 log.trace("QName:" + attributes.getQName(i)); 216 } 217 } 218 219 220 221 createdBean = false; 225 226 Object instance = null; 227 if ( beanClass != null ) { 228 instance = createBean(attributes); 229 if ( instance != null ) { 230 createdBean = true; 231 232 context.setBean( instance ); 233 digester.push(instance); 234 235 236 ElementDescriptor typeDescriptor = getElementDescriptor( descriptor ); 240 242 AttributeDescriptor[] attributeDescriptors 244 = typeDescriptor.getAttributeDescriptors(); 245 if ( attributeDescriptors != null ) { 246 for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) { 247 AttributeDescriptor attributeDescriptor = attributeDescriptors[i]; 248 249 String value = attributes.getValue( 254 attributeDescriptor.getURI(), 255 attributeDescriptor.getLocalName() 256 ); 257 258 if (value == null) { 259 value = attributes.getValue(attributeDescriptor.getQualifiedName()); 260 } 261 262 if (log.isTraceEnabled()) { 263 log.trace("Attr URL:" + attributeDescriptor.getURI()); 264 log.trace("Attr LocalName:" + attributeDescriptor.getLocalName() ); 265 log.trace(value); 266 } 267 268 Updater updater = attributeDescriptor.getUpdater(); 269 log.trace(updater); 270 if ( updater != null && value != null ) { 271 updater.update( context, value ); 272 } 273 } 274 } 275 276 addChildRules(); 277 278 if ( matchIDs ) { 280 String id = attributes.getValue( "id" ); 284 if ( id != null ) { 285 getBeansById().put( id, instance ); 286 } 287 } 288 } 289 } 290 } 291 292 295 public void end() { 296 if ( createdBean ) { 297 298 Updater updater = descriptor.getUpdater(); 300 Object instance = context.getBean(); 301 302 Object top = digester.pop(); 303 if (digester.getCount() == 0) { 304 context.setBean(null); 305 }else{ 306 context.setBean( digester.peek() ); 307 } 308 309 if ( updater != null ) { 310 if ( log.isDebugEnabled() ) { 311 log.debug( "Calling updater for: " + descriptor + " with: " 312 + instance + " on bean: " + context.getBean() ); 313 } 314 updater.update( context, instance ); 315 } else { 316 if ( log.isDebugEnabled() ) { 317 log.debug( "No updater for: " + descriptor + " with: " 318 + instance + " on bean: " + context.getBean() ); 319 } 320 } 321 } 322 } 323 324 327 public void finish() {} 328 329 330 333 334 342 public String getClassNameAttribute() { 343 return classNameAttribute; 344 } 345 346 355 public void setClassNameAttribute(String classNameAttribute) { 356 this.classNameAttribute = classNameAttribute; 357 } 358 359 362 368 protected Object createBean(Attributes attributes) { 369 if ( matchIDs ) { 376 String idref = attributes.getValue( "idref" ); 377 if ( idref != null ) { 378 log.trace( "Found IDREF" ); 382 Object bean = getBeansById().get( idref ); 383 if ( bean != null ) { 384 if (log.isTraceEnabled()) { 385 log.trace( "Matched bean " + bean ); 386 } 387 return bean; 388 } 389 log.trace( "No match found" ); 390 } 391 } 392 393 Class theClass = beanClass; 394 try { 395 396 String className = attributes.getValue(classNameAttribute); 397 if (className != null) { 398 theClass = getDigester().getClassLoader().loadClass(className); 400 } 401 if (log.isTraceEnabled()) { 402 log.trace( "Creating instance of " + theClass ); 403 } 404 return theClass.newInstance(); 405 406 } catch (Exception e) { 407 log.warn( "Could not create instance of type: " + theClass.getName() ); 408 return null; 409 } 410 } 411 412 413 protected void addChildRules() { 414 if ( ! addedChildren ) { 415 addedChildren = true; 416 417 addChildRules( pathPrefix, descriptor ); 418 } 419 } 420 421 427 protected void addChildRules(String prefix, ElementDescriptor currentDescriptor ) { 428 429 if (log.isTraceEnabled()) { 430 log.trace("Adding child rules for " + currentDescriptor + "@" + prefix); 431 } 432 433 ElementDescriptor typeDescriptor = getElementDescriptor( currentDescriptor ); 437 439 440 ElementDescriptor[] childDescriptors = typeDescriptor.getElementDescriptors(); 441 if ( childDescriptors != null ) { 442 for ( int i = 0, size = childDescriptors.length; i < size; i++ ) { 443 final ElementDescriptor childDescriptor = childDescriptors[i]; 444 if (log.isTraceEnabled()) { 445 log.trace("Processing child " + childDescriptor); 446 } 447 448 String qualifiedName = childDescriptor.getQualifiedName(); 449 if ( qualifiedName == null ) { 450 log.trace( "Ignoring" ); 451 continue; 452 } 453 String path = prefix + qualifiedName; 454 457 if ( qualifiedName.equals( currentDescriptor.getQualifiedName() ) 458 && currentDescriptor.getPropertyName() != null ) { 459 log.trace("Creating generic rule for recursive elements"); 460 int index = -1; 461 if (childDescriptor.isWrapCollectionsInElement()) { 462 index = prefix.indexOf(qualifiedName); 463 if (index == -1) { 464 log.debug( "Oops - this shouldn't happen" ); 466 continue; 467 } 468 int removeSlash = prefix.endsWith("/")?1:0; 469 path = "*/" + prefix.substring(index, prefix.length()-removeSlash); 470 }else{ 471 ElementDescriptor[] desc = currentDescriptor.getElementDescriptors(); 473 if (desc.length == 1) { 474 path = "*/"+desc[0].getQualifiedName(); 475 } 476 } 477 Rule rule = new BeanCreateRule( childDescriptor, context, path, matchIDs); 478 addRule(path, rule); 479 continue; 480 } 481 if ( childDescriptor.getUpdater() != null ) { 482 if (log.isTraceEnabled()) { 483 log.trace("Element has updater " 484 + ((MethodUpdater) childDescriptor.getUpdater()).getMethod().getName()); 485 } 486 if ( childDescriptor.isPrimitiveType() ) { 487 addPrimitiveTypeRule(path, childDescriptor); 488 489 } else { 490 ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors(); 492 if ( grandChildren != null && grandChildren.length > 0 ) { 493 ElementDescriptor grandChild = grandChildren[0]; 494 String grandChildQName = grandChild.getQualifiedName(); 495 if ( grandChildQName != null && grandChildQName.length() > 0 ) { 496 if (childDescriptor.isWrapCollectionsInElement()) { 497 path += '/' + grandChildQName; 498 499 } else { 500 path = prefix + (prefix.endsWith("/")?"":"/") + grandChildQName; 501 } 502 } 503 } 504 505 Class beanClass = childDescriptor.getSingularPropertyType(); 507 if ( XMLIntrospectorHelper.isPrimitiveType( beanClass ) ) { 508 addPrimitiveTypeRule(path, childDescriptor); 509 510 } else { 511 Rule rule = new BeanCreateRule( 512 childDescriptor, 513 context, 514 path + '/', 515 matchIDs ); 516 addRule( path, rule ); 517 } 518 } 519 } else { 520 log.trace("Element does not have updater"); 521 } 522 523 ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors(); 524 if ( grandChildren != null && grandChildren.length > 0 ) { 525 log.trace("Adding grand children"); 526 addChildRules( path + '/', childDescriptor ); 527 } 528 } 529 } 530 } 531 532 537 protected BeanReader getBeanReader() { 538 return (BeanReader) getDigester(); 541 } 542 543 550 protected ElementDescriptor getElementDescriptor( ElementDescriptor propertyDescriptor ) { 551 Class beanClass = propertyDescriptor.getSingularPropertyType(); 552 if ( beanClass != null ) { 553 XMLIntrospector introspector = getBeanReader().getXMLIntrospector(); 554 try { 555 XMLBeanInfo xmlInfo = introspector.introspect( beanClass ); 556 return xmlInfo.getElementDescriptor(); 557 558 } catch (Exception e) { 559 log.warn( "Could not introspect class: " + beanClass, e ); 560 } 561 } 562 return propertyDescriptor; 564 } 565 566 572 protected void addPrimitiveTypeRule(String path, final ElementDescriptor childDescriptor) { 573 Rule rule = new Rule() { 574 public void body(String text) throws Exception { 575 childDescriptor.getUpdater().update( context, text ); 576 } 577 }; 578 addRule( path, rule ); 579 } 580 581 587 protected void addRule(String path, Rule rule) { 588 Rules rules = digester.getRules(); 589 List matches = rules.match(null, path); 590 if ( matches.isEmpty() ) { 591 if ( log.isDebugEnabled() ) { 592 log.debug( "Adding digester rule for path: " + path + " rule: " + rule ); 593 } 594 digester.addRule( path, rule ); 595 596 } else { 597 if ( log.isDebugEnabled() ) { 598 log.debug( "Ignoring duplicate digester rule for path: " 599 + path + " rule: " + rule ); 600 log.debug( "New rule (not added): " + rule ); 601 log.debug( "Existing rule:" + matches.get(0) ); 602 } 603 } 604 } 605 606 612 protected Map getBeansById() { 613 Map beansById = (Map ) context.getVariable( "beans-index" ); 619 if ( beansById == null ) { 620 beansById = new HashMap (); 622 context.setVariable( "beans-index", beansById ); 623 log.trace( "Created new index-by-id map" ); 624 } 625 626 return beansById; 627 } 628 629 634 public String toString() { 635 return "BeanCreateRule [path prefix=" + pathPrefix + " descriptor=" + descriptor + "]"; 636 } 637 638 } 639 | Popular Tags |