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.helper;
|
---|
19 |
|
---|
20 | import java.io.File;
|
---|
21 | import java.io.FileInputStream;
|
---|
22 | import java.io.FileNotFoundException;
|
---|
23 | import java.io.IOException;
|
---|
24 | import java.io.UnsupportedEncodingException;
|
---|
25 | import java.util.Locale;
|
---|
26 | import org.apache.tools.ant.BuildException;
|
---|
27 | import org.apache.tools.ant.IntrospectionHelper;
|
---|
28 | import org.apache.tools.ant.Location;
|
---|
29 | import org.apache.tools.ant.Project;
|
---|
30 | import org.apache.tools.ant.ProjectHelper;
|
---|
31 | import org.apache.tools.ant.RuntimeConfigurable;
|
---|
32 | import org.apache.tools.ant.Target;
|
---|
33 | import org.apache.tools.ant.Task;
|
---|
34 | import org.apache.tools.ant.TypeAdapter;
|
---|
35 | import org.apache.tools.ant.TaskContainer;
|
---|
36 | import org.apache.tools.ant.UnknownElement;
|
---|
37 | import org.apache.tools.ant.util.FileUtils;
|
---|
38 | import org.apache.tools.ant.util.JAXPUtils;
|
---|
39 | import org.xml.sax.AttributeList;
|
---|
40 | import org.xml.sax.DocumentHandler;
|
---|
41 | import org.xml.sax.HandlerBase;
|
---|
42 | import org.xml.sax.InputSource;
|
---|
43 | import org.xml.sax.Locator;
|
---|
44 | import org.xml.sax.SAXException;
|
---|
45 | import org.xml.sax.SAXParseException;
|
---|
46 | import org.xml.sax.helpers.XMLReaderAdapter;
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Original helper.
|
---|
50 | *
|
---|
51 | */
|
---|
52 | public class ProjectHelperImpl extends ProjectHelper {
|
---|
53 |
|
---|
54 | /**
|
---|
55 | * SAX 1 style parser used to parse the given file. This may
|
---|
56 | * in fact be a SAX 2 XMLReader wrapped in an XMLReaderAdapter.
|
---|
57 | */
|
---|
58 | private org.xml.sax.Parser parser;
|
---|
59 |
|
---|
60 | /** The project to configure. */
|
---|
61 | private Project project;
|
---|
62 | /** The configuration file to parse. */
|
---|
63 | private File buildFile;
|
---|
64 | /**
|
---|
65 | * Parent directory of the build file. Used for resolving entities
|
---|
66 | * and setting the project's base directory.
|
---|
67 | */
|
---|
68 | private File buildFileParent;
|
---|
69 | /**
|
---|
70 | * Locator for the configuration file parser.
|
---|
71 | * Used for giving locations of errors etc.
|
---|
72 | */
|
---|
73 | private Locator locator;
|
---|
74 | /**
|
---|
75 | * Target that all other targets will depend upon implicitly.
|
---|
76 | *
|
---|
77 | * <p>This holds all tasks and data type definitions that have
|
---|
78 | * been placed outside of targets.</p>
|
---|
79 | */
|
---|
80 | private Target implicitTarget = new Target();
|
---|
81 | /**
|
---|
82 | * helper for path -> URI and URI -> path conversions.
|
---|
83 | */
|
---|
84 | private static FileUtils fu = FileUtils.newFileUtils();
|
---|
85 |
|
---|
86 | /**
|
---|
87 | * default constructor
|
---|
88 | */
|
---|
89 | public ProjectHelperImpl() {
|
---|
90 | implicitTarget.setName("");
|
---|
91 | }
|
---|
92 |
|
---|
93 | /**
|
---|
94 | * Parses the project file, configuring the project as it goes.
|
---|
95 | *
|
---|
96 | * @param project project instance to be configured.
|
---|
97 | * @param source the source from which the project is read.
|
---|
98 | * @exception BuildException if the configuration is invalid or cannot
|
---|
99 | * be read.
|
---|
100 | */
|
---|
101 | public void parse(Project project, Object source) throws BuildException {
|
---|
102 | if (!(source instanceof File)) {
|
---|
103 | throw new BuildException("Only File source supported by "
|
---|
104 | + "default plugin");
|
---|
105 | }
|
---|
106 | File buildFile = (File) source;
|
---|
107 | FileInputStream inputStream = null;
|
---|
108 | InputSource inputSource = null;
|
---|
109 |
|
---|
110 | this.project = project;
|
---|
111 | this.buildFile = new File(buildFile.getAbsolutePath());
|
---|
112 | buildFileParent = new File(this.buildFile.getParent());
|
---|
113 |
|
---|
114 | try {
|
---|
115 | try {
|
---|
116 | parser = JAXPUtils.getParser();
|
---|
117 | } catch (BuildException e) {
|
---|
118 | parser = new XMLReaderAdapter(JAXPUtils.getXMLReader());
|
---|
119 | }
|
---|
120 |
|
---|
121 |
|
---|
122 | String uri = fu.toURI(buildFile.getAbsolutePath());
|
---|
123 | inputStream = new FileInputStream(buildFile);
|
---|
124 | inputSource = new InputSource(inputStream);
|
---|
125 | inputSource.setSystemId(uri);
|
---|
126 | project.log("parsing buildfile " + buildFile + " with URI = "
|
---|
127 | + uri, Project.MSG_VERBOSE);
|
---|
128 | HandlerBase hb = new RootHandler(this);
|
---|
129 | parser.setDocumentHandler(hb);
|
---|
130 | parser.setEntityResolver(hb);
|
---|
131 | parser.setErrorHandler(hb);
|
---|
132 | parser.setDTDHandler(hb);
|
---|
133 | parser.parse(inputSource);
|
---|
134 | } catch (SAXParseException exc) {
|
---|
135 | Location location =
|
---|
136 | new Location(exc.getSystemId(), exc.getLineNumber(),
|
---|
137 | exc.getColumnNumber());
|
---|
138 |
|
---|
139 | Throwable t = exc.getException();
|
---|
140 | if (t instanceof BuildException) {
|
---|
141 | BuildException be = (BuildException) t;
|
---|
142 | if (be.getLocation() == Location.UNKNOWN_LOCATION) {
|
---|
143 | be.setLocation(location);
|
---|
144 | }
|
---|
145 | throw be;
|
---|
146 | }
|
---|
147 |
|
---|
148 | throw new BuildException(exc.getMessage(), t, location);
|
---|
149 | } catch (SAXException exc) {
|
---|
150 | Throwable t = exc.getException();
|
---|
151 | if (t instanceof BuildException) {
|
---|
152 | throw (BuildException) t;
|
---|
153 | }
|
---|
154 | throw new BuildException(exc.getMessage(), t);
|
---|
155 | } catch (FileNotFoundException exc) {
|
---|
156 | throw new BuildException(exc);
|
---|
157 | } catch (UnsupportedEncodingException exc) {
|
---|
158 | throw new BuildException("Encoding of project file is invalid.",
|
---|
159 | exc);
|
---|
160 | } catch (IOException exc) {
|
---|
161 | throw new BuildException("Error reading project file: "
|
---|
162 | + exc.getMessage(), exc);
|
---|
163 | } finally {
|
---|
164 | if (inputStream != null) {
|
---|
165 | try {
|
---|
166 | inputStream.close();
|
---|
167 | } catch (IOException ioe) {
|
---|
168 | // ignore this
|
---|
169 | }
|
---|
170 | }
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | /**
|
---|
175 | * The common superclass for all SAX event handlers used to parse
|
---|
176 | * the configuration file. Each method just throws an exception,
|
---|
177 | * so subclasses should override what they can handle.
|
---|
178 | *
|
---|
179 | * Each type of XML element (task, target, etc.) in Ant has
|
---|
180 | * a specific subclass.
|
---|
181 | *
|
---|
182 | * In the constructor, this class takes over the handling of SAX
|
---|
183 | * events from the parent handler and returns
|
---|
184 | * control back to the parent in the endElement method.
|
---|
185 | */
|
---|
186 | static class AbstractHandler extends HandlerBase {
|
---|
187 |
|
---|
188 | /**
|
---|
189 | * Previous handler for the document.
|
---|
190 | * When the next element is finished, control returns
|
---|
191 | * to this handler.
|
---|
192 | */
|
---|
193 | protected DocumentHandler parentHandler;
|
---|
194 |
|
---|
195 | /** Helper impl. With non-static internal classes, the compiler will generate
|
---|
196 | this automatically - but this will fail with some compilers ( reporting
|
---|
197 | "Expecting to find object/array on stack" ). If we pass it
|
---|
198 | explicitly it'll work with more compilers.
|
---|
199 | */
|
---|
200 | ProjectHelperImpl helperImpl;
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * Creates a handler and sets the parser to use it
|
---|
204 | * for the current element.
|
---|
205 | *
|
---|
206 | * @param helperImpl the ProjectHelperImpl instance associated
|
---|
207 | * with this handler.
|
---|
208 | *
|
---|
209 | * @param parentHandler The handler which should be restored to the
|
---|
210 | * parser at the end of the element.
|
---|
211 | * Must not be <code>null</code>.
|
---|
212 | */
|
---|
213 | public AbstractHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
|
---|
214 | this.parentHandler = parentHandler;
|
---|
215 | this.helperImpl = helperImpl;
|
---|
216 |
|
---|
217 | // Start handling SAX events
|
---|
218 | helperImpl.parser.setDocumentHandler(this);
|
---|
219 | }
|
---|
220 |
|
---|
221 | /**
|
---|
222 | * Handles the start of an element. This base implementation just
|
---|
223 | * throws an exception.
|
---|
224 | *
|
---|
225 | * @param tag The name of the element being started.
|
---|
226 | * Will not be <code>null</code>.
|
---|
227 | * @param attrs Attributes of the element being started.
|
---|
228 | * Will not be <code>null</code>.
|
---|
229 | *
|
---|
230 | * @exception SAXParseException if this method is not overridden, or in
|
---|
231 | * case of error in an overridden version
|
---|
232 | */
|
---|
233 | public void startElement(String tag, AttributeList attrs) throws SAXParseException {
|
---|
234 | throw new SAXParseException("Unexpected element \"" + tag + "\"", helperImpl.locator);
|
---|
235 | }
|
---|
236 |
|
---|
237 | /**
|
---|
238 | * Handles text within an element. This base implementation just
|
---|
239 | * throws an exception.
|
---|
240 | *
|
---|
241 | * @param buf A character array of the text within the element.
|
---|
242 | * Will not be <code>null</code>.
|
---|
243 | * @param start The start element in the array.
|
---|
244 | * @param count The number of characters to read from the array.
|
---|
245 | *
|
---|
246 | * @exception SAXParseException if this method is not overridden, or in
|
---|
247 | * case of error in an overridden version
|
---|
248 | */
|
---|
249 | public void characters(char[] buf, int start, int count) throws SAXParseException {
|
---|
250 | String s = new String(buf, start, count).trim();
|
---|
251 |
|
---|
252 | if (s.length() > 0) {
|
---|
253 | throw new SAXParseException("Unexpected text \"" + s + "\"", helperImpl.locator);
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | /**
|
---|
258 | * Handles the end of an element. Any required clean-up is performed
|
---|
259 | * by the finished() method and then the original handler is restored to
|
---|
260 | * the parser.
|
---|
261 | *
|
---|
262 | * @param name The name of the element which is ending.
|
---|
263 | * Will not be <code>null</code>.
|
---|
264 | *
|
---|
265 | * @exception SAXException in case of error (not thrown in
|
---|
266 | * this implementation)
|
---|
267 | */
|
---|
268 | public void endElement(String name) throws SAXException {
|
---|
269 | // Let parent resume handling SAX events
|
---|
270 | helperImpl.parser.setDocumentHandler(parentHandler);
|
---|
271 | }
|
---|
272 | }
|
---|
273 |
|
---|
274 | /**
|
---|
275 | * Handler for the root element. Its only child must be the "project" element.
|
---|
276 | */
|
---|
277 | static class RootHandler extends HandlerBase {
|
---|
278 | ProjectHelperImpl helperImpl;
|
---|
279 |
|
---|
280 | public RootHandler(ProjectHelperImpl helperImpl) {
|
---|
281 | this.helperImpl = helperImpl;
|
---|
282 | }
|
---|
283 |
|
---|
284 | /**
|
---|
285 | * Resolves file: URIs relative to the build file.
|
---|
286 | *
|
---|
287 | * @param publicId The public identifier, or <code>null</code>
|
---|
288 | * if none is available. Ignored in this
|
---|
289 | * implementation.
|
---|
290 | * @param systemId The system identifier provided in the XML
|
---|
291 | * document. Will not be <code>null</code>.
|
---|
292 | */
|
---|
293 | public InputSource resolveEntity(String publicId,
|
---|
294 | String systemId) {
|
---|
295 |
|
---|
296 | helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
|
---|
297 |
|
---|
298 | if (systemId.startsWith("file:")) {
|
---|
299 | String path = fu.fromURI(systemId);
|
---|
300 |
|
---|
301 | File file = new File(path);
|
---|
302 | if (!file.isAbsolute()) {
|
---|
303 | file = fu.resolveFile(helperImpl.buildFileParent, path);
|
---|
304 | }
|
---|
305 | try {
|
---|
306 | InputSource inputSource = new InputSource(new FileInputStream(file));
|
---|
307 | inputSource.setSystemId(fu.toURI(file.getAbsolutePath()));
|
---|
308 | return inputSource;
|
---|
309 | } catch (FileNotFoundException fne) {
|
---|
310 | helperImpl.project.log(file.getAbsolutePath() + " could not be found",
|
---|
311 | Project.MSG_WARN);
|
---|
312 | }
|
---|
313 | }
|
---|
314 | // use default if not file or file not found
|
---|
315 | return null;
|
---|
316 | }
|
---|
317 |
|
---|
318 | /**
|
---|
319 | * Handles the start of a project element. A project handler is created
|
---|
320 | * and initialised with the element name and attributes.
|
---|
321 | *
|
---|
322 | * @param tag The name of the element being started.
|
---|
323 | * Will not be <code>null</code>.
|
---|
324 | * @param attrs Attributes of the element being started.
|
---|
325 | * Will not be <code>null</code>.
|
---|
326 | *
|
---|
327 | * @exception SAXParseException if the tag given is not
|
---|
328 | * <code>"project"</code>
|
---|
329 | */
|
---|
330 | public void startElement(String tag, AttributeList attrs) throws SAXParseException {
|
---|
331 | if (tag.equals("project")) {
|
---|
332 | new ProjectHandler(helperImpl, this).init(tag, attrs);
|
---|
333 | } else {
|
---|
334 | throw new SAXParseException("Config file is not of expected "
|
---|
335 | + "XML type", helperImpl.locator);
|
---|
336 | }
|
---|
337 | }
|
---|
338 |
|
---|
339 | /**
|
---|
340 | * Sets the locator in the project helper for future reference.
|
---|
341 | *
|
---|
342 | * @param locator The locator used by the parser.
|
---|
343 | * Will not be <code>null</code>.
|
---|
344 | */
|
---|
345 | public void setDocumentLocator(Locator locator) {
|
---|
346 | helperImpl.locator = locator;
|
---|
347 | }
|
---|
348 | }
|
---|
349 |
|
---|
350 | /**
|
---|
351 | * Handler for the top level "project" element.
|
---|
352 | */
|
---|
353 | static class ProjectHandler extends AbstractHandler {
|
---|
354 |
|
---|
355 | /**
|
---|
356 | * Constructor which just delegates to the superconstructor.
|
---|
357 | *
|
---|
358 | * @param parentHandler The handler which should be restored to the
|
---|
359 | * parser at the end of the element.
|
---|
360 | * Must not be <code>null</code>.
|
---|
361 | */
|
---|
362 | public ProjectHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
|
---|
363 | super(helperImpl, parentHandler);
|
---|
364 | }
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Initialisation routine called after handler creation
|
---|
368 | * with the element name and attributes. The attributes which
|
---|
369 | * this handler can deal with are: <code>"default"</code>,
|
---|
370 | * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
|
---|
371 | *
|
---|
372 | * @param tag Name of the element which caused this handler
|
---|
373 | * to be created. Should not be <code>null</code>.
|
---|
374 | * Ignored in this implementation.
|
---|
375 | * @param attrs Attributes of the element which caused this
|
---|
376 | * handler to be created. Must not be <code>null</code>.
|
---|
377 | *
|
---|
378 | * @exception SAXParseException if an unexpected attribute is
|
---|
379 | * encountered or if the <code>"default"</code> attribute
|
---|
380 | * is missing.
|
---|
381 | */
|
---|
382 | public void init(String tag, AttributeList attrs) throws SAXParseException {
|
---|
383 | String def = null;
|
---|
384 | String name = null;
|
---|
385 | String id = null;
|
---|
386 | String baseDir = null;
|
---|
387 |
|
---|
388 | for (int i = 0; i < attrs.getLength(); i++) {
|
---|
389 | String key = attrs.getName(i);
|
---|
390 | String value = attrs.getValue(i);
|
---|
391 |
|
---|
392 | if (key.equals("default")) {
|
---|
393 | def = value;
|
---|
394 | } else if (key.equals("name")) {
|
---|
395 | name = value;
|
---|
396 | } else if (key.equals("id")) {
|
---|
397 | id = value;
|
---|
398 | } else if (key.equals("basedir")) {
|
---|
399 | baseDir = value;
|
---|
400 | } else {
|
---|
401 | throw new SAXParseException("Unexpected attribute \"" + attrs.getName(i) + "\"",
|
---|
402 | helperImpl.locator);
|
---|
403 | }
|
---|
404 | }
|
---|
405 |
|
---|
406 | if (def != null && !def.equals("")) {
|
---|
407 | helperImpl.project.setDefaultTarget(def);
|
---|
408 | } else {
|
---|
409 | throw new BuildException("The default attribute is required");
|
---|
410 | }
|
---|
411 |
|
---|
412 | if (name != null) {
|
---|
413 | helperImpl.project.setName(name);
|
---|
414 | helperImpl.project.addReference(name, helperImpl.project);
|
---|
415 | }
|
---|
416 |
|
---|
417 | if (id != null) {
|
---|
418 | helperImpl.project.addReference(id, helperImpl.project);
|
---|
419 | }
|
---|
420 |
|
---|
421 | if (helperImpl.project.getProperty("basedir") != null) {
|
---|
422 | helperImpl.project.setBasedir(helperImpl.project.getProperty("basedir"));
|
---|
423 | } else {
|
---|
424 | if (baseDir == null) {
|
---|
425 | helperImpl.project.setBasedir(helperImpl.buildFileParent.getAbsolutePath());
|
---|
426 | } else {
|
---|
427 | // check whether the user has specified an absolute path
|
---|
428 | if ((new File(baseDir)).isAbsolute()) {
|
---|
429 | helperImpl.project.setBasedir(baseDir);
|
---|
430 | } else {
|
---|
431 | File resolvedBaseDir = helperImpl.project.resolveFile(baseDir,
|
---|
432 | helperImpl.buildFileParent);
|
---|
433 | helperImpl.project.setBaseDir(resolvedBaseDir);
|
---|
434 | }
|
---|
435 | }
|
---|
436 | }
|
---|
437 |
|
---|
438 | helperImpl.project.addTarget("", helperImpl.implicitTarget);
|
---|
439 | }
|
---|
440 |
|
---|
441 | /**
|
---|
442 | * Handles the start of a top-level element within the project. An
|
---|
443 | * appropriate handler is created and initialised with the details
|
---|
444 | * of the element.
|
---|
445 | *
|
---|
446 | * @param name The name of the element being started.
|
---|
447 | * Will not be <code>null</code>.
|
---|
448 | * @param attrs Attributes of the element being started.
|
---|
449 | * Will not be <code>null</code>.
|
---|
450 | *
|
---|
451 | * @exception SAXParseException if the tag given is not
|
---|
452 | * <code>"taskdef"</code>, <code>"typedef"</code>,
|
---|
453 | * <code>"property"</code>, <code>"target"</code>
|
---|
454 | * or a data type definition
|
---|
455 | */
|
---|
456 | public void startElement(String name, AttributeList attrs) throws SAXParseException {
|
---|
457 | if (name.equals("target")) {
|
---|
458 | handleTarget(name, attrs);
|
---|
459 | } else {
|
---|
460 | handleElement(helperImpl, this, helperImpl.implicitTarget,
|
---|
461 | name, attrs);
|
---|
462 | }
|
---|
463 | }
|
---|
464 |
|
---|
465 | /**
|
---|
466 | * Handles a target definition element by creating a target handler
|
---|
467 | * and initialising is with the details of the element.
|
---|
468 | *
|
---|
469 | * @param tag The name of the element to be handled.
|
---|
470 | * Will not be <code>null</code>.
|
---|
471 | * @param attrs Attributes of the element to be handled.
|
---|
472 | * Will not be <code>null</code>.
|
---|
473 | *
|
---|
474 | * @exception SAXParseException if an error occurs initialising
|
---|
475 | * the handler
|
---|
476 | */
|
---|
477 | private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
|
---|
478 | new TargetHandler(helperImpl, this).init(tag, attrs);
|
---|
479 | }
|
---|
480 |
|
---|
481 | }
|
---|
482 |
|
---|
483 | /**
|
---|
484 | * Handler for "target" elements.
|
---|
485 | */
|
---|
486 | static class TargetHandler extends AbstractHandler {
|
---|
487 | private Target target;
|
---|
488 |
|
---|
489 | /**
|
---|
490 | * Constructor which just delegates to the superconstructor.
|
---|
491 | *
|
---|
492 | * @param parentHandler The handler which should be restored to the
|
---|
493 | * parser at the end of the element.
|
---|
494 | * Must not be <code>null</code>.
|
---|
495 | */
|
---|
496 | public TargetHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
|
---|
497 | super(helperImpl, parentHandler);
|
---|
498 | }
|
---|
499 |
|
---|
500 | /**
|
---|
501 | * Initialisation routine called after handler creation
|
---|
502 | * with the element name and attributes. The attributes which
|
---|
503 | * this handler can deal with are: <code>"name"</code>,
|
---|
504 | * <code>"depends"</code>, <code>"if"</code>,
|
---|
505 | * <code>"unless"</code>, <code>"id"</code> and
|
---|
506 | * <code>"description"</code>.
|
---|
507 | *
|
---|
508 | * @param tag Name of the element which caused this handler
|
---|
509 | * to be created. Should not be <code>null</code>.
|
---|
510 | * Ignored in this implementation.
|
---|
511 | * @param attrs Attributes of the element which caused this
|
---|
512 | * handler to be created. Must not be <code>null</code>.
|
---|
513 | *
|
---|
514 | * @exception SAXParseException if an unexpected attribute is encountered
|
---|
515 | * or if the <code>"name"</code> attribute is missing.
|
---|
516 | */
|
---|
517 | public void init(String tag, AttributeList attrs) throws SAXParseException {
|
---|
518 | String name = null;
|
---|
519 | String depends = "";
|
---|
520 | String ifCond = null;
|
---|
521 | String unlessCond = null;
|
---|
522 | String id = null;
|
---|
523 | String description = null;
|
---|
524 |
|
---|
525 | for (int i = 0; i < attrs.getLength(); i++) {
|
---|
526 | String key = attrs.getName(i);
|
---|
527 | String value = attrs.getValue(i);
|
---|
528 |
|
---|
529 | if (key.equals("name")) {
|
---|
530 | name = value;
|
---|
531 | if (name.equals("")) {
|
---|
532 | throw new BuildException("name attribute must not"
|
---|
533 | + " be empty",
|
---|
534 | new Location(helperImpl.locator));
|
---|
535 | }
|
---|
536 | } else if (key.equals("depends")) {
|
---|
537 | depends = value;
|
---|
538 | } else if (key.equals("if")) {
|
---|
539 | ifCond = value;
|
---|
540 | } else if (key.equals("unless")) {
|
---|
541 | unlessCond = value;
|
---|
542 | } else if (key.equals("id")) {
|
---|
543 | id = value;
|
---|
544 | } else if (key.equals("description")) {
|
---|
545 | description = value;
|
---|
546 | } else if (key.equals("address")) {
|
---|
547 | target.setAddress(value);
|
---|
548 | } else {
|
---|
549 | throw new SAXParseException("Unexpected attribute \""
|
---|
550 | + key + "\"", helperImpl.locator);
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 | if (name == null) {
|
---|
555 | throw new SAXParseException("target element appears without a name attribute",
|
---|
556 | helperImpl.locator);
|
---|
557 | }
|
---|
558 |
|
---|
559 | target = new Target();
|
---|
560 |
|
---|
561 | // implicit target must be first on dependency list
|
---|
562 | target.addDependency("");
|
---|
563 |
|
---|
564 | target.setName(name);
|
---|
565 | target.setIf(ifCond);
|
---|
566 | target.setUnless(unlessCond);
|
---|
567 | target.setDescription(description);
|
---|
568 | helperImpl.project.addTarget(name, target);
|
---|
569 |
|
---|
570 | if (id != null && !id.equals("")) {
|
---|
571 | helperImpl.project.addReference(id, target);
|
---|
572 | }
|
---|
573 |
|
---|
574 | // take care of dependencies
|
---|
575 |
|
---|
576 | if (depends.length() > 0) {
|
---|
577 | target.setDepends(depends);
|
---|
578 | }
|
---|
579 | }
|
---|
580 |
|
---|
581 | /**
|
---|
582 | * Handles the start of an element within a target.
|
---|
583 | *
|
---|
584 | * @param name The name of the element being started.
|
---|
585 | * Will not be <code>null</code>.
|
---|
586 | * @param attrs Attributes of the element being started.
|
---|
587 | * Will not be <code>null</code>.
|
---|
588 | *
|
---|
589 | * @exception SAXParseException if an error occurs when initialising
|
---|
590 | * the appropriate child handler
|
---|
591 | */
|
---|
592 | public void startElement(String name, AttributeList attrs) throws SAXParseException {
|
---|
593 | handleElement(helperImpl, this, target, name, attrs);
|
---|
594 | }
|
---|
595 | }
|
---|
596 |
|
---|
597 | /**
|
---|
598 | * Start a new DataTypeHandler if element is known to be a
|
---|
599 | * data-type and a TaskHandler otherwise.
|
---|
600 | *
|
---|
601 | * <p>Factored out of TargetHandler.</p>
|
---|
602 | *
|
---|
603 | * @since Ant 1.6
|
---|
604 | */
|
---|
605 | private static void handleElement(ProjectHelperImpl helperImpl,
|
---|
606 | DocumentHandler parent,
|
---|
607 | Target target, String elementName,
|
---|
608 | AttributeList attrs)
|
---|
609 | throws SAXParseException {
|
---|
610 | if (elementName.equals("description")) {
|
---|
611 | new DescriptionHandler(helperImpl, parent);
|
---|
612 | } else if (helperImpl.project.getDataTypeDefinitions()
|
---|
613 | .get(elementName) != null) {
|
---|
614 | new DataTypeHandler(helperImpl, parent, target)
|
---|
615 | .init(elementName, attrs);
|
---|
616 | } else {
|
---|
617 | new TaskHandler(helperImpl, parent, target, null, target)
|
---|
618 | .init(elementName, attrs);
|
---|
619 | }
|
---|
620 | }
|
---|
621 |
|
---|
622 | /**
|
---|
623 | * Handler for "description" elements.
|
---|
624 | */
|
---|
625 | static class DescriptionHandler extends AbstractHandler {
|
---|
626 |
|
---|
627 | /**
|
---|
628 | * Constructor which just delegates to the superconstructor.
|
---|
629 | *
|
---|
630 | * @param parentHandler The handler which should be restored to the
|
---|
631 | * parser at the end of the element.
|
---|
632 | * Must not be <code>null</code>.
|
---|
633 | */
|
---|
634 | public DescriptionHandler(ProjectHelperImpl helperImpl,
|
---|
635 | DocumentHandler parentHandler) {
|
---|
636 | super(helperImpl, parentHandler);
|
---|
637 | }
|
---|
638 |
|
---|
639 | /**
|
---|
640 | * Adds the text as description to the project.
|
---|
641 | *
|
---|
642 | * @param buf A character array of the text within the element.
|
---|
643 | * Will not be <code>null</code>.
|
---|
644 | * @param start The start element in the array.
|
---|
645 | * @param count The number of characters to read from the array.
|
---|
646 | */
|
---|
647 | public void characters(char[] buf, int start, int count) {
|
---|
648 | String text = new String(buf, start, count);
|
---|
649 | String currentDescription = helperImpl.project.getDescription();
|
---|
650 | if (currentDescription == null) {
|
---|
651 | helperImpl.project.setDescription(text);
|
---|
652 | } else {
|
---|
653 | helperImpl.project.setDescription(currentDescription + text);
|
---|
654 | }
|
---|
655 | }
|
---|
656 |
|
---|
657 | }
|
---|
658 |
|
---|
659 | /**
|
---|
660 | * Handler for all task elements.
|
---|
661 | */
|
---|
662 | static class TaskHandler extends AbstractHandler {
|
---|
663 | /** Containing target, if any. */
|
---|
664 | private Target target;
|
---|
665 | /**
|
---|
666 | * Container for the task, if any. If target is
|
---|
667 | * non-<code>null</code>, this must be too.
|
---|
668 | */
|
---|
669 | private TaskContainer container;
|
---|
670 | /**
|
---|
671 | * Task created by this handler.
|
---|
672 | */
|
---|
673 | private Task task;
|
---|
674 | /**
|
---|
675 | * Wrapper for the parent element, if any. The wrapper for this
|
---|
676 | * element will be added to this wrapper as a child.
|
---|
677 | */
|
---|
678 | private RuntimeConfigurable parentWrapper;
|
---|
679 | /**
|
---|
680 | * Wrapper for this element which takes care of actually configuring
|
---|
681 | * the element, if this element is contained within a target.
|
---|
682 | * Otherwise the configuration is performed with the configure method.
|
---|
683 | * @see ProjectHelper#configure(Object,AttributeList,Project)
|
---|
684 | */
|
---|
685 | private RuntimeConfigurable wrapper = null;
|
---|
686 |
|
---|
687 | /**
|
---|
688 | * Constructor.
|
---|
689 | *
|
---|
690 | * @param parentHandler The handler which should be restored to the
|
---|
691 | * parser at the end of the element.
|
---|
692 | * Must not be <code>null</code>.
|
---|
693 | *
|
---|
694 | * @param container Container for the element.
|
---|
695 | * Must not be <code>null</code>.
|
---|
696 | *
|
---|
697 | * @param parentWrapper Wrapper for the parent element, if any.
|
---|
698 | * May be <code>null</code>.
|
---|
699 | *
|
---|
700 | * @param target Target this element is part of.
|
---|
701 | * Must not be <code>null</code>.
|
---|
702 | */
|
---|
703 | public TaskHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler,
|
---|
704 | TaskContainer container,
|
---|
705 | RuntimeConfigurable parentWrapper, Target target) {
|
---|
706 | super(helperImpl, parentHandler);
|
---|
707 | this.container = container;
|
---|
708 | this.parentWrapper = parentWrapper;
|
---|
709 | this.target = target;
|
---|
710 | }
|
---|
711 |
|
---|
712 | /**
|
---|
713 | * Initialisation routine called after handler creation
|
---|
714 | * with the element name and attributes. This configures
|
---|
715 | * the element with its attributes and sets it up with
|
---|
716 | * its parent container (if any). Nested elements are then
|
---|
717 | * added later as the parser encounters them.
|
---|
718 | *
|
---|
719 | * @param tag Name of the element which caused this handler
|
---|
720 | * to be created. Must not be <code>null</code>.
|
---|
721 | *
|
---|
722 | * @param attrs Attributes of the element which caused this
|
---|
723 | * handler to be created. Must not be <code>null</code>.
|
---|
724 | *
|
---|
725 | * @exception SAXParseException in case of error (not thrown in
|
---|
726 | * this implementation)
|
---|
727 | */
|
---|
728 | public void init(String tag, AttributeList attrs) throws SAXParseException {
|
---|
729 | try {
|
---|
730 | task = helperImpl.project.createTask(tag);
|
---|
731 | } catch (BuildException e) {
|
---|
732 | // swallow here, will be thrown again in
|
---|
733 | // UnknownElement.maybeConfigure if the problem persists.
|
---|
734 | }
|
---|
735 |
|
---|
736 | if (task == null) {
|
---|
737 | task = new UnknownElement(tag);
|
---|
738 | task.setProject(helperImpl.project);
|
---|
739 | //XXX task.setTaskType(tag);
|
---|
740 | task.setTaskName(tag);
|
---|
741 | }
|
---|
742 |
|
---|
743 | task.setLocation(new Location(helperImpl.locator));
|
---|
744 | helperImpl.configureId(task, attrs);
|
---|
745 |
|
---|
746 | task.setOwningTarget(target);
|
---|
747 | container.addTask(task);
|
---|
748 | task.init();
|
---|
749 | wrapper = task.getRuntimeConfigurableWrapper();
|
---|
750 | wrapper.setAttributes(attrs);
|
---|
751 | if (parentWrapper != null) {
|
---|
752 | parentWrapper.addChild(wrapper);
|
---|
753 | }
|
---|
754 | }
|
---|
755 |
|
---|
756 | /**
|
---|
757 | * Adds text to the task, using the wrapper.
|
---|
758 | *
|
---|
759 | * @param buf A character array of the text within the element.
|
---|
760 | * Will not be <code>null</code>.
|
---|
761 | * @param start The start element in the array.
|
---|
762 | * @param count The number of characters to read from the array.
|
---|
763 | */
|
---|
764 | public void characters(char[] buf, int start, int count) {
|
---|
765 | wrapper.addText(buf, start, count);
|
---|
766 | }
|
---|
767 |
|
---|
768 | /**
|
---|
769 | * Handles the start of an element within a target. Task containers
|
---|
770 | * will always use another task handler, and all other tasks
|
---|
771 | * will always use a nested element handler.
|
---|
772 | *
|
---|
773 | * @param name The name of the element being started.
|
---|
774 | * Will not be <code>null</code>.
|
---|
775 | * @param attrs Attributes of the element being started.
|
---|
776 | * Will not be <code>null</code>.
|
---|
777 | *
|
---|
778 | * @exception SAXParseException if an error occurs when initialising
|
---|
779 | * the appropriate child handler
|
---|
780 | */
|
---|
781 | public void startElement(String name, AttributeList attrs) throws SAXParseException {
|
---|
782 | if (task instanceof TaskContainer) {
|
---|
783 | // task can contain other tasks - no other nested elements possible
|
---|
784 | new TaskHandler(helperImpl, this, (TaskContainer) task,
|
---|
785 | wrapper, target).init(name, attrs);
|
---|
786 | } else {
|
---|
787 | new NestedElementHandler(helperImpl, this, task,
|
---|
788 | wrapper, target).init(name, attrs);
|
---|
789 | }
|
---|
790 | }
|
---|
791 | }
|
---|
792 |
|
---|
793 | /**
|
---|
794 | * Handler for all nested properties.
|
---|
795 | */
|
---|
796 | static class NestedElementHandler extends AbstractHandler {
|
---|
797 | /** Parent object (task/data type/etc). */
|
---|
798 | private Object parent;
|
---|
799 | /** The nested element itself. */
|
---|
800 | private Object child;
|
---|
801 | /**
|
---|
802 | * Wrapper for the parent element, if any. The wrapper for this
|
---|
803 | * element will be added to this wrapper as a child.
|
---|
804 | */
|
---|
805 | private RuntimeConfigurable parentWrapper;
|
---|
806 | /**
|
---|
807 | * Wrapper for this element which takes care of actually configuring
|
---|
808 | * the element, if a parent wrapper is provided.
|
---|
809 | * Otherwise the configuration is performed with the configure method.
|
---|
810 | * @see ProjectHelper#configure(Object,AttributeList,Project)
|
---|
811 | */
|
---|
812 | private RuntimeConfigurable childWrapper = null;
|
---|
813 | /** Target this element is part of, if any. */
|
---|
814 | private Target target;
|
---|
815 |
|
---|
816 | /**
|
---|
817 | * Constructor.
|
---|
818 | *
|
---|
819 | * @param parentHandler The handler which should be restored to the
|
---|
820 | * parser at the end of the element.
|
---|
821 | * Must not be <code>null</code>.
|
---|
822 | *
|
---|
823 | * @param parent Parent of this element (task/data type/etc).
|
---|
824 | * Must not be <code>null</code>.
|
---|
825 | *
|
---|
826 | * @param parentWrapper Wrapper for the parent element, if any.
|
---|
827 | * Must not be <code>null</code>.
|
---|
828 | *
|
---|
829 | * @param target Target this element is part of.
|
---|
830 | * Must not be <code>null</code>.
|
---|
831 | */
|
---|
832 | public NestedElementHandler(ProjectHelperImpl helperImpl,
|
---|
833 | DocumentHandler parentHandler,
|
---|
834 | Object parent,
|
---|
835 | RuntimeConfigurable parentWrapper,
|
---|
836 | Target target) {
|
---|
837 | super(helperImpl, parentHandler);
|
---|
838 |
|
---|
839 | if (parent instanceof TypeAdapter) {
|
---|
840 | this.parent = ((TypeAdapter) parent).getProxy();
|
---|
841 | } else {
|
---|
842 | this.parent = parent;
|
---|
843 | }
|
---|
844 | this.parentWrapper = parentWrapper;
|
---|
845 | this.target = target;
|
---|
846 | }
|
---|
847 |
|
---|
848 | /**
|
---|
849 | * Initialisation routine called after handler creation
|
---|
850 | * with the element name and attributes. This configures
|
---|
851 | * the element with its attributes and sets it up with
|
---|
852 | * its parent container (if any). Nested elements are then
|
---|
853 | * added later as the parser encounters them.
|
---|
854 | *
|
---|
855 | * @param propType Name of the element which caused this handler
|
---|
856 | * to be created. Must not be <code>null</code>.
|
---|
857 | *
|
---|
858 | * @param attrs Attributes of the element which caused this
|
---|
859 | * handler to be created. Must not be <code>null</code>.
|
---|
860 | *
|
---|
861 | * @exception SAXParseException in case of error, such as a
|
---|
862 | * BuildException being thrown during configuration.
|
---|
863 | */
|
---|
864 | public void init(String propType, AttributeList attrs) throws SAXParseException {
|
---|
865 | Class parentClass = parent.getClass();
|
---|
866 | IntrospectionHelper ih =
|
---|
867 | IntrospectionHelper.getHelper(parentClass);
|
---|
868 |
|
---|
869 | try {
|
---|
870 | String elementName = propType.toLowerCase(Locale.US);
|
---|
871 | if (parent instanceof UnknownElement) {
|
---|
872 | UnknownElement uc = new UnknownElement(elementName);
|
---|
873 | uc.setProject(helperImpl.project);
|
---|
874 | ((UnknownElement) parent).addChild(uc);
|
---|
875 | child = uc;
|
---|
876 | } else {
|
---|
877 | child = ih.createElement(helperImpl.project, parent, elementName);
|
---|
878 | }
|
---|
879 |
|
---|
880 | helperImpl.configureId(child, attrs);
|
---|
881 |
|
---|
882 | childWrapper = new RuntimeConfigurable(child, propType);
|
---|
883 | childWrapper.setAttributes(attrs);
|
---|
884 | parentWrapper.addChild(childWrapper);
|
---|
885 | } catch (BuildException exc) {
|
---|
886 | throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
|
---|
887 | }
|
---|
888 | }
|
---|
889 |
|
---|
890 | /**
|
---|
891 | * Adds text to the element, using the wrapper.
|
---|
892 | *
|
---|
893 | * @param buf A character array of the text within the element.
|
---|
894 | * Will not be <code>null</code>.
|
---|
895 | * @param start The start element in the array.
|
---|
896 | * @param count The number of characters to read from the array.
|
---|
897 | */
|
---|
898 | public void characters(char[] buf, int start, int count) {
|
---|
899 | childWrapper.addText(buf, start, count);
|
---|
900 | }
|
---|
901 |
|
---|
902 | /**
|
---|
903 | * Handles the start of an element within this one. Task containers
|
---|
904 | * will always use a task handler, and all other elements
|
---|
905 | * will always use another nested element handler.
|
---|
906 | *
|
---|
907 | * @param name The name of the element being started.
|
---|
908 | * Will not be <code>null</code>.
|
---|
909 | * @param attrs Attributes of the element being started.
|
---|
910 | * Will not be <code>null</code>.
|
---|
911 | *
|
---|
912 | * @exception SAXParseException if an error occurs when initialising
|
---|
913 | * the appropriate child handler
|
---|
914 | */
|
---|
915 | public void startElement(String name, AttributeList attrs) throws SAXParseException {
|
---|
916 | if (child instanceof TaskContainer) {
|
---|
917 | // taskcontainer nested element can contain other tasks - no other
|
---|
918 | // nested elements possible
|
---|
919 | new TaskHandler(helperImpl, this, (TaskContainer) child,
|
---|
920 | childWrapper, target).init(name, attrs);
|
---|
921 | } else {
|
---|
922 | new NestedElementHandler(helperImpl, this, child,
|
---|
923 | childWrapper, target).init(name, attrs);
|
---|
924 | }
|
---|
925 | }
|
---|
926 | }
|
---|
927 |
|
---|
928 | /**
|
---|
929 | * Handler for all data types directly subordinate to project or target.
|
---|
930 | */
|
---|
931 | static class DataTypeHandler extends AbstractHandler {
|
---|
932 | /** Parent target, if any. */
|
---|
933 | private Target target;
|
---|
934 | /** The element being configured. */
|
---|
935 | private Object element;
|
---|
936 | /** Wrapper for this element, if it's part of a target. */
|
---|
937 | private RuntimeConfigurable wrapper = null;
|
---|
938 |
|
---|
939 | /**
|
---|
940 | * Constructor with a target specified.
|
---|
941 | *
|
---|
942 | * @param parentHandler The handler which should be restored to the
|
---|
943 | * parser at the end of the element.
|
---|
944 | * Must not be <code>null</code>.
|
---|
945 | *
|
---|
946 | * @param target The parent target of this element.
|
---|
947 | * Must not be <code>null</code>.
|
---|
948 | */
|
---|
949 | public DataTypeHandler(ProjectHelperImpl helperImpl,
|
---|
950 | DocumentHandler parentHandler, Target target) {
|
---|
951 | super(helperImpl, parentHandler);
|
---|
952 | this.target = target;
|
---|
953 | }
|
---|
954 |
|
---|
955 | /**
|
---|
956 | * Initialisation routine called after handler creation
|
---|
957 | * with the element name and attributes. This configures
|
---|
958 | * the element with its attributes and sets it up with
|
---|
959 | * its parent container (if any). Nested elements are then
|
---|
960 | * added later as the parser encounters them.
|
---|
961 | *
|
---|
962 | * @param propType Name of the element which caused this handler
|
---|
963 | * to be created. Must not be <code>null</code>.
|
---|
964 | *
|
---|
965 | * @param attrs Attributes of the element which caused this
|
---|
966 | * handler to be created. Must not be <code>null</code>.
|
---|
967 | *
|
---|
968 | * @exception SAXParseException in case of error, such as a
|
---|
969 | * BuildException being thrown during configuration.
|
---|
970 | */
|
---|
971 | public void init(String propType, AttributeList attrs) throws SAXParseException {
|
---|
972 | try {
|
---|
973 | element = helperImpl.project.createDataType(propType);
|
---|
974 | if (element == null) {
|
---|
975 | throw new BuildException("Unknown data type " + propType);
|
---|
976 | }
|
---|
977 |
|
---|
978 | wrapper = new RuntimeConfigurable(element, propType);
|
---|
979 | wrapper.setAttributes(attrs);
|
---|
980 | target.addDataType(wrapper);
|
---|
981 | } catch (BuildException exc) {
|
---|
982 | throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
|
---|
983 | }
|
---|
984 | }
|
---|
985 |
|
---|
986 | /**
|
---|
987 | * Adds text to the using the wrapper.
|
---|
988 | *
|
---|
989 | * @param buf A character array of the text within the element.
|
---|
990 | * Will not be <code>null</code>.
|
---|
991 | * @param start The start element in the array.
|
---|
992 | * @param count The number of characters to read from the array.
|
---|
993 | *
|
---|
994 | * @see ProjectHelper#addText(Project,Object,char[],int,int)
|
---|
995 | */
|
---|
996 | public void characters(char[] buf, int start, int count) {
|
---|
997 | wrapper.addText(buf, start, count);
|
---|
998 | }
|
---|
999 |
|
---|
1000 | /**
|
---|
1001 | * Handles the start of an element within this one.
|
---|
1002 | * This will always use a nested element handler.
|
---|
1003 | *
|
---|
1004 | * @param name The name of the element being started.
|
---|
1005 | * Will not be <code>null</code>.
|
---|
1006 | * @param attrs Attributes of the element being started.
|
---|
1007 | * Will not be <code>null</code>.
|
---|
1008 | *
|
---|
1009 | * @exception SAXParseException if an error occurs when initialising
|
---|
1010 | * the child handler
|
---|
1011 | */
|
---|
1012 | public void startElement(String name, AttributeList attrs) throws SAXParseException {
|
---|
1013 | new NestedElementHandler(helperImpl, this, element, wrapper, target).init(name, attrs);
|
---|
1014 | }
|
---|
1015 | }
|
---|
1016 |
|
---|
1017 | /**
|
---|
1018 | * Scans an attribute list for the <code>id</code> attribute and
|
---|
1019 | * stores a reference to the target object in the project if an
|
---|
1020 | * id is found.
|
---|
1021 | * <p>
|
---|
1022 | * This method was moved out of the configure method to allow
|
---|
1023 | * it to be executed at parse time.
|
---|
1024 | *
|
---|
1025 | * @see #configure(Object,AttributeList,Project)
|
---|
1026 | */
|
---|
1027 | private void configureId(Object target, AttributeList attr) {
|
---|
1028 | String id = attr.getValue("id");
|
---|
1029 | if (id != null) {
|
---|
1030 | project.addReference(id, target);
|
---|
1031 | }
|
---|
1032 | }
|
---|
1033 | }
|
---|