KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > MacroDef


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Locale JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27
28 import org.apache.tools.ant.AntTypeDefinition;
29 import org.apache.tools.ant.BuildException;
30 import org.apache.tools.ant.ComponentHelper;
31 import org.apache.tools.ant.Project;
32 import org.apache.tools.ant.ProjectHelper;
33 import org.apache.tools.ant.RuntimeConfigurable;
34 import org.apache.tools.ant.Task;
35 import org.apache.tools.ant.TaskContainer;
36 import org.apache.tools.ant.UnknownElement;
37
38 /**
39  * Describe class <code>MacroDef</code> here.
40  *
41  * @since Ant 1.6
42  */

43 public class MacroDef extends AntlibDefinition {
44
45     private NestedSequential nestedSequential;
46     private String JavaDoc name;
47     private boolean backTrace = true;
48     private List JavaDoc attributes = new ArrayList JavaDoc();
49     private Map JavaDoc elements = new HashMap JavaDoc();
50     private String JavaDoc textName = null;
51     private Text text = null;
52     private boolean hasImplicitElement = false;
53
54     /**
55      * Name of the definition
56      * @param name the name of the definition
57      */

58      public void setName(String JavaDoc name) {
59         this.name = name;
60     }
61
62     /**
63      * Add the text element.
64      * @param text the nested text element to add
65      * @since ant 1.6.1
66      */

67     public void addConfiguredText(Text text) {
68         if (this.text != null) {
69             throw new BuildException(
70                 "Only one nested text element allowed");
71         }
72         if (text.getName() == null) {
73             throw new BuildException(
74                 "the text nested element needed a \"name\" attribute");
75         }
76         // Check if used by attributes
77
for (Iterator JavaDoc i = attributes.iterator(); i.hasNext();) {
78             Attribute attribute = (Attribute) i.next();
79             if (text.getName().equals(attribute.getName())) {
80                 throw new BuildException(
81                     "the name \"" + text.getName()
82                     + "\" is already used as an attribute");
83             }
84         }
85         this.text = text;
86         this.textName = text.getName();
87     }
88
89     /**
90      * @return the nested text element
91      * @since ant 1.6.1
92      */

93     public Text getText() {
94         return text;
95     }
96
97     /**
98      * Set the backTrace attribute.
99      *
100      * @param backTrace if true and the macro instance generates
101      * an error, a backtrace of the location within
102      * the macro and call to the macro will be output.
103      * if false, only the location of the call to the
104      * macro will be shown. Default is true.
105      * @since ant 1.7
106      */

107     public void setBackTrace(boolean backTrace) {
108         this.backTrace = backTrace;
109     }
110
111     /**
112      * @return the backTrace attribute.
113      * @since ant 1.7
114      */

115     public boolean getBackTrace() {
116         return backTrace;
117     }
118
119     /**
120      * This is the sequential nested element of the macrodef.
121      *
122      * @return a sequential element to be configured.
123      */

124     public NestedSequential createSequential() {
125         if (this.nestedSequential != null) {
126             throw new BuildException("Only one sequential allowed");
127         }
128         this.nestedSequential = new NestedSequential();
129         return this.nestedSequential;
130     }
131
132     /**
133      * The class corresponding to the sequential nested element.
134      * This is a simple task container.
135      */

136     public static class NestedSequential implements TaskContainer {
137         private List JavaDoc nested = new ArrayList JavaDoc();
138
139         /**
140          * Add a task or type to the container.
141          *
142          * @param task an unknown element.
143          */

144         public void addTask(Task task) {
145             nested.add(task);
146         }
147
148         /**
149          * @return the list of unknown elements
150          */

151         public List JavaDoc getNested() {
152             return nested;
153         }
154
155         /**
156          * A compare function to compare this with another
157          * NestedSequential.
158          * It calls similar on the nested unknown elements.
159          *
160          * @param other the nested sequential to compare with.
161          * @return true if they are similar, false otherwise
162          */

163         public boolean similar(NestedSequential other) {
164             if (nested.size() != other.nested.size()) {
165                 return false;
166             }
167             for (int i = 0; i < nested.size(); ++i) {
168                 UnknownElement me = (UnknownElement) nested.get(i);
169                 UnknownElement o = (UnknownElement) other.nested.get(i);
170                 if (!me.similar(o)) {
171                     return false;
172                 }
173             }
174             return true;
175         }
176     }
177
178     /**
179      * Convert the nested sequential to an unknown element
180      * @return the nested sequential as an unknown element.
181      */

182     public UnknownElement getNestedTask() {
183         UnknownElement ret = new UnknownElement("sequential");
184         ret.setTaskName("sequential");
185         ret.setNamespace("");
186         ret.setQName("sequential");
187         new RuntimeConfigurable(ret, "sequential");
188         for (int i = 0; i < nestedSequential.getNested().size(); ++i) {
189             UnknownElement e =
190                 (UnknownElement) nestedSequential.getNested().get(i);
191             ret.addChild(e);
192             ret.getWrapper().addChild(e.getWrapper());
193         }
194         return ret;
195     }
196
197     /**
198      * Gets this macro's attribute (and define?) list.
199      *
200      * @return the nested Attributes
201      */

202     public List JavaDoc getAttributes() {
203         return attributes;
204     }
205
206     /**
207      * Gets this macro's elements.
208      *
209      * @return the map nested elements, keyed by element name, with
210      * {@link TemplateElement} values.
211      */

212     public Map JavaDoc getElements() {
213         return elements;
214     }
215
216     /**
217      * Check if a character is a valid character for an element or
218      * attribute name.
219      *
220      * @param c the character to check
221      * @return true if the character is a letter or digit or '.' or '-'
222      * attribute name
223      */

224     public static boolean isValidNameCharacter(char c) {
225         // ? is there an xml api for this ?
226
return Character.isLetterOrDigit(c) || c == '.' || c == '-';
227     }
228
229     /**
230      * Check if a string is a valid name for an element or attribute.
231      *
232      * @param name the string to check
233      * @return true if the name consists of valid name characters
234      */

235     private static boolean isValidName(String JavaDoc name) {
236         if (name.length() == 0) {
237             return false;
238         }
239         for (int i = 0; i < name.length(); ++i) {
240             if (!isValidNameCharacter(name.charAt(i))) {
241                 return false;
242             }
243         }
244         return true;
245     }
246
247     /**
248      * Add an attribute element.
249      *
250      * @param attribute an attribute nested element.
251      */

252     public void addConfiguredAttribute(Attribute attribute) {
253         if (attribute.getName() == null) {
254             throw new BuildException(
255                 "the attribute nested element needed a \"name\" attribute");
256         }
257         if (attribute.getName().equals(textName)) {
258             throw new BuildException(
259                 "the name \"" + attribute.getName()
260                 + "\" has already been used by the text element");
261         }
262         for (int i = 0; i < attributes.size(); ++i) {
263             Attribute att = (Attribute) attributes.get(i);
264             if (att.getName().equals(attribute.getName())) {
265                 throw new BuildException(
266                     "the name \"" + attribute.getName()
267                         + "\" has already been used in "
268                         + "another attribute element");
269             }
270         }
271         attributes.add(attribute);
272     }
273
274     /**
275      * Add an element element.
276      *
277      * @param element an element nested element.
278      */

279     public void addConfiguredElement(TemplateElement element) {
280         if (element.getName() == null) {
281             throw new BuildException(
282                 "the element nested element needed a \"name\" attribute");
283         }
284         if (elements.get(element.getName()) != null) {
285             throw new BuildException(
286                 "the element " + element.getName()
287                 + " has already been specified");
288         }
289         if (hasImplicitElement
290             || (element.isImplicit() && elements.size() != 0)) {
291             throw new BuildException(
292                 "Only one element allowed when using implicit elements");
293         }
294         hasImplicitElement = element.isImplicit();
295         elements.put(element.getName(), element);
296     }
297
298     /**
299      * Create a new ant type based on the embedded tasks and types.
300      */

301     public void execute() {
302         if (nestedSequential == null) {
303             throw new BuildException("Missing sequential element");
304         }
305         if (name == null) {
306             throw new BuildException("Name not specified");
307         }
308
309         name = ProjectHelper.genComponentName(getURI(), name);
310
311         MyAntTypeDefinition def = new MyAntTypeDefinition(this);
312         def.setName(name);
313         def.setClass(MacroInstance.class);
314
315         ComponentHelper helper = ComponentHelper.getComponentHelper(
316             getProject());
317
318         helper.addDataTypeDefinition(def);
319         log("creating macro " + name, Project.MSG_VERBOSE);
320     }
321
322
323     /**
324      * An attribute for the MacroDef task.
325      *
326      */

327     public static class Attribute {
328         private String JavaDoc name;
329         private String JavaDoc defaultValue;
330         private String JavaDoc description;
331
332         /**
333          * The name of the attribute.
334          *
335          * @param name the name of the attribute
336          */

337         public void setName(String JavaDoc name) {
338             if (!isValidName(name)) {
339                 throw new BuildException(
340                     "Illegal name [" + name + "] for attribute");
341             }
342             this.name = name.toLowerCase(Locale.US);
343         }
344
345         /**
346          * @return the name of the attribute
347          */

348         public String JavaDoc getName() {
349             return name;
350         }
351
352         /**
353          * The default value to use if the parameter is not
354          * used in the templated instance.
355          *
356          * @param defaultValue the default value
357          */

358         public void setDefault(String JavaDoc defaultValue) {
359             this.defaultValue = defaultValue;
360         }
361
362         /**
363          * @return the default value, null if not set
364          */

365         public String JavaDoc getDefault() {
366             return defaultValue;
367         }
368
369         /**
370          * @param desc Description of the element.
371          * @since ant 1.6.1
372          */

373         public void setDescription(String JavaDoc desc) {
374             description = desc;
375         }
376
377         /**
378          * @return the description of the element, or <code>null</code> if
379          * no description is available.
380          * @since ant 1.6.1
381          */

382         public String JavaDoc getDescription() {
383             return description;
384         }
385
386         /**
387          * equality method
388          *
389          * @param obj an <code>Object</code> value
390          * @return a <code>boolean</code> value
391          */

392         public boolean equals(Object JavaDoc obj) {
393             if (obj == null) {
394                 return false;
395             }
396             if (obj.getClass() != getClass()) {
397                 return false;
398             }
399             Attribute other = (Attribute) obj;
400             if (name == null) {
401                 if (other.name != null) {
402                     return false;
403                 }
404             } else if (!name.equals(other.name)) {
405                 return false;
406             }
407             if (defaultValue == null) {
408                 if (other.defaultValue != null) {
409                     return false;
410                 }
411             } else if (!defaultValue.equals(other.defaultValue)) {
412                 return false;
413             }
414             return true;
415         }
416
417         /**
418          * @return a hash code value for this object.
419          */

420         public int hashCode() {
421             return objectHashCode(defaultValue) + objectHashCode(name);
422         }
423     }
424
425     /**
426      * A nested text element for the MacroDef task.
427      * @since ant 1.6.1
428      */

429     public static class Text {
430         private String JavaDoc name;
431         private boolean optional;
432         private boolean trim;
433         private String JavaDoc description;
434
435         /**
436          * The name of the attribute.
437          *
438          * @param name the name of the attribute
439          */

440         public void setName(String JavaDoc name) {
441             if (!isValidName(name)) {
442                 throw new BuildException(
443                     "Illegal name [" + name + "] for attribute");
444             }
445             this.name = name.toLowerCase(Locale.US);
446         }
447
448         /**
449          * @return the name of the attribute
450          */

451         public String JavaDoc getName() {
452             return name;
453         }
454
455         /**
456          * The optional attribute of the text element.
457          *
458          * @param optional if true this is optional
459          */

460         public void setOptional(boolean optional) {
461             this.optional = optional;
462         }
463
464         /**
465          * @return true if the text is optional
466          */

467         public boolean getOptional() {
468             return optional;
469         }
470
471         /**
472          * The trim attribute of the text element.
473          *
474          * @param trim if true this String.trim() is called on
475          * the contents of the text element.
476          */

477         public void setTrim(boolean trim) {
478             this.trim = trim;
479         }
480
481         /**
482          * @return true if the text is trim
483          */

484         public boolean getTrim() {
485             return trim;
486         }
487
488         /**
489          * @param desc Description of the text.
490          */

491         public void setDescription(String JavaDoc desc) {
492             description = desc;
493         }
494
495         /**
496          * @return the description of the text, or <code>null</code> if
497          * no description is available.
498          */

499         public String JavaDoc getDescription() {
500             return description;
501         }
502
503         /**
504          * equality method
505          *
506          * @param obj an <code>Object</code> value
507          * @return a <code>boolean</code> value
508          */

509         public boolean equals(Object JavaDoc obj) {
510             if (obj == null) {
511                 return false;
512             }
513             if (obj.getClass() != getClass()) {
514                 return false;
515             }
516             Text other = (Text) obj;
517             if (name == null) {
518                 if (other.name != null) {
519                     return false;
520                 }
521             } else if (!name.equals(other.name)) {
522                 return false;
523             }
524             if (optional != other.optional) {
525                 return false;
526             }
527             if (trim != other.trim) {
528                 return false;
529             }
530             return true;
531         }
532
533         /**
534          * @return a hash code value for this object.
535          */

536         public int hashCode() {
537             return objectHashCode(name);
538         }
539     }
540
541     /**
542      * A nested element for the MacroDef task.
543      */

544     public static class TemplateElement {
545
546         private String JavaDoc name;
547         private String JavaDoc description;
548         private boolean optional = false;
549         private boolean implicit = false;
550
551         /**
552          * Sets the name of this element.
553          *
554          * @param name the name of the element
555          */

556         public void setName(String JavaDoc name) {
557             if (!isValidName(name)) {
558                 throw new BuildException(
559                     "Illegal name [" + name + "] for macro element");
560             }
561             this.name = name.toLowerCase(Locale.US);
562         }
563
564         /**
565          * Gets the name of this element.
566          *
567          * @return the name of the element.
568          */

569         public String JavaDoc getName() {
570             return name;
571         }
572
573         /**
574          * Sets a textual description of this element,
575          * for build documentation purposes only.
576          *
577          * @param desc Description of the element.
578          * @since ant 1.6.1
579          */

580         public void setDescription(String JavaDoc desc) {
581             description = desc;
582         }
583
584         /**
585          * Gets the description of this element.
586          *
587          * @return the description of the element, or <code>null</code> if
588          * no description is available.
589          * @since ant 1.6.1
590          */

591         public String JavaDoc getDescription() {
592             return description;
593         }
594
595         /**
596          * Sets whether this element is optional.
597          *
598          * @param optional if true this element may be left out, default
599          * is false.
600          */

601         public void setOptional(boolean optional) {
602             this.optional = optional;
603         }
604
605         /**
606          * Gets whether this element is optional.
607          *
608          * @return the optional attribute
609          */

610         public boolean isOptional() {
611             return optional;
612         }
613
614         /**
615          * Sets whether this element is implicit.
616          *
617          * @param implicit if true this element may be left out, default
618          * is false.
619          */

620         public void setImplicit(boolean implicit) {
621             this.implicit = implicit;
622         }
623
624         /**
625          * Gets whether this element is implicit.
626          *
627          * @return the implicit attribute
628          */

629         public boolean isImplicit() {
630             return implicit;
631         }
632
633         /**
634          * equality method.
635          *
636          * @param obj an <code>Object</code> value
637          * @return a <code>boolean</code> value
638          */

639         public boolean equals(Object JavaDoc obj) {
640             if (obj == this) {
641               return true;
642             }
643             if (obj == null || !obj.getClass().equals(getClass())) {
644                 return false;
645             }
646             TemplateElement t = (TemplateElement) obj;
647             return
648                 (name == null ? t.name == null : name.equals(t.name))
649                 && optional == t.optional
650                 && implicit == t.implicit;
651         }
652
653         /**
654          * @return a hash code value for this object.
655          */

656         public int hashCode() {
657             return objectHashCode(name)
658                 + (optional ? 1 : 0) + (implicit ? 1 : 0);
659         }
660
661     } // END static class TemplateElement
662

663     /**
664      * same or similar equality method for macrodef, ignores project and
665      * runtime info.
666      *
667      * @param obj an <code>Object</code> value
668      * @param same if true test for sameness, otherwise just similiar
669      * @return a <code>boolean</code> value
670      */

671     private boolean sameOrSimilar(Object JavaDoc obj, boolean same) {
672         if (obj == this) {
673             return true;
674         }
675
676         if (obj == null) {
677             return false;
678         }
679         if (!obj.getClass().equals(getClass())) {
680             return false;
681         }
682         MacroDef other = (MacroDef) obj;
683         if (name == null) {
684             return other.name == null;
685         }
686         if (!name.equals(other.name)) {
687             return false;
688         }
689         // Allow two macro definitions with the same location
690
// to be treated as similar - bugzilla 31215
691
if (other.getLocation() != null
692             && other.getLocation().equals(getLocation())
693             && !same) {
694             return true;
695         }
696         if (text == null) {
697             if (other.text != null) {
698                 return false;
699             }
700         } else {
701             if (!text.equals(other.text)) {
702                 return false;
703             }
704         }
705         if (getURI() == null || getURI().equals("")
706             || getURI().equals(ProjectHelper.ANT_CORE_URI)) {
707             if (!(other.getURI() == null || other.getURI().equals("")
708                   || other.getURI().equals(ProjectHelper.ANT_CORE_URI))) {
709                 return false;
710             }
711         } else {
712             if (!getURI().equals(other.getURI())) {
713                 return false;
714             }
715         }
716
717         if (!nestedSequential.similar(other.nestedSequential)) {
718             return false;
719         }
720         if (!attributes.equals(other.attributes)) {
721             return false;
722         }
723         if (!elements.equals(other.elements)) {
724             return false;
725         }
726         return true;
727     }
728
729     /**
730      * Similar method for this definition
731      *
732      * @param obj another definition
733      * @return true if the definitions are similar
734      */

735     public boolean similar(Object JavaDoc obj) {
736         return sameOrSimilar(obj, false);
737     }
738
739     /**
740      * Equality method for this definition
741      *
742      * @param obj another definition
743      * @return true if the definitions are the same
744      */

745     public boolean sameDefinition(Object JavaDoc obj) {
746         return sameOrSimilar(obj, true);
747     }
748
749     /**
750      * extends AntTypeDefinition, on create
751      * of the object, the template macro definition
752      * is given.
753      */

754     private static class MyAntTypeDefinition extends AntTypeDefinition {
755         private MacroDef macroDef;
756
757         /**
758          * Creates a new <code>MyAntTypeDefinition</code> instance.
759          *
760          * @param macroDef a <code>MacroDef</code> value
761          */

762         public MyAntTypeDefinition(MacroDef macroDef) {
763             this.macroDef = macroDef;
764         }
765
766         /**
767          * Create an instance of the definition.
768          * The instance may be wrapped in a proxy class.
769          * @param project the current project
770          * @return the created object
771          */

772         public Object JavaDoc create(Project project) {
773             Object JavaDoc o = super.create(project);
774             if (o == null) {
775                 return null;
776             }
777             ((MacroInstance) o).setMacroDef(macroDef);
778             return o;
779         }
780
781         /**
782          * Equality method for this definition
783          *
784          * @param other another definition
785          * @param project the current project
786          * @return true if the definitions are the same
787          */

788         public boolean sameDefinition(AntTypeDefinition other, Project project) {
789             if (!super.sameDefinition(other, project)) {
790                 return false;
791             }
792             MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
793             return macroDef.sameDefinition(otherDef.macroDef);
794         }
795
796         /**
797          * Similar method for this definition
798          *
799          * @param other another definition
800          * @param project the current project
801          * @return true if the definitions are the same
802          */

803         public boolean similarDefinition(
804             AntTypeDefinition other, Project project) {
805             if (!super.similarDefinition(other, project)) {
806                 return false;
807             }
808             MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
809             return macroDef.similar(otherDef.macroDef);
810         }
811     }
812
813     private static int objectHashCode(Object JavaDoc o) {
814         if (o == null) {
815             return 0;
816         } else {
817             return o.hashCode();
818         }
819     }
820
821 }
822
Popular Tags