1 16 package org.mortbay.xml; 17 18 import java.io.IOException ; 19 import java.io.InputStream ; 20 import java.io.StringReader ; 21 import java.lang.reflect.Array ; 22 import java.lang.reflect.Constructor ; 23 import java.lang.reflect.Field ; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.lang.reflect.Method ; 26 import java.lang.reflect.Modifier ; 27 import java.net.InetAddress ; 28 import java.net.MalformedURLException ; 29 import java.net.URL ; 30 import java.net.UnknownHostException ; 31 import java.util.HashMap ; 32 import java.util.Map ; 33 34 import org.apache.commons.logging.Log; 35 import org.mortbay.log.LogFactory; 36 import org.mortbay.util.InetAddrPort; 37 import org.mortbay.util.Loader; 38 import org.mortbay.util.LogSupport; 39 import org.mortbay.util.Resource; 40 import org.mortbay.util.TypeUtil; 41 import org.xml.sax.InputSource ; 42 import org.xml.sax.SAXException ; 43 44 45 52 public class XmlConfiguration 53 { 54 private static Log log = LogFactory.getLog(XmlConfiguration.class); 55 56 private static Class [] __primitives = { Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, 57 Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE}; 58 59 private static Class [] __primitiveHolders = { Boolean .class, Character .class, Byte .class, 60 Short .class, Integer .class, Long .class, Float .class, Double .class, Void .class}; 61 62 63 private static XmlParser __parser; 64 private XmlParser.Node _config; 65 private Map _idMap = new HashMap (); 66 67 68 private synchronized static void initParser() throws IOException 69 { 70 if (__parser != null) return; 71 72 __parser = new XmlParser(); 73 URL config13URL = XmlConfiguration.class.getClassLoader().getResource( 74 "org/mortbay/xml/configure_1_3.dtd"); 75 __parser.redirectEntity("configure.dtd", config13URL); 76 __parser.redirectEntity("configure_1_3.dtd", config13URL); 77 __parser.redirectEntity("http://jetty.mortbay.org/configure_1_3.dtd", config13URL); 78 __parser.redirectEntity("http://jetty.mortbay.org/configure.dtd", config13URL); 79 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.3//EN", config13URL); 80 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", config13URL); 81 82 URL config12URL = XmlConfiguration.class.getClassLoader().getResource( 83 "org/mortbay/xml/configure_1_2.dtd"); 84 __parser.redirectEntity("configure_1_2.dtd", config12URL); 85 __parser.redirectEntity("http://jetty.mortbay.org/configure_1_2.dtd", config12URL); 86 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.2//EN", config12URL); 87 88 URL config11URL = XmlConfiguration.class.getClassLoader().getResource( 89 "org/mortbay/xml/configure_1_1.dtd"); 90 __parser.redirectEntity("configure_1_1.dtd", config11URL); 91 __parser.redirectEntity("http://jetty.mortbay.org/configure_1_1.dtd", config11URL); 92 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.1//EN", config11URL); 93 94 URL config10URL = XmlConfiguration.class.getClassLoader().getResource( 95 "org/mortbay/xml/configure_1_0.dtd"); 96 __parser.redirectEntity("configure_1_0.dtd", config10URL); 97 __parser.redirectEntity("http://jetty.mortbay.org/configure_1_0.dtd", config10URL); 98 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.0//EN", config10URL); 99 } 100 101 102 107 public XmlConfiguration(URL configuration) throws SAXException , IOException 108 { 109 initParser(); 110 synchronized (__parser) 111 { 112 _config = __parser.parse(configuration.toString()); 113 } 114 } 115 116 117 125 public XmlConfiguration(String configuration) throws SAXException , IOException 126 { 127 initParser(); 128 configuration = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE Configure PUBLIC \"-//Mort Bay Consulting//DTD Configure 1.2//EN\" \"http://jetty.mortbay.org/configure_1_2.dtd\">" 129 + configuration; 130 InputSource source = new InputSource (new StringReader (configuration)); 131 synchronized (__parser) 132 { 133 _config = __parser.parse(source); 134 } 135 } 136 137 138 145 public XmlConfiguration(InputStream configuration) throws SAXException , IOException 146 { 147 initParser(); 148 InputSource source = new InputSource (configuration); 149 synchronized (__parser) 150 { 151 _config = __parser.parse(source); 152 } 153 } 154 155 156 167 public void configure(Object obj) throws ClassNotFoundException , NoSuchMethodException , 168 InvocationTargetException , InstantiationException , IllegalAccessException 169 { 170 Class oClass = nodeClass(_config); 172 if (oClass != null) 173 { 174 if (obj != null && !oClass.isInstance(obj)) 175 throw new IllegalArgumentException ("Object is not of type " + oClass); 176 if (obj == null) obj = oClass.newInstance(); 177 } 178 configure(obj, _config, 0); 179 } 180 181 182 192 public Object newInstance() throws ClassNotFoundException , NoSuchMethodException , 193 InvocationTargetException , InstantiationException , IllegalAccessException 194 { 195 Class oClass = nodeClass(_config); 196 Object obj = null; 197 if (oClass != null) obj = oClass.newInstance(); 198 configure(obj, _config, 0); 199 return obj; 200 } 201 202 203 private Class nodeClass(XmlParser.Node node) throws ClassNotFoundException 204 { 205 String className = node.getAttribute("class"); 206 if (className == null) return null; 207 208 return Loader.loadClass(XmlConfiguration.class, className); 209 } 210 211 212 217 private void configure(Object obj, XmlParser.Node cfg, int i) throws ClassNotFoundException , 218 NoSuchMethodException , InvocationTargetException , IllegalAccessException 219 { 220 XmlParser.Node node = null; 221 try 222 { 223 for (; i < cfg.size(); i++) 224 { 225 Object o = cfg.get(i); 226 if (o instanceof String ) continue; 227 node = (XmlParser.Node) o; 228 229 String tag = node.getTag(); 230 if ("Set".equals(tag)) 231 set(obj, node); 232 else if ("Put".equals(tag)) 233 put(obj, node); 234 else if ("Call".equals(tag)) 235 call(obj, node); 236 else if ("Get".equals(tag)) 237 get(obj, node); 238 else if ("New".equals(tag)) 239 newObj(obj, node); 240 else if ("Ref".equals(tag)) 241 refObj(obj, node); 242 else 243 throw new IllegalStateException ("Unknown tag: " + tag); 244 } 245 } 246 catch(InvocationTargetException e) 247 { 248 log.warn("Exception at "+node.toString(),e.getTargetException()); 249 throw e; 250 } 251 catch (Error e) 252 { 253 log.debug(node); 254 throw e; 255 } 256 catch (Exception e) 257 { 258 log.debug(node); 259 if (e instanceof NoSuchMethodException ) throw (NoSuchMethodException ) e; 260 if (e instanceof InvocationTargetException ) throw (InvocationTargetException ) e; 261 if (e instanceof IllegalAccessException ) throw (IllegalAccessException ) e; 262 if (e instanceof RuntimeException ) throw (RuntimeException ) e; 263 } 264 } 265 266 267 274 private void set(Object obj, XmlParser.Node node) throws ClassNotFoundException , 275 NoSuchMethodException , InvocationTargetException , IllegalAccessException 276 { 277 String attr = node.getAttribute("name"); 278 String name = "set" + attr.substring(0, 1).toUpperCase() + attr.substring(1); 279 Object value = value(obj, node); 280 Object [] arg = { value}; 281 282 Class oClass = nodeClass(node); 283 if (oClass != null) 284 obj = null; 285 else 286 oClass = obj.getClass(); 287 288 Class [] vClass = { Object .class}; 289 if (value != null) vClass[0] = value.getClass(); 290 291 if (log.isDebugEnabled()) 292 log.debug(obj + "." + name + "(" + vClass[0] + " " + value + ")"); 293 294 try 296 { 297 Method set = oClass.getMethod(name, vClass); 298 set.invoke(obj, arg); 299 return; 300 } 301 catch (IllegalArgumentException e) 302 { 303 LogSupport.ignore(log, e); 304 } 305 catch (IllegalAccessException e) 306 { 307 LogSupport.ignore(log, e); 308 } 309 catch (NoSuchMethodException e) 310 { 311 LogSupport.ignore(log, e); 312 } 313 314 try 316 { 317 Field type = vClass[0].getField("TYPE"); 318 vClass[0] = (Class ) type.get(null); 319 Method set = oClass.getMethod(name, vClass); 320 set.invoke(obj, arg); 321 return; 322 } 323 catch (NoSuchFieldException e) 324 { 325 LogSupport.ignore(log, e); 326 } 327 catch (IllegalArgumentException e) 328 { 329 LogSupport.ignore(log, e); 330 } 331 catch (IllegalAccessException e) 332 { 333 LogSupport.ignore(log, e); 334 } 335 catch (NoSuchMethodException e) 336 { 337 LogSupport.ignore(log, e); 338 } 339 340 try 342 { 343 Field field = oClass.getField(attr); 344 if (Modifier.isPublic(field.getModifiers())) 345 { 346 field.set(obj, value); 347 return; 348 } 349 } 350 catch (NoSuchFieldException e) 351 { 352 LogSupport.ignore(log, e); 353 } 354 355 Method [] sets = oClass.getMethods(); 357 Method set = null; 358 for (int s = 0; sets != null && s < sets.length; s++) 359 { 360 if (name.equals(sets[s].getName()) && sets[s].getParameterTypes().length == 1) 361 { 362 try 364 { 365 set = sets[s]; 366 sets[s].invoke(obj, arg); 367 return; 368 } 369 catch (IllegalArgumentException e) 370 { 371 LogSupport.ignore(log, e); 372 } 373 catch (IllegalAccessException e) 374 { 375 LogSupport.ignore(log, e); 376 } 377 } 378 } 379 380 if (set != null) 382 { 383 try 384 { 385 Class sClass = set.getParameterTypes()[0]; 386 if (sClass.isPrimitive()) 387 { 388 for (int t = 0; t < __primitives.length; t++) 389 { 390 if (sClass.equals(__primitives[t])) 391 { 392 sClass = __primitiveHolders[t]; 393 break; 394 } 395 } 396 } 397 Constructor cons = sClass.getConstructor(vClass); 398 arg[0] = cons.newInstance(arg); 399 set.invoke(obj, arg); 400 return; 401 } 402 catch (NoSuchMethodException e) 403 { 404 LogSupport.ignore(log, e); 405 } 406 catch (IllegalAccessException e) 407 { 408 LogSupport.ignore(log, e); 409 } 410 catch (InstantiationException e) 411 { 412 LogSupport.ignore(log, e); 413 } 414 } 415 416 throw new NoSuchMethodException (oClass + "." + name + "(" + vClass[0] + ")"); 418 } 419 420 421 426 private void put(Object obj, XmlParser.Node node) throws NoSuchMethodException , 427 ClassNotFoundException , InvocationTargetException , IllegalAccessException 428 { 429 if (!(obj instanceof Map )) 430 throw new IllegalArgumentException ("Object for put is not a Map: " + obj); 431 Map map = (Map ) obj; 432 433 String name = node.getAttribute("name"); 434 Object value = value(obj, node); 435 map.put(name, value); 436 if (log.isDebugEnabled()) log.debug(obj + ".put(" + name + "+" + value + ")"); 437 } 438 439 440 445 private Object get(Object obj, XmlParser.Node node) throws NoSuchMethodException , 446 ClassNotFoundException , InvocationTargetException , IllegalAccessException 447 { 448 Class oClass = nodeClass(node); 449 if (oClass != null) 450 obj = null; 451 else 452 oClass = obj.getClass(); 453 454 String name = node.getAttribute("name"); 455 String id = node.getAttribute("id"); 456 if (log.isDebugEnabled()) log.debug("get " + name); 457 458 try 459 { 460 Method method = oClass.getMethod("get" + name.substring(0, 1).toUpperCase() 462 + name.substring(1), (java.lang.Class []) null); 463 obj = method.invoke(obj, (java.lang.Object []) null); 464 configure(obj, node, 0); 465 } 466 catch (NoSuchMethodException nsme) 467 { 468 try 469 { 470 Field field = oClass.getField(name); 471 obj = field.get(obj); 472 configure(obj, node, 0); 473 } 474 catch (NoSuchFieldException nsfe) 475 { 476 throw nsme; 477 } 478 } 479 if (id != null) _idMap.put(id, obj); 480 return obj; 481 } 482 483 484 492 private Object call(Object obj, XmlParser.Node node) throws NoSuchMethodException , 493 ClassNotFoundException , InvocationTargetException , IllegalAccessException 494 { 495 String id = node.getAttribute("id"); 496 Class oClass = nodeClass(node); 497 if (oClass != null) 498 obj = null; 499 else if (obj != null) oClass = obj.getClass(); 500 if (oClass == null) throw new IllegalArgumentException (node.toString()); 501 502 int size = 0; 503 int argi = node.size(); 504 for (int i = 0; i < node.size(); i++) 505 { 506 Object o = node.get(i); 507 if (o instanceof String ) continue; 508 if (!((XmlParser.Node) o).getTag().equals("Arg")) 509 { 510 argi = i; 511 break; 512 } 513 size++; 514 } 515 516 Object [] arg = new Object [size]; 517 for (int i = 0, j = 0; j < size; i++) 518 { 519 Object o = node.get(i); 520 if (o instanceof String ) continue; 521 arg[j++] = value(obj, (XmlParser.Node) o); 522 } 523 524 String method = node.getAttribute("name"); 525 if (log.isDebugEnabled()) log.debug("call " + method); 526 527 Method [] methods = oClass.getMethods(); 529 for (int c = 0; methods != null && c < methods.length; c++) 530 { 531 if (!methods[c].getName().equals(method)) continue; 532 if (methods[c].getParameterTypes().length != size) continue; 533 if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null)) continue; 534 if ((obj == null) && methods[c].getDeclaringClass() != oClass) continue; 535 536 Object n = null; 537 boolean called = false; 538 try 539 { 540 n = methods[c].invoke(obj, arg); 541 called = true; 542 } 543 catch (IllegalAccessException e) 544 { 545 LogSupport.ignore(log, e); 546 } 547 catch (IllegalArgumentException e) 548 { 549 LogSupport.ignore(log, e); 550 } 551 if (called) 552 { 553 if (id != null) _idMap.put(id, n); 554 configure(n, node, argi); 555 return n; 556 } 557 } 558 559 throw new IllegalStateException ("No Method: " + node + " on " + oClass); 560 } 561 562 563 569 private Object newObj(Object obj, XmlParser.Node node) throws NoSuchMethodException , 570 ClassNotFoundException , InvocationTargetException , IllegalAccessException 571 { 572 Class oClass = nodeClass(node); 573 String id = node.getAttribute("id"); 574 int size = 0; 575 int argi = node.size(); 576 for (int i = 0; i < node.size(); i++) 577 { 578 Object o = node.get(i); 579 if (o instanceof String ) continue; 580 if (!((XmlParser.Node) o).getTag().equals("Arg")) 581 { 582 argi = i; 583 break; 584 } 585 size++; 586 } 587 588 Object [] arg = new Object [size]; 589 for (int i = 0, j = 0; j < size; i++) 590 { 591 Object o = node.get(i); 592 if (o instanceof String ) continue; 593 arg[j++] = value(obj, (XmlParser.Node) o); 594 } 595 596 if (log.isDebugEnabled()) log.debug("new " + oClass); 597 598 Constructor [] constructors = oClass.getConstructors(); 600 for (int c = 0; constructors != null && c < constructors.length; c++) 601 { 602 if (constructors[c].getParameterTypes().length != size) continue; 603 604 Object n = null; 605 boolean called = false; 606 try 607 { 608 n = constructors[c].newInstance(arg); 609 called = true; 610 } 611 catch (IllegalAccessException e) 612 { 613 LogSupport.ignore(log, e); 614 } 615 catch (InstantiationException e) 616 { 617 LogSupport.ignore(log, e); 618 } 619 catch (IllegalArgumentException e) 620 { 621 LogSupport.ignore(log, e); 622 } 623 if (called) 624 { 625 if (id != null) _idMap.put(id, n); 626 configure(n, node, argi); 627 return n; 628 } 629 } 630 631 throw new IllegalStateException ("No Constructor: " + node + " on " + obj); 632 } 633 634 635 641 private Object refObj(Object obj, XmlParser.Node node) throws NoSuchMethodException , 642 ClassNotFoundException , InvocationTargetException , IllegalAccessException 643 { 644 String id = node.getAttribute("id"); 645 obj = _idMap.get(id); 646 if (obj == null) throw new IllegalStateException ("No object for id=" + id); 647 configure(obj, node, 0); 648 return obj; 649 } 650 651 652 658 private Object newArray(Object obj, XmlParser.Node node) throws NoSuchMethodException , 659 ClassNotFoundException , InvocationTargetException , IllegalAccessException 660 { 661 Class aClass = java.lang.Object .class; 663 String type = node.getAttribute("type"); 664 String id = node.getAttribute("id"); 665 if (type != null) 666 { 667 aClass = TypeUtil.fromName(type); 668 if (aClass == null) 669 { 670 if ("String".equals(type)) 671 aClass = java.lang.String .class; 672 else if ("URL".equals(type)) 673 aClass = java.net.URL .class; 674 else if ("InetAddress".equals(type)) 675 aClass = java.net.InetAddress .class; 676 else if ("InetAddrPort".equals(type)) 677 aClass = org.mortbay.util.InetAddrPort.class; 678 else 679 aClass = Loader.loadClass(XmlConfiguration.class, type); 680 } 681 } 682 683 Object array = Array.newInstance(aClass, node.size()); 684 if (id != null) _idMap.put(id, obj); 685 686 for (int i = 0; i < node.size(); i++) 687 { 688 Object o = node.get(i); 689 if (o instanceof String ) continue; 690 XmlParser.Node item = (XmlParser.Node) o; 691 if (!item.getTag().equals("Item")) throw new IllegalStateException ("Not an Item"); 692 id = item.getAttribute("id"); 693 Object v = value(obj, item); 694 if (v != null) Array.set(array, i, v); 695 if (id != null) _idMap.put(id, v); 696 } 697 698 return array; 699 } 700 701 702 707 private Object value(Object obj, XmlParser.Node node) throws NoSuchMethodException , 708 ClassNotFoundException , InvocationTargetException , IllegalAccessException 709 { 710 Object value = null; 711 712 String type = node.getAttribute("type"); 714 715 String ref = node.getAttribute("ref"); 717 if (ref != null) 718 { 719 value = _idMap.get(ref); 720 } 721 else 722 { 723 if (node.size() == 0) 725 { 726 if ("String".equals(type)) return ""; 727 return null; 728 } 729 730 int first = 0; 732 int last = node.size() - 1; 733 734 if (type == null || !"String".equals(type)) 736 { 737 Object item = null; 739 while (first <= last) 740 { 741 item = node.get(first); 742 if (!(item instanceof String )) break; 743 item = ((String ) item).trim(); 744 if (((String ) item).length() > 0) break; 745 first++; 746 } 747 748 while (first < last) 750 { 751 item = node.get(last); 752 if (!(item instanceof String )) break; 753 item = ((String ) item).trim(); 754 if (((String ) item).length() > 0) break; 755 last--; 756 } 757 758 if (first > last) return null; 760 } 761 762 if (first == last) 763 value = itemValue(obj, node.get(first)); 765 else 766 { 767 StringBuffer buf = new StringBuffer (); 769 synchronized (buf) 770 { 771 for (int i = first; i <= last; i++) 772 { 773 Object item = node.get(i); 774 buf.append(itemValue(obj, item)); 775 } 776 value = buf.toString(); 777 } 778 } 779 } 780 781 if (value == null) 783 { 784 if ("String".equals(type)) return ""; 785 return null; 786 } 787 788 if (type == null) 790 { 791 if (value != null && value instanceof String ) return ((String ) value).trim(); 792 return value; 793 } 794 795 if ("String".equals(type) || "java.lang.String".equals(type)) return value.toString(); 796 797 Class pClass = TypeUtil.fromName(type); 798 if (pClass != null) return TypeUtil.valueOf(pClass, value.toString()); 799 800 if ("URL".equals(type) || "java.net.URL".equals(type)) 801 { 802 if (value instanceof URL ) return value; 803 try 804 { 805 return new URL (value.toString()); 806 } 807 catch (MalformedURLException e) 808 { 809 throw new InvocationTargetException (e); 810 } 811 } 812 813 if ("InetAddress".equals(type) || "java.net.InetAddress".equals(type)) 814 { 815 if (value instanceof InetAddress ) return value; 816 try 817 { 818 return InetAddress.getByName(value.toString()); 819 } 820 catch (UnknownHostException e) 821 { 822 throw new InvocationTargetException (e); 823 } 824 } 825 826 if ("InetAddrPort".equals(type) || "org.mortbay.util.InetAddrPort".equals(type)) 827 { 828 if (value instanceof InetAddrPort) return value; 829 try 830 { 831 return new InetAddrPort(value.toString()); 832 } 833 catch (UnknownHostException e) 834 { 835 throw new InvocationTargetException (e); 836 } 837 } 838 839 throw new IllegalStateException ("Unknown type " + type); 840 } 841 842 843 847 private Object itemValue(Object obj, Object item) throws NoSuchMethodException , 848 ClassNotFoundException , InvocationTargetException , IllegalAccessException 849 { 850 if (item instanceof String ) return item; 852 853 XmlParser.Node node = (XmlParser.Node) item; 854 String tag = node.getTag(); 855 if ("Call".equals(tag)) return call(obj, node); 856 if ("Get".equals(tag)) return get(obj, node); 857 if ("New".equals(tag)) return newObj(obj, node); 858 if ("Ref".equals(tag)) return refObj(obj, node); 859 if ("Array".equals(tag)) return newArray(obj, node); 860 861 if ("SystemProperty".equals(tag)) 862 { 863 String name = node.getAttribute("name"); 864 String defaultValue = node.getAttribute("default"); 865 return System.getProperty(name, defaultValue); 866 } 867 868 log.warn("Unknown value tag: " + node, new Throwable ()); 869 return null; 870 } 871 872 873 874 875 public static void main(String [] arg) 876 { 877 try 878 { 879 for (int i = 0; i < arg.length; i++) 880 new XmlConfiguration(Resource.newResource(arg[i]).getURL()).newInstance(); 881 } 882 catch (Exception e) 883 { 884 log.warn(LogSupport.EXCEPTION, e); 885 } 886 } 887 } 888 889 | Popular Tags |