1 22 package org.jboss.xb.binding; 23 24 import org.jboss.logging.Logger; 25 import org.jboss.util.NestedRuntimeException; 26 import org.jboss.xb.binding.introspection.FieldInfo; 27 import org.xml.sax.Attributes ; 28 import org.apache.xerces.xs.XSTypeDefinition; 29 30 import java.lang.reflect.Constructor ; 31 import java.util.Map ; 32 import java.util.HashMap ; 33 import java.util.Collection ; 34 import java.util.ArrayList ; 35 36 43 public class MappingObjectModelFactory 44 implements GenericObjectModelFactory 45 { 46 private final static Logger log = Logger.getLogger(MappingObjectModelFactory.class); 47 48 51 private final Map elementToClassMapping = new HashMap (); 52 53 56 private final Map elementToFieldMapping = new HashMap (); 57 58 60 66 public void mapElementToClass(String element, Class cls) 67 { 68 ElementToClassMapping mapping = new ElementToClassMapping(element, cls); 69 addElementToClassMapping(mapping); 70 if(log.isTraceEnabled()) 71 { 72 log.trace(mapping); 73 } 74 } 75 76 84 public void mapElementToField(String element, Class cls, String field, TypeBinding converter) 85 { 86 ElementToFieldMapping mapping = new ElementToFieldMapping(element, cls, field, converter); 87 addElementToFieldMapping(mapping); 88 if(log.isTraceEnabled()) 89 { 90 log.trace(mapping); 91 } 92 } 93 94 96 public Object newRoot(Object root, 97 UnmarshallingContext ctx, 98 String namespaceURI, 99 String localName, 100 Attributes attrs) 101 { 102 if(log.isTraceEnabled()) 103 { 104 log.trace("newRoot root=" + 105 root + 106 " namespaceURI=" + 107 namespaceURI + 108 " localName=" + 109 localName + 110 " attributes=" + 111 attrs 112 ); 113 } 114 115 if(root == null) 116 { 117 ElementToClassMapping mapping = (ElementToClassMapping)elementToClassMapping.get(localName); 118 if(mapping != null) 119 { 120 if(log.isTraceEnabled()) 121 { 122 log.trace("creating root using " + mapping); 123 } 124 root = newInstance(mapping.cls); 125 } 126 else 127 { 128 root = create(namespaceURI, localName, ctx.getType()); 129 } 130 131 if(root == null) 132 { 133 throw new IllegalStateException ( 134 "Failed to resolve Java type binding for root element: ns=" + namespaceURI + ", local=" + localName 135 ); 136 } 137 } 138 139 if(attrs != null) 140 { 141 for(int i = 0; i < attrs.getLength(); ++i) 142 { 143 try 144 { 145 if(attrs.getLocalName(i).length() > 0) 146 { 147 if(!attrs.getQName(i).startsWith("xsi:")) { 149 setAttribute(root, attrs.getLocalName(i), attrs.getValue(i), ctx); 150 } 151 } 152 } 153 catch(Exception e) 154 { 155 String msg = "Failed to set attribute " + attrs.getQName(i) + "=" + attrs.getValue(i); 156 log.error(msg, e); 157 throw new IllegalStateException (msg + ": " + e.getMessage()); 158 } 159 } 160 } 161 162 return root; 163 } 164 165 167 public Object newChild(Object o, 168 UnmarshallingContext ctx, 169 String namespaceURI, 170 String localName, 171 Attributes attrs) 172 { 173 if(log.isTraceEnabled()) 174 { 175 log.trace("newChild object=" + 176 o + 177 " namespaceURI=" + 178 namespaceURI + 179 " localName=" + 180 localName + 181 " attributes=" + 182 attrs 183 ); 184 } 185 186 if(o == null) 187 { 188 throw new RuntimeException ("Attempt to add a new child to a null parent localName=" + localName); 189 } 190 191 Object child = null; 192 193 ElementToClassMapping mapping = (ElementToClassMapping)elementToClassMapping.get(localName); 194 XSTypeDefinition type = ctx.getType(); 195 if(mapping != null) 196 { 197 if(log.isTraceEnabled()) 198 { 199 log.trace("newChild using mapping " + mapping); 200 } 201 202 try 203 { 204 if(!(o instanceof Collection )) 205 { 206 ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get( 207 new ElementToFieldMappingKey(localName, o.getClass()) 208 ); 209 210 FieldInfo fieldInfo; 211 if(fieldMapping != null) 212 { 213 fieldInfo = fieldMapping.fieldInfo; 214 } 215 else 216 { 217 String fieldName = Util.xmlNameToFieldName(localName, true); 218 fieldInfo = FieldInfo.getFieldInfo(o.getClass(), fieldName, true); 219 } 220 221 child = get(o, localName, fieldInfo); 222 } 223 224 if(child == null) 225 { 226 child = newInstance(mapping.cls); 227 } 228 229 if(attrs != null) 230 { 231 for(int i = 0; i < attrs.getLength(); ++i) 232 { 233 if(attrs.getLocalName(i).length() > 0) 234 { 235 if(!attrs.getQName(i).startsWith("xsi:")) { 237 setAttribute(child, attrs.getLocalName(i), attrs.getValue(i), ctx); 238 } 239 } 240 } 241 } 242 } 243 catch(RuntimeException e) 244 { 245 throw e; 246 } 247 catch(Exception e) 248 { 249 throw new NestedRuntimeException("newChild failed for o=" + 250 o + 251 ", uri=" + 252 namespaceURI + 253 ", local=" 254 + localName + ", attrs=" + attrs, e 255 ); 256 } 257 } 258 else 259 { 260 if(o instanceof Collection ) 261 { 262 child = create(namespaceURI, localName, type); 263 } 264 else 265 { 266 Class oCls; 267 if(o instanceof Immutable) 268 { 269 oCls = ((Immutable)o).cls; 270 } 271 else 272 { 273 oCls = o.getClass(); 274 } 275 276 String fieldName = Util.xmlNameToFieldName(localName, true); 277 FieldInfo fieldInfo = FieldInfo.getFieldInfo(oCls, fieldName, true); 278 if(Collection .class.isAssignableFrom(fieldInfo.getType())) 279 { 280 child = get(o, localName, fieldInfo); 281 282 Object item = null; 285 if(type == null || type != null && type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) 286 { 287 item = create(namespaceURI, localName, type); 288 } 289 290 if(item != null) 291 { 292 if(child == null) 293 { 294 setChild(new ArrayList (), o, localName); 295 } 296 child = item; 297 } 298 else 299 { 300 if(child == null) 301 { 302 child = new ArrayList (); 303 } 304 } 305 } 306 else if(!Util.isAttributeType(fieldInfo.getType())) 307 { 308 ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get( 310 new ElementToFieldMappingKey(localName, o.getClass()) 311 ); 312 TypeBinding converter = fieldMapping == null ? null : fieldMapping.converter; 313 314 if(converter == null) 316 { 317 child = newInstance(fieldInfo.getType()); 318 } 319 } 320 } 321 } 322 323 return child; 324 } 325 326 public void addChild(Object parent, 327 Object child, 328 UnmarshallingContext ctx, 329 String namespaceURI, 330 String localName) 331 { 332 if(log.isTraceEnabled()) 333 { 334 log.trace("addChild parent=" + 335 parent + 336 " child=" + 337 child + 338 " namespaceURI=" + 339 namespaceURI + 340 " localName=" + 341 localName 342 ); 343 } 344 345 if(child instanceof Immutable) 346 { 347 child = ((Immutable)child).newInstance(); 348 } 349 setChild(child, parent, localName); 350 } 351 352 public void setValue(Object o, UnmarshallingContext ctx, String namespaceURI, String localName, String value) 353 { 354 if(log.isTraceEnabled()) 355 { 356 log.trace("setValue object=" + 357 o + 358 " ctx=" + 359 ctx + 360 " namespaceURI=" + 361 namespaceURI + 362 " localName=" + 363 localName + 364 " value=" + 365 value 366 ); 367 } 368 369 setAttribute(o, localName, value, ctx); 370 } 371 372 public Object completeRoot(Object root, UnmarshallingContext navigator, String namespaceURI, String localName) 373 { 374 if(log.isTraceEnabled()) 375 { 376 log.trace("completeRoot root=" + 377 root + 378 " navigator=" + 379 navigator + 380 " namespaceURI=" + 381 namespaceURI + 382 " localName=" + 383 localName 384 ); 385 } 386 387 if(root instanceof Immutable) 388 { 389 root = ((Immutable)root).newInstance(); 390 } 391 return root; 392 } 393 394 396 private void addElementToClassMapping(ElementToClassMapping mapping) 397 { 398 elementToClassMapping.put(mapping.element, mapping); 399 } 400 401 private void addElementToFieldMapping(ElementToFieldMapping mapping) 402 { 403 elementToFieldMapping.put(mapping.key, mapping); 404 } 405 406 private void setChild(Object child, Object parent, String localName) 407 { 408 boolean trace = log.isTraceEnabled(); 409 Object value = child; 410 if(parent instanceof Collection ) 411 { 412 if(trace) 413 { 414 log.trace("Add " + value + " to collection " + parent); 415 } 416 ((Collection )parent).add(value); 417 } 418 else 419 { 420 final ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get( 421 new ElementToFieldMappingKey(localName, parent.getClass()) 422 ); 423 if(fieldMapping != null) 424 { 425 if(trace) 426 { 427 log.trace("Add " + value + " to " + parent + " using field mapping " + fieldMapping); 428 } 429 set(parent, value, localName, fieldMapping.fieldInfo); 430 } 431 else 432 { 433 Class parentCls = parent instanceof Immutable ? 434 ((Immutable)parent).cls : 435 parent.getClass(); 436 437 String fieldName = Util.xmlNameToFieldName(localName, true); 438 FieldInfo fieldInfo = FieldInfo.getFieldInfo(parentCls, fieldName, false); 439 if(trace) 440 { 441 log.trace("Add " + value + " to property " + fieldName + " of " + parentCls); 442 } 443 444 if(fieldInfo != null) 445 { 446 if(!(child instanceof Collection ) && Collection .class.isAssignableFrom(fieldInfo.getType())) 447 { 448 Object o = get(parent, localName, fieldInfo); 449 Collection col = (Collection )o; 450 if(trace) 451 { 452 log.trace("Add " + value + " to collection " + col + " retrieved from " + fieldName); 453 } 454 col.add(child); 455 } 456 else 457 { 458 set(parent, value, localName, fieldInfo); 459 } 460 } 461 } 462 } 463 } 464 465 private void setAttribute(Object o, String localName, String value, UnmarshallingContext ctx) 466 { 467 if(o instanceof Collection ) 468 { 469 XSTypeDefinition type = ctx.getType(); 470 if(type == null) 471 { 472 log.warn("Type is not available for collection item " + localName + "=" + value + " -> adding as string."); 473 ((Collection )o).add(value); 474 } 475 else 476 { 477 if(type.getName() == null) 478 { 479 throw new IllegalStateException ("Name is null for simple type?!"); 480 } 481 482 Object trgValue = SimpleTypeBindings.unmarshal(type.getName(), value, ctx.getNamespaceContext()); 483 ((Collection )o).add(trgValue); 484 } 485 } 486 else 487 { 488 Object fieldValue = null; 489 final ElementToFieldMapping fieldMapping = (ElementToFieldMapping)elementToFieldMapping.get( 490 new ElementToFieldMappingKey(localName, o.getClass()) 491 ); 492 493 if(fieldMapping != null) 494 { 495 fieldValue = fieldMapping.converter.unmarshal(value); 496 set(o, fieldValue, localName, fieldMapping.fieldInfo); 497 } 498 else 499 { 500 Class oCls; 501 if(o instanceof Immutable) 502 { 503 oCls = ((Immutable)o).cls; 504 } 505 else 506 { 507 oCls = o.getClass(); 508 } 509 510 final String fieldName = Util.xmlNameToFieldName(localName, true); 511 FieldInfo fieldInfo = FieldInfo.getFieldInfo(oCls, fieldName, true); 512 513 fieldValue = SimpleTypeBindings.unmarshal(value, fieldInfo.getType()); 514 set(o, fieldValue, localName, fieldInfo); 515 } 516 } 517 } 518 519 527 private static Object create(String namespaceURI, String localName, XSTypeDefinition type) 528 { 529 Object o = null; 530 531 String clsName = type != null && type.getName() != null ? 532 Util.xmlNameToClassName(namespaceURI, type.getName(), true) : 533 Util.xmlNameToClassName(namespaceURI, localName, true); 534 535 Class cls = null; 536 try 537 { 538 cls = Thread.currentThread().getContextClassLoader().loadClass(clsName); 539 } 540 catch(ClassNotFoundException e) 541 { 542 if(log.isTraceEnabled()) 543 { 544 log.trace("create: failed to load class " + clsName); 545 } 546 } 547 548 if(cls != null) 549 { 550 o = newInstance(cls); 551 } 552 553 return o; 554 } 555 556 private static Object get(Object o, String localName, FieldInfo fieldInfo) 557 { 558 if(log.isTraceEnabled()) 559 { 560 log.trace("get object=" + o + " localName=" + localName); 561 } 562 563 Object value; 564 if(o instanceof Immutable) 565 { 566 Immutable con = ((Immutable)o); 567 value = con.getChild(localName); 568 } 569 else 570 { 571 value = fieldInfo.getValue(o); 572 } 573 return value; 574 } 575 576 private static void set(Object parent, Object child, String localName, FieldInfo fieldInfo) 577 { 578 if(log.isTraceEnabled()) 579 { 580 log.trace("set parent=" + parent + " child=" + child + " localName=" + localName); 581 } 582 583 if(fieldInfo.isWritable()) 584 { 585 fieldInfo.setValue(parent, child); 586 } 587 else if(parent instanceof Immutable) 588 { 589 ((Immutable)parent).addChild(localName, child); 590 } 591 else 592 { 593 throw new IllegalStateException ("Neither write method nor field were found for " + fieldInfo.getName() + 594 " and the parent object is not an immutable container: parent=" + 595 parent.getClass() + 596 ", localName=" + localName + ", parent=" + parent + ", child=" + child 597 ); 598 } 599 } 600 601 private static Object newInstance(Class cls) 602 { 603 if(log.isTraceEnabled()) 604 { 605 log.trace("new " + cls.getName()); 606 } 607 608 Object instance; 609 try 610 { 611 Constructor ctor = cls.getConstructor(null); 612 instance = ctor.newInstance(null); 613 } 614 catch(NoSuchMethodException e) 615 { 616 log.warn("No no-arg constructor in " + cls); 617 instance = new Immutable(cls); 618 } 619 catch(Exception e) 620 { 621 throw new IllegalStateException ("Failed to create an instance of " + 622 cls + 623 " with the no-arg constructor: " 624 + e.getMessage() 625 ); 626 } 627 return instance; 628 } 629 630 632 private class ElementToClassMapping 633 { 634 public final String element; 635 636 public final Class cls; 637 638 public ElementToClassMapping(String element, Class cls) 639 { 640 this.element = element; 641 this.cls = cls; 642 } 643 644 public String toString() 645 { 646 StringBuffer buffer = new StringBuffer (); 647 buffer.append("ElementToClass@").append(System.identityHashCode(this)); 648 buffer.append("{element=").append(element); 649 if(cls != null) 650 { 651 buffer.append(" class=").append(cls.getName()); 652 } 653 buffer.append("}"); 654 return buffer.toString(); 655 } 656 657 public boolean equals(Object o) 658 { 659 if(this == o) 660 { 661 return true; 662 } 663 if(!(o instanceof ElementToClassMapping)) 664 { 665 return false; 666 } 667 668 final ElementToClassMapping classMapping = (ElementToClassMapping)o; 669 670 if(cls != null ? !cls.equals(classMapping.cls) : classMapping.cls != null) 671 { 672 return false; 673 } 674 675 return true; 676 } 677 678 public int hashCode() 679 { 680 return (cls != null ? cls.hashCode() : 0); 681 } 682 } 683 684 private class ElementToFieldMappingKey 685 { 686 public final String element; 687 688 public final Class cls; 689 690 public ElementToFieldMappingKey(String element, Class cls) 691 { 692 this.element = element; 693 this.cls = cls; 694 } 695 696 public boolean equals(Object o) 697 { 698 if(this == o) 699 { 700 return true; 701 } 702 if(!(o instanceof ElementToFieldMappingKey)) 703 { 704 return false; 705 } 706 707 final ElementToFieldMappingKey elementToFieldMappingKey = (ElementToFieldMappingKey)o; 708 709 if(cls != null ? !cls.equals(elementToFieldMappingKey.cls) : elementToFieldMappingKey.cls != null) 710 { 711 return false; 712 } 713 if(element != null ? 714 !element.equals(elementToFieldMappingKey.element) : 715 elementToFieldMappingKey.element != null) 716 { 717 return false; 718 } 719 720 return true; 721 } 722 723 public int hashCode() 724 { 725 int result; 726 result = (element != null ? element.hashCode() : 0); 727 result = 29 * result + (cls != null ? cls.hashCode() : 0); 728 return result; 729 } 730 } 731 732 private class ElementToFieldMapping 733 { 734 public final String element; 735 public final Class cls; 736 public final TypeBinding converter; 737 public final ElementToFieldMappingKey key; 738 public final FieldInfo fieldInfo; 739 740 public ElementToFieldMapping(String element, Class cls, String fieldName, TypeBinding converter) 741 { 742 this.element = element; 743 this.cls = cls; 744 this.converter = converter; 745 key = new ElementToFieldMappingKey(element, cls); 746 fieldInfo = FieldInfo.getFieldInfo(cls, fieldName, true); 747 } 748 749 public String toString() 750 { 751 StringBuffer buffer = new StringBuffer (); 752 buffer.append("ElementToField@").append(System.identityHashCode(this)); 753 buffer.append("{element=").append(element); 754 if(cls != null) 755 { 756 buffer.append(" class=").append(cls.getName()); 757 } 758 buffer.append(" field=").append(fieldInfo.getName()); 759 if(converter != null) 760 { 761 buffer.append(" convertor=").append(converter.getClass().getName()); 762 } 763 buffer.append("}"); 764 return buffer.toString(); 765 } 766 767 public boolean equals(Object o) 768 { 769 if(this == o) 770 { 771 return true; 772 } 773 if(!(o instanceof ElementToFieldMapping)) 774 { 775 return false; 776 } 777 778 final ElementToFieldMapping elementToFieldMapping = (ElementToFieldMapping)o; 779 780 if(cls != null ? !cls.equals(elementToFieldMapping.cls) : elementToFieldMapping.cls != null) 781 { 782 return false; 783 } 784 if(element != null ? !element.equals(elementToFieldMapping.element) : elementToFieldMapping.element != null) 785 { 786 return false; 787 } 788 789 if(!fieldInfo.getName().equals(elementToFieldMapping.fieldInfo.getName())) 790 { 791 return false; 792 } 793 794 return true; 795 } 796 797 public int hashCode() 798 { 799 int result; 800 result = (element != null ? element.hashCode() : 0); 801 result = 29 * result + (cls != null ? cls.hashCode() : 0); 802 result = 29 * result + fieldInfo.getName().hashCode(); 803 return result; 804 } 805 } 806 } 807 | Popular Tags |