| /* |
| * Copyright 2003-2007 the original author or authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package groovy.util; |
| |
| |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import org.apache.tools.ant.BuildLogger; |
| import org.apache.tools.ant.NoBannerLogger; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.RuntimeConfigurable; |
| import org.apache.tools.ant.Target; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.UnknownElement; |
| import org.apache.tools.ant.helper.AntXMLContext; |
| import org.apache.tools.ant.helper.ProjectHelper2; |
| import org.codehaus.groovy.ant.FileScanner; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.helpers.AttributesImpl; |
| import groovy.xml.QName; |
| |
| /** |
| * Allows Ant tasks to be used with GroovyMarkup |
| * |
| * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>, changes by Dierk Koenig (dk) |
| * @version $Revision$ |
| */ |
| public class AntBuilder extends BuilderSupport { |
| |
| private static final Class[] ADD_TASK_PARAM_TYPES = { String.class }; |
| |
| private final Logger log = Logger.getLogger(getClass().getName()); |
| private Project project; |
| private final AntXMLContext antXmlContext; |
| private final ProjectHelper2.ElementHandler antElementHandler = new ProjectHelper2.ElementHandler(); |
| private final Target collectorTarget; |
| private Object lastCompletedNode; |
| |
| |
| |
| public AntBuilder() { |
| this(createProject()); |
| } |
| |
| public AntBuilder(final Project project) { |
| this(project, new Target()); |
| } |
| |
| public AntBuilder(final Project project, final Target owningTarget) { |
| this.project = project; |
| |
| collectorTarget = owningTarget; |
| |
| antXmlContext = new AntXMLContext(project); |
| collectorTarget.setProject(project); |
| antXmlContext.setCurrentTarget(collectorTarget); |
| antXmlContext.setLocator(new AntBuilderLocator()); |
| |
| // FileScanner is a Groovy hack (utility?) |
| project.addDataTypeDefinition("fileScanner", FileScanner.class); |
| } |
| |
| public AntBuilder(final Task parentTask) { |
| this(parentTask.getProject(), parentTask.getOwningTarget()); |
| |
| // define "owning" task as wrapper to avoid having tasks added to the target |
| // but it needs to be an UnknownElement and no access is available from |
| // task to its original UnknownElement |
| final UnknownElement ue = new UnknownElement(parentTask.getTaskName()); |
| ue.setProject(parentTask.getProject()); |
| ue.setTaskType(parentTask.getTaskType()); |
| ue.setTaskName(parentTask.getTaskName()); |
| ue.setLocation(parentTask.getLocation()); |
| ue.setOwningTarget(parentTask.getOwningTarget()); |
| ue.setRuntimeConfigurableWrapper(parentTask.getRuntimeConfigurableWrapper()); |
| parentTask.getRuntimeConfigurableWrapper().setProxy(ue); |
| antXmlContext.pushWrapper(parentTask.getRuntimeConfigurableWrapper()); |
| } |
| |
| /**# |
| * Gets the Ant project in which the tasks are executed |
| * @return the project |
| */ |
| public Project getProject() { |
| return project; |
| } |
| |
| /** |
| * @return Factory method to create new Project instances |
| */ |
| protected static Project createProject() { |
| Project project = new Project(); |
| BuildLogger logger = new NoBannerLogger(); |
| |
| logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO); |
| logger.setOutputPrintStream(System.out); |
| logger.setErrorPrintStream(System.err); |
| |
| project.addBuildListener(logger); |
| |
| project.init(); |
| project.getBaseDir(); |
| return project; |
| } |
| |
| protected void setParent(Object parent, Object child) { |
| } |
| |
| |
| /** |
| * We don't want to return the node as created in {@link #createNode(Object, Map, Object)} |
| * but the one made ready by {@link #nodeCompleted(Object, Object)} |
| * @see groovy.util.BuilderSupport#doInvokeMethod(java.lang.String, java.lang.Object, java.lang.Object) |
| */ |
| protected Object doInvokeMethod(String methodName, Object name, Object args) { |
| super.doInvokeMethod(methodName, name, args); |
| |
| |
| // return the completed node |
| return lastCompletedNode; |
| } |
| |
| /** |
| * Determines, when the ANT Task that is represented by the "node" should perform. |
| * Node must be an ANT Task or no "perform" is called. |
| * If node is an ANT Task, it performs right after complete contstruction. |
| * If node is nested in a TaskContainer, calling "perform" is delegated to that |
| * TaskContainer. |
| * @param parent note: null when node is root |
| * @param node the node that now has all its children applied |
| */ |
| protected void nodeCompleted(final Object parent, final Object node) { |
| |
| antElementHandler.onEndElement(null, null, antXmlContext); |
| |
| lastCompletedNode = node; |
| if (parent != null) { |
| log.finest("parent is not null: no perform on nodeCompleted"); |
| return; // parent will care about when children perform |
| } |
| |
| // as in Target.execute() |
| if (node instanceof Task) { |
| Object task = node; |
| // "Unwrap" the UnknownElement to return the real task to the calling code |
| if (node instanceof UnknownElement) { |
| final UnknownElement unknownElement = (UnknownElement) node; |
| unknownElement.maybeConfigure(); |
| task = unknownElement.getRealThing(); |
| } |
| |
| lastCompletedNode = task; |
| // UnknownElement may wrap everything: task, path, ... |
| if (task instanceof Task) { |
| ((Task) task).perform(); |
| } |
| } |
| else { |
| final RuntimeConfigurable r = (RuntimeConfigurable) node; |
| r.maybeConfigure(project); |
| } |
| } |
| |
| protected Object createNode(Object tagName) { |
| return createNode(tagName, Collections.EMPTY_MAP); |
| } |
| |
| protected Object createNode(Object name, Object value) { |
| Object task = createNode(name); |
| setText(task, value.toString()); |
| return task; |
| } |
| |
| protected Object createNode(Object name, Map attributes, Object value) { |
| Object task = createNode(name, attributes); |
| setText(task, value.toString()); |
| return task; |
| } |
| |
| /** |
| * Builds an {@link Attributes} from a {@link Map} |
| * |
| * @param attributes the attributes to wrap |
| * @return the wrapped attributes |
| */ |
| protected static Attributes buildAttributes(final Map attributes) { |
| final AttributesImpl attr = new AttributesImpl(); |
| for (final Iterator iter=attributes.entrySet().iterator(); iter.hasNext(); ) { |
| final Map.Entry entry = (Map.Entry) iter.next(); |
| final String attributeName = (String) entry.getKey(); |
| final String attributeValue = String.valueOf(entry.getValue()); |
| attr.addAttribute(null, attributeName, attributeName, "CDATA", attributeValue); |
| } |
| return attr; |
| } |
| |
| protected Object createNode(final Object name, final Map attributes) { |
| |
| String tagName = name.toString(); |
| String ns = ""; |
| |
| if(name instanceof QName) { |
| QName q = (QName)name; |
| tagName = q.getLocalPart(); |
| ns = q.getNamespaceURI(); |
| } |
| |
| try |
| { |
| antElementHandler.onStartElement(ns, tagName, tagName, buildAttributes(attributes), antXmlContext); |
| } |
| catch (final SAXParseException e) |
| { |
| log.log(Level.SEVERE, "Caught: " + e, e); |
| } |
| |
| final RuntimeConfigurable wrapper = (RuntimeConfigurable) antXmlContext.getWrapperStack().lastElement(); |
| return wrapper.getProxy(); |
| } |
| |
| protected void setText(Object task, String text) { |
| final char[] characters = text.toCharArray(); |
| try { |
| antElementHandler.characters(characters, 0, characters.length, antXmlContext); |
| } |
| catch (final SAXParseException e) { |
| log.log(Level.WARNING, "SetText failed: " + task + ". Reason: " + e, e); |
| } |
| } |
| |
| public Project getAntProject() { |
| return project; |
| } |
| } |
| |
| /** |
| * Would be nice to retrieve location information (from AST?). |
| * In a first time, without info |
| */ |
| class AntBuilderLocator implements Locator { |
| public int getColumnNumber() |
| { |
| return 0; |
| } |
| public int getLineNumber() |
| { |
| return 0; |
| } |
| public String getPublicId() |
| { |
| return ""; |
| } |
| public String getSystemId() |
| { |
| return ""; |
| } |
| } |