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

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

initial import of LiRK3

File size: 22.9 KB
Line 
1/*
2 * Copyright 2003-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.taskdefs;
19
20import java.util.ArrayList;
21import java.util.List;
22import java.util.Map;
23import java.util.Locale;
24import java.util.HashMap;
25import java.util.Iterator;
26
27import org.apache.tools.ant.AntTypeDefinition;
28import org.apache.tools.ant.BuildException;
29import org.apache.tools.ant.ComponentHelper;
30import org.apache.tools.ant.Project;
31import org.apache.tools.ant.ProjectHelper;
32import org.apache.tools.ant.RuntimeConfigurable;
33import org.apache.tools.ant.Task;
34import org.apache.tools.ant.TaskContainer;
35import org.apache.tools.ant.UnknownElement;
36
37/**
38 * Describe class <code>MacroDef</code> here.
39 *
40 * @since Ant 1.6
41 */
42public class MacroDef extends AntlibDefinition {
43 private NestedSequential nestedSequential;
44 private String name;
45 private List attributes = new ArrayList();
46 private Map elements = new HashMap();
47 private String textName = null;
48 private Text text = null;
49 private boolean hasImplicitElement = false;
50
51 /**
52 * Name of the definition
53 * @param name the name of the definition
54 */
55 public void setName(String name) {
56 this.name = name;
57 }
58
59 /**
60 * Add the text element.
61 * @param text the nested text element to add
62 * @since ant 1.6.1
63 */
64 public void addConfiguredText(Text text) {
65 if (this.text != null) {
66 throw new BuildException(
67 "Only one nested text element allowed");
68 }
69 if (text.getName() == null) {
70 throw new BuildException(
71 "the text nested element needed a \"name\" attribute");
72 }
73 // Check if used by attributes
74 for (Iterator i = attributes.iterator(); i.hasNext();) {
75 Attribute attribute = (Attribute) i.next();
76 if (text.getName().equals(attribute.getName())) {
77 throw new BuildException(
78 "the name \"" + text.getName()
79 + "\" is already used as an attribute");
80 }
81 }
82 this.text = text;
83 this.textName = text.getName();
84 }
85
86 /**
87 * @return the nested text element
88 * @since ant 1.6.1
89 */
90
91 public Text getText() {
92 return text;
93 }
94
95 /**
96 * This is the sequential nested element of the macrodef.
97 *
98 * @return a sequential element to be configured.
99 */
100 public NestedSequential createSequential() {
101 if (this.nestedSequential != null) {
102 throw new BuildException("Only one sequential allowed");
103 }
104 this.nestedSequential = new NestedSequential();
105 return this.nestedSequential;
106 }
107
108 /**
109 * The class corresponding to the sequential nested element.
110 * This is a simple task container.
111 */
112 public static class NestedSequential implements TaskContainer {
113 private List nested = new ArrayList();
114
115 /**
116 * Add a task or type to the container.
117 *
118 * @param task an unknown element.
119 */
120 public void addTask(Task task) {
121 nested.add(task);
122 }
123
124 /**
125 * @return the list of unknown elements
126 */
127 public List getNested() {
128 return nested;
129 }
130
131 /**
132 * A compare function to compare this with another
133 * NestedSequential.
134 * It calls similar on the nested unknown elements.
135 *
136 * @param other the nested sequential to compare with.
137 * @return true if they are similar, false otherwise
138 */
139 public boolean similar(NestedSequential other) {
140 if (nested.size() != other.nested.size()) {
141 return false;
142 }
143 for (int i = 0; i < nested.size(); ++i) {
144 UnknownElement me = (UnknownElement) nested.get(i);
145 UnknownElement o = (UnknownElement) other.nested.get(i);
146 if (!me.similar(o)) {
147 return false;
148 }
149 }
150 return true;
151 }
152 }
153
154 /**
155 * Convert the nested sequential to an unknown element
156 * @return the nested sequential as an unknown element.
157 */
158 public UnknownElement getNestedTask() {
159 UnknownElement ret = new UnknownElement("sequential");
160 ret.setTaskName("sequential");
161 ret.setNamespace("");
162 ret.setQName("sequential");
163 new RuntimeConfigurable(ret, "sequential");
164 for (int i = 0; i < nestedSequential.getNested().size(); ++i) {
165 UnknownElement e =
166 (UnknownElement) nestedSequential.getNested().get(i);
167 ret.addChild(e);
168 ret.getWrapper().addChild(e.getWrapper());
169 }
170 return ret;
171 }
172
173 /**
174 * @return the nested Attributes
175 */
176 public List getAttributes() {
177 return attributes;
178 }
179
180 /**
181 * @return the nested elements
182 */
183 public Map getElements() {
184 return elements;
185 }
186
187 /**
188 * Check if a character is a valid character for an element or
189 * attribute name
190 * @param c the character to check
191 * @return true if the character is a letter or digit or '.' or '-'
192 * attribute name
193 */
194 public static boolean isValidNameCharacter(char c) {
195 // ? is there an xml api for this ?
196 return Character.isLetterOrDigit(c) || c == '.' || c == '-';
197 }
198
199 /**
200 * Check if a string is a valid name for an element or
201 * attribute
202 * @param name the string to check
203 * @return true if the name consists of valid name characters
204 */
205 private static boolean isValidName(String name) {
206 if (name.length() == 0) {
207 return false;
208 }
209 for (int i = 0; i < name.length(); ++i) {
210 if (!isValidNameCharacter(name.charAt(i))) {
211 return false;
212 }
213 }
214 return true;
215 }
216
217 /**
218 * Add an attribute element.
219 *
220 * @param attribute an attribute nested element.
221 */
222 public void addConfiguredAttribute(Attribute attribute) {
223 if (attribute.getName() == null) {
224 throw new BuildException(
225 "the attribute nested element needed a \"name\" attribute");
226 }
227 if (attribute.getName().equals(textName)) {
228 throw new BuildException(
229 "the attribute name \"" + attribute.getName()
230 + "\" has already been used by the text element");
231 }
232 for (int i = 0; i < attributes.size(); ++i) {
233 if (((Attribute) attributes.get(i)).getName().equals(
234 attribute.getName())) {
235 throw new BuildException(
236 "the attribute " + attribute.getName()
237 + " has already been specified");
238 }
239 }
240 attributes.add(attribute);
241 }
242
243 /**
244 * Add an element element.
245 *
246 * @param element an element nested element.
247 */
248 public void addConfiguredElement(TemplateElement element) {
249 if (element.getName() == null) {
250 throw new BuildException(
251 "the element nested element needed a \"name\" attribute");
252 }
253 if (elements.get(element.getName()) != null) {
254 throw new BuildException(
255 "the element " + element.getName()
256 + " has already been specified");
257 }
258 if (hasImplicitElement
259 || (element.isImplicit() && elements.size() != 0)) {
260 throw new BuildException(
261 "Only one element allowed when using implicit elements");
262 }
263 hasImplicitElement = element.isImplicit();
264 elements.put(element.getName(), element);
265 }
266
267 /**
268 * Create a new ant type based on the embedded tasks and types.
269 *
270 */
271 public void execute() {
272 if (nestedSequential == null) {
273 throw new BuildException("Missing sequential element");
274 }
275 if (name == null) {
276 throw new BuildException("Name not specified");
277 }
278
279 name = ProjectHelper.genComponentName(getURI(), name);
280
281 MyAntTypeDefinition def = new MyAntTypeDefinition(this);
282 def.setName(name);
283 def.setClass(MacroInstance.class);
284
285 ComponentHelper helper = ComponentHelper.getComponentHelper(
286 getProject());
287
288 helper.addDataTypeDefinition(def);
289 }
290
291
292 /**
293 * A nested element for the MacroDef task.
294 *
295 */
296 public static class Attribute {
297 private String name;
298 private String defaultValue;
299 private String description;
300
301 /**
302 * The name of the attribute.
303 *
304 * @param name the name of the attribute
305 */
306 public void setName(String name) {
307 if (!isValidName(name)) {
308 throw new BuildException(
309 "Illegal name [" + name + "] for attribute");
310 }
311 this.name = name.toLowerCase(Locale.US);
312 }
313
314 /**
315 * @return the name of the attribute
316 */
317 public String getName() {
318 return name;
319 }
320
321 /**
322 * The default value to use if the parameter is not
323 * used in the templated instance.
324 *
325 * @param defaultValue the default value
326 */
327 public void setDefault(String defaultValue) {
328 this.defaultValue = defaultValue;
329 }
330
331 /**
332 * @return the default value, null if not set
333 */
334 public String getDefault() {
335 return defaultValue;
336 }
337
338 /**
339 * @param desc Description of the element.
340 * @since ant 1.6.1
341 */
342 public void setDescription(String desc) {
343 description = desc;
344 }
345
346 /**
347 * @return the description of the element, or <code>null</code> if
348 * no description is available.
349 * @since ant 1.6.1
350 */
351 public String getDescription() {
352 return description;
353 }
354
355 /**
356 * equality method
357 *
358 * @param obj an <code>Object</code> value
359 * @return a <code>boolean</code> value
360 */
361 public boolean equals(Object obj) {
362 if (obj == null) {
363 return false;
364 }
365 if (obj.getClass() != getClass()) {
366 return false;
367 }
368 Attribute other = (Attribute) obj;
369 if (name == null) {
370 if (other.name != null) {
371 return false;
372 }
373 } else if (!name.equals(other.name)) {
374 return false;
375 }
376 if (defaultValue == null) {
377 if (other.defaultValue != null) {
378 return false;
379 }
380 } else if (!defaultValue.equals(other.defaultValue)) {
381 return false;
382 }
383 return true;
384 }
385
386 /**
387 * @return a hash code value for this object.
388 */
389 public int hashCode() {
390 return objectHashCode(defaultValue) + objectHashCode(name);
391 }
392 }
393
394 /**
395 * A nested text element for the MacroDef task.
396 * @since ant 1.6.1
397 */
398 public static class Text {
399 private String name;
400 private boolean optional;
401 private boolean trim;
402 private String description;
403
404 /**
405 * The name of the attribute.
406 *
407 * @param name the name of the attribute
408 */
409 public void setName(String name) {
410 if (!isValidName(name)) {
411 throw new BuildException(
412 "Illegal name [" + name + "] for attribute");
413 }
414 this.name = name.toLowerCase(Locale.US);
415 }
416
417 /**
418 * @return the name of the attribute
419 */
420 public String getName() {
421 return name;
422 }
423
424 /**
425 * The optional attribute of the text element.
426 *
427 * @param optional if true this is optional
428 */
429 public void setOptional(boolean optional) {
430 this.optional = optional;
431 }
432
433 /**
434 * @return true if the text is optional
435 */
436 public boolean getOptional() {
437 return optional;
438 }
439
440 /**
441 * The trim attribute of the text element.
442 *
443 * @param trim if true this String.trim() is called on
444 * the contents of the text element.
445 */
446 public void setTrim(boolean trim) {
447 this.trim = trim;
448 }
449
450 /**
451 * @return true if the text is trim
452 */
453 public boolean getTrim() {
454 return trim;
455 }
456
457 /**
458 * @param desc Description of the text.
459 */
460 public void setDescription(String desc) {
461 description = desc;
462 }
463
464 /**
465 * @return the description of the text, or <code>null</code> if
466 * no description is available.
467 */
468 public String getDescription() {
469 return description;
470 }
471
472 /**
473 * equality method
474 *
475 * @param obj an <code>Object</code> value
476 * @return a <code>boolean</code> value
477 */
478 public boolean equals(Object obj) {
479 if (obj == null) {
480 return false;
481 }
482 if (obj.getClass() != getClass()) {
483 return false;
484 }
485 Text other = (Text) obj;
486 if (name == null) {
487 if (other.name != null) {
488 return false;
489 }
490 } else if (!name.equals(other.name)) {
491 return false;
492 }
493 if (optional != other.optional) {
494 return false;
495 }
496 if (trim != other.trim) {
497 return false;
498 }
499 return true;
500 }
501
502 /**
503 * @return a hash code value for this object.
504 */
505 public int hashCode() {
506 return objectHashCode(name);
507 }
508 }
509
510 /**
511 * A nested element for the MacroDef task.
512 *
513 */
514 public static class TemplateElement {
515 private String name;
516 private boolean optional = false;
517 private boolean implicit = false;
518 private String description;
519
520 /**
521 * The name of the element.
522 *
523 * @param name the name of the element.
524 */
525 public void setName(String name) {
526 if (!isValidName(name)) {
527 throw new BuildException(
528 "Illegal name [" + name + "] for attribute");
529 }
530 this.name = name.toLowerCase(Locale.US);
531 }
532
533 /**
534 * @return the name of the element.
535 */
536 public String getName() {
537 return name;
538 }
539
540 /**
541 * is this element optional ?
542 *
543 * @param optional if true this element may be left out, default
544 * is false.
545 */
546 public void setOptional(boolean optional) {
547 this.optional = optional;
548 }
549
550 /**
551 * @return the optional attribute
552 */
553 public boolean isOptional() {
554 return optional;
555 }
556
557 /**
558 * is this element implicit ?
559 *
560 * @param implicit if true this element may be left out, default
561 * is false.
562 */
563 public void setImplicit(boolean implicit) {
564 this.implicit = implicit;
565 }
566
567 /**
568 * @return the implicit attribute
569 */
570 public boolean isImplicit() {
571 return implicit;
572 }
573
574 /**
575 * @param desc Description of the element.
576 * @since ant 1.6.1
577 */
578 public void setDescription(String desc) {
579 description = desc;
580 }
581
582 /**
583 * @return the description of the element, or <code>null</code> if
584 * no description is available.
585 * @since ant 1.6.1
586 */
587 public String getDescription() {
588 return description;
589 }
590
591 /**
592 * equality method
593 *
594 * @param obj an <code>Object</code> value
595 * @return a <code>boolean</code> value
596 */
597 public boolean equals(Object obj) {
598 if (obj == null) {
599 return false;
600 }
601 if (obj.getClass() != getClass()) {
602 return false;
603 }
604 TemplateElement other = (TemplateElement) obj;
605 if (name == null) {
606 if (other.name != null) {
607 return false;
608 }
609 } else if (!name.equals(other.name)) {
610 return false;
611 }
612 return optional == other.optional && implicit == other.implicit;
613 }
614
615 /**
616 * @return a hash code value for this object.
617 */
618 public int hashCode() {
619 return objectHashCode(name)
620 + (optional ? 1 : 0) + (implicit ? 1 : 0);
621 }
622 }
623
624 /**
625 * same or similar equality method for macrodef, ignores project and
626 * runtime info.
627 *
628 * @param obj an <code>Object</code> value
629 * @param same if true test for sameness, otherwise just similiar
630 * @return a <code>boolean</code> value
631 */
632 private boolean sameOrSimilar(Object obj, boolean same) {
633 if (obj == this) {
634 return true;
635 }
636
637 if (obj == null) {
638 return false;
639 }
640 if (!obj.getClass().equals(getClass())) {
641 return false;
642 }
643 MacroDef other = (MacroDef) obj;
644 if (name == null) {
645 return other.name == null;
646 }
647 if (!name.equals(other.name)) {
648 return false;
649 }
650 // Allow two macro definitions with the same location
651 // to be treated as similar - bugzilla 31215
652 if (other.getLocation() != null
653 && other.getLocation().equals(getLocation())
654 && !same) {
655 return true;
656 }
657 if (text == null) {
658 if (other.text != null) {
659 return false;
660 }
661 } else {
662 if (!text.equals(other.text)) {
663 return false;
664 }
665 }
666 if (getURI() == null || getURI().equals("")
667 || getURI().equals(ProjectHelper.ANT_CORE_URI)) {
668 if (!(other.getURI() == null || other.getURI().equals("")
669 || other.getURI().equals(ProjectHelper.ANT_CORE_URI))) {
670 return false;
671 }
672 } else {
673 if (!getURI().equals(other.getURI())) {
674 return false;
675 }
676 }
677
678 if (!nestedSequential.similar(other.nestedSequential)) {
679 return false;
680 }
681 if (!attributes.equals(other.attributes)) {
682 return false;
683 }
684 if (!elements.equals(other.elements)) {
685 return false;
686 }
687 return true;
688 }
689
690 /**
691 * Similar method for this definition
692 *
693 * @param obj another definition
694 * @return true if the definitions are similar
695 */
696 public boolean similar(Object obj) {
697 return sameOrSimilar(obj, false);
698 }
699
700 /**
701 * Equality method for this definition
702 *
703 * @param obj another definition
704 * @return true if the definitions are the same
705 */
706 public boolean sameDefinition(Object obj) {
707 return sameOrSimilar(obj, true);
708 }
709
710 /**
711 * extends AntTypeDefinition, on create
712 * of the object, the template macro definition
713 * is given.
714 */
715 private static class MyAntTypeDefinition extends AntTypeDefinition {
716 private MacroDef macroDef;
717
718 /**
719 * Creates a new <code>MyAntTypeDefinition</code> instance.
720 *
721 * @param macroDef a <code>MacroDef</code> value
722 */
723 public MyAntTypeDefinition(MacroDef macroDef) {
724 this.macroDef = macroDef;
725 }
726
727 /**
728 * create an instance of the definition.
729 * The instance may be wrapped in a proxy class.
730 * @param project the current project
731 * @return the created object
732 */
733 public Object create(Project project) {
734 Object o = super.create(project);
735 if (o == null) {
736 return null;
737 }
738 ((MacroInstance) o).setMacroDef(macroDef);
739 return o;
740 }
741
742 /**
743 * Equality method for this definition
744 *
745 * @param other another definition
746 * @param project the current project
747 * @return true if the definitions are the same
748 */
749 public boolean sameDefinition(AntTypeDefinition other, Project project) {
750 if (!super.sameDefinition(other, project)) {
751 return false;
752 }
753 MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
754 return macroDef.sameDefinition(otherDef.macroDef);
755 }
756
757 /**
758 * Similar method for this definition
759 *
760 * @param other another definition
761 * @param project the current project
762 * @return true if the definitions are the same
763 */
764 public boolean similarDefinition(
765 AntTypeDefinition other, Project project) {
766 if (!super.similarDefinition(other, project)) {
767 return false;
768 }
769 MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
770 return macroDef.similar(otherDef.macroDef);
771 }
772 }
773
774 private static int objectHashCode(Object o) {
775 if (o == null) {
776 return 0;
777 } else {
778 return o.hashCode();
779 }
780 }
781}
Note: See TracBrowser for help on using the repository browser.