1 18 19 package org.apache.tools.ant; 20 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Modifier ; 23 import java.lang.reflect.InvocationTargetException ; 24 import java.io.InputStream ; 25 import java.io.IOException ; 26 import java.io.File ; 27 import java.io.StringWriter ; 28 import java.io.PrintWriter ; 29 import java.util.Enumeration ; 30 import java.util.Hashtable ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.Properties ; 34 import java.util.Set ; 35 import java.util.Stack ; 36 37 import org.apache.tools.ant.taskdefs.Typedef; 38 import org.apache.tools.ant.taskdefs.Definer; 39 import org.apache.tools.ant.launch.Launcher; 40 import org.apache.tools.ant.util.FileUtils; 41 42 58 public class ComponentHelper { 59 60 private AntTypeTable antTypeTable; 61 62 63 private Hashtable taskClassDefinitions = new Hashtable (); 64 65 private boolean rebuildTaskClassDefinitions = true; 66 67 68 private Hashtable typeClassDefinitions = new Hashtable (); 69 70 private boolean rebuildTypeClassDefinitions = true; 71 72 73 private Set checkedNamespaces = new HashSet (); 74 75 79 private Stack antLibStack = new Stack (); 80 81 private String antLibCurrentUri = null; 82 83 87 private ComponentHelper next; 88 89 92 private Project project; 93 94 97 private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load default task list"; 98 101 private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list"; 102 103 106 public static final String COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper"; 107 108 111 private static final String BUILD_SYSCLASSPATH_ONLY = "only"; 112 113 117 private static final String ANT_PROPERTY_TASK = "property"; 118 119 private static Properties [] defaultDefinitions = new Properties [2]; 121 122 123 129 public static ComponentHelper getComponentHelper(Project project) { 130 if (project == null) { 131 return null; 132 } 133 ComponentHelper ph = (ComponentHelper) project.getReference( 135 COMPONENT_HELPER_REFERENCE); 136 if (ph != null) { 137 return ph; 138 } 139 ph = new ComponentHelper(); 140 ph.setProject(project); 141 142 project.addReference(COMPONENT_HELPER_REFERENCE, ph); 143 return ph; 144 } 145 146 149 protected ComponentHelper() { 150 } 151 152 157 public void setNext(ComponentHelper next) { 158 this.next = next; 159 } 160 161 166 public ComponentHelper getNext() { 167 return next; 168 } 169 170 175 public void setProject(Project project) { 176 this.project = project; 177 antTypeTable = new AntTypeTable(project); 178 } 179 180 186 public void initSubProject(ComponentHelper helper) { 187 AntTypeTable typeTable = helper.antTypeTable; 189 for (Iterator i = typeTable.values().iterator(); i.hasNext();) { 190 AntTypeDefinition def = (AntTypeDefinition) i.next(); 191 antTypeTable.put(def.getName(), def); 192 } 193 for (Iterator i = helper.checkedNamespaces.iterator(); i.hasNext();) { 195 checkedNamespaces.add(i.next()); 196 } 197 } 198 199 211 public Object createComponent(UnknownElement ue, 212 String ns, 213 String componentType) 214 throws BuildException { 215 Object component = createComponent(componentType); 216 if (component instanceof Task) { 217 Task task = (Task) component; 218 task.setLocation(ue.getLocation()); 219 task.setTaskType(componentType); 220 task.setTaskName(ue.getTaskName()); 221 task.setOwningTarget(ue.getOwningTarget()); 222 task.init(); 223 } 224 return component; 225 } 226 227 235 public Object createComponent(String componentName) { 236 AntTypeDefinition def = getDefinition(componentName); 237 return (def == null) ? null : def.create(project); 238 } 239 240 248 public Class getComponentClass(String componentName) { 249 AntTypeDefinition def = getDefinition(componentName); 250 return (def == null) ? null : def.getExposedClass(project); 251 } 252 253 258 public AntTypeDefinition getDefinition(String componentName) { 259 checkNamespace(componentName); 260 return antTypeTable.getDefinition(componentName); 261 } 262 263 268 public void initDefaultDefinitions() { 269 initTasks(); 270 initTypes(); 271 } 272 273 291 public void addTaskDefinition(String taskName, Class taskClass) { 292 checkTaskClass(taskClass); 293 AntTypeDefinition def = new AntTypeDefinition(); 294 def.setName(taskName); 295 def.setClassLoader(taskClass.getClassLoader()); 296 def.setClass(taskClass); 297 def.setAdapterClass(TaskAdapter.class); 298 def.setClassName(taskClass.getName()); 299 def.setAdaptToClass(Task.class); 300 updateDataTypeDefinition(def); 301 } 302 303 315 public void checkTaskClass(final Class taskClass) throws BuildException { 316 if (!Modifier.isPublic(taskClass.getModifiers())) { 317 final String message = taskClass + " is not public"; 318 project.log(message, Project.MSG_ERR); 319 throw new BuildException(message); 320 } 321 if (Modifier.isAbstract(taskClass.getModifiers())) { 322 final String message = taskClass + " is abstract"; 323 project.log(message, Project.MSG_ERR); 324 throw new BuildException(message); 325 } 326 try { 327 taskClass.getConstructor((Class []) null); 328 } catch (NoSuchMethodException e) { 331 final String message = "No public no-arg constructor in " 332 + taskClass; 333 project.log(message, Project.MSG_ERR); 334 throw new BuildException(message); 335 } 336 if (!Task.class.isAssignableFrom(taskClass)) { 337 TaskAdapter.checkTaskClass(taskClass, project); 338 } 339 } 340 341 348 public Hashtable getTaskDefinitions() { 349 synchronized (taskClassDefinitions) { 350 synchronized (antTypeTable) { 351 if (rebuildTaskClassDefinitions) { 352 taskClassDefinitions.clear(); 353 for (Iterator i = antTypeTable.keySet().iterator(); 354 i.hasNext();) { 355 String name = (String ) i.next(); 356 Class clazz = antTypeTable.getExposedClass(name); 357 if (clazz == null) { 358 continue; 359 } 360 if (Task.class.isAssignableFrom(clazz)) { 361 taskClassDefinitions.put( 362 name, antTypeTable.getTypeClass(name)); 363 } 364 } 365 rebuildTaskClassDefinitions = false; 366 } 367 } 368 } 369 return taskClassDefinitions; 370 } 371 372 373 380 public Hashtable getDataTypeDefinitions() { 381 synchronized (typeClassDefinitions) { 382 synchronized (antTypeTable) { 383 if (rebuildTypeClassDefinitions) { 384 typeClassDefinitions.clear(); 385 for (Iterator i = antTypeTable.keySet().iterator(); 386 i.hasNext();) { 387 String name = (String ) i.next(); 388 Class clazz = antTypeTable.getExposedClass(name); 389 if (clazz == null) { 390 continue; 391 } 392 if (!(Task.class.isAssignableFrom(clazz))) { 393 typeClassDefinitions.put( 394 name, antTypeTable.getTypeClass(name)); 395 } 396 } 397 rebuildTypeClassDefinitions = false; 398 } 399 } 400 } 401 return typeClassDefinitions; 402 } 403 404 417 public void addDataTypeDefinition(String typeName, Class typeClass) { 418 AntTypeDefinition def = new AntTypeDefinition(); 419 def.setName(typeName); 420 def.setClass(typeClass); 421 updateDataTypeDefinition(def); 422 project.log(" +User datatype: " + typeName + " " 423 + typeClass.getName(), Project.MSG_DEBUG); 424 } 425 426 431 public void addDataTypeDefinition(AntTypeDefinition def) { 432 updateDataTypeDefinition(def); 433 } 434 435 442 public Hashtable getAntTypeTable() { 443 return antTypeTable; 444 } 445 446 460 public Task createTask(String taskType) throws BuildException { 461 Task task = createNewTask(taskType); 462 if (task == null && taskType.equals(ANT_PROPERTY_TASK)) { 463 addTaskDefinition(ANT_PROPERTY_TASK, 466 org.apache.tools.ant.taskdefs.Property.class); 467 task = createNewTask(taskType); 468 } 469 return task; 470 } 471 472 484 private Task createNewTask(String taskType) throws BuildException { 485 Class c = getComponentClass(taskType); 486 if (c == null || !(Task.class.isAssignableFrom(c))) { 487 return null; 488 } 489 Object obj = createComponent(taskType); 490 if (obj == null) { 491 return null; 492 } 493 if (!(obj instanceof Task)) { 494 throw new BuildException( 495 "Expected a Task from '" + taskType 496 + "' but got an instance of " + obj.getClass().getName() 497 + " instead"); 498 } 499 Task task = (Task) obj; 500 task.setTaskType(taskType); 501 502 task.setTaskName(taskType); 504 505 project.log(" +Task: " + taskType, Project.MSG_DEBUG); 506 return task; 507 } 508 509 521 public Object createDataType(String typeName) throws BuildException { 522 return createComponent(typeName); 523 } 524 525 537 public String getElementName(Object element) { 538 return getElementName(element, false); 539 } 540 541 553 public String getElementName(Object o, boolean brief) { 554 Class elementClass = o.getClass(); 558 String elementClassname = elementClass.getName(); 559 for (Iterator i = antTypeTable.values().iterator(); i.hasNext();) { 560 AntTypeDefinition def = (AntTypeDefinition) i.next(); 561 if (elementClassname.equals(def.getClassName()) 562 && (elementClass == def.getExposedClass(project))) { 563 String name = def.getName(); 564 return brief ? name : "The <" + name + "> type"; 565 } 566 } 567 return getUnmappedElementName(o.getClass(), brief); 568 } 569 570 580 public static String getElementName(Project p, Object o, boolean brief) { 581 if (p == null) { 582 p = getProject(o); 583 } 584 return p == null ? getUnmappedElementName(o.getClass(), brief) 585 : getComponentHelper(p).getElementName(o, brief); 586 } 587 588 private static String getUnmappedElementName(Class c, boolean brief) { 589 if (brief) { 590 String name = c.getName(); 591 return name.substring(name.lastIndexOf('.') + 1); 592 } 593 return c.toString(); 594 } 595 596 private static Project getProject(Object o) { 597 if (o instanceof ProjectComponent) { 598 return ((ProjectComponent) o).getProject(); 599 } 600 try { 601 Method m = o.getClass().getMethod("getProject", (Class []) null); 602 if (Project.class == m.getReturnType()) { 603 return (Project) m.invoke(o, (Object []) null); 604 } 605 } catch (Exception e) { 606 } 608 return null; 609 } 610 611 617 private boolean validDefinition(AntTypeDefinition def) { 618 return !(def.getTypeClass(project) == null 619 || def.getExposedClass(project) == null); 620 } 621 622 628 private boolean sameDefinition( 629 AntTypeDefinition def, AntTypeDefinition old) { 630 boolean defValid = validDefinition(def); 631 boolean sameValidity = (defValid == validDefinition(old)); 632 return sameValidity && (!defValid || def.sameDefinition(old, project)); 634 } 635 636 641 private void updateDataTypeDefinition(AntTypeDefinition def) { 642 String name = def.getName(); 643 synchronized (antTypeTable) { 644 rebuildTaskClassDefinitions = true; 645 rebuildTypeClassDefinitions = true; 646 AntTypeDefinition old = antTypeTable.getDefinition(name); 647 if (old != null) { 648 if (sameDefinition(def, old)) { 649 return; 650 } 651 Class oldClass = antTypeTable.getExposedClass(name); 652 boolean isTask = 653 (oldClass != null && Task.class.isAssignableFrom(oldClass)); 654 project.log("Trying to override old definition of " 655 + (isTask ? "task " : "datatype ") + name, 656 (def.similarDefinition(old, project)) 657 ? Project.MSG_VERBOSE : Project.MSG_WARN); 658 } 659 project.log(" +Datatype " + name + " " + def.getClassName(), 660 Project.MSG_DEBUG); 661 antTypeTable.put(name, def); 662 } 663 } 664 665 669 public void enterAntLib(String uri) { 670 antLibCurrentUri = uri; 671 antLibStack.push(uri); 672 } 673 674 677 public String getCurrentAntlibUri() { 678 return antLibCurrentUri; 679 } 680 681 684 public void exitAntLib() { 685 antLibStack.pop(); 686 antLibCurrentUri = (antLibStack.size() == 0) 687 ? null : (String ) antLibStack.peek(); 688 } 689 690 693 private void initTasks() { 694 ClassLoader classLoader = getClassLoader(null); 695 Properties props = getDefaultDefinitions(false); 696 Enumeration e = props.propertyNames(); 697 while (e.hasMoreElements()) { 698 String name = (String ) e.nextElement(); 699 String className = props.getProperty(name); 700 AntTypeDefinition def = new AntTypeDefinition(); 701 def.setName(name); 702 def.setClassName(className); 703 def.setClassLoader(classLoader); 704 def.setAdaptToClass(Task.class); 705 def.setAdapterClass(TaskAdapter.class); 706 antTypeTable.put(name, def); 707 } 708 } 709 710 private ClassLoader getClassLoader(ClassLoader classLoader) { 711 String buildSysclasspath = project.getProperty(MagicNames.BUILD_SYSCLASSPATH); 712 if (project.getCoreLoader() != null 713 && !(BUILD_SYSCLASSPATH_ONLY.equals(buildSysclasspath))) { 714 classLoader = project.getCoreLoader(); 715 } 716 return classLoader; 717 } 718 719 728 private static synchronized Properties getDefaultDefinitions(boolean type) 729 throws BuildException { 730 int idx = type ? 1 : 0; 731 if (defaultDefinitions[idx] == null) { 732 String resource = type 733 ? MagicNames.TYPEDEFS_PROPERTIES_RESOURCE 734 : MagicNames.TASKDEF_PROPERTIES_RESOURCE; 735 String errorString = type 736 ? ERROR_NO_TYPE_LIST_LOAD 737 : ERROR_NO_TASK_LIST_LOAD; 738 InputStream in = null; 739 try { 740 in = ComponentHelper.class.getResourceAsStream( 741 resource); 742 if (in == null) { 743 throw new BuildException(errorString); 744 } 745 Properties p = new Properties (); 746 p.load(in); 747 defaultDefinitions[idx] = p; 748 } catch (IOException e) { 749 throw new BuildException(errorString, e); 750 } finally { 751 FileUtils.close(in); 752 } 753 } 754 return defaultDefinitions[idx]; 755 } 756 757 760 private void initTypes() { 761 ClassLoader classLoader = getClassLoader(null); 762 Properties props = getDefaultDefinitions(true); 763 Enumeration e = props.propertyNames(); 764 while (e.hasMoreElements()) { 765 String name = (String ) e.nextElement(); 766 String className = props.getProperty(name); 767 AntTypeDefinition def = new AntTypeDefinition(); 768 def.setName(name); 769 def.setClassName(className); 770 def.setClassLoader(classLoader); 771 antTypeTable.put(name, def); 772 } 773 } 774 775 779 private synchronized void checkNamespace(String componentName) { 780 String uri = ProjectHelper.extractUriFromComponentName(componentName); 781 if ("".equals(uri)) { 782 uri = ProjectHelper.ANT_CORE_URI; 783 } 784 if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) { 785 return; } 787 if (checkedNamespaces.contains(uri)) { 788 return; } 790 checkedNamespaces.add(uri); 791 Typedef definer = new Typedef(); 792 definer.setProject(project); 793 definer.init(); 794 definer.setURI(uri); 795 definer.setTaskName(uri); 797 definer.setResource(Definer.makeResourceFromURI(uri)); 800 definer.setOnError(new Typedef.OnError(Typedef.OnError.POLICY_IGNORE)); 802 definer.execute(); 803 } 804 805 811 public String diagnoseCreationFailure(String componentName, String type) { 812 StringWriter errorText = new StringWriter (); 813 PrintWriter out = new PrintWriter (errorText); 814 out.println("Problem: failed to create " + type + " " + componentName); 815 boolean lowlevel = false; 817 boolean jars = false; 818 boolean definitions = false; 819 boolean antTask; 820 String home = System.getProperty(Launcher.USER_HOMEDIR); 821 File libDir = new File (home, Launcher.USER_LIBDIR); 822 String antHomeLib; 823 boolean probablyIDE = false; 824 String anthome = System.getProperty(MagicNames.ANT_HOME); 825 if (anthome != null) { 826 File antHomeLibDir = new File (anthome, "lib"); 827 antHomeLib = antHomeLibDir.getAbsolutePath(); 828 } else { 829 probablyIDE = true; 831 antHomeLib = "ANT_HOME" + File.separatorChar + "lib"; 832 } 833 StringBuffer dirListingText = new StringBuffer (); 834 final String tab = " -"; 835 dirListingText.append(tab); 836 dirListingText.append(antHomeLib); 837 dirListingText.append('\n'); 838 if (probablyIDE) { 839 dirListingText.append(tab); 840 dirListingText.append("the IDE Ant configuration dialogs"); 841 } else { 842 dirListingText.append(tab); 843 dirListingText.append(libDir); 844 dirListingText.append('\n'); 845 dirListingText.append(tab); 846 dirListingText.append( 847 "a directory added on the command line with the -lib argument"); 848 } 849 850 String dirListing = dirListingText.toString(); 851 852 AntTypeDefinition def = getDefinition(componentName); 854 if (def == null) { 855 boolean isAntlib = componentName.indexOf(MagicNames.ANTLIB_PREFIX) == 0; 857 out.println("Cause: The name is undefined."); 858 out.println("Action: Check the spelling."); 859 out.println("Action: Check that any custom tasks/types have been declared."); 860 out.println("Action: Check that any <presetdef>/<macrodef>" 861 + " declarations have taken place."); 862 if (isAntlib) { 863 out.println(); 864 out.println("This appears to be an antlib declaration. "); 865 out.println("Action: Check that the implementing library exists in one of:"); 866 out.println(dirListing); 867 } 868 definitions = true; 869 } else { 870 final String classname = def.getClassName(); 872 antTask = classname.startsWith("org.apache.tools.ant."); 873 boolean optional = classname.startsWith("org.apache.tools.ant.taskdefs.optional"); 874 optional |= classname.startsWith("org.apache.tools.ant.types.optional"); 875 876 Class clazz = null; 878 try { 879 clazz = def.innerGetTypeClass(); 880 } catch (ClassNotFoundException e) { 881 out.println("Cause: the class " + classname + " was not found."); 882 jars = true; 883 if (optional) { 884 out.println(" This looks like one of Ant's optional components."); 885 out.println("Action: Check that the appropriate optional JAR exists in"); 886 out.println(dirListing); 887 } else { 888 out.println("Action: Check that the component has been correctly declared"); 889 out.println(" and that the implementing JAR is in one of:"); 890 out.println(dirListing); 891 definitions = true; 892 } 893 } catch (NoClassDefFoundError ncdfe) { 894 jars = true; 895 out.println("Cause: Could not load a dependent class " 896 + ncdfe.getMessage()); 897 if (optional) { 898 out.println(" It is not enough to have Ant's optional JARs"); 899 out.println(" you need the JAR files that the" 900 + " optional tasks depend upon."); 901 out.println(" Ant's optional task dependencies are" 902 + " listed in the manual."); 903 } else { 904 out.println(" This class may be in a separate JAR" 905 + " that is not installed."); 906 } 907 out.println("Action: Determine what extra JAR files are" 908 + " needed, and place them in one of:"); 909 out.println(dirListing); 910 } 911 if (clazz != null) { 913 try { 915 def.innerCreateAndSet(clazz, project); 916 out.println("The component could be instantiated."); 918 } catch (NoSuchMethodException e) { 919 lowlevel = true; 920 out.println("Cause: The class " + classname 921 + " has no compatible constructor."); 922 923 } catch (InstantiationException e) { 924 lowlevel = true; 925 out.println("Cause: The class " + classname 926 + " is abstract and cannot be instantiated."); 927 } catch (IllegalAccessException e) { 928 lowlevel = true; 929 out.println("Cause: The constructor for " + classname 930 + " is private and cannot be invoked."); 931 } catch (InvocationTargetException ex) { 932 lowlevel = true; 933 Throwable t = ex.getTargetException(); 934 out.println("Cause: The constructor threw the exception"); 935 out.println(t.toString()); 936 t.printStackTrace(out); 937 } catch (NoClassDefFoundError ncdfe) { 938 jars = true; 939 out.println("Cause: A class needed by class " 940 + classname + " cannot be found: "); 941 out.println(" " + ncdfe.getMessage()); 942 out.println("Action: Determine what extra JAR files are" 943 + " needed, and place them in:"); 944 out.println(dirListing); 945 } 946 } 947 out.println(); 948 out.println("Do not panic, this is a common problem."); 949 if (definitions) { 950 out.println("It may just be a typographical error in the build file " 951 + "or the task/type declaration."); 952 } 953 if (jars) { 954 out.println("The commonest cause is a missing JAR."); 955 } 956 if (lowlevel) { 957 out.println("This is quite a low level problem, which may need " 958 + "consultation with the author of the task."); 959 if (antTask) { 960 out.println("This may be the Ant team. Please file a " 961 + "defect or contact the developer team."); 962 } else { 963 out.println("This does not appear to be a task bundled with Ant."); 964 out.println("Please take it up with the supplier of the third-party " 965 + type + "."); 966 out.println("If you have written it yourself, you probably have a bug to fix."); 967 } 968 } else { 969 out.println(); 970 out.println("This is not a bug; it is a configuration problem"); 971 } 972 } 973 out.flush(); 974 out.close(); 975 return errorText.toString(); 976 } 977 978 981 private static class AntTypeTable extends Hashtable { 982 private Project project; 983 984 AntTypeTable(Project project) { 985 this.project = project; 986 } 987 988 AntTypeDefinition getDefinition(String key) { 989 return (AntTypeDefinition) (super.get(key)); 990 } 991 992 public Object get(Object key) { 993 return getTypeClass((String ) key); 994 } 995 996 Object create(String name) { 997 AntTypeDefinition def = getDefinition(name); 998 return (def == null) ? null : def.create(project); 999 } 1000 1001 Class getTypeClass(String name) { 1002 AntTypeDefinition def = getDefinition(name); 1003 return (def == null) ? null : def.getTypeClass(project); 1004 } 1005 1006 Class getExposedClass(String name) { 1007 AntTypeDefinition def = getDefinition(name); 1008 return (def == null) ? null : def.getExposedClass(project); 1009 } 1010 1011 public boolean contains(Object clazz) { 1012 boolean found = false; 1013 if (clazz instanceof Class ) { 1014 for (Iterator i = values().iterator(); i.hasNext() && !found;) { 1015 found |= (((AntTypeDefinition) (i.next())).getExposedClass( 1016 project) == clazz); 1017 } 1018 } 1019 return found; 1020 } 1021 1022 public boolean containsValue(Object value) { 1023 return contains(value); 1024 } 1025 } 1026 1027} 1028 | Popular Tags |