1 26 27 package com.caucho.config; 28 29 import com.caucho.config.types.ResinType; 30 import com.caucho.config.types.Validator; 31 import com.caucho.el.ELParser; 32 import com.caucho.el.Expr; 33 import com.caucho.util.CompileException; 34 import com.caucho.util.L10N; 35 import com.caucho.util.LineCompileException; 36 import com.caucho.vfs.Depend; 37 import com.caucho.vfs.Dependency; 38 import com.caucho.vfs.Path; 39 import com.caucho.vfs.ReadStream; 40 import com.caucho.vfs.Vfs; 41 import com.caucho.xml.QAbstractNode; 42 import com.caucho.xml.QDocument; 43 import com.caucho.xml.QElement; 44 import com.caucho.xml.QName; 45 import com.caucho.xml.QNode; 46 import com.caucho.xml.XmlUtil; 47 48 import org.w3c.dom.*; 49 50 import javax.el.ELException; 51 import javax.el.ELResolver; 52 import java.io.IOException ; 53 import java.util.ArrayList ; 54 import java.util.logging.Level ; 55 import java.util.logging.Logger ; 56 57 66 public class NodeBuilder { 67 private final static L10N L = new L10N(NodeBuilder.class); 68 private final static Logger log 69 = Logger.getLogger(NodeBuilder.class.getName()); 70 71 private final static QName RESIN_TYPE = new QName("resin:type"); 72 private final static QName RESIN_TYPE_NS 73 = new QName("resin:type", "http://caucho.com/ns/resin/core"); 74 75 private static ThreadLocal <NodeBuilder> _currentBuilder 76 = new ThreadLocal <NodeBuilder>(); 77 78 private Config _config; 79 80 private ArrayList <ValidatorEntry> _validators 81 = new ArrayList <ValidatorEntry>(); 82 83 private ConfigELContext _elContext; 84 private ELResolver _varResolver; 85 86 NodeBuilder() 87 { 88 _elContext = new ConfigELContext(); 89 _varResolver = _elContext.getVariableResolver(); 90 } 91 92 NodeBuilder(ConfigELContext context) 93 { 94 _elContext = context; 95 _varResolver = _elContext.getVariableResolver(); 96 } 97 98 NodeBuilder(Config config) 99 { 100 _config = config; 101 _elContext = config.getELContext(); 102 103 if (_elContext == null) 104 _elContext = new ConfigELContext(); 105 106 _varResolver = _elContext.getVariableResolver(); 107 } 108 109 public static NodeBuilder createForProgram() 110 { 111 return new NodeBuilder(new ConfigELContext((ELResolver) null)); 112 } 113 114 public static NodeBuilder getCurrentBuilder() 115 { 116 return _currentBuilder.get(); 117 } 118 119 static void setCurrentBuilder(NodeBuilder builder) 121 { 122 _currentBuilder.set(builder); 123 } 124 125 public Config getConfig() 126 { 127 return _config; 128 } 129 130 133 private boolean isEL() 134 { 135 return _config == null || _config.isEL(); 137 } 138 139 147 public Object configure(Object bean, Node top) 148 throws LineConfigException 149 { 150 NodeBuilder oldBuilder = _currentBuilder.get(); 151 Object oldFile = _elContext.getValue("__FILE__"); 152 try { 153 _currentBuilder.set(this); 154 155 if (top instanceof QNode) { 156 _elContext.setValue("__FILE__", ((QNode) top).getBaseURI()); 157 } 158 159 TypeStrategy typeStrategy; 160 typeStrategy = TypeStrategyFactory.getTypeStrategy(bean.getClass()); 161 162 return configureImpl(typeStrategy, bean, top); 163 } catch (LineConfigException e) { 164 throw e; 165 } catch (Exception e) { 166 throw error(e, top); 167 } finally { 168 _currentBuilder.set(oldBuilder); 169 170 _elContext.setValue("__FILE__", oldFile); 171 } 172 } 173 174 180 public void configureBean(Object bean, Node top) 181 throws LineConfigException 182 { 183 NodeBuilder oldBuilder = _currentBuilder.get(); 184 try { 185 _currentBuilder.set(this); 186 187 if (top instanceof QNode) { 188 _elContext.setValue("__FILE__", ((QNode) top).getBaseURI()); 189 } 190 191 TypeStrategy typeStrategy; 192 typeStrategy = TypeStrategyFactory.getTypeStrategy(bean.getClass()); 193 typeStrategy.configureBean(this, bean, top); 194 } catch (LineConfigException e) { 195 throw e; 196 } catch (Exception e) { 197 throw error(e, top); 198 } finally { 199 _currentBuilder.set(oldBuilder); 200 } 201 } 202 203 210 public void configureAttribute(Object bean, Node attribute) 211 throws LineConfigException 212 { 213 String attrName = attribute.getNodeName(); 214 215 if (attrName.equals("resin:type")) 216 return; 217 else if (attrName.startsWith("xmlns")) 218 return; 219 220 NodeBuilder oldBuilder = getCurrentBuilder(); 221 try { 222 setCurrentBuilder(this); 223 224 TypeStrategy typeStrategy = TypeStrategyFactory.getTypeStrategy(bean.getClass()); 225 226 typeStrategy.configureAttribute(this, bean, attribute); 227 } 228 catch (LineConfigException e) { 229 throw e; 230 } 231 catch (Exception e) { 232 throw error(e, attribute); 233 } finally { 234 setCurrentBuilder(oldBuilder); 235 } 236 } 237 238 247 Object configureImpl(TypeStrategy typeStrategy, 248 Object bean, 249 Node top) 250 throws LineConfigException 251 { 252 try { 253 typeStrategy.configureBean(this, bean, top); 254 255 typeStrategy.init(bean); 256 257 return typeStrategy.replaceObject(bean); 258 } catch (LineConfigException e) { 259 throw e; 260 } catch (Exception e) { 261 throw error(e, top); 262 } 263 } 264 265 276 Object configureChildImpl(TypeStrategy typeStrategy, Node top, Object parent) 277 throws Exception 278 { 279 Object bean = createResinType(top); 280 281 if (bean == null && ! hasChildren(top)) { 282 String value = textValue(top); 283 284 if (isEL() && value != null && 285 value.startsWith("${") && value.endsWith("}")) { 286 bean = evalObject(value); 287 288 return bean; 289 } 290 } 291 292 if (bean == null) 293 bean = typeStrategy.create(); 294 295 typeStrategy = TypeStrategyFactory.getTypeStrategy(bean.getClass()); 296 297 typeStrategy.setParent(bean, parent); 298 299 return configureImpl(typeStrategy, bean, top); 300 } 301 302 310 public void configureBeanImpl(TypeStrategy typeStrategy, 311 Object bean, 312 Node top) 313 throws Exception 314 { 315 if (top instanceof Attr || top instanceof CharacterData) { 317 QName qName = new QName("#text"); 318 319 AttributeStrategy attrStrategy = typeStrategy.getAttributeStrategy(qName); 320 321 attrStrategy.configure(this, bean, qName, top); 322 323 return; 324 } 325 326 configureBeanAttributesImpl(typeStrategy, bean, top); 327 328 Node child = top.getFirstChild(); 329 330 for (; child != null; child = child.getNextSibling()) { 331 configureAttributeImpl(typeStrategy, bean, child); 332 } 333 } 334 335 public void configureBeanAttributesImpl(TypeStrategy typeStrategy, 336 Object bean, 337 Node top) 338 throws Exception 339 { 340 NamedNodeMap attrList = top.getAttributes(); 341 if (attrList != null) { 342 int length = attrList.getLength(); 343 for (int i = 0; i < length; i++) { 344 Node child = attrList.item(i); 345 346 configureAttributeImpl(typeStrategy, bean, child); 347 } 348 } 349 } 350 351 354 void configureAttributeImpl(TypeStrategy typeStrategy, 355 Object bean, 356 Node node) 357 throws Exception 358 { 359 try { 360 QName qName = ((QAbstractNode) node).getQName(); 361 362 if (node instanceof Comment) { 363 return; 364 } 365 else if (node instanceof DocumentType) { 366 return; 367 } 368 else if (node instanceof ProcessingInstruction) { 369 return; 370 } 371 else if (node instanceof CharacterData) { 372 String data = ((CharacterData) node).getData(); 373 374 if (XmlUtil.isWhitespace(data)) 375 return; 376 377 qName = new QName("#text"); 378 } 379 380 if (qName.getName().startsWith("xmlns")) 381 return; 382 else if (qName.getName().equals("resin:type")) 383 return; 384 385 AttributeStrategy attrStrategy = typeStrategy.getAttributeStrategy(qName); 386 387 if (attrStrategy == null) 388 throw error(L.l("{0} is an unknown property of {1}.", 389 qName, typeStrategy), 390 node); 391 392 attrStrategy.configure(this, bean, qName, node); 393 } catch (LineConfigException e) { 394 throw e; 395 } catch (Exception e) { 396 throw error(e, node); 397 } 398 } 399 400 ArrayList <Dependency> getDependencyList(Node node) 401 { 402 ArrayList <Dependency> dependList = null; 403 404 if (node instanceof QElement) { 405 QElement qelt = (QElement) node; 406 407 412 413 ArrayList <Path> pathList; 414 pathList = ((QDocument) qelt.getOwnerDocument()).getDependList(); 415 416 if (pathList != null) { 417 dependList = new ArrayList <Dependency>(); 418 419 for (int i = 0; i < pathList.size(); i++) { 420 dependList.add(new Depend(pathList.get(i))); 421 } 422 } 423 } 424 425 return dependList; 426 } 427 428 435 public Object configureObject(Node node, Object parent) 436 throws Exception 437 { 438 Object resinTypeValue = createResinType(node); 439 440 if (resinTypeValue != null) { 441 Class type = resinTypeValue.getClass(); 442 TypeStrategy typeStrategy = TypeStrategyFactory.getTypeStrategy(type); 443 444 typeStrategy.setParent(resinTypeValue, parent); 445 446 return configureImpl(typeStrategy, resinTypeValue, node); 447 } 448 449 if (hasChildren(node)) 450 throw error(L.l("unexpected node {0}", node.getNodeName()), node); 452 String value = textValue(node); 453 454 if (value == null) 455 return null; 456 else if (isEL() && value.indexOf("${") >= 0) 457 return evalObject(value); 458 else 459 return value; 460 } 461 462 public String configureString(Node child) 463 throws Exception 464 { 465 String value = configureRawString(child); 466 467 if (value == null) 468 return ""; 469 else if (isEL() && value.indexOf("${") >= 0) 470 return evalString(value); 471 else 472 return value; 473 } 474 475 public String configureRawString(Node child) 476 throws Exception 477 { 478 Object resinTypeValue = createResinType(child); 479 480 if (resinTypeValue != null) { 481 TypeStrategy typeStrategy 482 = TypeStrategyFactory.getTypeStrategy(resinTypeValue.getClass()); 483 484 return String.valueOf(configureImpl(typeStrategy, resinTypeValue, child)); 485 } 486 487 if (hasChildren(child)) 488 throw error(L.l("unexpected child nodes"), child); 490 String value = textValue(child); 491 492 return value; 493 } 494 495 public String configureRawStringNoTrim(Node child) 496 throws Exception 497 { 498 Object resinTypeValue = createResinType(child); 499 500 if (resinTypeValue != null) { 501 TypeStrategy typeStrategy 502 = TypeStrategyFactory.getTypeStrategy(resinTypeValue.getClass()); 503 504 return String.valueOf(configureImpl(typeStrategy, resinTypeValue, child)); 505 } 506 507 if (hasChildren(child)) 508 throw error(L.l("unexpected child nodes"), child); 510 String value = textValueNoTrim(child); 511 512 return value; 513 } 514 515 518 Object createResinType(Node child) 519 throws Exception 520 { 521 String type = getValue(RESIN_TYPE, child, null); 522 523 type = getValue(RESIN_TYPE_NS, child, type); 524 525 if (type == null) 526 return null; 527 528 ResinType resinType = null; 529 530 resinType = new ResinType(); 531 resinType.addText(type); 532 resinType.init(); 533 534 return resinType.create(null); 535 } 536 537 545 Object configureCreate(Class type, Node node) 546 throws Exception 547 { 548 Object value = type.newInstance(); 549 550 return configure(value, node); 551 } 552 553 556 public ConfigELContext getELContext() 557 { 558 return _elContext; 559 } 560 561 564 public void setELContext(ConfigELContext elContext) 565 { 566 _elContext = elContext; 567 } 568 569 572 public Object putVar(String name, Object value) 573 { 574 ELResolver resolver = _elContext.getELResolver(); 575 Object oldValue = resolver.getValue(_elContext, name, null); 576 577 resolver.setValue(_elContext, null, name, value); 578 579 return oldValue; 580 } 581 582 585 public Object getVar(String name) 586 { 587 return _elContext.getELResolver().getValue(_elContext, null, name); 588 } 589 590 void addValidator(Validator validator) 591 { 592 _validators.add(new ValidatorEntry(validator)); 593 } 594 595 static boolean hasChildren(Node node) 596 { 597 Node ptr; 598 599 NamedNodeMap attrList = node.getAttributes(); 600 if (attrList != null) { 601 for (int i = 0; i < attrList.getLength(); i++) { 602 if (! attrList.item(i).getNodeName().startsWith("xml")) 603 return true; 604 } 605 } 606 607 for (ptr = node.getFirstChild(); ptr != null; ptr = ptr.getNextSibling()) { 608 if (ptr instanceof Element) 609 return true; 610 } 611 612 return false; 613 } 614 615 static String getValue(QName name, Node node, String defaultValue) 616 { 617 NamedNodeMap attrList = node.getAttributes(); 618 if (attrList != null) { 619 for (int i = 0; i < attrList.getLength(); i++) { 620 if (attrList.item(i).getNodeName().equals(name.getName())) 621 return attrList.item(i).getNodeValue(); 622 } 623 } 624 625 Node ptr; 626 627 for (ptr = node.getFirstChild(); ptr != null; ptr = ptr.getNextSibling()) { 628 QName qName = ((QAbstractNode) ptr).getQName(); 629 630 if (name.equals(qName)) 631 return textValue(ptr); 632 } 633 634 return defaultValue; 635 } 636 637 640 static String textValue(Node node) 641 { 642 if (node instanceof Attr) 643 return node.getNodeValue(); 644 else { 645 String value = XmlUtil.textValue(node); 646 647 if (value == null || value.equals("")) 648 return ""; 649 else if (node instanceof Element) { 650 String space = ((Element) node).getAttribute("xml:space"); 651 652 if (! space.equals("")) 653 return value; 654 } 655 656 return value.trim(); 657 } 658 } 659 660 663 static String textValueNoTrim(Node node) 664 { 665 if (node instanceof Attr) 666 return node.getNodeValue(); 667 else { 668 String value = XmlUtil.textValue(node); 669 670 if (value == null) 671 return ""; 672 673 return value; 674 } 675 } 676 677 680 public String evalString(String exprString) 681 throws ELException 682 { 683 if (exprString.indexOf("${") >= 0 && isEL()) { 684 ELParser parser = new ELParser(getELContext(), exprString); 685 parser.setCheckEscape(true); 686 Expr expr = parser.parse(); 687 688 return expr.evalString(getELContext()); 689 } 690 else 691 return exprString; 692 } 693 694 697 public boolean evalBoolean(String exprString) 698 throws ELException 699 { 700 if (exprString.indexOf("${") >= 0 && isEL()) { 701 ELParser parser = new ELParser(getELContext(), exprString); 702 parser.setCheckEscape(true); 703 Expr expr = parser.parse(); 704 705 return expr.evalBoolean(getELContext()); 706 } 707 else if (exprString.equals("false") 708 || exprString.equals("no") 709 || exprString.equals("") 710 || exprString.equals("0")) { 711 return false; 712 } 713 else 714 return true; 715 } 716 717 720 public long evalLong(String exprString) 721 throws ELException 722 { 723 if (exprString.indexOf("${") >= 0 && isEL()) { 724 ELParser parser = new ELParser(getELContext(), exprString); 725 parser.setCheckEscape(true); 726 Expr expr = parser.parse(); 727 728 return expr.evalLong(getELContext()); 729 } 730 else 731 return Expr.toLong(exprString, null); 732 } 733 734 737 public double evalDouble(String exprString) 738 throws ELException 739 { 740 if (exprString.indexOf("${") >= 0 && isEL()) { 741 ELParser parser = new ELParser(getELContext(), exprString); 742 parser.setCheckEscape(true); 743 Expr expr = parser.parse(); 744 745 return expr.evalDouble(getELContext()); 746 } 747 else 748 return Expr.toDouble(exprString, null); 749 } 750 751 754 public Object evalObject(String exprString) 755 throws ELException 756 { 757 if (exprString.indexOf("${") >= 0 && isEL()) { 758 ELParser parser = new ELParser(getELContext(), exprString); 759 parser.setCheckEscape(true); 760 Expr expr = parser.parse(); 761 762 return expr.getValue(getELContext()); 763 } 764 else 765 return exprString; 766 } 767 768 771 public Object evalELObject(Node node) 772 throws ELException 773 { 774 if (hasChildren(node)) 775 return null; 776 777 String value = textValue(node); 778 779 if (value == null) 780 return null; 781 else if (isEL() && value.indexOf("${") >= 0) { 782 ELParser parser = new ELParser(getELContext(), value); 783 parser.setCheckEscape(true); 784 Expr expr = parser.parse(); 785 786 return expr.getValue(getELContext()); 787 } 788 else 789 return null; 790 } 791 792 public static LineConfigException error(String msg, Node node) 793 { 794 String filename = null; 795 int line = 0; 796 797 if (node instanceof QAbstractNode) { 798 QAbstractNode qnode = (QAbstractNode) node; 799 800 filename = qnode.getFilename(); 801 line = qnode.getLine(); 802 } 803 804 if (filename != null) 805 return new LineConfigException(filename, line, msg); 806 else 807 return new LineConfigException(msg); 808 } 809 810 public static LineConfigException error(Throwable e, Node node) 811 { 812 String systemId = null; 813 String filename = null; 814 int line = 0; 815 816 if (node instanceof QAbstractNode) { 817 QAbstractNode qnode = (QAbstractNode) node; 818 819 systemId = qnode.getBaseURI(); 820 filename = qnode.getFilename(); 821 line = qnode.getLine(); 822 } 823 824 for (; e.getCause() != null; e = e.getCause()) { 825 if (e instanceof LineCompileException) 826 break; 827 else if (e instanceof LineConfigRuntimeException) 828 break; 829 else if (e instanceof CompileException) 830 break; 831 } 832 833 if (e instanceof LineConfigException) 834 return (LineConfigException) e; 835 else if (e instanceof LineConfigRuntimeException) 836 throw (LineConfigRuntimeException) e; 837 else if (e instanceof LineRuntimeException) 838 throw (LineRuntimeException) e; 839 else if (e instanceof ConfigException && 840 e.getMessage() != null && 841 filename != null) { 842 String sourceLines = getSourceLines(systemId, line); 843 844 return new LineConfigException(filename, line, 845 e.getMessage() + sourceLines, 846 e); 847 } 848 else if (e instanceof LineCompileException) { 849 return new LineConfigException(e.getMessage(), e); 850 } 851 else if (e instanceof CompileException && e.getMessage() != null) { 852 return new LineConfigException(filename, line, e); 853 } 854 else { 855 log.log(Level.CONFIG, e.toString(), e); 856 857 String msg = filename + ":" + line + ": " + e; 858 859 if (e instanceof RuntimeException ) { 860 throw new LineRuntimeException(msg, e); 861 } 862 else if (e instanceof Error ) { 863 throw new LineRuntimeException(msg, e); 865 } 867 else 868 return new LineConfigException(msg, e); 869 } 870 } 871 872 private static String getSourceLines(String systemId, int errorLine) 873 { 874 if (systemId == null) 875 return ""; 876 877 ReadStream is = null; 878 try { 879 is = Vfs.lookup().lookup(systemId).openRead(); 880 int line = 0; 881 StringBuilder sb = new StringBuilder ("\n\n"); 882 String text; 883 while ((text = is.readLine()) != null) { 884 line++; 885 886 if (errorLine - 2 <= line && line <= errorLine + 2) { 887 sb.append(line); 888 sb.append(": "); 889 sb.append(text); 890 sb.append("\n"); 891 } 892 } 893 894 return sb.toString(); 895 } catch (IOException e) { 896 log.log(Level.FINEST, e.toString(), e); 897 898 return ""; 899 } finally { 900 if (is != null) 901 is.close(); 902 } 903 } 904 905 static class ValidatorEntry { 906 private Validator _validator; 907 private ClassLoader _loader; 908 909 ValidatorEntry(Validator validator) 910 { 911 _validator = validator; 912 913 _loader = Thread.currentThread().getContextClassLoader(); 914 } 915 916 void validate() 917 throws ConfigException 918 { 919 Thread thread = Thread.currentThread(); 920 ClassLoader oldLoader = thread.getContextClassLoader(); 921 922 try { 923 thread.setContextClassLoader(_loader); 924 925 _validator.validate(); 926 } finally { 927 thread.setContextClassLoader(oldLoader); 928 } 929 } 930 } 931 } 932 | Popular Tags |