KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.BufferedReader JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.InputStreamReader JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Vector JavaDoc;
28 import org.apache.tools.ant.helper.ProjectHelper2;
29 import org.apache.tools.ant.util.LoaderUtils;
30 import org.xml.sax.AttributeList JavaDoc;
31
32 /**
33  * Configures a Project (complete with Targets and Tasks) based on
34  * a XML build file. It'll rely on a plugin to do the actual processing
35  * of the xml file.
36  *
37  * This class also provide static wrappers for common introspection.
38  *
39  * All helper plugins must provide backward compatibility with the
40  * original ant patterns, unless a different behavior is explicitly
41  * specified. For example, if namespace is used on the <project> tag
42  * the helper can expect the entire build file to be namespace-enabled.
43  * Namespaces or helper-specific tags can provide meta-information to
44  * the helper, allowing it to use new ( or different policies ).
45  *
46  * However, if no namespace is used the behavior should be exactly
47  * identical with the default helper.
48  *
49  */

50 public class ProjectHelper {
51     /** The URI for ant name space */
52     public static final String JavaDoc ANT_CORE_URI = "antlib:org.apache.tools.ant";
53
54     /** The URI for antlib current definitions */
55     public static final String JavaDoc ANT_CURRENT_URI = "ant:current";
56
57     /** The URI for defined types/tasks - the format is antlib:<package> */
58     public static final String JavaDoc ANTLIB_URI = "antlib:";
59
60     /** Polymorphic attribute */
61     public static final String JavaDoc ANT_TYPE = "ant-type";
62
63     /**
64      * Name of JVM system property which provides the name of the
65      * ProjectHelper class to use.
66      */

67     public static final String JavaDoc HELPER_PROPERTY =
68         "org.apache.tools.ant.ProjectHelper";
69
70     /**
71      * The service identifier in jars which provide Project Helper
72      * implementations.
73      */

74     public static final String JavaDoc SERVICE_ID =
75         "META-INF/services/org.apache.tools.ant.ProjectHelper";
76
77     /**
78      * name of project helper reference that we add to a project
79      */

80     public static final String JavaDoc PROJECTHELPER_REFERENCE = "ant.projectHelper";
81
82     /**
83      * Configures the project with the contents of the specified XML file.
84      *
85      * @param project The project to configure. Must not be <code>null</code>.
86      * @param buildFile An XML file giving the project's configuration.
87      * Must not be <code>null</code>.
88      *
89      * @exception BuildException if the configuration is invalid or cannot
90      * be read
91      */

92     public static void configureProject(Project project, File JavaDoc buildFile)
93         throws BuildException {
94         ProjectHelper helper = ProjectHelper.getProjectHelper();
95         project.addReference(PROJECTHELPER_REFERENCE, helper);
96         helper.parse(project, buildFile);
97     }
98
99     /** Default constructor */
100     public ProjectHelper() {
101     }
102
103     // -------------------- Common properties --------------------
104
// The following properties are required by import ( and other tasks
105
// that read build files using ProjectHelper ).
106

107     // A project helper may process multiple files. We'll keep track
108
// of them - to avoid loops and to allow caching. The caching will
109
// probably accelerate things like <antCall>.
110
// The key is the absolute file, the value is a processed tree.
111
// Since the tree is composed of UE and RC - it can be reused !
112
// protected Hashtable processedFiles=new Hashtable();
113

114     private Vector JavaDoc importStack = new Vector JavaDoc();
115
116     // Temporary - until we figure a better API
117
/** EXPERIMENTAL WILL_CHANGE
118      *
119      */

120 // public Hashtable getProcessedFiles() {
121
// return processedFiles;
122
// }
123

124     /** EXPERIMENTAL WILL_CHANGE
125      * Import stack.
126      * Used to keep track of imported files. Error reporting should
127      * display the import path.
128      *
129      * @return the stack of import source objects.
130      */

131     public Vector JavaDoc getImportStack() {
132         return importStack;
133     }
134
135
136     // -------------------- Parse method --------------------
137
/**
138      * Parses the project file, configuring the project as it goes.
139      *
140      * @param project The project for the resulting ProjectHelper to configure.
141      * Must not be <code>null</code>.
142      * @param source The source for XML configuration. A helper must support
143      * at least File, for backward compatibility. Helpers may
144      * support URL, InputStream, etc or specialized types.
145      *
146      * @since Ant1.5
147      * @exception BuildException if the configuration is invalid or cannot
148      * be read
149      */

150     public void parse(Project project, Object JavaDoc source) throws BuildException {
151         throw new BuildException("ProjectHelper.parse() must be implemented "
152             + "in a helper plugin " + this.getClass().getName());
153     }
154
155
156     /**
157      * Discovers a project helper instance. Uses the same patterns
158      * as JAXP, commons-logging, etc: a system property, a JDK1.3
159      * service discovery, default.
160      *
161      * @return a ProjectHelper, either a custom implementation
162      * if one is available and configured, or the default implementation
163      * otherwise.
164      *
165      * @exception BuildException if a specified helper class cannot
166      * be loaded/instantiated.
167      */

168     public static ProjectHelper getProjectHelper()
169         throws BuildException {
170         // Identify the class loader we will be using. Ant may be
171
// in a webapp or embedded in a different app
172
ProjectHelper helper = null;
173
174         // First, try the system property
175
String JavaDoc helperClass = System.getProperty(HELPER_PROPERTY);
176         try {
177             if (helperClass != null) {
178                 helper = newHelper(helperClass);
179             }
180         } catch (SecurityException JavaDoc e) {
181             System.out.println("Unable to load ProjectHelper class \""
182                 + helperClass + " specified in system property "
183                 + HELPER_PROPERTY);
184         }
185
186         // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
187
// automatically if in CLASSPATH, with the right META-INF/services.
188
if (helper == null) {
189             try {
190                 ClassLoader JavaDoc classLoader = LoaderUtils.getContextClassLoader();
191                 InputStream JavaDoc is = null;
192                 if (classLoader != null) {
193                     is = classLoader.getResourceAsStream(SERVICE_ID);
194                 }
195                 if (is == null) {
196                     is = ClassLoader.getSystemResourceAsStream(SERVICE_ID);
197                 }
198
199                 if (is != null) {
200                     // This code is needed by EBCDIC and other strange systems.
201
// It's a fix for bugs reported in xerces
202
InputStreamReader JavaDoc isr;
203                     try {
204                         isr = new InputStreamReader JavaDoc(is, "UTF-8");
205                     } catch (java.io.UnsupportedEncodingException JavaDoc e) {
206                         isr = new InputStreamReader JavaDoc(is);
207                     }
208                     BufferedReader JavaDoc rd = new BufferedReader JavaDoc(isr);
209
210                     String JavaDoc helperClassName = rd.readLine();
211                     rd.close();
212
213                     if (helperClassName != null
214                         && !"".equals(helperClassName)) {
215
216                         helper = newHelper(helperClassName);
217                     }
218                 }
219             } catch (Exception JavaDoc ex) {
220                 System.out.println("Unable to load ProjectHelper "
221                     + "from service \"" + SERVICE_ID);
222             }
223         }
224
225         if (helper != null) {
226             return helper;
227         } else {
228             return new ProjectHelper2();
229         }
230     }
231
232     /**
233      * Creates a new helper instance from the name of the class.
234      * It'll first try the thread class loader, then Class.forName()
235      * will load from the same loader that loaded this class.
236      *
237      * @param helperClass The name of the class to create an instance
238      * of. Must not be <code>null</code>.
239      *
240      * @return a new instance of the specified class.
241      *
242      * @exception BuildException if the class cannot be found or
243      * cannot be appropriate instantiated.
244      */

245     private static ProjectHelper newHelper(String JavaDoc helperClass)
246         throws BuildException {
247         ClassLoader JavaDoc classLoader = LoaderUtils.getContextClassLoader();
248         try {
249             Class JavaDoc clazz = null;
250             if (classLoader != null) {
251                 try {
252                     clazz = classLoader.loadClass(helperClass);
253                 } catch (ClassNotFoundException JavaDoc ex) {
254                     // try next method
255
}
256             }
257             if (clazz == null) {
258                 clazz = Class.forName(helperClass);
259             }
260             return ((ProjectHelper) clazz.newInstance());
261         } catch (Exception JavaDoc e) {
262             throw new BuildException(e);
263         }
264     }
265
266     /**
267      * JDK1.1 compatible access to the context class loader.
268      * Cut&paste from JAXP.
269      *
270      * @deprecated since 1.6.x.
271      * Use LoaderUtils.getContextClassLoader()
272      *
273      * @return the current context class loader, or <code>null</code>
274      * if the context class loader is unavailable.
275      */

276     public static ClassLoader JavaDoc getContextClassLoader() {
277         if (!LoaderUtils.isContextLoaderAvailable()) {
278             return null;
279         }
280
281         return LoaderUtils.getContextClassLoader();
282     }
283
284     // -------------------- Static utils, used by most helpers ----------------
285

286     /**
287      * Configures an object using an introspection handler.
288      *
289      * @param target The target object to be configured.
290      * Must not be <code>null</code>.
291      * @param attrs A list of attributes to configure within the target.
292      * Must not be <code>null</code>.
293      * @param project The project containing the target.
294      * Must not be <code>null</code>.
295      *
296      * @deprecated since 1.6.x.
297      * Use IntrospectionHelper for each property.
298      *
299      * @exception BuildException if any of the attributes can't be handled by
300      * the target
301      */

302     public static void configure(Object JavaDoc target, AttributeList JavaDoc attrs,
303                                  Project project) throws BuildException {
304         if (target instanceof TypeAdapter) {
305             target = ((TypeAdapter) target).getProxy();
306         }
307
308         IntrospectionHelper ih =
309             IntrospectionHelper.getHelper(project, target.getClass());
310
311         for (int i = 0; i < attrs.getLength(); i++) {
312             // reflect these into the target
313
String JavaDoc value = replaceProperties(project, attrs.getValue(i),
314                                              project.getProperties());
315             try {
316                 ih.setAttribute(project, target,
317                                 attrs.getName(i).toLowerCase(Locale.US), value);
318
319             } catch (BuildException be) {
320                 // id attribute must be set externally
321
if (!attrs.getName(i).equals("id")) {
322                     throw be;
323                 }
324             }
325         }
326     }
327
328     /**
329      * Adds the content of #PCDATA sections to an element.
330      *
331      * @param project The project containing the target.
332      * Must not be <code>null</code>.
333      * @param target The target object to be configured.
334      * Must not be <code>null</code>.
335      * @param buf A character array of the text within the element.
336      * Will not be <code>null</code>.
337      * @param start The start element in the array.
338      * @param count The number of characters to read from the array.
339      *
340      * @exception BuildException if the target object doesn't accept text
341      */

342     public static void addText(Project project, Object JavaDoc target, char[] buf,
343         int start, int count) throws BuildException {
344         addText(project, target, new String JavaDoc(buf, start, count));
345     }
346
347     /**
348      * Adds the content of #PCDATA sections to an element.
349      *
350      * @param project The project containing the target.
351      * Must not be <code>null</code>.
352      * @param target The target object to be configured.
353      * Must not be <code>null</code>.
354      * @param text Text to add to the target.
355      * May be <code>null</code>, in which case this
356      * method call is a no-op.
357      *
358      * @exception BuildException if the target object doesn't accept text
359      */

360     public static void addText(Project project, Object JavaDoc target, String JavaDoc text)
361         throws BuildException {
362
363         if (text == null) {
364             return;
365         }
366
367         if (target instanceof TypeAdapter) {
368             target = ((TypeAdapter) target).getProxy();
369         }
370
371         IntrospectionHelper.getHelper(project, target.getClass()).addText(project,
372             target, text);
373     }
374
375     /**
376      * Stores a configured child element within its parent object.
377      *
378      * @param project Project containing the objects.
379      * May be <code>null</code>.
380      * @param parent Parent object to add child to.
381      * Must not be <code>null</code>.
382      * @param child Child object to store in parent.
383      * Should not be <code>null</code>.
384      * @param tag Name of element which generated the child.
385      * May be <code>null</code>, in which case
386      * the child is not stored.
387      */

388     public static void storeChild(Project project, Object JavaDoc parent,
389          Object JavaDoc child, String JavaDoc tag) {
390         IntrospectionHelper ih
391             = IntrospectionHelper.getHelper(project, parent.getClass());
392         ih.storeElement(project, parent, child, tag);
393     }
394
395     /**
396      * Replaces <code>${xxx}</code> style constructions in the given value with
397      * the string value of the corresponding properties.
398      *
399      * @param project The project containing the properties to replace.
400      * Must not be <code>null</code>.
401      *
402      * @param value The string to be scanned for property references.
403      * May be <code>null</code>.
404      *
405      * @exception BuildException if the string contains an opening
406      * <code>${</code> without a closing
407      * <code>}</code>
408      * @return the original string with the properties replaced, or
409      * <code>null</code> if the original string is <code>null</code>.
410      *
411      * @deprecated since 1.6.x.
412      * Use project.replaceProperties().
413      * @since 1.5
414      */

415      public static String JavaDoc replaceProperties(Project project, String JavaDoc value)
416             throws BuildException {
417         // needed since project properties are not accessible
418
return project.replaceProperties(value);
419      }
420
421     /**
422      * Replaces <code>${xxx}</code> style constructions in the given value
423      * with the string value of the corresponding data types.
424      *
425      * @param project The container project. This is used solely for
426      * logging purposes. Must not be <code>null</code>.
427      * @param value The string to be scanned for property references.
428      * May be <code>null</code>, in which case this
429      * method returns immediately with no effect.
430      * @param keys Mapping (String to String) of property names to their
431      * values. Must not be <code>null</code>.
432      *
433      * @exception BuildException if the string contains an opening
434      * <code>${</code> without a closing
435      * <code>}</code>
436      * @return the original string with the properties replaced, or
437      * <code>null</code> if the original string is <code>null</code>.
438      * @deprecated since 1.6.x.
439      * Use PropertyHelper.
440      */

441      public static String JavaDoc replaceProperties(Project project, String JavaDoc value,
442          Hashtable JavaDoc keys) throws BuildException {
443         PropertyHelper ph = PropertyHelper.getPropertyHelper(project);
444         return ph.replaceProperties(null, value, keys);
445     }
446
447     /**
448      * Parses a string containing <code>${xxx}</code> style property
449      * references into two lists. The first list is a collection
450      * of text fragments, while the other is a set of string property names.
451      * <code>null</code> entries in the first list indicate a property
452      * reference from the second list.
453      *
454      * @param value Text to parse. Must not be <code>null</code>.
455      * @param fragments List to add text fragments to.
456      * Must not be <code>null</code>.
457      * @param propertyRefs List to add property names to.
458      * Must not be <code>null</code>.
459      *
460      * @deprecated since 1.6.x.
461      * Use PropertyHelper.
462      * @exception BuildException if the string contains an opening
463      * <code>${</code> without a closing
464      * <code>}</code>
465      */

466     public static void parsePropertyString(String JavaDoc value, Vector JavaDoc fragments,
467                                            Vector JavaDoc propertyRefs)
468         throws BuildException {
469         PropertyHelper.parsePropertyStringDefault(value, fragments,
470                 propertyRefs);
471     }
472     /**
473      * Map a namespaced {uri,name} to an internal string format.
474      * For BC purposes the names from the ant core uri will be
475      * mapped to "name", other names will be mapped to
476      * uri + ":" + name.
477      * @param uri The namepace URI
478      * @param name The localname
479      * @return The stringified form of the ns name
480      */

481     public static String JavaDoc genComponentName(String JavaDoc uri, String JavaDoc name) {
482         if (uri == null || uri.equals("") || uri.equals(ANT_CORE_URI)) {
483             return name;
484         }
485         return uri + ":" + name;
486     }
487
488     /**
489      * extract a uri from a component name
490      *
491      * @param componentName The stringified form for {uri, name}
492      * @return The uri or "" if not present
493      */

494     public static String JavaDoc extractUriFromComponentName(String JavaDoc componentName) {
495         if (componentName == null) {
496             return "";
497         }
498         int index = componentName.lastIndexOf(':');
499         if (index == -1) {
500             return "";
501         }
502         return componentName.substring(0, index);
503     }
504
505     /**
506      * extract the element name from a component name
507      *
508      * @param componentName The stringified form for {uri, name}
509      * @return The element name of the component
510      */

511     public static String JavaDoc extractNameFromComponentName(String JavaDoc componentName) {
512         int index = componentName.lastIndexOf(':');
513         if (index == -1) {
514             return componentName;
515         }
516         return componentName.substring(index + 1);
517     }
518
519     /**
520      * Add location to build exception.
521      * @param ex the build exception, if the build exception
522      * does not include
523      * @param newLocation the location of the calling task (may be null)
524      * @return a new build exception based in the build exception with
525      * location set to newLocation. If the original exception
526      * did not have a location, just return the build exception
527      */

528     public static BuildException addLocationToBuildException(
529         BuildException ex, Location newLocation) {
530         if (ex.getLocation() == null || ex.getMessage() == null) {
531             return ex;
532         }
533         String JavaDoc errorMessage
534             = "The following error occurred while executing this line:"
535             + System.getProperty("line.separator")
536             + ex.getLocation().toString()
537             + ex.getMessage();
538         if (newLocation == null) {
539             return new BuildException(errorMessage, ex);
540         } else {
541             return new BuildException(
542                 errorMessage, ex, newLocation);
543         }
544     }
545 }
546
Popular Tags