1 | /*
|
---|
2 | * Copyright 2000-2005 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.InputStream;
|
---|
24 | import java.io.IOException;
|
---|
25 | import java.io.UnsupportedEncodingException;
|
---|
26 | import java.net.URL;
|
---|
27 | import java.util.HashMap;
|
---|
28 | import java.util.Hashtable;
|
---|
29 | import java.util.Map;
|
---|
30 | import java.util.Stack;
|
---|
31 |
|
---|
32 | import org.xml.sax.Locator;
|
---|
33 | import org.xml.sax.InputSource;
|
---|
34 | import org.xml.sax.SAXParseException;
|
---|
35 | import org.xml.sax.SAXException;
|
---|
36 | import org.xml.sax.Attributes;
|
---|
37 | import org.xml.sax.helpers.DefaultHandler;
|
---|
38 |
|
---|
39 | import org.apache.tools.ant.util.JAXPUtils;
|
---|
40 | import org.apache.tools.ant.util.FileUtils;
|
---|
41 |
|
---|
42 | import org.apache.tools.ant.ProjectHelper;
|
---|
43 | import org.apache.tools.ant.Project;
|
---|
44 | import org.apache.tools.ant.Target;
|
---|
45 | import org.apache.tools.ant.Task;
|
---|
46 | import org.apache.tools.ant.RuntimeConfigurable;
|
---|
47 | import org.apache.tools.ant.BuildException;
|
---|
48 | import org.apache.tools.ant.Location;
|
---|
49 | import org.apache.tools.ant.UnknownElement;
|
---|
50 |
|
---|
51 | import org.xml.sax.XMLReader;
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * Sax2 based project reader
|
---|
55 | *
|
---|
56 | */
|
---|
57 | public class ProjectHelper2 extends ProjectHelper {
|
---|
58 | /* Stateless */
|
---|
59 |
|
---|
60 | // singletons - since all state is in the context
|
---|
61 | private static AntHandler elementHandler = new ElementHandler();
|
---|
62 | private static AntHandler targetHandler = new TargetHandler();
|
---|
63 | private static AntHandler mainHandler = new MainHandler();
|
---|
64 | private static AntHandler projectHandler = new ProjectHandler();
|
---|
65 |
|
---|
66 | /**
|
---|
67 | * helper for path -> URI and URI -> path conversions.
|
---|
68 | */
|
---|
69 | private static FileUtils fu = FileUtils.newFileUtils();
|
---|
70 |
|
---|
71 | /**
|
---|
72 | * Parse an unknown element from a url
|
---|
73 | *
|
---|
74 | * @param project the current project
|
---|
75 | * @param source the url containing the task
|
---|
76 | * @return a configured task
|
---|
77 | * @exception BuildException if an error occurs
|
---|
78 | */
|
---|
79 | public UnknownElement parseUnknownElement(Project project, URL source)
|
---|
80 | throws BuildException {
|
---|
81 | Target dummyTarget = new Target();
|
---|
82 | dummyTarget.setProject(project);
|
---|
83 |
|
---|
84 | AntXMLContext context = new AntXMLContext(project);
|
---|
85 | context.addTarget(dummyTarget);
|
---|
86 | context.setImplicitTarget(dummyTarget);
|
---|
87 |
|
---|
88 | parse(context.getProject(), source,
|
---|
89 | new RootHandler(context, elementHandler));
|
---|
90 | Task[] tasks = dummyTarget.getTasks();
|
---|
91 | if (tasks.length != 1) {
|
---|
92 | throw new BuildException("No tasks defined");
|
---|
93 | }
|
---|
94 | return (UnknownElement) tasks[0];
|
---|
95 | }
|
---|
96 | /**
|
---|
97 | * Parse a source xml input.
|
---|
98 | *
|
---|
99 | * @param project the current project
|
---|
100 | * @param source the xml source
|
---|
101 | * @exception BuildException if an error occurs
|
---|
102 | */
|
---|
103 | public void parse(Project project, Object source)
|
---|
104 | throws BuildException {
|
---|
105 | getImportStack().addElement(source);
|
---|
106 | //System.out.println("Adding " + source);
|
---|
107 | AntXMLContext context = null;
|
---|
108 | context = (AntXMLContext) project.getReference("ant.parsing.context");
|
---|
109 | // System.out.println("Parsing " + getImportStack().size() + " " +
|
---|
110 | // context+ " " + getImportStack() );
|
---|
111 | if (context == null) {
|
---|
112 | context = new AntXMLContext(project);
|
---|
113 | project.addReference("ant.parsing.context", context);
|
---|
114 | project.addReference("ant.targets", context.getTargets());
|
---|
115 | }
|
---|
116 |
|
---|
117 | if (getImportStack().size() > 1) {
|
---|
118 | // we are in an imported file.
|
---|
119 | context.setIgnoreProjectTag(true);
|
---|
120 | Target currentTarget = context.getCurrentTarget();
|
---|
121 | Target currentImplicit = context.getImplicitTarget();
|
---|
122 | Map currentTargets = context.getCurrentTargets();
|
---|
123 | try {
|
---|
124 | Target newCurrent = new Target();
|
---|
125 | newCurrent.setProject(project);
|
---|
126 | newCurrent.setName("");
|
---|
127 | context.setCurrentTarget(newCurrent);
|
---|
128 | context.setCurrentTargets(new HashMap());
|
---|
129 | context.setImplicitTarget(newCurrent);
|
---|
130 | parse(project, source, new RootHandler(context, mainHandler));
|
---|
131 | newCurrent.execute();
|
---|
132 | } finally {
|
---|
133 | context.setCurrentTarget(currentTarget);
|
---|
134 | context.setImplicitTarget(currentImplicit);
|
---|
135 | context.setCurrentTargets(currentTargets);
|
---|
136 | }
|
---|
137 | } else {
|
---|
138 | // top level file
|
---|
139 | context.setCurrentTargets(new HashMap());
|
---|
140 | parse(project, source, new RootHandler(context, mainHandler));
|
---|
141 | // Execute the top-level target
|
---|
142 | context.getImplicitTarget().execute();
|
---|
143 | }
|
---|
144 | }
|
---|
145 |
|
---|
146 | /**
|
---|
147 | * Parses the project file, configuring the project as it goes.
|
---|
148 | *
|
---|
149 | * @param project the current project
|
---|
150 | * @param source the xml source
|
---|
151 | * @param handler the root handler to use (contains the current context)
|
---|
152 | * @exception BuildException if the configuration is invalid or cannot
|
---|
153 | * be read
|
---|
154 | */
|
---|
155 | public void parse(Project project, Object source, RootHandler handler)
|
---|
156 | throws BuildException {
|
---|
157 |
|
---|
158 | AntXMLContext context = handler.context;
|
---|
159 |
|
---|
160 | File buildFile = null;
|
---|
161 | URL url = null;
|
---|
162 | String buildFileName = null;
|
---|
163 |
|
---|
164 | if (source instanceof File) {
|
---|
165 | buildFile = (File) source;
|
---|
166 | buildFile = fu.normalize(buildFile.getAbsolutePath());
|
---|
167 | context.setBuildFile(buildFile);
|
---|
168 | buildFileName = buildFile.toString();
|
---|
169 | // } else if (source instanceof InputStream ) {
|
---|
170 | } else if (source instanceof URL) {
|
---|
171 | if (handler.getCurrentAntHandler() != elementHandler) {
|
---|
172 | throw new BuildException(
|
---|
173 | "Source " + source.getClass().getName()
|
---|
174 | + " not supported by this plugin for "
|
---|
175 | + " non task xml");
|
---|
176 | }
|
---|
177 | url = (URL) source;
|
---|
178 | buildFileName = url.toString();
|
---|
179 | // } else if (source instanceof InputSource ) {
|
---|
180 | } else {
|
---|
181 | throw new BuildException("Source " + source.getClass().getName()
|
---|
182 | + " not supported by this plugin");
|
---|
183 | }
|
---|
184 |
|
---|
185 | InputStream inputStream = null;
|
---|
186 | InputSource inputSource = null;
|
---|
187 |
|
---|
188 |
|
---|
189 | try {
|
---|
190 | /**
|
---|
191 | * SAX 2 style parser used to parse the given file.
|
---|
192 | */
|
---|
193 | XMLReader parser = JAXPUtils.getNamespaceXMLReader();
|
---|
194 |
|
---|
195 | String uri = null;
|
---|
196 | if (buildFile != null) {
|
---|
197 | uri = fu.toURI(buildFile.getAbsolutePath());
|
---|
198 | inputStream = new FileInputStream(buildFile);
|
---|
199 | } else {
|
---|
200 | inputStream = url.openStream();
|
---|
201 | uri = url.toString(); // ?? OK ??
|
---|
202 | }
|
---|
203 |
|
---|
204 | inputSource = new InputSource(inputStream);
|
---|
205 | if (uri != null) {
|
---|
206 | inputSource.setSystemId(uri);
|
---|
207 | }
|
---|
208 | project.log("parsing buildfile " + buildFileName
|
---|
209 | + " with URI = " + uri, Project.MSG_VERBOSE);
|
---|
210 |
|
---|
211 | DefaultHandler hb = handler;
|
---|
212 |
|
---|
213 | parser.setContentHandler(hb);
|
---|
214 | parser.setEntityResolver(hb);
|
---|
215 | parser.setErrorHandler(hb);
|
---|
216 | parser.setDTDHandler(hb);
|
---|
217 | parser.parse(inputSource);
|
---|
218 | } catch (SAXParseException exc) {
|
---|
219 | Location location = new Location(exc.getSystemId(),
|
---|
220 | exc.getLineNumber(), exc.getColumnNumber());
|
---|
221 |
|
---|
222 | Throwable t = exc.getException();
|
---|
223 | if (t instanceof BuildException) {
|
---|
224 | BuildException be = (BuildException) t;
|
---|
225 | if (be.getLocation() == Location.UNKNOWN_LOCATION) {
|
---|
226 | be.setLocation(location);
|
---|
227 | }
|
---|
228 | throw be;
|
---|
229 | } else if (t == null) {
|
---|
230 | t = exc;
|
---|
231 | }
|
---|
232 |
|
---|
233 | throw new BuildException(exc.getMessage(), t, location);
|
---|
234 | } catch (SAXException exc) {
|
---|
235 | Throwable t = exc.getException();
|
---|
236 | if (t instanceof BuildException) {
|
---|
237 | throw (BuildException) t;
|
---|
238 | } else if (t == null) {
|
---|
239 | t = exc;
|
---|
240 | }
|
---|
241 | throw new BuildException(exc.getMessage(), t);
|
---|
242 | } catch (FileNotFoundException exc) {
|
---|
243 | throw new BuildException(exc);
|
---|
244 | } catch (UnsupportedEncodingException exc) {
|
---|
245 | throw new BuildException("Encoding of project file "
|
---|
246 | + buildFileName + " is invalid.",
|
---|
247 | exc);
|
---|
248 | } catch (IOException exc) {
|
---|
249 | throw new BuildException("Error reading project file "
|
---|
250 | + buildFileName + ": " + exc.getMessage(),
|
---|
251 | exc);
|
---|
252 | } finally {
|
---|
253 | if (inputStream != null) {
|
---|
254 | try {
|
---|
255 | inputStream.close();
|
---|
256 | } catch (IOException ioe) {
|
---|
257 | // ignore this
|
---|
258 | }
|
---|
259 | }
|
---|
260 | }
|
---|
261 | }
|
---|
262 |
|
---|
263 | /**
|
---|
264 | * The common superclass for all SAX event handlers used to parse
|
---|
265 | * the configuration file.
|
---|
266 | *
|
---|
267 | * The context will hold all state information. At each time
|
---|
268 | * there is one active handler for the current element. It can
|
---|
269 | * use onStartChild() to set an alternate handler for the child.
|
---|
270 | */
|
---|
271 | public static class AntHandler {
|
---|
272 | /**
|
---|
273 | * Handles the start of an element. This base implementation does
|
---|
274 | * nothing.
|
---|
275 | *
|
---|
276 | * @param uri the namespace URI for the tag
|
---|
277 | * @param tag The name of the element being started.
|
---|
278 | * Will not be <code>null</code>.
|
---|
279 | * @param qname The qualified name of the element.
|
---|
280 | * @param attrs Attributes of the element being started.
|
---|
281 | * Will not be <code>null</code>.
|
---|
282 | * @param context The context that this element is in.
|
---|
283 | *
|
---|
284 | * @exception SAXParseException if this method is not overridden, or in
|
---|
285 | * case of error in an overridden version
|
---|
286 | */
|
---|
287 | public void onStartElement(String uri, String tag, String qname,
|
---|
288 | Attributes attrs,
|
---|
289 | AntXMLContext context)
|
---|
290 | throws SAXParseException {
|
---|
291 | }
|
---|
292 |
|
---|
293 | /**
|
---|
294 | * Handles the start of an element. This base implementation just
|
---|
295 | * throws an exception - you must override this method if you expect
|
---|
296 | * child elements.
|
---|
297 | *
|
---|
298 | * @param uri The namespace uri for this element.
|
---|
299 | * @param tag The name of the element being started.
|
---|
300 | * Will not be <code>null</code>.
|
---|
301 | * @param qname The qualified name for this element.
|
---|
302 | * @param attrs Attributes of the element being started.
|
---|
303 | * Will not be <code>null</code>.
|
---|
304 | * @param context The current context.
|
---|
305 | * @return a handler (in the derived classes)
|
---|
306 | *
|
---|
307 | * @exception SAXParseException if this method is not overridden, or in
|
---|
308 | * case of error in an overridden version
|
---|
309 | */
|
---|
310 | public AntHandler onStartChild(String uri, String tag, String qname,
|
---|
311 | Attributes attrs,
|
---|
312 | AntXMLContext context)
|
---|
313 | throws SAXParseException {
|
---|
314 | throw new SAXParseException("Unexpected element \"" + qname
|
---|
315 | + " \"", context.getLocator());
|
---|
316 | }
|
---|
317 |
|
---|
318 | /**
|
---|
319 | * Handle the end of a element.
|
---|
320 | *
|
---|
321 | * @param uri the namespace uri of the element
|
---|
322 | * @param tag the tag of the element
|
---|
323 | * @param qname the qualified name of the element
|
---|
324 | * @param context the current context
|
---|
325 | * @exception SAXParseException if an error occurs
|
---|
326 | */
|
---|
327 | public void onEndChild(String uri, String tag, String qname,
|
---|
328 | AntXMLContext context)
|
---|
329 | throws SAXParseException {
|
---|
330 | }
|
---|
331 |
|
---|
332 | /**
|
---|
333 | * This method is called when this element and all elements nested into it have been
|
---|
334 | * handled. I.e., this happens at the </end_tag_of_the_element>.
|
---|
335 | * @param uri the namespace uri for this element
|
---|
336 | * @param tag the element name
|
---|
337 | * @param context the current context
|
---|
338 | */
|
---|
339 | public void onEndElement(String uri, String tag,
|
---|
340 | AntXMLContext context) {
|
---|
341 | }
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * Handles text within an element. This base implementation just
|
---|
345 | * throws an exception, you must override it if you expect content.
|
---|
346 | *
|
---|
347 | * @param buf A character array of the text within the element.
|
---|
348 | * Will not be <code>null</code>.
|
---|
349 | * @param start The start element in the array.
|
---|
350 | * @param count The number of characters to read from the array.
|
---|
351 | * @param context The current context.
|
---|
352 | *
|
---|
353 | * @exception SAXParseException if this method is not overridden, or in
|
---|
354 | * case of error in an overridden version
|
---|
355 | */
|
---|
356 | public void characters(char[] buf, int start, int count, AntXMLContext context)
|
---|
357 | throws SAXParseException {
|
---|
358 | String s = new String(buf, start, count).trim();
|
---|
359 |
|
---|
360 | if (s.length() > 0) {
|
---|
361 | throw new SAXParseException("Unexpected text \"" + s
|
---|
362 | + "\"", context.getLocator());
|
---|
363 | }
|
---|
364 | }
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Will be called every time a namespace is reached.
|
---|
368 | * It'll verify if the ns was processed, and if not load the task
|
---|
369 | * definitions.
|
---|
370 | * @param uri The namespace uri.
|
---|
371 | */
|
---|
372 | protected void checkNamespace(String uri) {
|
---|
373 |
|
---|
374 | }
|
---|
375 | }
|
---|
376 |
|
---|
377 | /**
|
---|
378 | * Handler for ant processing. Uses a stack of AntHandlers to
|
---|
379 | * implement each element ( the original parser used a recursive behavior,
|
---|
380 | * with the implicit execution stack )
|
---|
381 | */
|
---|
382 | public static class RootHandler extends DefaultHandler {
|
---|
383 | private Stack antHandlers = new Stack();
|
---|
384 | private AntHandler currentHandler = null;
|
---|
385 | private AntXMLContext context;
|
---|
386 |
|
---|
387 | /**
|
---|
388 | * Creates a new RootHandler instance.
|
---|
389 | *
|
---|
390 | * @param context The context for the handler.
|
---|
391 | * @param rootHandler The handler for the root element.
|
---|
392 | */
|
---|
393 | public RootHandler(AntXMLContext context, AntHandler rootHandler) {
|
---|
394 | currentHandler = rootHandler;
|
---|
395 | antHandlers.push(currentHandler);
|
---|
396 | this.context = context;
|
---|
397 | }
|
---|
398 |
|
---|
399 | /**
|
---|
400 | * Returns the current ant handler object.
|
---|
401 | * @return the current ant handler.
|
---|
402 | */
|
---|
403 | public AntHandler getCurrentAntHandler() {
|
---|
404 | return currentHandler;
|
---|
405 | }
|
---|
406 |
|
---|
407 | /**
|
---|
408 | * Resolves file: URIs relative to the build file.
|
---|
409 | *
|
---|
410 | * @param publicId The public identifier, or <code>null</code>
|
---|
411 | * if none is available. Ignored in this
|
---|
412 | * implementation.
|
---|
413 | * @param systemId The system identifier provided in the XML
|
---|
414 | * document. Will not be <code>null</code>.
|
---|
415 | * @return an inputsource for this identifier
|
---|
416 | */
|
---|
417 | public InputSource resolveEntity(String publicId,
|
---|
418 | String systemId) {
|
---|
419 |
|
---|
420 | context.getProject().log("resolving systemId: "
|
---|
421 | + systemId, Project.MSG_VERBOSE);
|
---|
422 |
|
---|
423 | if (systemId.startsWith("file:")) {
|
---|
424 | String path = fu.fromURI(systemId);
|
---|
425 |
|
---|
426 | File file = new File(path);
|
---|
427 | if (!file.isAbsolute()) {
|
---|
428 | file = fu.resolveFile(context.getBuildFileParent(), path);
|
---|
429 | }
|
---|
430 | try {
|
---|
431 | InputSource inputSource =
|
---|
432 | new InputSource(new FileInputStream(file));
|
---|
433 | inputSource.setSystemId(fu.toURI(file.getAbsolutePath()));
|
---|
434 | return inputSource;
|
---|
435 | } catch (FileNotFoundException fne) {
|
---|
436 | context.getProject().log(file.getAbsolutePath()
|
---|
437 | + " could not be found", Project.MSG_WARN);
|
---|
438 | }
|
---|
439 |
|
---|
440 | }
|
---|
441 | // use default if not file or file not found
|
---|
442 | return null;
|
---|
443 | }
|
---|
444 |
|
---|
445 | /**
|
---|
446 | * Handles the start of a project element. A project handler is created
|
---|
447 | * and initialised with the element name and attributes.
|
---|
448 | *
|
---|
449 | * @param uri The namespace uri for this element.
|
---|
450 | * @param tag The name of the element being started.
|
---|
451 | * Will not be <code>null</code>.
|
---|
452 | * @param qname The qualified name for this element.
|
---|
453 | * @param attrs Attributes of the element being started.
|
---|
454 | * Will not be <code>null</code>.
|
---|
455 | *
|
---|
456 | * @exception org.xml.sax.SAXParseException if the tag given is not
|
---|
457 | * <code>"project"</code>
|
---|
458 | */
|
---|
459 | public void startElement(String uri, String tag, String qname, Attributes attrs)
|
---|
460 | throws SAXParseException {
|
---|
461 | AntHandler next
|
---|
462 | = currentHandler.onStartChild(uri, tag, qname, attrs, context);
|
---|
463 | antHandlers.push(currentHandler);
|
---|
464 | currentHandler = next;
|
---|
465 | currentHandler.onStartElement(uri, tag, qname, attrs, context);
|
---|
466 | }
|
---|
467 |
|
---|
468 | /**
|
---|
469 | * Sets the locator in the project helper for future reference.
|
---|
470 | *
|
---|
471 | * @param locator The locator used by the parser.
|
---|
472 | * Will not be <code>null</code>.
|
---|
473 | */
|
---|
474 | public void setDocumentLocator(Locator locator) {
|
---|
475 | context.setLocator(locator);
|
---|
476 | }
|
---|
477 |
|
---|
478 | /**
|
---|
479 | * Handles the end of an element. Any required clean-up is performed
|
---|
480 | * by the onEndElement() method and then the original handler
|
---|
481 | * is restored to the parser.
|
---|
482 | *
|
---|
483 | * @param uri The namespace URI for this element.
|
---|
484 | * @param name The name of the element which is ending.
|
---|
485 | * Will not be <code>null</code>.
|
---|
486 | * @param qName The qualified name for this element.
|
---|
487 | *
|
---|
488 | * @exception SAXException in case of error (not thrown in
|
---|
489 | * this implementation)
|
---|
490 | *
|
---|
491 | */
|
---|
492 | public void endElement(String uri, String name, String qName) throws SAXException {
|
---|
493 | currentHandler.onEndElement(uri, name, context);
|
---|
494 | AntHandler prev = (AntHandler) antHandlers.pop();
|
---|
495 | currentHandler = prev;
|
---|
496 | if (currentHandler != null) {
|
---|
497 | currentHandler.onEndChild(uri, name, qName, context);
|
---|
498 | }
|
---|
499 | }
|
---|
500 |
|
---|
501 | /**
|
---|
502 | * Handle text within an element, calls currentHandler.characters.
|
---|
503 | *
|
---|
504 | * @param buf A character array of the test.
|
---|
505 | * @param start The start offset in the array.
|
---|
506 | * @param count The number of characters to read.
|
---|
507 | * @exception SAXParseException if an error occurs
|
---|
508 | */
|
---|
509 | public void characters(char[] buf, int start, int count)
|
---|
510 | throws SAXParseException {
|
---|
511 | currentHandler.characters(buf, start, count, context);
|
---|
512 | }
|
---|
513 |
|
---|
514 | /**
|
---|
515 | * Start a namespace prefix to uri mapping
|
---|
516 | *
|
---|
517 | * @param prefix the namespace prefix
|
---|
518 | * @param uri the namespace uri
|
---|
519 | */
|
---|
520 | public void startPrefixMapping(String prefix, String uri) {
|
---|
521 | context.startPrefixMapping(prefix, uri);
|
---|
522 | }
|
---|
523 |
|
---|
524 | /**
|
---|
525 | * End a namepace prefix to uri mapping
|
---|
526 | *
|
---|
527 | * @param prefix the prefix that is not mapped anymore
|
---|
528 | */
|
---|
529 | public void endPrefixMapping(String prefix) {
|
---|
530 | context.endPrefixMapping(prefix);
|
---|
531 | }
|
---|
532 | }
|
---|
533 |
|
---|
534 | /**
|
---|
535 | * The main handler - it handles the <project> tag.
|
---|
536 | *
|
---|
537 | * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
|
---|
538 | */
|
---|
539 | public static class MainHandler extends AntHandler {
|
---|
540 |
|
---|
541 | /**
|
---|
542 | * Handle the project tag
|
---|
543 | *
|
---|
544 | * @param uri The namespace uri.
|
---|
545 | * @param name The element tag.
|
---|
546 | * @param qname The element qualified name.
|
---|
547 | * @param attrs The attributes of the element.
|
---|
548 | * @param context The current context.
|
---|
549 | * @return The project handler that handles subelements of project
|
---|
550 | * @exception SAXParseException if the qualified name is not "project".
|
---|
551 | */
|
---|
552 | public AntHandler onStartChild(String uri, String name, String qname,
|
---|
553 | Attributes attrs,
|
---|
554 | AntXMLContext context)
|
---|
555 | throws SAXParseException {
|
---|
556 | if (name.equals("project")
|
---|
557 | && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
|
---|
558 | return ProjectHelper2.projectHandler;
|
---|
559 | } else {
|
---|
560 | // if (context.importlevel > 0) {
|
---|
561 | // // we are in an imported file. Allow top-level <target>.
|
---|
562 | // if (qname.equals( "target" ) )
|
---|
563 | // return ProjectHelper2.targetHandler;
|
---|
564 | // }
|
---|
565 | if (name.equals(qname)) {
|
---|
566 | throw new SAXParseException("Unexpected element \"{" + uri
|
---|
567 | + "}" + name + "\" {" + ANT_CORE_URI + "}" + name,
|
---|
568 | context.getLocator());
|
---|
569 | } else {
|
---|
570 | throw new SAXParseException("Unexpected element \"" + qname
|
---|
571 | + "\" " + name, context.getLocator());
|
---|
572 | }
|
---|
573 | }
|
---|
574 | }
|
---|
575 | }
|
---|
576 |
|
---|
577 | /**
|
---|
578 | * Handler for the top level "project" element.
|
---|
579 | */
|
---|
580 | public static class ProjectHandler extends AntHandler {
|
---|
581 |
|
---|
582 | /**
|
---|
583 | * Initialisation routine called after handler creation
|
---|
584 | * with the element name and attributes. The attributes which
|
---|
585 | * this handler can deal with are: <code>"default"</code>,
|
---|
586 | * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
|
---|
587 | *
|
---|
588 | * @param uri The namespace URI for this element.
|
---|
589 | * @param tag Name of the element which caused this handler
|
---|
590 | * to be created. Should not be <code>null</code>.
|
---|
591 | * Ignored in this implementation.
|
---|
592 | * @param qname The qualified name for this element.
|
---|
593 | * @param attrs Attributes of the element which caused this
|
---|
594 | * handler to be created. Must not be <code>null</code>.
|
---|
595 | * @param context The current context.
|
---|
596 | *
|
---|
597 | * @exception SAXParseException if an unexpected attribute is
|
---|
598 | * encountered or if the <code>"default"</code> attribute
|
---|
599 | * is missing.
|
---|
600 | */
|
---|
601 | public void onStartElement(String uri, String tag, String qname,
|
---|
602 | Attributes attrs,
|
---|
603 | AntXMLContext context)
|
---|
604 | throws SAXParseException {
|
---|
605 | String id = null;
|
---|
606 | String baseDir = null;
|
---|
607 | boolean nameAttributeSet = false;
|
---|
608 |
|
---|
609 | Project project = context.getProject();
|
---|
610 | // Set the location of the implicit target associated with the project tag
|
---|
611 | context.getImplicitTarget().setLocation(
|
---|
612 | new Location(context.getLocator()));
|
---|
613 |
|
---|
614 | /** XXX I really don't like this - the XML processor is still
|
---|
615 | * too 'involved' in the processing. A better solution (IMO)
|
---|
616 | * would be to create UE for Project and Target too, and
|
---|
617 | * then process the tree and have Project/Target deal with
|
---|
618 | * its attributes ( similar with Description ).
|
---|
619 | *
|
---|
620 | * If we eventually switch to ( or add support for ) DOM,
|
---|
621 | * things will work smoothly - UE can be avoided almost completely
|
---|
622 | * ( it could still be created on demand, for backward compatibility )
|
---|
623 | */
|
---|
624 |
|
---|
625 | for (int i = 0; i < attrs.getLength(); i++) {
|
---|
626 | String attrUri = attrs.getURI(i);
|
---|
627 | if (attrUri != null
|
---|
628 | && !attrUri.equals("")
|
---|
629 | && !attrUri.equals(uri)) {
|
---|
630 | continue; // Ignore attributes from unknown uris
|
---|
631 | }
|
---|
632 | String key = attrs.getLocalName(i);
|
---|
633 | String value = attrs.getValue(i);
|
---|
634 |
|
---|
635 | if (key.equals("default")) {
|
---|
636 | if (value != null && !value.equals("")) {
|
---|
637 | if (!context.isIgnoringProjectTag()) {
|
---|
638 | project.setDefault(value);
|
---|
639 | }
|
---|
640 | }
|
---|
641 | } else if (key.equals("name")) {
|
---|
642 | if (value != null) {
|
---|
643 | context.setCurrentProjectName(value);
|
---|
644 | nameAttributeSet = true;
|
---|
645 | if (!context.isIgnoringProjectTag()) {
|
---|
646 | project.setName(value);
|
---|
647 | project.addReference(value, project);
|
---|
648 | }
|
---|
649 | }
|
---|
650 | } else if (key.equals("id")) {
|
---|
651 | if (value != null) {
|
---|
652 | // What's the difference between id and name ?
|
---|
653 | if (!context.isIgnoringProjectTag()) {
|
---|
654 | project.addReference(value, project);
|
---|
655 | }
|
---|
656 | }
|
---|
657 | } else if (key.equals("basedir")) {
|
---|
658 | if (!context.isIgnoringProjectTag()) {
|
---|
659 | baseDir = value;
|
---|
660 | }
|
---|
661 | } else {
|
---|
662 | // XXX ignore attributes in a different NS ( maybe store them ? )
|
---|
663 | throw new SAXParseException("Unexpected attribute \""
|
---|
664 | + attrs.getQName(i) + "\"", context.getLocator());
|
---|
665 | }
|
---|
666 | }
|
---|
667 |
|
---|
668 | // XXX Move to Project ( so it is shared by all helpers )
|
---|
669 | String antFileProp = "ant.file." + context.getCurrentProjectName();
|
---|
670 | String dup = project.getProperty(antFileProp);
|
---|
671 | if (dup != null && nameAttributeSet) {
|
---|
672 | File dupFile = new File(dup);
|
---|
673 | if (context.isIgnoringProjectTag()
|
---|
674 | && !dupFile.equals(context.getBuildFile())) {
|
---|
675 | project.log("Duplicated project name in import. Project "
|
---|
676 | + context.getCurrentProjectName() + " defined first in "
|
---|
677 | + dup + " and again in " + context.getBuildFile(),
|
---|
678 | Project.MSG_WARN);
|
---|
679 | }
|
---|
680 | }
|
---|
681 |
|
---|
682 | if (context.getBuildFile() != null) {
|
---|
683 | project.setUserProperty("ant.file."
|
---|
684 | + context.getCurrentProjectName(),
|
---|
685 | context.getBuildFile().toString());
|
---|
686 | }
|
---|
687 |
|
---|
688 | if (context.isIgnoringProjectTag()) {
|
---|
689 | // no further processing
|
---|
690 | return;
|
---|
691 | }
|
---|
692 | // set explicitly before starting ?
|
---|
693 | if (project.getProperty("basedir") != null) {
|
---|
694 | project.setBasedir(project.getProperty("basedir"));
|
---|
695 | } else {
|
---|
696 | // Default for baseDir is the location of the build file.
|
---|
697 | if (baseDir == null) {
|
---|
698 | project.setBasedir(context.getBuildFileParent().getAbsolutePath());
|
---|
699 | } else {
|
---|
700 | // check whether the user has specified an absolute path
|
---|
701 | if ((new File(baseDir)).isAbsolute()) {
|
---|
702 | project.setBasedir(baseDir);
|
---|
703 | } else {
|
---|
704 | project.setBaseDir(fu.resolveFile(
|
---|
705 | context.getBuildFileParent(), baseDir));
|
---|
706 | }
|
---|
707 | }
|
---|
708 | }
|
---|
709 |
|
---|
710 | project.addTarget("", context.getImplicitTarget());
|
---|
711 | context.setCurrentTarget(context.getImplicitTarget());
|
---|
712 | }
|
---|
713 |
|
---|
714 | /**
|
---|
715 | * Handles the start of a top-level element within the project. An
|
---|
716 | * appropriate handler is created and initialised with the details
|
---|
717 | * of the element.
|
---|
718 | *
|
---|
719 | * @param uri The namespace URI for this element.
|
---|
720 | * @param name The name of the element being started.
|
---|
721 | * Will not be <code>null</code>.
|
---|
722 | * @param qname The qualified name for this element.
|
---|
723 | * @param attrs Attributes of the element being started.
|
---|
724 | * Will not be <code>null</code>.
|
---|
725 | * @param context The context for this element.
|
---|
726 | * @return a target or an element handler.
|
---|
727 | *
|
---|
728 | * @exception org.xml.sax.SAXParseException if the tag given is not
|
---|
729 | * <code>"taskdef"</code>, <code>"typedef"</code>,
|
---|
730 | * <code>"property"</code>, <code>"target"</code>
|
---|
731 | * or a data type definition
|
---|
732 | */
|
---|
733 | public AntHandler onStartChild(String uri, String name, String qname,
|
---|
734 | Attributes attrs,
|
---|
735 | AntXMLContext context)
|
---|
736 | throws SAXParseException {
|
---|
737 | if (name.equals("target")
|
---|
738 | && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
|
---|
739 | return ProjectHelper2.targetHandler;
|
---|
740 | } else {
|
---|
741 | return ProjectHelper2.elementHandler;
|
---|
742 | }
|
---|
743 | }
|
---|
744 |
|
---|
745 | }
|
---|
746 |
|
---|
747 | /**
|
---|
748 | * Handler for "target" elements.
|
---|
749 | */
|
---|
750 | public static class TargetHandler extends AntHandler {
|
---|
751 |
|
---|
752 | /**
|
---|
753 | * Initialisation routine called after handler creation
|
---|
754 | * with the element name and attributes. The attributes which
|
---|
755 | * this handler can deal with are: <code>"name"</code>,
|
---|
756 | * <code>"depends"</code>, <code>"if"</code>,
|
---|
757 | * <code>"unless"</code>, <code>"id"</code> and
|
---|
758 | * <code>"description"</code>.
|
---|
759 | *
|
---|
760 | * @param uri The namespace URI for this element.
|
---|
761 | * @param tag Name of the element which caused this handler
|
---|
762 | * to be created. Should not be <code>null</code>.
|
---|
763 | * Ignored in this implementation.
|
---|
764 | * @param qname The qualified name for this element.
|
---|
765 | * @param attrs Attributes of the element which caused this
|
---|
766 | * handler to be created. Must not be <code>null</code>.
|
---|
767 | * @param context The current context.
|
---|
768 | *
|
---|
769 | * @exception SAXParseException if an unexpected attribute is encountered
|
---|
770 | * or if the <code>"name"</code> attribute is missing.
|
---|
771 | */
|
---|
772 | public void onStartElement(String uri, String tag, String qname,
|
---|
773 | Attributes attrs,
|
---|
774 | AntXMLContext context)
|
---|
775 | throws SAXParseException {
|
---|
776 | String name = null;
|
---|
777 | String depends = "";
|
---|
778 |
|
---|
779 | Project project = context.getProject();
|
---|
780 | Target target = new Target();
|
---|
781 | target.setProject(project);
|
---|
782 | target.setLocation(new Location(context.getLocator()));
|
---|
783 | context.addTarget(target);
|
---|
784 |
|
---|
785 | for (int i = 0; i < attrs.getLength(); i++) {
|
---|
786 | String attrUri = attrs.getURI(i);
|
---|
787 | if (attrUri != null
|
---|
788 | && !attrUri.equals("")
|
---|
789 | && !attrUri.equals(uri)) {
|
---|
790 | continue; // Ignore attributes from unknown uris
|
---|
791 | }
|
---|
792 | String key = attrs.getLocalName(i);
|
---|
793 | String value = attrs.getValue(i);
|
---|
794 |
|
---|
795 | if (key.equals("name")) {
|
---|
796 | name = value;
|
---|
797 | if ("".equals(name)) {
|
---|
798 | throw new BuildException("name attribute must "
|
---|
799 | + "not be empty");
|
---|
800 | }
|
---|
801 | } else if (key.equals("depends")) {
|
---|
802 | depends = value;
|
---|
803 | } else if (key.equals("if")) {
|
---|
804 | target.setIf(value);
|
---|
805 | } else if (key.equals("unless")) {
|
---|
806 | target.setUnless(value);
|
---|
807 | } else if (key.equals("id")) {
|
---|
808 | if (value != null && !value.equals("")) {
|
---|
809 | context.getProject().addReference(value, target);
|
---|
810 | }
|
---|
811 | } else if (key.equals("description")) {
|
---|
812 | target.setDescription(value);
|
---|
813 | } else if (key.equals("address")) {
|
---|
814 | target.setAddress(value);
|
---|
815 | } else {
|
---|
816 | throw new SAXParseException("Unexpected attribute \""
|
---|
817 | + key + "\"", context.getLocator());
|
---|
818 | }
|
---|
819 | }
|
---|
820 |
|
---|
821 | if (name == null) {
|
---|
822 | throw new SAXParseException("target element appears without "
|
---|
823 | + "a name attribute", context.getLocator());
|
---|
824 | }
|
---|
825 |
|
---|
826 | Hashtable currentTargets = project.getTargets();
|
---|
827 |
|
---|
828 | // If the name has already been defined ( import for example )
|
---|
829 | if (currentTargets.containsKey(name)) {
|
---|
830 | if (context.getCurrentTargets().get(name) != null) {
|
---|
831 | throw new BuildException(
|
---|
832 | "Duplicate target '" + name + "'", target.getLocation());
|
---|
833 | }
|
---|
834 | // Alter the name.
|
---|
835 | if (context.getCurrentProjectName() != null) {
|
---|
836 | String newName = context.getCurrentProjectName()
|
---|
837 | + "." + name;
|
---|
838 | project.log("Already defined in main or a previous import, "
|
---|
839 | + "define " + name + " as " + newName,
|
---|
840 | Project.MSG_VERBOSE);
|
---|
841 | name = newName;
|
---|
842 | } else {
|
---|
843 | project.log("Already defined in main or a previous import, "
|
---|
844 | + "ignore " + name, Project.MSG_VERBOSE);
|
---|
845 | name = null;
|
---|
846 | }
|
---|
847 | }
|
---|
848 |
|
---|
849 | if (name != null) {
|
---|
850 | target.setName(name);
|
---|
851 | context.getCurrentTargets().put(name, target);
|
---|
852 | project.addOrReplaceTarget(name, target);
|
---|
853 | }
|
---|
854 |
|
---|
855 | // take care of dependencies
|
---|
856 | if (depends.length() > 0) {
|
---|
857 | target.setDepends(depends);
|
---|
858 | }
|
---|
859 | }
|
---|
860 |
|
---|
861 | /**
|
---|
862 | * Handles the start of an element within a target.
|
---|
863 | *
|
---|
864 | * @param uri The namespace URI for this element.
|
---|
865 | * @param name The name of the element being started.
|
---|
866 | * Will not be <code>null</code>.
|
---|
867 | * @param qname The qualified name for this element.
|
---|
868 | * @param attrs Attributes of the element being started.
|
---|
869 | * Will not be <code>null</code>.
|
---|
870 | * @param context The current context.
|
---|
871 | * @return an element handler.
|
---|
872 | *
|
---|
873 | * @exception SAXParseException if an error occurs when initialising
|
---|
874 | * the appropriate child handler
|
---|
875 | */
|
---|
876 | public AntHandler onStartChild(String uri, String name, String qname,
|
---|
877 | Attributes attrs,
|
---|
878 | AntXMLContext context)
|
---|
879 | throws SAXParseException {
|
---|
880 | return ProjectHelper2.elementHandler;
|
---|
881 | }
|
---|
882 |
|
---|
883 | /**
|
---|
884 | * Handle the end of the project, sets the current target of the
|
---|
885 | * context to be the implicit target.
|
---|
886 | *
|
---|
887 | * @param uri The namespace URI of the element.
|
---|
888 | * @param tag The name of the element.
|
---|
889 | * @param context The current context.
|
---|
890 | */
|
---|
891 | public void onEndElement(String uri, String tag, AntXMLContext context) {
|
---|
892 | context.setCurrentTarget(context.getImplicitTarget());
|
---|
893 | }
|
---|
894 | }
|
---|
895 |
|
---|
896 | /**
|
---|
897 | * Handler for all project elements ( tasks, data types )
|
---|
898 | */
|
---|
899 | public static class ElementHandler extends AntHandler {
|
---|
900 |
|
---|
901 | /**
|
---|
902 | * Constructor.
|
---|
903 | */
|
---|
904 | public ElementHandler() {
|
---|
905 | }
|
---|
906 |
|
---|
907 | /**
|
---|
908 | * Initialisation routine called after handler creation
|
---|
909 | * with the element name and attributes. This configures
|
---|
910 | * the element with its attributes and sets it up with
|
---|
911 | * its parent container (if any). Nested elements are then
|
---|
912 | * added later as the parser encounters them.
|
---|
913 | *
|
---|
914 | * @param uri The namespace URI for this element.
|
---|
915 | * @param tag Name of the element which caused this handler
|
---|
916 | * to be created. Must not be <code>null</code>.
|
---|
917 | * @param qname The qualified name for this element.
|
---|
918 | * @param attrs Attributes of the element which caused this
|
---|
919 | * handler to be created. Must not be <code>null</code>.
|
---|
920 | * @param context The current context.
|
---|
921 | *
|
---|
922 | * @exception SAXParseException in case of error (not thrown in
|
---|
923 | * this implementation)
|
---|
924 | */
|
---|
925 | public void onStartElement(String uri, String tag, String qname,
|
---|
926 | Attributes attrs,
|
---|
927 | AntXMLContext context)
|
---|
928 | throws SAXParseException {
|
---|
929 | RuntimeConfigurable parentWrapper = context.currentWrapper();
|
---|
930 | Object parent = null;
|
---|
931 |
|
---|
932 | if (parentWrapper != null) {
|
---|
933 | parent = parentWrapper.getProxy();
|
---|
934 | }
|
---|
935 |
|
---|
936 | /* UnknownElement is used for tasks and data types - with
|
---|
937 | delayed eval */
|
---|
938 | UnknownElement task = new UnknownElement(tag);
|
---|
939 | task.setProject(context.getProject());
|
---|
940 | task.setNamespace(uri);
|
---|
941 | task.setQName(qname);
|
---|
942 | task.setTaskType(
|
---|
943 | ProjectHelper.genComponentName(task.getNamespace(), tag));
|
---|
944 | task.setTaskName(qname);
|
---|
945 |
|
---|
946 | Location location = new Location(context.getLocator().getSystemId(),
|
---|
947 | context.getLocator().getLineNumber(),
|
---|
948 | context.getLocator().getColumnNumber());
|
---|
949 | task.setLocation(location);
|
---|
950 | task.setOwningTarget(context.getCurrentTarget());
|
---|
951 |
|
---|
952 | context.configureId(task, attrs);
|
---|
953 |
|
---|
954 | if (parent != null) {
|
---|
955 | // Nested element
|
---|
956 | ((UnknownElement) parent).addChild(task);
|
---|
957 | } else {
|
---|
958 | // Task included in a target ( including the default one ).
|
---|
959 | context.getCurrentTarget().addTask(task);
|
---|
960 | }
|
---|
961 |
|
---|
962 | // container.addTask(task);
|
---|
963 | // This is a nop in UE: task.init();
|
---|
964 |
|
---|
965 | RuntimeConfigurable wrapper
|
---|
966 | = new RuntimeConfigurable(task, task.getTaskName());
|
---|
967 |
|
---|
968 | for (int i = 0; i < attrs.getLength(); i++) {
|
---|
969 | String name = attrs.getLocalName(i);
|
---|
970 | String attrUri = attrs.getURI(i);
|
---|
971 | if (attrUri != null
|
---|
972 | && !attrUri.equals("")
|
---|
973 | && !attrUri.equals(uri)) {
|
---|
974 | name = attrUri + ":" + attrs.getQName(i);
|
---|
975 | }
|
---|
976 | String value = attrs.getValue(i);
|
---|
977 | // PR: Hack for ant-type value
|
---|
978 | // an ant-type is a component name which can
|
---|
979 | // be namespaced, need to extract the name
|
---|
980 | // and convert from qualified name to uri/name
|
---|
981 | if (ANT_TYPE.equals(name)
|
---|
982 | || (ANT_CORE_URI.equals(attrUri)
|
---|
983 | && ANT_TYPE.equals(attrs.getLocalName(i)))) {
|
---|
984 | name = ANT_TYPE;
|
---|
985 | int index = value.indexOf(":");
|
---|
986 | if (index != -1) {
|
---|
987 | String prefix = value.substring(0, index);
|
---|
988 | String mappedUri = context.getPrefixMapping(prefix);
|
---|
989 | if (mappedUri == null) {
|
---|
990 | throw new BuildException(
|
---|
991 | "Unable to find XML NS prefix " + prefix);
|
---|
992 | }
|
---|
993 | value = ProjectHelper.genComponentName(
|
---|
994 | mappedUri, value.substring(index + 1));
|
---|
995 | }
|
---|
996 | }
|
---|
997 | wrapper.setAttribute(name, value);
|
---|
998 | }
|
---|
999 |
|
---|
1000 | if (parentWrapper != null) {
|
---|
1001 | parentWrapper.addChild(wrapper);
|
---|
1002 | }
|
---|
1003 |
|
---|
1004 | context.pushWrapper(wrapper);
|
---|
1005 | }
|
---|
1006 |
|
---|
1007 | /**
|
---|
1008 | * Adds text to the task, using the wrapper
|
---|
1009 | *
|
---|
1010 | * @param buf A character array of the text within the element.
|
---|
1011 | * Will not be <code>null</code>.
|
---|
1012 | * @param start The start element in the array.
|
---|
1013 | * @param count The number of characters to read from the array.
|
---|
1014 | * @param context The current context.
|
---|
1015 | *
|
---|
1016 | * @exception SAXParseException if the element doesn't support text
|
---|
1017 | *
|
---|
1018 | * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
|
---|
1019 | */
|
---|
1020 | public void characters(char[] buf, int start, int count,
|
---|
1021 | AntXMLContext context)
|
---|
1022 | throws SAXParseException {
|
---|
1023 | RuntimeConfigurable wrapper = context.currentWrapper();
|
---|
1024 | wrapper.addText(buf, start, count);
|
---|
1025 | }
|
---|
1026 |
|
---|
1027 | /**
|
---|
1028 | * Handles the start of an element within a target. Task containers
|
---|
1029 | * will always use another task handler, and all other tasks
|
---|
1030 | * will always use a nested element handler.
|
---|
1031 | *
|
---|
1032 | * @param uri The namespace URI for this element.
|
---|
1033 | * @param tag The name of the element being started.
|
---|
1034 | * Will not be <code>null</code>.
|
---|
1035 | * @param qname The qualified name for this element.
|
---|
1036 | * @param attrs Attributes of the element being started.
|
---|
1037 | * Will not be <code>null</code>.
|
---|
1038 | * @param context The current context.
|
---|
1039 | * @return The handler for elements.
|
---|
1040 | *
|
---|
1041 | * @exception SAXParseException if an error occurs when initialising
|
---|
1042 | * the appropriate child handler
|
---|
1043 | */
|
---|
1044 | public AntHandler onStartChild(String uri, String tag, String qname,
|
---|
1045 | Attributes attrs,
|
---|
1046 | AntXMLContext context)
|
---|
1047 | throws SAXParseException {
|
---|
1048 | return ProjectHelper2.elementHandler;
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | /**
|
---|
1052 | * Handles the end of the element. This pops the wrapper from
|
---|
1053 | * the context.
|
---|
1054 | *
|
---|
1055 | * @param uri The namespace URI for the element.
|
---|
1056 | * @param tag The name of the element.
|
---|
1057 | * @param context The current context.
|
---|
1058 | */
|
---|
1059 | public void onEndElement(String uri, String tag, AntXMLContext context) {
|
---|
1060 | context.popWrapper();
|
---|
1061 | }
|
---|
1062 | }
|
---|
1063 | }
|
---|