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 |
|
---|
18 | package org.apache.tools.ant;
|
---|
19 |
|
---|
20 | import java.io.BufferedReader;
|
---|
21 | import java.io.File;
|
---|
22 | import java.io.InputStream;
|
---|
23 | import java.io.InputStreamReader;
|
---|
24 | import java.util.Hashtable;
|
---|
25 | import java.util.Locale;
|
---|
26 | import java.util.Vector;
|
---|
27 | import org.apache.tools.ant.helper.ProjectHelper2;
|
---|
28 | import org.apache.tools.ant.util.LoaderUtils;
|
---|
29 | import 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 | */
|
---|
49 | public 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 | }
|
---|