1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package groovy.util;
47
48
49 import java.util.Collections;
50 import java.util.Iterator;
51 import java.util.Map;
52 import java.util.logging.Level;
53 import java.util.logging.Logger;
54
55 import org.apache.tools.ant.BuildLogger;
56 import org.apache.tools.ant.NoBannerLogger;
57 import org.apache.tools.ant.Project;
58 import org.apache.tools.ant.RuntimeConfigurable;
59 import org.apache.tools.ant.Target;
60 import org.apache.tools.ant.Task;
61 import org.apache.tools.ant.UnknownElement;
62 import org.apache.tools.ant.helper.AntXMLContext;
63 import org.apache.tools.ant.helper.ProjectHelper2;
64 import org.codehaus.groovy.ant.FileScanner;
65 import org.xml.sax.Attributes;
66 import org.xml.sax.Locator;
67 import org.xml.sax.SAXParseException;
68 import org.xml.sax.helpers.AttributesImpl;
69 import groovy.xml.QName;
70
71 /***
72 * Allows Ant tasks to be used with GroovyMarkup
73 *
74 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>, changes by Dierk Koenig (dk)
75 * @version $Revision: 4077 $
76 */
77 public class AntBuilder extends BuilderSupport {
78
79 private static final Class[] addTaskParamTypes = { String.class };
80
81 private Logger log = Logger.getLogger(getClass().getName());
82 private Project project;
83 private final AntXMLContext antXmlContext;
84 private final ProjectHelper2.ElementHandler antElementHandler = new ProjectHelper2.ElementHandler();
85 private final Target collectorTarget;
86 private Object lastCompletedNode;
87
88
89
90 public AntBuilder() {
91 this(createProject());
92 }
93
94 public AntBuilder(final Project project) {
95 this(project, new Target());
96 }
97
98 public AntBuilder(final Project project, final Target owningTarget) {
99 this.project = project;
100
101 collectorTarget = owningTarget;
102
103 antXmlContext = new AntXMLContext(project);
104 collectorTarget.setProject(project);
105 antXmlContext.setCurrentTarget(collectorTarget);
106 antXmlContext.setLocator(new AntBuilderLocator());
107
108
109 project.addDataTypeDefinition("fileScanner", FileScanner.class);
110 }
111
112
113 protected Project getProject() {
114 return project;
115 }
116
117 /***
118 * @return Factory method to create new Project instances
119 */
120 protected static Project createProject() {
121 Project project = new Project();
122 BuildLogger logger = new NoBannerLogger();
123
124 logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
125 logger.setOutputPrintStream(System.out);
126 logger.setErrorPrintStream(System.err);
127
128 project.addBuildListener(logger);
129
130 project.init();
131 project.getBaseDir();
132 return project;
133 }
134
135 protected void setParent(Object parent, Object child) {
136 }
137
138
139 /***
140 * We don't want to return the node as created in {@link #createNode(Object, Map, Object)}
141 * but the one made ready by {@link #nodeCompleted(Object, Object)}
142 * @see groovy.util.BuilderSupport#doInvokeMethod(java.lang.String, java.lang.Object, java.lang.Object)
143 */
144 protected Object doInvokeMethod(String methodName, Object name, Object args) {
145 super.doInvokeMethod(methodName, name, args);
146
147
148
149 return lastCompletedNode;
150 }
151
152 /***
153 * Determines, when the ANT Task that is represented by the "node" should perform.
154 * Node must be an ANT Task or no "perform" is called.
155 * If node is an ANT Task, it performs right after complete contstruction.
156 * If node is nested in a TaskContainer, calling "perform" is delegated to that
157 * TaskContainer.
158 * @param parent note: null when node is root
159 * @param node the node that now has all its children applied
160 */
161 protected void nodeCompleted(final Object parent, final Object node) {
162
163 antElementHandler.onEndElement(null, null, antXmlContext);
164
165 lastCompletedNode = node;
166 if (parent != null) {
167 log.finest("parent is not null: no perform on nodeCompleted");
168 return;
169 }
170
171
172 if (node instanceof Task) {
173 Object task = node;
174
175 if (node instanceof UnknownElement) {
176 final UnknownElement unknownElement = (UnknownElement) node;
177 unknownElement.maybeConfigure();
178 task = unknownElement.getRealThing();
179 }
180
181 lastCompletedNode = task;
182
183 if (task instanceof Task) {
184 ((Task) task).perform();
185 }
186 }
187 else {
188 final RuntimeConfigurable r = (RuntimeConfigurable) node;
189 r.maybeConfigure(project);
190 }
191 }
192
193 protected Object createNode(Object tagName) {
194 return createNode(tagName, Collections.EMPTY_MAP);
195 }
196
197 protected Object createNode(Object name, Object value) {
198 Object task = createNode(name);
199 setText(task, value.toString());
200 return task;
201 }
202
203 protected Object createNode(Object name, Map attributes, Object value) {
204 Object task = createNode(name, attributes);
205 setText(task, value.toString());
206 return task;
207 }
208
209 /***
210 * Builds an {@link Attributes} from a {@link Map}
211 * @param attributes the attributes to wrap
212 */
213 protected static Attributes buildAttributes(final Map attributes) {
214 final AttributesImpl attr = new AttributesImpl();
215 for (final Iterator iter=attributes.entrySet().iterator(); iter.hasNext(); ) {
216 final Map.Entry entry = (Map.Entry) iter.next();
217 final String attributeName = (String) entry.getKey();
218 final String attributeValue = String.valueOf(entry.getValue());
219 attr.addAttribute(null, attributeName, attributeName, "CDATA", attributeValue);
220 }
221 return attr;
222 }
223
224 protected Object createNode(final Object name, final Map attributes) {
225
226 String tagName = name.toString();
227 String ns = "";
228
229 if(name instanceof QName) {
230 QName q = (QName)name;
231 tagName = q.getLocalPart();
232 ns = q.getNamespaceURI();
233 }
234
235 try
236 {
237 antElementHandler.onStartElement(ns, tagName, tagName, buildAttributes(attributes), antXmlContext);
238 }
239 catch (final SAXParseException e)
240 {
241 log.log(Level.SEVERE, "Caught: " + e, e);
242 }
243
244 final RuntimeConfigurable wrapper = (RuntimeConfigurable) antXmlContext.getWrapperStack().lastElement();
245 return wrapper.getProxy();
246 }
247
248 protected void setText(Object task, String text) {
249 final char[] characters = text.toCharArray();
250 try {
251 antElementHandler.characters(characters, 0, characters.length, antXmlContext);
252 }
253 catch (final SAXParseException e) {
254 log.log(Level.WARNING, "SetText failed: " + task + ". Reason: " + e, e);
255 }
256 }
257
258 public Project getAntProject() {
259 return project;
260 }
261 }
262
263 /***
264 * Would be nice to retrieve location information (from AST?).
265 * In a first time, without info
266 */
267 class AntBuilderLocator implements Locator {
268 public int getColumnNumber()
269 {
270 return 0;
271 }
272 public int getLineNumber()
273 {
274 return 0;
275 }
276 public String getPublicId()
277 {
278 return "";
279 }
280 public String getSystemId()
281 {
282 return "";
283 }
284 }