source: release-kits/lirk3/resources/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/ProjectHelper.java@ 14982

Last change on this file since 14982 was 14982, checked in by oranfry, 16 years ago

initial import of LiRK3

File size: 20.9 KB
Line 
1/*
2 * Copyright 2000-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant;
19
20import java.io.BufferedReader;
21import java.io.File;
22import java.io.InputStream;
23import java.io.InputStreamReader;
24import java.util.Hashtable;
25import java.util.Locale;
26import java.util.Vector;
27import org.apache.tools.ant.helper.ProjectHelper2;
28import org.apache.tools.ant.util.LoaderUtils;
29import org.xml.sax.AttributeList;
30
31/**
32 * Configures a Project (complete with Targets and Tasks) based on
33 * a XML build file. It'll rely on a plugin to do the actual processing
34 * of the xml file.
35 *
36 * This class also provide static wrappers for common introspection.
37 *
38 * All helper plugins must provide backward compatibility with the
39 * original ant patterns, unless a different behavior is explicitly
40 * specified. For example, if namespace is used on the <project> tag
41 * the helper can expect the entire build file to be namespace-enabled.
42 * Namespaces or helper-specific tags can provide meta-information to
43 * the helper, allowing it to use new ( or different policies ).
44 *
45 * However, if no namespace is used the behavior should be exactly
46 * identical with the default helper.
47 *
48 */
49public class ProjectHelper {
50 /** The URI for ant name space */
51 public static final String ANT_CORE_URI = "antlib:org.apache.tools.ant";
52
53 /** The URI for antlib current definitions */
54 public static final String ANT_CURRENT_URI = "ant:current";
55
56 /** The URI for defined types/tasks - the format is antlib:<package> */
57 public static final String ANTLIB_URI = "antlib:";
58
59 /** Polymorphic attribute */
60 public static final String ANT_TYPE = "ant-type";
61
62 /**
63 * Name of JVM system property which provides the name of the
64 * ProjectHelper class to use.
65 */
66 public static final String HELPER_PROPERTY =
67 "org.apache.tools.ant.ProjectHelper";
68
69 /**
70 * The service identifier in jars which provide Project Helper
71 * implementations.
72 */
73 public static final String SERVICE_ID =
74 "META-INF/services/org.apache.tools.ant.ProjectHelper";
75
76 /**
77 * Configures the project with the contents of the specified XML file.
78 *
79 * @param project The project to configure. Must not be <code>null</code>.
80 * @param buildFile An XML file giving the project's configuration.
81 * Must not be <code>null</code>.
82 *
83 * @deprecated Use the non-static parse method
84 * @exception BuildException if the configuration is invalid or cannot
85 * be read
86 */
87 public static void configureProject(Project project, File buildFile)
88 throws BuildException {
89 ProjectHelper helper = ProjectHelper.getProjectHelper();
90 project.addReference("ant.projectHelper", helper);
91 helper.parse(project, buildFile);
92 }
93
94 /** Default constructor */
95 public ProjectHelper() {
96 }
97
98 // -------------------- Common properties --------------------
99 // The following properties are required by import ( and other tasks
100 // that read build files using ProjectHelper ).
101
102 // A project helper may process multiple files. We'll keep track
103 // of them - to avoid loops and to allow caching. The caching will
104 // probably accelerate things like <antCall>.
105 // The key is the absolute file, the value is a processed tree.
106 // Since the tree is composed of UE and RC - it can be reused !
107 // protected Hashtable processedFiles=new Hashtable();
108
109 private Vector importStack = new Vector();
110
111 // Temporary - until we figure a better API
112 /** EXPERIMENTAL WILL_CHANGE
113 *
114 */
115// public Hashtable getProcessedFiles() {
116// return processedFiles;
117// }
118
119 /** EXPERIMENTAL WILL_CHANGE
120 * Import stack.
121 * Used to keep track of imported files. Error reporting should
122 * display the import path.
123 *
124 * @return the stack of import source objects.
125 */
126 public Vector getImportStack() {
127 return importStack;
128 }
129
130
131 // -------------------- Parse method --------------------
132 /**
133 * Parses the project file, configuring the project as it goes.
134 *
135 * @param project The project for the resulting ProjectHelper to configure.
136 * Must not be <code>null</code>.
137 * @param source The source for XML configuration. A helper must support
138 * at least File, for backward compatibility. Helpers may
139 * support URL, InputStream, etc or specialized types.
140 *
141 * @since Ant1.5
142 * @exception BuildException if the configuration is invalid or cannot
143 * be read
144 */
145 public void parse(Project project, Object source) throws BuildException {
146 throw new BuildException("ProjectHelper.parse() must be implemented "
147 + "in a helper plugin " + this.getClass().getName());
148 }
149
150
151 /**
152 * Discovers a project helper instance. Uses the same patterns
153 * as JAXP, commons-logging, etc: a system property, a JDK1.3
154 * service discovery, default.
155 *
156 * @return a ProjectHelper, either a custom implementation
157 * if one is available and configured, or the default implementation
158 * otherwise.
159 *
160 * @exception BuildException if a specified helper class cannot
161 * be loaded/instantiated.
162 */
163 public static ProjectHelper getProjectHelper()
164 throws BuildException {
165 // Identify the class loader we will be using. Ant may be
166 // in a webapp or embedded in a different app
167 ProjectHelper helper = null;
168
169 // First, try the system property
170 String helperClass = System.getProperty(HELPER_PROPERTY);
171 try {
172 if (helperClass != null) {
173 helper = newHelper(helperClass);
174 }
175 } catch (SecurityException e) {
176 System.out.println("Unable to load ProjectHelper class \""
177 + helperClass + " specified in system property "
178 + HELPER_PROPERTY);
179 }
180
181 // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
182 // automatically if in CLASSPATH, with the right META-INF/services.
183 if (helper == null) {
184 try {
185 ClassLoader classLoader = LoaderUtils.getContextClassLoader();
186 InputStream is = null;
187 if (classLoader != null) {
188 is = classLoader.getResourceAsStream(SERVICE_ID);
189 }
190 if (is == null) {
191 is = ClassLoader.getSystemResourceAsStream(SERVICE_ID);
192 }
193
194 if (is != null) {
195 // This code is needed by EBCDIC and other strange systems.
196 // It's a fix for bugs reported in xerces
197 InputStreamReader isr;
198 try {
199 isr = new InputStreamReader(is, "UTF-8");
200 } catch (java.io.UnsupportedEncodingException e) {
201 isr = new InputStreamReader(is);
202 }
203 BufferedReader rd = new BufferedReader(isr);
204
205 String helperClassName = rd.readLine();
206 rd.close();
207
208 if (helperClassName != null
209 && !"".equals(helperClassName)) {
210
211 helper = newHelper(helperClassName);
212 }
213 }
214 } catch (Exception ex) {
215 System.out.println("Unable to load ProjectHelper "
216 + "from service \"" + SERVICE_ID);
217 }
218 }
219
220 if (helper != null) {
221 return helper;
222 } else {
223 try {
224 // Default
225 // return new ProjectHelperImpl();
226 return new ProjectHelper2();
227 } catch (Throwable e) {
228 String message = "Unable to load default ProjectHelper due to "
229 + e.getClass().getName() + ": " + e.getMessage();
230 throw new BuildException(message, e);
231 }
232 }
233 }
234
235 /**
236 * Creates a new helper instance from the name of the class.
237 * It'll first try the thread class loader, then Class.forName()
238 * will load from the same loader that loaded this class.
239 *
240 * @param helperClass The name of the class to create an instance
241 * of. Must not be <code>null</code>.
242 *
243 * @return a new instance of the specified class.
244 *
245 * @exception BuildException if the class cannot be found or
246 * cannot be appropriate instantiated.
247 */
248 private static ProjectHelper newHelper(String helperClass)
249 throws BuildException {
250 ClassLoader classLoader = LoaderUtils.getContextClassLoader();
251 try {
252 Class clazz = null;
253 if (classLoader != null) {
254 try {
255 clazz = classLoader.loadClass(helperClass);
256 } catch (ClassNotFoundException ex) {
257 // try next method
258 }
259 }
260 if (clazz == null) {
261 clazz = Class.forName(helperClass);
262 }
263 return ((ProjectHelper) clazz.newInstance());
264 } catch (Exception e) {
265 throw new BuildException(e);
266 }
267 }
268
269 /**
270 * JDK1.1 compatible access to the context class loader.
271 * Cut&paste from JAXP.
272 *
273 * @deprecated Use LoaderUtils.getContextClassLoader()
274 * @return the current context class loader, or <code>null</code>
275 * if the context class loader is unavailable.
276 */
277 public static ClassLoader getContextClassLoader() {
278 if (!LoaderUtils.isContextLoaderAvailable()) {
279 return null;
280 }
281
282 return LoaderUtils.getContextClassLoader();
283 }
284
285 // -------------------- Static utils, used by most helpers ----------------
286
287 /**
288 * Configures an object using an introspection handler.
289 *
290 * @param target The target object to be configured.
291 * Must not be <code>null</code>.
292 * @param attrs A list of attributes to configure within the target.
293 * Must not be <code>null</code>.
294 * @param project The project containing the target.
295 * Must not be <code>null</code>.
296 *
297 * @deprecated Use IntrospectionHelper for each property
298 * @exception BuildException if any of the attributes can't be handled by
299 * the target
300 */
301 public static void configure(Object target, AttributeList attrs,
302 Project project) throws BuildException {
303 if (target instanceof TypeAdapter) {
304 target = ((TypeAdapter) target).getProxy();
305 }
306
307 IntrospectionHelper ih =
308 IntrospectionHelper.getHelper(target.getClass());
309
310 project.addBuildListener(ih);
311
312 for (int i = 0; i < attrs.getLength(); i++) {
313 // reflect these into the target
314 String value = replaceProperties(project, attrs.getValue(i),
315 project.getProperties());
316 try {
317 ih.setAttribute(project, target,
318 attrs.getName(i).toLowerCase(Locale.US), value);
319
320 } catch (BuildException be) {
321 // id attribute must be set externally
322 if (!attrs.getName(i).equals("id")) {
323 throw be;
324 }
325 }
326 }
327 }
328
329 /**
330 * Adds the content of #PCDATA sections to an element.
331 *
332 * @param project The project containing the target.
333 * Must not be <code>null</code>.
334 * @param target The target object to be configured.
335 * Must not be <code>null</code>.
336 * @param buf A character array of the text within the element.
337 * Will not be <code>null</code>.
338 * @param start The start element in the array.
339 * @param count The number of characters to read from the array.
340 *
341 * @exception BuildException if the target object doesn't accept text
342 */
343 public static void addText(Project project, Object target, char[] buf,
344 int start, int count) throws BuildException {
345 addText(project, target, new String(buf, start, count));
346 }
347
348 /**
349 * Adds the content of #PCDATA sections to an element.
350 *
351 * @param project The project containing the target.
352 * Must not be <code>null</code>.
353 * @param target The target object to be configured.
354 * Must not be <code>null</code>.
355 * @param text Text to add to the target.
356 * May be <code>null</code>, in which case this
357 * method call is a no-op.
358 *
359 * @exception BuildException if the target object doesn't accept text
360 */
361 public static void addText(Project project, Object target, String text)
362 throws BuildException {
363
364 if (text == null) {
365 return;
366 }
367
368 if (target instanceof TypeAdapter) {
369 target = ((TypeAdapter) target).getProxy();
370 }
371
372 IntrospectionHelper.getHelper(target.getClass()).addText(project,
373 target, text);
374 }
375
376 /**
377 * Stores a configured child element within its parent object.
378 *
379 * @param project Project containing the objects.
380 * May be <code>null</code>.
381 * @param parent Parent object to add child to.
382 * Must not be <code>null</code>.
383 * @param child Child object to store in parent.
384 * Should not be <code>null</code>.
385 * @param tag Name of element which generated the child.
386 * May be <code>null</code>, in which case
387 * the child is not stored.
388 */
389 public static void storeChild(Project project, Object parent,
390 Object child, String tag) {
391 IntrospectionHelper ih
392 = IntrospectionHelper.getHelper(parent.getClass());
393 ih.storeElement(project, parent, child, tag);
394 }
395
396 /**
397 * Replaces <code>${xxx}</code> style constructions in the given value with
398 * the string value of the corresponding properties.
399 *
400 * @param project The project containing the properties to replace.
401 * Must not be <code>null</code>.
402 *
403 * @param value The string to be scanned for property references.
404 * May be <code>null</code>.
405 *
406 * @exception BuildException if the string contains an opening
407 * <code>${</code> without a closing
408 * <code>}</code>
409 * @return the original string with the properties replaced, or
410 * <code>null</code> if the original string is <code>null</code>.
411 *
412 * @deprecated Use project.replaceProperties()
413 * @since 1.5
414 */
415 public static String replaceProperties(Project project, String 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 Use PropertyHelper
439 */
440 public static String replaceProperties(Project project, String value,
441 Hashtable keys) throws BuildException {
442 PropertyHelper ph = PropertyHelper.getPropertyHelper(project);
443 return ph.replaceProperties(null, value, keys);
444 }
445
446 /**
447 * Parses a string containing <code>${xxx}</code> style property
448 * references into two lists. The first list is a collection
449 * of text fragments, while the other is a set of string property names.
450 * <code>null</code> entries in the first list indicate a property
451 * reference from the second list.
452 *
453 * @param value Text to parse. Must not be <code>null</code>.
454 * @param fragments List to add text fragments to.
455 * Must not be <code>null</code>.
456 * @param propertyRefs List to add property names to.
457 * Must not be <code>null</code>.
458 *
459 * @deprecated Use PropertyHelper
460 * @exception BuildException if the string contains an opening
461 * <code>${</code> without a closing
462 * <code>}</code>
463 */
464 public static void parsePropertyString(String value, Vector fragments,
465 Vector propertyRefs)
466 throws BuildException {
467 PropertyHelper.parsePropertyStringDefault(value, fragments,
468 propertyRefs);
469 }
470 /**
471 * Map a namespaced {uri,name} to an internal string format.
472 * For BC purposes the names from the ant core uri will be
473 * mapped to "name", other names will be mapped to
474 * uri + ":" + name.
475 * @param uri The namepace URI
476 * @param name The localname
477 * @return The stringified form of the ns name
478 */
479 public static String genComponentName(String uri, String name) {
480 if (uri == null || uri.equals("") || uri.equals(ANT_CORE_URI)) {
481 return name;
482 }
483 return uri + ":" + name;
484 }
485
486 /**
487 * extract a uri from a component name
488 *
489 * @param componentName The stringified form for {uri, name}
490 * @return The uri or "" if not present
491 */
492 public static String extractUriFromComponentName(String componentName) {
493 if (componentName == null) {
494 return "";
495 }
496 int index = componentName.lastIndexOf(':');
497 if (index == -1) {
498 return "";
499 }
500 return componentName.substring(0, index);
501 }
502
503 /**
504 * extract the element name from a component name
505 *
506 * @param componentName The stringified form for {uri, name}
507 * @return The element name of the component
508 */
509 public static String extractNameFromComponentName(String componentName) {
510 int index = componentName.lastIndexOf(':');
511 if (index == -1) {
512 return componentName;
513 }
514 return componentName.substring(index + 1);
515 }
516
517 /**
518 * Add location to build exception.
519 * @param ex the build exception, if the build exception
520 * does not include
521 * @param newLocation the location of the calling task (may be null)
522 * @return a new build exception based in the build exception with
523 * location set to newLocation. If the original exception
524 * did not have a location, just return the build exception
525 */
526 public static BuildException addLocationToBuildException(
527 BuildException ex, Location newLocation) {
528 if (ex.getLocation() == null || ex.getMessage() == null) {
529 return ex;
530 }
531 String errorMessage
532 = "The following error occurred while executing this line:"
533 + System.getProperty("line.separator")
534 + ex.getLocation().toString()
535 + ex.getMessage();
536 if (newLocation == null) {
537 return new BuildException(errorMessage, ex);
538 } else {
539 return new BuildException(
540 errorMessage, ex, newLocation);
541 }
542 }
543}
Note: See TracBrowser for help on using the repository browser.