1 29 30 package com.caucho.config; 31 32 import com.caucho.config.j2ee.InjectIntrospector; 33 import com.caucho.config.types.Validator; 34 import com.caucho.loader.Environment; 35 import com.caucho.loader.EnvironmentListener; 36 import com.caucho.loader.WeakDestroyListener; 37 import com.caucho.util.CharBuffer; 38 import com.caucho.util.L10N; 39 import com.caucho.util.NotImplementedException; 40 import com.caucho.vfs.Depend; 41 import com.caucho.vfs.PersistentDependency; 42 import com.caucho.xml.CauchoNode; 43 import com.caucho.xml.QAbstractNode; 44 import com.caucho.xml.QName; 45 46 import org.w3c.dom.Node ; 47 48 import javax.annotation.PostConstruct; 49 import javax.annotation.PreDestroy; 50 import javax.el.ELContext; 51 import java.lang.ref.SoftReference ; 52 import java.lang.reflect.InvocationTargetException ; 53 import java.lang.reflect.Method ; 54 import java.lang.reflect.Modifier ; 55 import java.util.ArrayList ; 56 import java.util.HashMap ; 57 58 public class BeanTypeStrategy extends TypeStrategy { 59 protected static final L10N L = new L10N(BeanTypeStrategy.class); 60 61 private static final QName TEXT = new QName("text"); 62 private static final QName VALUE = new QName("value"); 63 64 private SoftReference <Method []> _methodsRef; 65 private HashMap <QName,AttributeStrategy> _nsAttributeMap 66 = new HashMap <QName,AttributeStrategy>(); 67 private final Class _type; 68 69 private ArrayList <BuilderProgram> _injectList 70 = new ArrayList <BuilderProgram>(); 71 72 private final Method _setParent; 73 private final Method _setLocation; 74 private final Method _addDependency; 75 private final Method _setSystemId; 76 private final Method _setNode; 77 private final ArrayList <Method > _initList = new ArrayList <Method >(); 78 private final ArrayList <Method > _destroyList = new ArrayList <Method >(); 79 private final Method _replaceObject; 80 81 BeanTypeStrategy(Class type) 82 { 83 _type = type; 84 85 Method setParent = null; 86 87 _injectList = InjectIntrospector.introspect(type); 88 89 setParent = findMethod("setParent", new Class [] { null }); 90 91 _setParent = setParent; 92 93 scanMethods(type); 94 95 100 101 _replaceObject = findMethod("replaceObject", new Class [0]); 102 103 _setLocation = findMethod("setConfigLocation", 104 new Class [] { String .class, int.class }); 105 106 _addDependency = findMethod("addDependency", 107 new Class [] { PersistentDependency.class }); 108 109 _setSystemId = findMethod("setConfigSystemId", 110 new Class [] { String .class }); 111 112 116 117 _setNode = findMethod("setConfigNode", new Class [] { Node.class }); 118 } 119 120 123 public Class getType() 124 { 125 return _type; 126 } 127 128 131 public String getTypeName() 132 { 133 return getType().getName(); 134 } 135 136 140 public Object create() 141 throws Exception 142 { 143 Object bean = _type.newInstance(); 144 145 return bean; 146 } 147 148 155 public void setParent(Object bean, Object parent) 156 throws Exception 157 { 158 if (_setParent != null) { 159 try { 160 if (parent != null && 162 _setParent.getParameterTypes()[0].isAssignableFrom(parent.getClass())) 163 _setParent.invoke(bean, parent); 164 } catch (InvocationTargetException e) { 165 if (e.getCause() instanceof Exception ) 166 throw (Exception ) e.getCause(); 167 else 168 throw e; 169 } 170 } 171 } 172 173 180 public AttributeStrategy getAttributeStrategy(QName attrName) 181 throws Exception 182 { 183 AttributeStrategy strategy = _nsAttributeMap.get(attrName); 184 185 if (strategy == null) { 186 strategy = getAttributeStrategyImpl(attrName); 187 188 if (strategy == null && attrName.getName().equals("#text")) { 189 strategy = getAttributeStrategyImpl(TEXT); 190 191 if (strategy == null) 192 strategy = getAttributeStrategyImpl(VALUE); 193 } 194 195 if (strategy == null) 196 throw new ConfigException(L.l("'{0}' is an unknown property of '{1}'.", 197 attrName.getName(), _type.getName())); 198 199 _nsAttributeMap.put(attrName, strategy); 200 } 201 202 return strategy; 203 } 204 205 208 public Object configure(NodeBuilder builder, Node node, Object parent) 209 throws Exception 210 { 211 return builder.configureChildImpl(this, node, parent); 212 } 213 214 public void configureBean(NodeBuilder builder, Object bean, Node node) 215 throws Exception 216 { 217 Thread thread = Thread.currentThread(); 218 ClassLoader oldLoader = thread.getContextClassLoader(); 219 220 try { 221 if (node instanceof CauchoNode) { 222 CauchoNode cauchoNode = (CauchoNode) node; 223 224 if (_setNode != null) 225 _setNode.invoke(bean, cauchoNode); 226 227 if (_setLocation != null) 228 _setLocation.invoke(bean, cauchoNode.getFilename(), cauchoNode.getLine()); 229 230 if (_setSystemId != null) 231 _setSystemId.invoke(bean, cauchoNode.getBaseURI()); 232 } 233 234 if (_addDependency != null && (node instanceof QAbstractNode)) { 235 QAbstractNode qAbstractNode = (QAbstractNode) node; 236 ArrayList <Depend> dependList = qAbstractNode.getDependencyList(); 237 238 for (int i = 0; dependList != null && i < dependList.size(); i++) 239 _addDependency.invoke(bean, dependList.get(i)); 240 } 241 242 for (int i = 0; i < _injectList.size(); i++) { 243 try { 244 _injectList.get(i).configure(bean); 245 } catch (Throwable e) { 246 throw new ConfigException(e); 247 } 248 } 249 250 super.configureBean(builder, bean, node); 251 252 if (bean instanceof Validator) 253 builder.addValidator((Validator) bean); 254 } finally { 255 thread.setContextClassLoader(oldLoader); 256 } 257 } 258 259 262 protected AttributeStrategy getAttributeStrategyImpl(QName qName) 263 throws Exception 264 { 265 String name = qName.getName(); 266 267 AttributeStrategy strategy = null; 268 269 Method builderMethod = findProgramBuilderMethod(); 270 271 AttributeStrategy flow = getFlowAttribute(qName); 272 if (flow != null) { 273 if (builderMethod != null) 274 return new ProgramAttributeStrategy(builderMethod); 275 276 return flow; 277 } 278 279 if (name.equals("#text")) 281 name = "text"; 282 283 Method setterMethod = findOneArgSetter(name); 284 Method createMethod = findCreate(name); 285 if (createMethod != null) { 286 return new CreateAttributeStrategy(createMethod, setterMethod); 287 } 288 289 if (setterMethod == null) { 290 } 291 else if (qName.getName().equals("#text")) { 292 strategy = TextAttributeMarshal.create(setterMethod); 293 294 return strategy; 295 } 296 else { 297 strategy = new SetterAttributeStrategy(setterMethod); 298 299 return strategy; 300 } 301 302 if (builderMethod != null) 303 return new ProgramAttributeStrategy(builderMethod); 304 305 strategy = getEnvironmentAttribute(qName); 306 307 if (strategy != null) 308 return strategy; 309 310 Method method = findSetPropertyMethod(); 311 312 if (method != null) { 313 if (QName.class.isAssignableFrom(method.getParameterTypes()[0])) 314 return new QNameMapAttributeStrategy(method, qName); 315 else 316 return new PrimitivePropertyStrategy(method, name); 317 } 318 319 return null; 320 } 321 322 325 public AttributeStrategy getFlowAttribute(QName name) 326 throws Exception 327 { 328 return TypeStrategyFactory.getFlowAttribute(getType(),name); 329 } 330 331 334 public AttributeStrategy getEnvironmentAttribute(QName name) 335 throws Exception 336 { 337 return null; 338 } 339 340 343 public void init(Object bean) 344 throws Exception 345 { 346 try { 347 for (int i = 0; i < _initList.size(); i++) 348 _initList.get(i).invoke(bean); 349 } catch (InvocationTargetException e) { 350 Throwable cause = e.getCause(); 351 352 if (cause instanceof Exception ) 353 throw (Exception ) cause; 354 else 355 throw new ConfigException(cause); 356 } 357 358 for (int i = 0; i < _destroyList.size(); i++) { 359 Method method = _destroyList.get(i); 360 EnvironmentListener listener; 361 listener = new WeakDestroyListener(method, bean); 362 363 Environment.addEnvironmentListener(listener); 364 } 365 } 366 367 372 public Object replaceObject(Object bean) 373 throws Exception 374 { 375 if (_replaceObject != null) 376 return _replaceObject.invoke(bean); 377 else 378 return bean; 379 } 380 381 protected Method findOneArgSetter(String attributeName) 382 { 383 String methodSuffix = attributeNameToBeanName(attributeName); 384 385 Method method = findSetter("set" + methodSuffix); 386 387 if (method == null) 388 method = findSetter("add" + methodSuffix); 389 390 return method; 391 } 392 393 private void scanMethods(Class cl) 394 { 395 if (cl == null || Object .class.equals(cl)) 396 return; 397 398 Method []methods = cl.getDeclaredMethods(); 399 400 for (int i = 0; i < methods.length; i++) { 401 Method method = methods[i]; 402 403 if (method.isAnnotationPresent(PostConstruct.class)) { 404 if (method.getParameterTypes().length != 0) 405 throw new ConfigException(L.l("{0}::{1} is an invalid @PostConstruct method. @PostConstruct must have zero arguments.", 406 method.getDeclaringClass().getName(), 407 method.getName())); 408 409 if (! hasMethod(_initList, method)) 410 _initList.add(method); 411 } 412 else if (method.isAnnotationPresent(PreDestroy.class)) { 413 if (method.getParameterTypes().length != 0) 414 throw new ConfigException(L.l("{0}::{1} is an invalid @PreDestroy method. @PreDestroy must have zero arguments.", 415 method.getDeclaringClass().getName(), 416 method.getName())); 417 418 _destroyList.add(method); 419 } 420 } 421 422 scanMethods(cl.getSuperclass()); 423 } 424 425 private boolean hasMethod(ArrayList <Method > methodList, Method method) 426 { 427 for (int i = 0; i < methodList.size(); i++) { 428 if (methodList.get(i).getName() == method.getName()) 429 return true; 430 } 431 432 return false; 433 } 434 435 protected Method findCreate(String attributeName) 436 { 437 String methodSuffix = attributeNameToBeanName(attributeName); 438 439 return findMethod("create" + methodSuffix, new Class [0]); 440 } 441 442 protected Method findSetter(String methodName) 443 { 444 Method method = findSetter(methodName, false); 445 446 if (method != null) 447 return method; 448 449 return findSetter(methodName, true); 450 } 451 452 455 protected Method findSetter(String methodName, 456 boolean ignoreCase) 457 { 458 Method bestMethod = null; 459 460 Method [] methods = getMethods(); 461 462 for (int i = 0; i < methods.length; i++) { 463 Method method = methods[i]; 464 465 if (! Modifier.isPublic(method.getModifiers())) 466 continue; 467 468 if (!ignoreCase && !method.getName().equals(methodName)) 469 continue; 470 if (ignoreCase && !method.getName().equalsIgnoreCase(methodName)) 471 continue; 472 if (method.getParameterTypes().length != 1) 473 continue; 474 475 if (method.getParameterTypes()[0].equals(String .class)) 476 return method; 477 478 bestMethod = method; 479 } 480 481 return bestMethod; 482 } 483 484 491 protected static String attributeNameToBeanName(String name) 492 { 493 CharBuffer cb = CharBuffer.allocate(); 494 495 for (int i = 0; i < name.length(); i++) { 496 char ch = name.charAt(i); 497 498 if (ch == '-') 499 cb.append(Character.toUpperCase(name.charAt(++i))); 500 else if (ch == ':') 501 cb.clear(); 502 else if (ch == '.') 503 cb.append('_'); 504 else 505 cb.append(ch); 506 } 507 508 if (Character.isLowerCase(cb.charAt(0))) 509 cb.setCharAt(0, Character.toUpperCase(cb.charAt(0))); 510 511 return cb.close(); 512 } 513 514 protected Method findSetPropertyMethod() 515 { 516 Method method; 517 518 method = findSetPropertyMethod("setProperty"); 519 if (method != null) 520 return method; 521 522 method = findSetPropertyMethod("setAttribute"); 523 if (method != null) 524 return method; 525 526 method = findSetPropertyMethod("put"); 527 if (method != null) 528 return method; 529 530 method = findSetPropertyMethod("set"); 531 if (method != null) 532 return method; 533 534 return method; 535 } 536 537 protected Method findSetPropertyMethod(String methodName) 538 { 539 Method method; 540 541 method = findSetPropertyMethod(methodName, 542 String .class, BuilderProgram.class); 543 if (method != null) 544 return method; 545 546 method = findSetPropertyMethod(methodName, 547 Object .class, BuilderProgram.class); 548 if (method != null) 549 return method; 550 551 method = findSetPropertyMethod(methodName, QName.class, null); 552 if (method != null) 553 return method; 554 555 method = findSetPropertyMethod(methodName, String .class, String .class); 556 if (method != null) 557 return method; 558 559 method = findSetPropertyMethod(methodName, String .class, Object .class); 560 if (method != null) 561 return method; 562 method = findSetPropertyMethod(methodName, String .class, null); 563 if (method != null) 564 return method; 565 566 method = findSetPropertyMethod(methodName, Object .class, Object .class); 567 if (method != null) 568 return method; 569 method = findSetPropertyMethod(methodName, Object .class, null); 570 if (method != null) 571 return method; 572 573 return null; 574 } 575 576 protected Method findSetPropertyMethod(String name, 577 Class keyClass, 578 Class valueClass) 579 { 580 Method []methods = getMethods(); 581 582 for (int i = 0; i < methods.length; i++) { 583 Method method = methods[i]; 584 585 if (! method.getName().equals(name)) 586 continue; 587 else if (! Modifier.isPublic(method.getModifiers())) 588 continue; 589 590 Class []methodTypes = method.getParameterTypes(); 591 592 if (methodTypes.length != 2) 593 continue; 594 595 if (! methodTypes[0].equals(keyClass)) 596 continue; 597 598 if (valueClass != null && ! methodTypes[1].equals(valueClass)) 599 continue; 600 601 return method; 602 } 603 604 return null; 605 } 606 607 protected Method findProgramBuilderMethod() 608 { 609 Method method = findMethod("addBuilderProgram", 610 new Class [] { BuilderProgram.class }); 611 612 if (method != null) 613 return method; 614 615 return method; 616 } 617 618 protected Method findMethod(String methodName, Class [] parameterTypes) 619 { 620 Method []methods = getMethods(); 621 622 loop: 623 for (int i = 0; i < methods.length; i++) { 624 Method method = methods[i]; 625 626 if (! method.getName().equals(methodName)) 627 continue; 628 else if (! Modifier.isPublic(method.getModifiers())) 629 continue; 630 631 Class []methodTypes = method.getParameterTypes(); 632 633 if (methodTypes.length != parameterTypes.length) 634 continue; 635 636 for (int j = 0; j < methodTypes.length; j++) { 637 if (parameterTypes[j] != null && ! methodTypes[j].equals(parameterTypes[j])) 638 continue loop; 639 } 640 641 return method; 642 } 643 644 return null; 645 } 646 647 private Method []getMethods() 648 { 649 SoftReference <Method []> methodsRef = _methodsRef; 650 Method [] methods; 651 652 if (methodsRef != null && (methods = methodsRef.get()) != null) 653 return methods; 654 655 ArrayList <Method > methodList = new ArrayList <Method >(); 656 657 getMethods(methodList, _type); 658 659 methods = methodList.toArray(new Method [methodList.size()]); 660 661 _methodsRef = new SoftReference <Method []>(methods); 662 663 return methods; 664 } 665 666 public static void getMethods(ArrayList <Method > list, Class type) 667 { 668 if (type == null) 669 return; 670 671 if (Modifier.isPublic(type.getModifiers())) { 672 Method []methods = type.getDeclaredMethods(); 673 674 for (int i = 0; i < methods.length; i++) { 675 if (! contains(list, methods[i])) 676 list.add(methods[i]); 677 } 678 } 679 680 Class []interfaces = type.getInterfaces(); 681 for (int i = 0; i < interfaces.length; i++) 682 getMethods(list, interfaces[i]); 683 684 getMethods(list, type.getSuperclass()); 685 } 686 687 public static boolean contains(ArrayList <Method > list, Method method) 688 { 689 for (int i = 0; i < list.size(); i++) { 690 if (isMatch(list.get(i), method)) 691 return true; 692 } 693 694 return false; 695 } 696 697 public static boolean isMatch(Method methodA, Method methodB) 698 { 699 if (! methodA.getName().equals(methodB.getName())) 700 return false; 701 702 Class []paramA = methodA.getParameterTypes(); 703 Class []paramB = methodB.getParameterTypes(); 704 705 if (paramA.length != paramB.length) 706 return false; 707 708 for (int i = 0; i < paramA.length; i++) { 709 if (! paramA[i].equals(paramB[i])) 710 return false; 711 } 712 713 return true; 714 } 715 716 protected static void invokeBeanMethod(Object bean, Method method, Object [] args) 717 throws ConfigException 718 { 719 try { 720 method.invoke(bean, args); 721 } 722 catch (IllegalArgumentException e) { 723 throw new ConfigException(L.l("{0}: parameter type mismatch invoking method `{1}'.", bean.getClass().getName(), method.toString()), e); 725 } 726 catch (IllegalAccessException e) { 727 throw new ConfigException(L.l("Bean method `{0}' isn't accessible.", method.toString()), e); 728 } 729 catch (InvocationTargetException e) { 730 throw new ConfigException(e.getCause()); 731 } 732 } 733 734 protected ELContext getEnvironment() 735 { 736 return Config.getEnvironment(); 737 } 738 739 protected static NotImplementedException notImplemented() 740 { 741 return new NotImplementedException(L.l("Not implemented.")); 742 } 743 744 public String toString() 745 { 746 return "BeanTypeStrategy[" + _type.getName() + "]"; 747 } 748 } 749 | Popular Tags |