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