source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/helper/ProjectHelper2.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 43.4 KB
Line 
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
18package org.apache.tools.ant.helper;
19
20import java.io.File;
21import java.io.FileInputStream;
22import java.io.FileNotFoundException;
23import java.io.InputStream;
24import java.io.IOException;
25import java.io.UnsupportedEncodingException;
26import java.net.URL;
27import java.util.HashMap;
28import java.util.Hashtable;
29import java.util.Map;
30import java.util.Stack;
31
32import org.xml.sax.Locator;
33import org.xml.sax.InputSource;
34import org.xml.sax.SAXParseException;
35import org.xml.sax.SAXException;
36import org.xml.sax.Attributes;
37import org.xml.sax.helpers.DefaultHandler;
38
39import org.apache.tools.ant.util.JAXPUtils;
40import org.apache.tools.ant.util.FileUtils;
41
42import org.apache.tools.ant.ProjectHelper;
43import org.apache.tools.ant.Project;
44import org.apache.tools.ant.Target;
45import org.apache.tools.ant.Task;
46import org.apache.tools.ant.RuntimeConfigurable;
47import org.apache.tools.ant.BuildException;
48import org.apache.tools.ant.Location;
49import org.apache.tools.ant.UnknownElement;
50
51import org.xml.sax.XMLReader;
52
53/**
54 * Sax2 based project reader
55 *
56 */
57public 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 &lt;/end_tag_of_the_element&gt;.
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 &lt;project&gt; 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}
Note: See TracBrowser for help on using the repository browser.