1 | /*
|
---|
2 | * Copyright 2003-2004 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 |
|
---|
18 | package org.apache.tools.ant.taskdefs;
|
---|
19 |
|
---|
20 | import java.util.ArrayList;
|
---|
21 | import java.util.List;
|
---|
22 | import java.util.Iterator;
|
---|
23 | import java.util.Locale;
|
---|
24 | import java.util.Map;
|
---|
25 | import java.util.Set;
|
---|
26 | import java.util.HashSet;
|
---|
27 | import java.util.HashMap;
|
---|
28 | import java.util.Hashtable;
|
---|
29 | import java.util.Enumeration;
|
---|
30 |
|
---|
31 | import org.apache.tools.ant.BuildException;
|
---|
32 | import org.apache.tools.ant.DynamicAttribute;
|
---|
33 | import org.apache.tools.ant.ProjectHelper;
|
---|
34 | import org.apache.tools.ant.RuntimeConfigurable;
|
---|
35 | import org.apache.tools.ant.Target;
|
---|
36 | import org.apache.tools.ant.Task;
|
---|
37 | import org.apache.tools.ant.TaskContainer;
|
---|
38 | import org.apache.tools.ant.UnknownElement;
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * The class to be placed in the ant type definition.
|
---|
42 | * It is given a pointer to the template definition,
|
---|
43 | * and makes a copy of the unknown element, substituting
|
---|
44 | * the parameter values in attributes and text.
|
---|
45 | * @since Ant 1.6
|
---|
46 | */
|
---|
47 | public class MacroInstance extends Task implements DynamicAttribute, TaskContainer {
|
---|
48 | private MacroDef macroDef;
|
---|
49 | private Map map = new HashMap();
|
---|
50 | private Map nsElements = null;
|
---|
51 | private Map presentElements;
|
---|
52 | private Hashtable localProperties;
|
---|
53 | private String text = null;
|
---|
54 | private String implicitTag = null;
|
---|
55 | private List unknownElements = new ArrayList();
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * Called from MacroDef.MyAntTypeDefinition#create()
|
---|
59 | *
|
---|
60 | * @param macroDef a <code>MacroDef</code> value
|
---|
61 | */
|
---|
62 | public void setMacroDef(MacroDef macroDef) {
|
---|
63 | this.macroDef = macroDef;
|
---|
64 | }
|
---|
65 |
|
---|
66 | /**
|
---|
67 | * @return the macro definition object for this macro instance.
|
---|
68 | */
|
---|
69 | public MacroDef getMacroDef() {
|
---|
70 | return macroDef;
|
---|
71 | }
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * A parameter name value pair as a xml attribute.
|
---|
75 | *
|
---|
76 | * @param name the name of the attribute
|
---|
77 | * @param value the value of the attribute
|
---|
78 | */
|
---|
79 | public void setDynamicAttribute(String name, String value) {
|
---|
80 | map.put(name, value);
|
---|
81 | }
|
---|
82 |
|
---|
83 | /**
|
---|
84 | * Method present for BC purposes.
|
---|
85 | * @param name not used
|
---|
86 | * @return nothing
|
---|
87 | * @deprecated
|
---|
88 | * @throws BuildException always
|
---|
89 | */
|
---|
90 | public Object createDynamicElement(String name) throws BuildException {
|
---|
91 | throw new BuildException("Not implemented any more");
|
---|
92 | }
|
---|
93 |
|
---|
94 | private Map getNsElements() {
|
---|
95 | if (nsElements == null) {
|
---|
96 | nsElements = new HashMap();
|
---|
97 | for (Iterator i = macroDef.getElements().entrySet().iterator();
|
---|
98 | i.hasNext();) {
|
---|
99 | Map.Entry entry = (Map.Entry) i.next();
|
---|
100 | nsElements.put((String) entry.getKey(),
|
---|
101 | entry.getValue());
|
---|
102 | MacroDef.TemplateElement te = (MacroDef.TemplateElement)
|
---|
103 | entry.getValue();
|
---|
104 | if (te.isImplicit()) {
|
---|
105 | implicitTag = te.getName();
|
---|
106 | }
|
---|
107 | }
|
---|
108 | }
|
---|
109 | return nsElements;
|
---|
110 | }
|
---|
111 |
|
---|
112 | /**
|
---|
113 | * Add a unknownElement for the macro instances nested elements.
|
---|
114 | *
|
---|
115 | * @param nestedTask a nested element.
|
---|
116 | */
|
---|
117 | public void addTask(Task nestedTask) {
|
---|
118 | unknownElements.add(nestedTask);
|
---|
119 | }
|
---|
120 |
|
---|
121 | private void processTasks() {
|
---|
122 | if (implicitTag != null) {
|
---|
123 | return;
|
---|
124 | }
|
---|
125 | for (Iterator i = unknownElements.iterator(); i.hasNext();) {
|
---|
126 | UnknownElement ue = (UnknownElement) i.next();
|
---|
127 | String name = ProjectHelper.extractNameFromComponentName(
|
---|
128 | ue.getTag()).toLowerCase(Locale.US);
|
---|
129 | if (getNsElements().get(name) == null) {
|
---|
130 | throw new BuildException("unsupported element " + name);
|
---|
131 | }
|
---|
132 | if (presentElements.get(name) != null) {
|
---|
133 | throw new BuildException("Element " + name + " already present");
|
---|
134 | }
|
---|
135 | presentElements.put(name, ue.getChildren());
|
---|
136 | }
|
---|
137 | }
|
---|
138 |
|
---|
139 | /**
|
---|
140 | * Embedded element in macro instance
|
---|
141 | */
|
---|
142 | public static class Element implements TaskContainer {
|
---|
143 | private List unknownElements = new ArrayList();
|
---|
144 |
|
---|
145 | /**
|
---|
146 | * Add an unknown element (to be snipped into the macroDef instance)
|
---|
147 | *
|
---|
148 | * @param nestedTask an unknown element
|
---|
149 | */
|
---|
150 | public void addTask(Task nestedTask) {
|
---|
151 | unknownElements.add(nestedTask);
|
---|
152 | }
|
---|
153 |
|
---|
154 | /**
|
---|
155 | * @return the list of unknown elements
|
---|
156 | */
|
---|
157 | public List getUnknownElements() {
|
---|
158 | return unknownElements;
|
---|
159 | }
|
---|
160 | }
|
---|
161 |
|
---|
162 | private static final int STATE_NORMAL = 0;
|
---|
163 | private static final int STATE_EXPECT_BRACKET = 1;
|
---|
164 | private static final int STATE_EXPECT_NAME = 2;
|
---|
165 |
|
---|
166 | private String macroSubs(String s, Map macroMapping) {
|
---|
167 | if (s == null) {
|
---|
168 | return null;
|
---|
169 | }
|
---|
170 | StringBuffer ret = new StringBuffer();
|
---|
171 | StringBuffer macroName = null;
|
---|
172 | boolean inMacro = false;
|
---|
173 | int state = STATE_NORMAL;
|
---|
174 | for (int i = 0; i < s.length(); ++i) {
|
---|
175 | char ch = s.charAt(i);
|
---|
176 | switch (state) {
|
---|
177 | case STATE_NORMAL:
|
---|
178 | if (ch == '@') {
|
---|
179 | state = STATE_EXPECT_BRACKET;
|
---|
180 | } else {
|
---|
181 | ret.append(ch);
|
---|
182 | }
|
---|
183 | break;
|
---|
184 | case STATE_EXPECT_BRACKET:
|
---|
185 | if (ch == '{') {
|
---|
186 | state = STATE_EXPECT_NAME;
|
---|
187 | macroName = new StringBuffer();
|
---|
188 | } else if (ch == '@') {
|
---|
189 | state = STATE_NORMAL;
|
---|
190 | ret.append('@');
|
---|
191 | } else {
|
---|
192 | state = STATE_NORMAL;
|
---|
193 | ret.append('@');
|
---|
194 | ret.append(ch);
|
---|
195 | }
|
---|
196 | break;
|
---|
197 | case STATE_EXPECT_NAME:
|
---|
198 | if (ch == '}') {
|
---|
199 | state = STATE_NORMAL;
|
---|
200 | String name = macroName.toString().toLowerCase(Locale.US);
|
---|
201 | String value = (String) macroMapping.get(name);
|
---|
202 | if (value == null) {
|
---|
203 | ret.append("@{" + name + "}");
|
---|
204 | } else {
|
---|
205 | ret.append(value);
|
---|
206 | }
|
---|
207 | macroName = null;
|
---|
208 | } else {
|
---|
209 | macroName.append(ch);
|
---|
210 | }
|
---|
211 | break;
|
---|
212 | default:
|
---|
213 | break;
|
---|
214 | }
|
---|
215 | }
|
---|
216 | switch (state) {
|
---|
217 | case STATE_NORMAL:
|
---|
218 | break;
|
---|
219 | case STATE_EXPECT_BRACKET:
|
---|
220 | ret.append('@');
|
---|
221 | break;
|
---|
222 | case STATE_EXPECT_NAME:
|
---|
223 | ret.append("@{");
|
---|
224 | ret.append(macroName.toString());
|
---|
225 | break;
|
---|
226 | default:
|
---|
227 | break;
|
---|
228 | }
|
---|
229 |
|
---|
230 | return ret.toString();
|
---|
231 | }
|
---|
232 |
|
---|
233 | /**
|
---|
234 | * Set the text contents for the macro.
|
---|
235 | * @param text the text to be added to the macro.
|
---|
236 | */
|
---|
237 |
|
---|
238 | public void addText(String text) {
|
---|
239 | this.text = text;
|
---|
240 | }
|
---|
241 |
|
---|
242 | private UnknownElement copy(UnknownElement ue) {
|
---|
243 | UnknownElement ret = new UnknownElement(ue.getTag());
|
---|
244 | ret.setNamespace(ue.getNamespace());
|
---|
245 | ret.setProject(getProject());
|
---|
246 | ret.setQName(ue.getQName());
|
---|
247 | ret.setTaskType(ue.getTaskType());
|
---|
248 | ret.setTaskName(ue.getTaskName());
|
---|
249 | ret.setLocation(ue.getLocation());
|
---|
250 | if (getOwningTarget() == null) {
|
---|
251 | Target t = new Target();
|
---|
252 | t.setProject(getProject());
|
---|
253 | ret.setOwningTarget(t);
|
---|
254 | } else {
|
---|
255 | ret.setOwningTarget(getOwningTarget());
|
---|
256 | }
|
---|
257 | RuntimeConfigurable rc = new RuntimeConfigurable(
|
---|
258 | ret, ue.getTaskName());
|
---|
259 | rc.setPolyType(ue.getWrapper().getPolyType());
|
---|
260 | Map map = ue.getWrapper().getAttributeMap();
|
---|
261 | for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
|
---|
262 | Map.Entry entry = (Map.Entry) i.next();
|
---|
263 | rc.setAttribute(
|
---|
264 | (String) entry.getKey(),
|
---|
265 | macroSubs((String) entry.getValue(), localProperties));
|
---|
266 | }
|
---|
267 | rc.addText(macroSubs(ue.getWrapper().getText().toString(),
|
---|
268 | localProperties));
|
---|
269 |
|
---|
270 | Enumeration e = ue.getWrapper().getChildren();
|
---|
271 | while (e.hasMoreElements()) {
|
---|
272 | RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement();
|
---|
273 | UnknownElement unknownElement = (UnknownElement) r.getProxy();
|
---|
274 | String tag = unknownElement.getTaskType();
|
---|
275 | if (tag != null) {
|
---|
276 | tag = tag.toLowerCase(Locale.US);
|
---|
277 | }
|
---|
278 | MacroDef.TemplateElement templateElement =
|
---|
279 | (MacroDef.TemplateElement) getNsElements().get(tag);
|
---|
280 | if (templateElement == null) {
|
---|
281 | UnknownElement child = copy(unknownElement);
|
---|
282 | rc.addChild(child.getWrapper());
|
---|
283 | ret.addChild(child);
|
---|
284 | } else if (templateElement.isImplicit()) {
|
---|
285 | if (unknownElements.size() == 0 && !templateElement.isOptional()) {
|
---|
286 | throw new BuildException(
|
---|
287 | "Missing nested elements for implicit element "
|
---|
288 | + templateElement.getName());
|
---|
289 | }
|
---|
290 | for (Iterator i = unknownElements.iterator();
|
---|
291 | i.hasNext();) {
|
---|
292 | UnknownElement child = (UnknownElement) i.next();
|
---|
293 | rc.addChild(child.getWrapper());
|
---|
294 | ret.addChild(child);
|
---|
295 | }
|
---|
296 | } else {
|
---|
297 | List list = (List) presentElements.get(tag);
|
---|
298 | if (list == null) {
|
---|
299 | if (!templateElement.isOptional()) {
|
---|
300 | throw new BuildException(
|
---|
301 | "Required nested element "
|
---|
302 | + templateElement.getName() + " missing");
|
---|
303 | }
|
---|
304 | continue;
|
---|
305 | }
|
---|
306 | for (Iterator i = list.iterator();
|
---|
307 | i.hasNext();) {
|
---|
308 | UnknownElement child = (UnknownElement) i.next();
|
---|
309 | rc.addChild(child.getWrapper());
|
---|
310 | ret.addChild(child);
|
---|
311 | }
|
---|
312 | }
|
---|
313 | }
|
---|
314 | return ret;
|
---|
315 | }
|
---|
316 |
|
---|
317 | /**
|
---|
318 | * Execute the templates instance.
|
---|
319 | * Copies the unknown element, substitutes the attributes,
|
---|
320 | * and calls perform on the unknown element.
|
---|
321 | *
|
---|
322 | */
|
---|
323 | public void execute() {
|
---|
324 | presentElements = new HashMap();
|
---|
325 | getNsElements();
|
---|
326 | processTasks();
|
---|
327 | localProperties = new Hashtable();
|
---|
328 | Set copyKeys = new HashSet(map.keySet());
|
---|
329 | for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) {
|
---|
330 | MacroDef.Attribute attribute = (MacroDef.Attribute) i.next();
|
---|
331 | String value = (String) map.get(attribute.getName());
|
---|
332 | if (value == null && "description".equals(attribute.getName())) {
|
---|
333 | value = getDescription();
|
---|
334 | }
|
---|
335 | if (value == null) {
|
---|
336 | value = attribute.getDefault();
|
---|
337 | value = macroSubs(value, localProperties);
|
---|
338 | }
|
---|
339 | if (value == null) {
|
---|
340 | throw new BuildException(
|
---|
341 | "required attribute " + attribute.getName() + " not set");
|
---|
342 | }
|
---|
343 | localProperties.put(attribute.getName(), value);
|
---|
344 | copyKeys.remove(attribute.getName());
|
---|
345 | }
|
---|
346 | if (copyKeys.contains("id")) {
|
---|
347 | copyKeys.remove("id");
|
---|
348 | }
|
---|
349 | if (macroDef.getText() != null) {
|
---|
350 | if (text == null) {
|
---|
351 | if (!macroDef.getText().getOptional()) {
|
---|
352 | throw new BuildException(
|
---|
353 | "required text missing");
|
---|
354 | }
|
---|
355 | text = "";
|
---|
356 | }
|
---|
357 | if (macroDef.getText().getTrim()) {
|
---|
358 | text = text.trim();
|
---|
359 | }
|
---|
360 | localProperties.put(macroDef.getText().getName(), text);
|
---|
361 | } else {
|
---|
362 | if (text != null && !text.trim().equals("")) {
|
---|
363 | throw new BuildException(
|
---|
364 | "The \"" + getTaskName() + "\" macro does not support"
|
---|
365 | + " nested text data.");
|
---|
366 | }
|
---|
367 | }
|
---|
368 | if (copyKeys.size() != 0) {
|
---|
369 | throw new BuildException(
|
---|
370 | "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ")
|
---|
371 | + copyKeys);
|
---|
372 | }
|
---|
373 |
|
---|
374 | // need to set the project on unknown element
|
---|
375 | UnknownElement c = copy(macroDef.getNestedTask());
|
---|
376 | c.init();
|
---|
377 | try {
|
---|
378 | c.perform();
|
---|
379 | } catch (BuildException ex) {
|
---|
380 | throw ProjectHelper.addLocationToBuildException(
|
---|
381 | ex, getLocation());
|
---|
382 | }
|
---|
383 | presentElements = null;
|
---|
384 | localProperties = null;
|
---|
385 | }
|
---|
386 | }
|
---|