KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > ComponentHelper


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant;
20
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.lang.reflect.InvocationTargetException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.StringWriter JavaDoc;
28 import java.io.PrintWriter JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.Hashtable JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.Properties JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.Stack JavaDoc;
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 /**
43  * Component creation and configuration.
44  *
45  * The class is based around handing component
46  * definitions in an AntTypeTable.
47  *
48  * The old task/type methods have been kept
49  * for backward compatibly.
50  * Project will just delegate its calls to this class.
51  *
52  * A very simple hook mechanism is provided that allows users to plug
53  * in custom code. It is also possible to replace the default behavior
54  * ( for example in an app embedding ant )
55  *
56  * @since Ant1.6
57  */

58 public class ComponentHelper {
59     /** Map from component name to anttypedefinition */
60     private AntTypeTable antTypeTable;
61
62     /** Map of tasks generated from antTypeTable */
63     private Hashtable JavaDoc taskClassDefinitions = new Hashtable JavaDoc();
64     /** flag to rebuild taskClassDefinitions */
65     private boolean rebuildTaskClassDefinitions = true;
66
67     /** Map of types generated from antTypeTable */
68     private Hashtable JavaDoc typeClassDefinitions = new Hashtable JavaDoc();
69     /** flag to rebuild typeClassDefinitions */
70     private boolean rebuildTypeClassDefinitions = true;
71
72     /** Set of namespaces that have been checked for antlibs */
73     private Set JavaDoc checkedNamespaces = new HashSet JavaDoc();
74
75     /**
76      * Stack of antlib contexts used to resolve definitions while
77      * processing antlib
78      */

79     private Stack JavaDoc antLibStack = new Stack JavaDoc();
80     /** current antlib uri */
81     private String JavaDoc antLibCurrentUri = null;
82
83     /**
84      * this does not appear to be used anywhere in the Ant codebase
85      * even via its accessors
86      */

87     private ComponentHelper next;
88
89     /**
90      * Project that owns a component helper
91      */

92     private Project project;
93
94     /**
95      * Error string when the file taskdefs/defaults.properties cannot be found
96      */

97     private static final String JavaDoc ERROR_NO_TASK_LIST_LOAD = "Can't load default task list";
98     /**
99      * Error string when the typedefs/defaults.properties cannot be found
100      */

101     private static final String JavaDoc ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list";
102
103     /**
104      * reference under which we register ourselves with a project -{@value}
105      */

106     public static final String JavaDoc COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper";
107
108     /**
109      * string used to control build.syspath policy {@value}
110      */

111     private static final String JavaDoc BUILD_SYSCLASSPATH_ONLY = "only";
112
113     /**
114      * special name of ant's property task -{@value}. There is some
115      * contrived work here to enable this early.
116      */

117     private static final String JavaDoc ANT_PROPERTY_TASK = "property";
118
119     // {tasks, types}
120
private static Properties JavaDoc[] defaultDefinitions = new Properties JavaDoc[2];
121
122
123     /**
124      * Find a project component for a specific project, creating
125      * it if it does not exist.
126      * @param project the project.
127      * @return the project component for a specific project.
128      */

129     public static ComponentHelper getComponentHelper(Project project) {
130         if (project == null) {
131             return null;
132         }
133         // Singleton for now, it may change ( per/classloader )
134
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     /**
147      * Creates a new ComponentHelper instance.
148      */

149     protected ComponentHelper() {
150     }
151
152     /**
153      * Set the next chained component helper.
154      *
155      * @param next the next chained component helper.
156      */

157     public void setNext(ComponentHelper next) {
158         this.next = next;
159     }
160
161     /**
162      * Get the next chained component helper.
163      *
164      * @return the next chained component helper.
165      */

166     public ComponentHelper getNext() {
167         return next;
168     }
169
170     /**
171      * Sets the project for this component helper.
172      *
173      * @param project the project for this helper.
174      */

175     public void setProject(Project project) {
176         this.project = project;
177         antTypeTable = new AntTypeTable(project);
178     }
179
180     /**
181      * Used with creating child projects. Each child
182      * project inherits the component definitions
183      * from its parent.
184      * @param helper the component helper of the parent project.
185      */

186     public void initSubProject(ComponentHelper helper) {
187         // add the types of the parent project
188
AntTypeTable typeTable = helper.antTypeTable;
189         for (Iterator JavaDoc i = typeTable.values().iterator(); i.hasNext();) {
190             AntTypeDefinition def = (AntTypeDefinition) i.next();
191             antTypeTable.put(def.getName(), def);
192         }
193         // add the parsed namespaces of the parent project
194
for (Iterator JavaDoc i = helper.checkedNamespaces.iterator(); i.hasNext();) {
195             checkedNamespaces.add(i.next());
196         }
197     }
198
199     /**
200      * Factory method to create the components.
201      *
202      * This should be called by UnknownElement.
203      *
204      * @param ue The Unknown Element creating this component.
205      * @param ns Namespace URI. Also available as ue.getNamespace().
206      * @param componentType The component type,
207      * Also available as ue.getComponentName().
208      * @return the created component.
209      * @throws BuildException if an error occurs.
210      */

211     public Object JavaDoc createComponent(UnknownElement ue,
212                                   String JavaDoc ns,
213                                   String JavaDoc componentType)
214         throws BuildException {
215         Object JavaDoc 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     /**
228      * Create an object for a component.
229      *
230      * @param componentName the name of the component, if
231      * the component is in a namespace, the
232      * name is prefixed with the namespace uri and ":".
233      * @return the class if found or null if not.
234      */

235     public Object JavaDoc createComponent(String JavaDoc componentName) {
236         AntTypeDefinition def = getDefinition(componentName);
237         return (def == null) ? null : def.create(project);
238     }
239
240     /**
241      * Return the class of the component name.
242      *
243      * @param componentName the name of the component, if
244      * the component is in a namespace, the
245      * name is prefixed with the namespace uri and ":".
246      * @return the class if found or null if not.
247      */

248     public Class JavaDoc getComponentClass(String JavaDoc componentName) {
249         AntTypeDefinition def = getDefinition(componentName);
250         return (def == null) ? null : def.getExposedClass(project);
251     }
252
253     /**
254      * Return the antTypeDefinition for a componentName.
255      * @param componentName the name of the component.
256      * @return the ant definition or null if not present.
257      */

258     public AntTypeDefinition getDefinition(String JavaDoc componentName) {
259         checkNamespace(componentName);
260         return antTypeTable.getDefinition(componentName);
261     }
262
263     /**
264      * This method is initialization code implementing the original ant component
265      * loading from /org/apache/tools/ant/taskdefs/default.properties
266      * and /org/apache/tools/ant/types/default.properties.
267      */

268     public void initDefaultDefinitions() {
269         initTasks();
270         initTypes();
271     }
272
273     /**
274      * Adds a new task definition to the project.
275      * Attempting to override an existing definition with an
276      * equivalent one (i.e. with the same classname) results in
277      * a verbose log message. Attempting to override an existing definition
278      * with a different one results in a warning log message.
279      *
280      * @param taskName The name of the task to add.
281      * Must not be <code>null</code>.
282      * @param taskClass The full name of the class implementing the task.
283      * Must not be <code>null</code>.
284      *
285      * @exception BuildException if the class is unsuitable for being an Ant
286      * task. An error level message is logged before
287      * this exception is thrown.
288      *
289      * @see #checkTaskClass(Class)
290      */

291     public void addTaskDefinition(String JavaDoc taskName, Class JavaDoc 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     /**
304      * Checks whether or not a class is suitable for serving as Ant task.
305      * Ant task implementation classes must be public, concrete, and have
306      * a no-arg constructor.
307      *
308      * @param taskClass The class to be checked.
309      * Must not be <code>null</code>.
310      *
311      * @exception BuildException if the class is unsuitable for being an Ant
312      * task. An error level message is logged before
313      * this exception is thrown.
314      */

315     public void checkTaskClass(final Class JavaDoc taskClass) throws BuildException {
316         if (!Modifier.isPublic(taskClass.getModifiers())) {
317             final String JavaDoc 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 JavaDoc message = taskClass + " is abstract";
323             project.log(message, Project.MSG_ERR);
324             throw new BuildException(message);
325         }
326         try {
327             taskClass.getConstructor((Class JavaDoc[]) null);
328             // don't have to check for public, since
329
// getConstructor finds public constructors only.
330
} catch (NoSuchMethodException JavaDoc e) {
331             final String JavaDoc 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     /**
342      * Returns the current task definition hashtable. The returned hashtable is
343      * "live" and so should not be modified.
344      *
345      * @return a map of from task name to implementing class
346      * (String to Class).
347      */

348     public Hashtable JavaDoc getTaskDefinitions() {
349         synchronized (taskClassDefinitions) {
350             synchronized (antTypeTable) {
351                 if (rebuildTaskClassDefinitions) {
352                     taskClassDefinitions.clear();
353                     for (Iterator JavaDoc i = antTypeTable.keySet().iterator();
354                          i.hasNext();) {
355                         String JavaDoc name = (String JavaDoc) i.next();
356                         Class JavaDoc 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     /**
374      * Returns the current type definition hashtable. The returned hashtable is
375      * "live" and so should not be modified.
376      *
377      * @return a map of from type name to implementing class
378      * (String to Class).
379      */

380     public Hashtable JavaDoc getDataTypeDefinitions() {
381         synchronized (typeClassDefinitions) {
382             synchronized (antTypeTable) {
383                 if (rebuildTypeClassDefinitions) {
384                     typeClassDefinitions.clear();
385                     for (Iterator JavaDoc i = antTypeTable.keySet().iterator();
386                          i.hasNext();) {
387                         String JavaDoc name = (String JavaDoc) i.next();
388                         Class JavaDoc 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     /**
405      * Adds a new datatype definition.
406      * Attempting to override an existing definition with an
407      * equivalent one (i.e. with the same classname) results in
408      * a verbose log message. Attempting to override an existing definition
409      * with a different one results in a warning log message, but the
410      * definition is changed.
411      *
412      * @param typeName The name of the datatype.
413      * Must not be <code>null</code>.
414      * @param typeClass The full name of the class implementing the datatype.
415      * Must not be <code>null</code>.
416      */

417     public void addDataTypeDefinition(String JavaDoc typeName, Class JavaDoc 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     /**
427      * Describe <code>addDataTypeDefinition</code> method here.
428      *
429      * @param def an <code>AntTypeDefinition</code> value.
430      */

431     public void addDataTypeDefinition(AntTypeDefinition def) {
432         updateDataTypeDefinition(def);
433     }
434
435     /**
436      * Returns the current datatype definition hashtable. The returned
437      * hashtable is "live" and so should not be modified.
438      *
439      * @return a map of from datatype name to implementing class
440      * (String to Class).
441      */

442     public Hashtable JavaDoc getAntTypeTable() {
443         return antTypeTable;
444     }
445
446     /**
447      * Creates a new instance of a task.
448      *
449      * Called from Project.createTask(), which can be called by tasks.
450      *
451      * @param taskType The name of the task to create an instance of.
452      * Must not be <code>null</code>.
453      *
454      * @return an instance of the specified task, or <code>null</code> if
455      * the task name is not recognised.
456      *
457      * @exception BuildException if the task name is recognised but task
458      * creation fails.
459      */

460     public Task createTask(String JavaDoc taskType) throws BuildException {
461         Task task = createNewTask(taskType);
462         if (task == null && taskType.equals(ANT_PROPERTY_TASK)) {
463             // quick fix for Ant.java use of property before
464
// initializing the project
465
addTaskDefinition(ANT_PROPERTY_TASK,
466                               org.apache.tools.ant.taskdefs.Property.class);
467             task = createNewTask(taskType);
468         }
469         return task;
470     }
471
472     /**
473      * Creates a new instance of a task.
474      * @since ant1.6
475      * @param taskType The name of the task to create an instance of.
476      * Must not be <code>null</code>.
477      *
478      * @return an instance of the specified task, or <code>null</code> if
479      * the task name is not recognised.
480      *
481      * @exception BuildException if the task name is recognised but task
482      * creation fails.
483      */

484     private Task createNewTask(String JavaDoc taskType) throws BuildException {
485         Class JavaDoc c = getComponentClass(taskType);
486         if (c == null || !(Task.class.isAssignableFrom(c))) {
487             return null;
488         }
489         Object JavaDoc 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         // set default value, can be changed by the user
503
task.setTaskName(taskType);
504
505         project.log(" +Task: " + taskType, Project.MSG_DEBUG);
506         return task;
507     }
508
509     /**
510      * Creates a new instance of a data type.
511      *
512      * @param typeName The name of the data type to create an instance of.
513      * Must not be <code>null</code>.
514      *
515      * @return an instance of the specified data type, or <code>null</code> if
516      * the data type name is not recognised.
517      *
518      * @exception BuildException if the data type name is recognised but
519      * instance creation fails.
520      */

521     public Object JavaDoc createDataType(String JavaDoc typeName) throws BuildException {
522         return createComponent(typeName);
523     }
524
525     /**
526      * Returns a description of the type of the given element.
527      * <p>
528      * This is useful for logging purposes.
529      *
530      * @param element The element to describe.
531      * Must not be <code>null</code>.
532      *
533      * @return a description of the element type.
534      *
535      * @since Ant 1.6
536      */

537     public String JavaDoc getElementName(Object JavaDoc element) {
538         return getElementName(element, false);
539     }
540
541     /**
542      * Returns a description of the type of the given element.
543      * <p>
544      * This is useful for logging purposes.
545      *
546      * @param o The element to describe.
547      * Must not be <code>null</code>.
548      * @param brief whether to use a brief description.
549      * @return a description of the element type.
550      *
551      * @since Ant 1.7
552      */

553     public String JavaDoc getElementName(Object JavaDoc o, boolean brief) {
554         // PR: I do not know what to do if the object class
555
// has multiple defines
556
// but this is for logging only...
557
Class JavaDoc elementClass = o.getClass();
558         String JavaDoc elementClassname = elementClass.getName();
559         for (Iterator JavaDoc 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 JavaDoc name = def.getName();
564                 return brief ? name : "The <" + name + "> type";
565             }
566         }
567         return getUnmappedElementName(o.getClass(), brief);
568     }
569
570     /**
571      * Convenient way to get some element name even when you may not have a
572      * Project context.
573      * @param p The optional Project instance.
574      * @param o The element to describe.
575      * Must not be <code>null</code>.
576      * @param brief whether to use a brief description.
577      * @return a description of the element type.
578      * @since Ant 1.7
579      */

580     public static String JavaDoc getElementName(Project p, Object JavaDoc 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 JavaDoc getUnmappedElementName(Class JavaDoc c, boolean brief) {
589         if (brief) {
590             String JavaDoc name = c.getName();
591             return name.substring(name.lastIndexOf('.') + 1);
592         }
593         return c.toString();
594     }
595
596     private static Project getProject(Object JavaDoc o) {
597         if (o instanceof ProjectComponent) {
598             return ((ProjectComponent) o).getProject();
599         }
600         try {
601             Method JavaDoc m = o.getClass().getMethod("getProject", (Class JavaDoc[]) null);
602             if (Project.class == m.getReturnType()) {
603                 return (Project) m.invoke(o, (Object JavaDoc[]) null);
604             }
605         } catch (Exception JavaDoc e) {
606             //too bad
607
}
608         return null;
609     }
610
611     /**
612      * Check if definition is a valid definition--it may be a
613      * definition of an optional task that does not exist.
614      * @param def the definition to test.
615      * @return true if exposed type of definition is present.
616      */

617     private boolean validDefinition(AntTypeDefinition def) {
618         return !(def.getTypeClass(project) == null
619             || def.getExposedClass(project) == null);
620     }
621
622     /**
623      * Check if two definitions are the same.
624      * @param def the new definition.
625      * @param old the old definition.
626      * @return true if the two definitions are the same.
627      */

628     private boolean sameDefinition(
629         AntTypeDefinition def, AntTypeDefinition old) {
630         boolean defValid = validDefinition(def);
631         boolean sameValidity = (defValid == validDefinition(old));
632         //must have same validity; then if they are valid they must also be the same:
633
return sameValidity && (!defValid || def.sameDefinition(old, project));
634     }
635
636     /**
637      * Update the component definition table with a new or
638      * modified definition.
639      * @param def the definition to update or insert.
640      */

641     private void updateDataTypeDefinition(AntTypeDefinition def) {
642         String JavaDoc 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 JavaDoc 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     /**
666      * Called at the start of processing an antlib.
667      * @param uri the uri that is associated with this antlib.
668      */

669     public void enterAntLib(String JavaDoc uri) {
670         antLibCurrentUri = uri;
671         antLibStack.push(uri);
672     }
673
674     /**
675      * @return the current antlib uri.
676      */

677     public String JavaDoc getCurrentAntlibUri() {
678         return antLibCurrentUri;
679     }
680
681     /**
682      * Called at the end of processing an antlib.
683      */

684     public void exitAntLib() {
685         antLibStack.pop();
686         antLibCurrentUri = (antLibStack.size() == 0)
687             ? null : (String JavaDoc) antLibStack.peek();
688     }
689
690     /**
691      * Load ant's tasks.
692      */

693     private void initTasks() {
694         ClassLoader JavaDoc classLoader = getClassLoader(null);
695         Properties JavaDoc props = getDefaultDefinitions(false);
696         Enumeration JavaDoc e = props.propertyNames();
697         while (e.hasMoreElements()) {
698             String JavaDoc name = (String JavaDoc) e.nextElement();
699             String JavaDoc 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 JavaDoc getClassLoader(ClassLoader JavaDoc classLoader) {
711         String JavaDoc 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     /**
720      * Load default task or type definitions - just the names,
721      * no class loading.
722      * Caches results between calls to reduce overhead.
723      * @param type true for typedefs, false for taskdefs
724      * @return a mapping from definition names to class names
725      * @throws BuildException if there was some problem loading
726      * or parsing the definitions list
727      */

728     private static synchronized Properties JavaDoc getDefaultDefinitions(boolean type)
729         throws BuildException {
730         int idx = type ? 1 : 0;
731         if (defaultDefinitions[idx] == null) {
732             String JavaDoc resource = type
733                 ? MagicNames.TYPEDEFS_PROPERTIES_RESOURCE
734                 : MagicNames.TASKDEF_PROPERTIES_RESOURCE;
735             String JavaDoc errorString = type
736                 ? ERROR_NO_TYPE_LIST_LOAD
737                 : ERROR_NO_TASK_LIST_LOAD;
738             InputStream JavaDoc in = null;
739             try {
740                 in = ComponentHelper.class.getResourceAsStream(
741                     resource);
742                 if (in == null) {
743                     throw new BuildException(errorString);
744                 }
745                 Properties JavaDoc p = new Properties JavaDoc();
746                 p.load(in);
747                 defaultDefinitions[idx] = p;
748             } catch (IOException JavaDoc e) {
749                 throw new BuildException(errorString, e);
750             } finally {
751                 FileUtils.close(in);
752             }
753         }
754         return defaultDefinitions[idx];
755     }
756
757     /**
758      * Load ant's datatypes.
759      */

760     private void initTypes() {
761         ClassLoader JavaDoc classLoader = getClassLoader(null);
762         Properties JavaDoc props = getDefaultDefinitions(true);
763         Enumeration JavaDoc e = props.propertyNames();
764         while (e.hasMoreElements()) {
765             String JavaDoc name = (String JavaDoc) e.nextElement();
766             String JavaDoc 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     /**
776      * Called for each component name, check if the
777      * associated URI has been examined for antlibs.
778      */

779     private synchronized void checkNamespace(String JavaDoc componentName) {
780         String JavaDoc uri = ProjectHelper.extractUriFromComponentName(componentName);
781         if ("".equals(uri)) {
782             uri = ProjectHelper.ANT_CORE_URI;
783         }
784         if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) {
785             return; // namespace that does not contain antlib
786
}
787         if (checkedNamespaces.contains(uri)) {
788             return; // Already processed
789
}
790         checkedNamespaces.add(uri);
791         Typedef definer = new Typedef();
792         definer.setProject(project);
793         definer.init();
794         definer.setURI(uri);
795         //there to stop error messages being "null"
796
definer.setTaskName(uri);
797         //if this is left out, bad things happen. like all build files break
798
//on the first element encountered.
799
definer.setResource(Definer.makeResourceFromURI(uri));
800         // a fishing expedition :- ignore errors if antlib not present
801
definer.setOnError(new Typedef.OnError(Typedef.OnError.POLICY_IGNORE));
802         definer.execute();
803     }
804
805     /**
806      * Handler called to do decent diagnosis on instantiation failure.
807      * @param componentName component name.
808      * @param type component type, used in error messages
809      * @return a string containing as much diagnostics info as possible.
810      */

811     public String JavaDoc diagnoseCreationFailure(String JavaDoc componentName, String JavaDoc type) {
812         StringWriter JavaDoc errorText = new StringWriter JavaDoc();
813         PrintWriter JavaDoc out = new PrintWriter JavaDoc(errorText);
814         out.println("Problem: failed to create " + type + " " + componentName);
815         //class of problem
816
boolean lowlevel = false;
817         boolean jars = false;
818         boolean definitions = false;
819         boolean antTask;
820         String JavaDoc home = System.getProperty(Launcher.USER_HOMEDIR);
821         File JavaDoc libDir = new File JavaDoc(home, Launcher.USER_LIBDIR);
822         String JavaDoc antHomeLib;
823         boolean probablyIDE = false;
824         String JavaDoc anthome = System.getProperty(MagicNames.ANT_HOME);
825         if (anthome != null) {
826             File JavaDoc antHomeLibDir = new File JavaDoc(anthome, "lib");
827             antHomeLib = antHomeLibDir.getAbsolutePath();
828         } else {
829             //running under an IDE that doesn't set ANT_HOME
830
probablyIDE = true;
831             antHomeLib = "ANT_HOME" + File.separatorChar + "lib";
832         }
833         StringBuffer JavaDoc dirListingText = new StringBuffer JavaDoc();
834         final String JavaDoc 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 JavaDoc dirListing = dirListingText.toString();
851
852         //look up the name
853
AntTypeDefinition def = getDefinition(componentName);
854         if (def == null) {
855             //not a known type
856
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             //we are defined, so it is an instantiation problem
871
final String JavaDoc 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             //start with instantiating the class.
877
Class JavaDoc clazz = null;
878             try {
879                 clazz = def.innerGetTypeClass();
880             } catch (ClassNotFoundException JavaDoc 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 JavaDoc 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             //here we successfully loaded the class or failed.
912
if (clazz != null) {
913                 //success: proceed with more steps
914
try {
915                     def.innerCreateAndSet(clazz, project);
916                     //hey, there is nothing wrong with us
917
out.println("The component could be instantiated.");
918                 } catch (NoSuchMethodException JavaDoc e) {
919                     lowlevel = true;
920                     out.println("Cause: The class " + classname
921                             + " has no compatible constructor.");
922
923                 } catch (InstantiationException JavaDoc e) {
924                     lowlevel = true;
925                     out.println("Cause: The class " + classname
926                             + " is abstract and cannot be instantiated.");
927                 } catch (IllegalAccessException JavaDoc e) {
928                     lowlevel = true;
929                     out.println("Cause: The constructor for " + classname
930                             + " is private and cannot be invoked.");
931                 } catch (InvocationTargetException JavaDoc ex) {
932                     lowlevel = true;
933                     Throwable JavaDoc t = ex.getTargetException();
934                     out.println("Cause: The constructor threw the exception");
935                     out.println(t.toString());
936                     t.printStackTrace(out);
937                 } catch (NoClassDefFoundError JavaDoc 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     /**
979      * Map that contains the component definitions.
980      */

981     private static class AntTypeTable extends Hashtable JavaDoc {
982         private Project project;
983
984         AntTypeTable(Project project) {
985             this.project = project;
986         }
987
988         AntTypeDefinition getDefinition(String JavaDoc key) {
989             return (AntTypeDefinition) (super.get(key));
990         }
991
992         public Object JavaDoc get(Object JavaDoc key) {
993             return getTypeClass((String JavaDoc) key);
994         }
995
996         Object JavaDoc create(String JavaDoc name) {
997             AntTypeDefinition def = getDefinition(name);
998             return (def == null) ? null : def.create(project);
999         }
1000
1001        Class JavaDoc getTypeClass(String JavaDoc name) {
1002            AntTypeDefinition def = getDefinition(name);
1003            return (def == null) ? null : def.getTypeClass(project);
1004        }
1005
1006        Class JavaDoc getExposedClass(String JavaDoc name) {
1007            AntTypeDefinition def = getDefinition(name);
1008            return (def == null) ? null : def.getExposedClass(project);
1009        }
1010
1011        public boolean contains(Object JavaDoc clazz) {
1012            boolean found = false;
1013            if (clazz instanceof Class JavaDoc) {
1014                for (Iterator JavaDoc 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 JavaDoc value) {
1023            return contains(value);
1024        }
1025    }
1026
1027}
1028
Popular Tags