1 22 package org.jboss.xb.binding; 23 24 import org.xml.sax.Attributes ; 25 import org.jboss.logging.Logger; 26 import org.jboss.xb.binding.parser.JBossXBParser; 27 import org.apache.xerces.xs.XSTypeDefinition; 28 29 import javax.xml.namespace.QName ; 30 import javax.xml.namespace.NamespaceContext ; 31 import java.util.Map ; 32 import java.util.HashMap ; 33 import java.util.Collections ; 34 import java.util.StringTokenizer ; 35 import java.util.Iterator ; 36 import java.util.List ; 37 import java.util.ArrayList ; 38 import java.lang.reflect.InvocationTargetException ; 39 import java.lang.reflect.Method ; 40 41 49 public class ObjectModelBuilder 50 implements UnmarshallingContext, JBossXBParser.ContentHandler 51 { 52 55 private static final Logger log = Logger.getLogger(ObjectModelBuilder.class); 56 57 61 private static final Object IGNORED = new Object (); 62 63 66 private Object root; 67 68 71 private Stack all = new StackImpl(); 72 73 76 private Stack accepted = new StackImpl(); 77 78 private GenericObjectModelFactory curFactory; 79 private String curNameSwitchingFactory; 80 private String curNsSwitchingFactory; 81 private Stack nameSwitchingFactory; 82 private Stack nsSwitchingFactory; 83 84 87 private GenericObjectModelFactory defaultFactory; 88 89 92 private Map factoriesToNs = Collections.EMPTY_MAP; 93 94 97 private final NamespaceRegistry nsRegistry = new NamespaceRegistry(); 98 99 private XSTypeDefinition currentType; 100 101 private boolean trace = log.isTraceEnabled(); 102 103 105 public void mapFactoryToNamespace(ObjectModelFactory factory, String namespaceUri) 106 { 107 if(factoriesToNs == Collections.EMPTY_MAP) 108 { 109 factoriesToNs = new HashMap (); 110 } 111 factoriesToNs.put(namespaceUri, getGenericObjectModelFactory(factory)); 112 } 113 114 public void init(ObjectModelFactory defaultFactory, Object root) 115 { 116 this.defaultFactory = getGenericObjectModelFactory(defaultFactory); 117 all.clear(); 118 accepted.clear(); 119 this.root = root; 120 } 121 122 public void pushFactory(String namespaceURI, String localName, GenericObjectModelFactory factory) 123 { 124 if(curNsSwitchingFactory != null) 125 { 126 if(nsSwitchingFactory == null) 127 { 128 nsSwitchingFactory = new StackImpl(); 129 nameSwitchingFactory = new StackImpl(); 130 } 131 nsSwitchingFactory.push(curNsSwitchingFactory); 132 nameSwitchingFactory.push(curNameSwitchingFactory); 133 } 134 curNsSwitchingFactory = namespaceURI; 135 curNameSwitchingFactory = localName; 136 curFactory = factory; 137 } 138 139 public void popFactory() 140 { 141 if(nsSwitchingFactory == null || nsSwitchingFactory.isEmpty()) 142 { 143 curNameSwitchingFactory = null; 144 curNsSwitchingFactory = null; 145 } 146 else 147 { 148 curNameSwitchingFactory = (String )nameSwitchingFactory.pop(); 149 curNsSwitchingFactory = (String )nsSwitchingFactory.pop(); 150 } 151 152 curFactory = getFactory(curNsSwitchingFactory); 153 } 154 155 157 public Iterator getNamespaceURIs() 158 { 159 return nsRegistry.getRegisteredURIs(); 160 } 161 162 public NamespaceContext getNamespaceContext() 163 { 164 return nsRegistry; 165 } 166 167 172 public QName resolveQName(String value) 173 { 174 StringTokenizer st = new StringTokenizer (value, ":"); 175 if(st.countTokens() == 1) 176 return new QName (value); 177 178 if(st.countTokens() != 2) 179 throw new IllegalArgumentException ("Illegal QName: " + value); 180 181 String prefix = st.nextToken(); 182 String local = st.nextToken(); 183 String nsURI = nsRegistry.getNamespaceURI(prefix); 184 if (nsURI == null) 185 throw new IllegalStateException ("Cannot obtain namespace URI for prefix: " + prefix); 186 187 return new QName (nsURI, local, prefix); 188 } 189 190 public String getChildContent(String namespaceURI, String qName) 191 { 192 throw new UnsupportedOperationException (); 194 } 196 197 public XSTypeDefinition getType() 198 { 199 return currentType; 200 } 201 202 204 public void startPrefixMapping(String prefix, String uri) 205 { 206 nsRegistry.addPrefixMapping(prefix, uri); 207 } 208 209 public void endPrefixMapping(String prefix) 210 { 211 nsRegistry.removePrefixMapping(prefix); 212 } 213 214 public void processingInstruction(String target, String data) 215 { 216 if(!"jbossxb".equals(target)) 217 { 218 return; 219 } 220 221 int i = data.indexOf("factory=\""); 222 if(i != -1) 223 { 224 int end = data.indexOf('\"', i + 9); 225 if(end == -1) 226 { 227 throw new JBossXBRuntimeException( 228 "Property 'factory' is not terminated with '\"' in processing instruction: " + data 229 ); 230 } 231 232 String factoryProp = data.substring(i + 9, end); 233 Class factoryCls; 234 try 235 { 236 factoryCls = Thread.currentThread().getContextClassLoader().loadClass(factoryProp); 237 } 238 catch(ClassNotFoundException e) 239 { 240 throw new JBossXBRuntimeException("Failed to load factory class : " + e.getMessage(), e); 241 } 242 243 ObjectModelFactory factory; 244 try 245 { 246 factory = (ObjectModelFactory)factoryCls.newInstance(); 247 } 248 catch(Exception e) 249 { 250 throw new JBossXBRuntimeException("Failed to instantiate factory " + factoryProp + ": " + e.getMessage(), 251 e 252 ); 253 } 254 255 i = data.indexOf("ns=\""); 256 if(i == -1) 257 { 258 throw new JBossXBRuntimeException( 259 "Property 'ns' not found in factory mapping processing instruction: " + data 260 ); 261 } 262 263 end = data.indexOf("\"", i + 4); 264 if(end == -1) 265 { 266 throw new JBossXBRuntimeException( 267 "Property 'ns' is not terminated with '\"' in processing instruction: " + data 268 ); 269 } 270 271 String nsProp = data.substring(i + 4, end); 272 mapFactoryToNamespace(factory, nsProp); 273 } 274 else 275 { 276 throw new JBossXBRuntimeException( 277 "Unexpected data in processing instruction: target=" + target + ", data=" + data 278 ); 279 } 280 } 281 282 public Object getRoot() 283 { 284 if(!all.isEmpty()) 285 { 286 popAll(); 287 popAccepted(); 288 } 289 return root; 290 } 291 292 public void startElement(String namespaceURI, 293 String localName, 294 String qName, 295 Attributes atts, 296 XSTypeDefinition type) 297 { 298 Object parent = accepted.isEmpty() ? root : peekAccepted(); 299 300 currentType = type; 302 303 Object element; 304 if(!namespaceURI.equals(curNsSwitchingFactory)) 305 { 306 GenericObjectModelFactory newFactory = getFactory(namespaceURI); 307 if(newFactory != curFactory) 308 { 309 element = newFactory.newRoot(parent, this, namespaceURI, localName, atts); 310 } 311 else 312 { 313 element = newFactory.newChild(parent, this, namespaceURI, localName, atts); 314 } 315 316 pushFactory(namespaceURI, localName, newFactory); 319 } 320 else 321 { 322 element = curFactory.newChild(parent, this, namespaceURI, localName, atts); 323 } 324 325 if(element == null) 326 { 327 pushAll(IGNORED); 328 329 if(trace) 330 { 331 log.trace("ignored " + namespaceURI + ':' + qName); 332 } 333 } 334 else 335 { 336 pushAll(element); 337 pushAccepted(element); 338 339 if(trace) 340 { 341 log.trace("accepted " + namespaceURI + ':' + qName); 342 } 343 } 344 } 345 346 public void endElement(String namespaceURI, String localName, String qName) 347 { 348 AllElement element = popAll(); 349 350 if(!accepted.isEmpty()) 351 { 352 Object acceptedElement = peekAccepted(); 353 if(element.characters != null && element.characters.length() > 0) 354 { 355 String characters = element.characters.toString().trim(); 356 if(characters.length() > 0) 357 { 358 curFactory.setValue(acceptedElement, this, namespaceURI, localName, characters); 359 } 360 } 361 } 362 363 if(localName.equals(curNameSwitchingFactory) && namespaceURI.equals(curNsSwitchingFactory)) 364 { 365 popFactory(); 366 } 367 368 if(element.element != IGNORED) 369 { 370 popAccepted(); 371 Object parent = (accepted.isEmpty() ? null : peekAccepted()); 372 373 if(parent != null) 374 { 375 curFactory.addChild(parent, element.element, this, namespaceURI, localName); 376 } 377 else 378 { 379 root = curFactory.completeRoot(element.element, this, namespaceURI, localName); 380 } 381 } 382 } 383 384 public void characters(char[] ch, int start, int length) 385 { 386 if(!accepted.isEmpty()) 387 { 388 String str = String.valueOf(ch, start, length); 389 AllElement allElement = peekAll(); 390 if(allElement.characters == null) 391 { 392 allElement.characters = new StringBuffer (str); 393 } 394 else 395 { 396 allElement.characters.append(str); 397 } 398 } 399 } 400 401 403 private GenericObjectModelFactory getFactory(String namespaceUri) 404 { 405 GenericObjectModelFactory factory = (GenericObjectModelFactory)factoriesToNs.get(namespaceUri); 406 if(factory == null) 407 { 408 factory = defaultFactory; 409 } 410 return factory; 411 } 412 413 static Object invokeFactory(Object factory, Method method, Object [] args) 414 { 415 try 416 { 417 return method.invoke(factory, args); 418 } 419 catch(InvocationTargetException e) 420 { 421 Throwable te = e.getCause(); 422 if(te instanceof RuntimeException ) 423 { 424 throw (RuntimeException )te; 425 } 426 427 String msg = "Failed to invoke method " + method + ", factory=" + factory; 428 log.error(msg, e.getTargetException()); 429 430 IllegalStateException ise = new IllegalStateException (msg); 431 ise.initCause(te); 432 throw ise; 433 } 434 catch(Exception e) 435 { 436 String msg = "Failed to invoke method " + method.getName() + ", factory=" + factory; 437 log.error(msg, e); 438 IllegalStateException ise = new IllegalStateException (msg); 439 ise.initCause(e); 440 throw ise; 441 } 442 } 443 444 static Method getMethodForElement(Object factory, String name, Class [] params) 445 { 446 Method method = null; 447 try 448 { 449 method = factory.getClass().getMethod(name, params); 450 } 451 catch(NoSuchMethodException e) 452 { 453 } 454 catch(SecurityException e) 455 { 456 throw e; 457 } 458 459 return method; 460 } 461 462 static final GenericObjectModelFactory getGenericObjectModelFactory(ObjectModelFactory factory) 463 { 464 if(!(factory instanceof GenericObjectModelFactory)) 465 { 466 factory = new DelegatingObjectModelFactory(factory); 467 } 468 return factory instanceof GenericObjectModelFactory ? 469 (GenericObjectModelFactory)factory : 470 new DelegatingObjectModelFactory(factory); 471 } 472 473 private void pushAccepted(Object o) 474 { 475 accepted.push(o); 476 } 477 478 private Object popAccepted() 479 { 480 return accepted.pop(); 481 } 482 483 private Object peekAccepted() 484 { 485 return accepted.peek(); 486 } 487 488 private void pushAll(Object o) 489 { 490 all.push(new AllElement(o)); 491 } 492 493 private AllElement popAll() 494 { 495 return (AllElement)all.pop(); 496 } 497 498 private AllElement peekAll() 499 { 500 return (AllElement)all.peek(); 501 } 502 503 private static final class AllElement 504 { 505 public final Object element; 506 public StringBuffer characters; 507 508 public AllElement(Object element) 509 { 510 this.element = element; 511 } 512 } 513 514 private static interface Stack 515 { 516 void clear(); 517 518 void push(Object o); 519 520 Object pop(); 521 522 Object peek(); 523 524 boolean isEmpty(); 525 } 526 527 private static class StackImpl 528 implements Stack 529 { 530 private List list = new ArrayList (); 531 532 public void clear() 533 { 534 list.clear(); 535 } 536 537 public void push(Object o) 538 { 539 list.add(o); 540 } 541 542 public Object pop() 543 { 544 return list.remove(list.size() - 1); 545 } 546 547 public Object peek() 548 { 549 return list.get(list.size() - 1); 550 } 551 552 public boolean isEmpty() 553 { 554 return list.isEmpty(); 555 } 556 } 557 } 558 | Popular Tags |