| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.easyant.core.ant.helper; |
| |
| import org.apache.easyant.core.ant.Phase; |
| import org.apache.easyant.core.ant.ProjectUtils; |
| import org.apache.tools.ant.*; |
| import org.apache.tools.ant.helper.AntXMLContext; |
| import org.apache.tools.ant.helper.ProjectHelper2; |
| import org.apache.tools.ant.types.Resource; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXParseException; |
| |
| import java.util.Map; |
| |
| /** |
| * This class is the custom project helper used by easyant introducing support for phase concept |
| */ |
| public class EasyAntProjectHelper extends ProjectHelper2 { |
| |
| public EasyAntProjectHelper() { |
| super(); |
| setProjectHandler(new EasyAntProjectHandler()); |
| setTargetHandler(new EasyAntTargetHandler()); |
| } |
| |
| @Override |
| public boolean canParseBuildFile(Resource buildFile) { |
| return buildFile.getName().endsWith(".ant") || buildFile.getName().endsWith(".xml"); |
| } |
| |
| /** |
| * Handler for the top level "project" element. |
| */ |
| public static class EasyAntProjectHandler extends ProjectHandler { |
| |
| /** |
| * Handles the start of a top-level element within the project. An appropriate handler is created and |
| * initialised with the details of the element. |
| * |
| * @param uri The namespace URI for this element. |
| * @param name The name of the element being started. Will not be <code>null</code>. |
| * @param qname The qualified name for this element. |
| * @param attrs Attributes of the element being started. Will not be <code>null</code>. |
| * @param context The context for this element. |
| * @return a target or an element handler. |
| * @throws org.xml.sax.SAXParseException if the tag given is not <code>"taskdef"</code>, <code>"typedef"</code>, |
| * <code>"property"</code>, <code>"target"</code>, <code>"phase"</code> or a data type definition |
| */ |
| public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, AntXMLContext context) |
| throws SAXParseException { |
| |
| return (name.equals("target") || name.equals("phase") || name.equals("extension-point")) |
| && (uri.equals("") || uri.equals(ANT_CORE_URI)) ? getTargetHandler() : getElementHandler(); |
| } |
| } |
| |
| /** |
| * Handler for "target" and "phase" elements. |
| */ |
| public static class EasyAntTargetHandler extends TargetHandler { |
| |
| /** |
| * Initialisation routine called after handler creation with the element name and attributes. The attributes |
| * which this handler can deal with are: <code>"name"</code>, <code>"depends"</code>, <code>"if"</code>, |
| * <code>"unless"</code>, <code>"id"</code> and <code>"description"</code>. |
| * |
| * @param uri The namespace URI for this element. |
| * @param tag Name of the element which caused this handler to be created. Should not be <code>null</code>. |
| * Ignored in this implementation. |
| * @param qname The qualified name for this element. |
| * @param attrs Attributes of the element which caused this handler to be created. Must not be <code>null</code>. |
| * @param context The current context. |
| * @throws SAXParseException if an unexpected attribute is encountered or if the <code>"name"</code> attribute is missing. |
| */ |
| public void onStartElement(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) |
| throws SAXParseException { |
| |
| String name = null; |
| String depends = ""; |
| String extensionPoint = null; |
| String phase = null; |
| OnMissingExtensionPoint extensionPointMissing = null; |
| |
| Project project = context.getProject(); |
| |
| Target target; |
| if ("extension-point".equals(tag)) { |
| target = new ExtensionPoint(); |
| } else if ("phase".equals(tag)) { |
| target = new Phase(); |
| } else { |
| target = new Target(); |
| } |
| |
| target.setProject(project); |
| target.setLocation(new Location(context.getLocator())); |
| context.addTarget(target); |
| |
| for (int i = 0; i < attrs.getLength(); i++) { |
| String attrUri = attrs.getURI(i); |
| if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) { |
| continue; // Ignore attributes from unknown uris |
| } |
| String key = attrs.getLocalName(i); |
| String value = attrs.getValue(i); |
| |
| if (key.equals("name")) { |
| name = value; |
| if ("".equals(name)) { |
| throw new BuildException("name attribute must " + "not be empty"); |
| } |
| } else if (key.equals("depends")) { |
| depends = value; |
| } else if (key.equals("if")) { |
| target.setIf(value); |
| } else if (key.equals("unless")) { |
| target.setUnless(value); |
| } else if (key.equals("id")) { |
| if (value != null && !value.equals("")) { |
| context.getProject().addReference(value, target); |
| } |
| } else if (key.equals("description")) { |
| target.setDescription(value); |
| } else if (key.equals("extensionOf")) { |
| extensionPoint = value; |
| } else if (key.equals("onMissingExtensionPoint")) { |
| try { |
| extensionPointMissing = OnMissingExtensionPoint.valueOf(value); |
| } catch (IllegalArgumentException e) { |
| throw new BuildException("Invalid onMissingExtensionPoint " + value); |
| } |
| } else if (key.equals("phase")) { |
| phase = value; |
| } else { |
| throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.getLocator()); |
| } |
| } |
| |
| if (name == null) { |
| throw new SAXParseException("target element appears without a name attribute", context.getLocator()); |
| } |
| |
| boolean isPhase = target instanceof Phase; |
| |
| String prefix = null; |
| boolean isInIncludeMode = context.isIgnoringProjectTag() && isInIncludeMode(); |
| String sep = getCurrentPrefixSeparator(); |
| |
| if (isInIncludeMode && !isPhase) { |
| prefix = getTargetPrefix(context); |
| if (prefix == null) { |
| throw new BuildException("can't include build file " + context.getBuildFile() |
| + ", no as attribute has been given" + " and the project tag doesn't" |
| + " specify a name attribute"); |
| } |
| name = prefix + sep + name; |
| } |
| |
| // Check if this target is in the current build file |
| if (context.getCurrentTargets().get(name) != null) { |
| throw new BuildException("Duplicate target '" + name + "'", target.getLocation()); |
| } |
| Map<String, Target> projectTargets = project.getTargets(); |
| boolean usedTarget = false; |
| // If the name has not already been defined define it |
| if (projectTargets.containsKey(name)) { |
| project.log("Already defined in main or a previous import, ignore " + name, Project.MSG_VERBOSE); |
| } else { |
| target.setName(name); |
| context.getCurrentTargets().put(name, target); |
| project.addOrReplaceTarget(name, target); |
| usedTarget = true; |
| } |
| |
| if (!depends.isEmpty()) { |
| if (!isInIncludeMode) { |
| target.setDepends(depends); |
| } else { |
| for (String curTarget : Target.parseDepends(depends, name, "depends")) { |
| if (projectTargets.containsKey(curTarget) && (projectTargets.get(curTarget) instanceof Phase)) { |
| |
| target.addDependency(curTarget); |
| } else { |
| target.addDependency(prefix + sep + curTarget); |
| } |
| } |
| } |
| } |
| if (!isInIncludeMode && context.isIgnoringProjectTag() && (prefix = getTargetPrefix(context)) != null) { |
| // In an imported file (and not completely |
| // ignoring the project tag or having a preconfigured prefix) |
| String newName = prefix + sep + name; |
| Target newTarget = usedTarget ? new Target(target) : target; |
| newTarget.setName(newName); |
| context.getCurrentTargets().put(newName, newTarget); |
| project.addOrReplaceTarget(newName, newTarget); |
| } |
| if (extensionPointMissing != null && extensionPoint == null) { |
| throw new BuildException("onMissingExtensionPoint attribute cannot " |
| + "be specified unless extensionOf is specified", target.getLocation()); |
| } |
| if (extensionPoint != null) { |
| ProjectHelper helper = ProjectUtils.getConfiguredProjectHelper(context.getProject()); |
| for (String tgName : Target.parseDepends(extensionPoint, name, "extensionOf")) { |
| if (isInIncludeMode()) { |
| tgName = prefix + sep + tgName; |
| } |
| if (extensionPointMissing == null) { |
| extensionPointMissing = OnMissingExtensionPoint.FAIL; |
| } |
| |
| // defer extensionpoint resolution until the full |
| // import stack has been processed |
| helper.getExtensionStack().add(new String[]{tgName, name, extensionPointMissing.name()}); |
| } |
| } |
| if (phase != null) { |
| if (!projectTargets.containsKey(phase)) { |
| if (!Project.toBoolean(project.getProperty("audit.mode"))) { |
| throw new BuildException("can't add target " + name + " to phase " + phase |
| + " because the phase" + " is unknown."); |
| } else { |
| Phase p = new Phase(); |
| p.setName(phase); |
| project.addTarget(p); |
| } |
| } |
| |
| Target t = projectTargets.get(phase); |
| if (t != null) { |
| if (!(t instanceof Phase)) { |
| throw new BuildException("referenced target " + phase + " is not a phase"); |
| } |
| t.addDependency(name); |
| } |
| } |
| |
| } |
| |
| private String getTargetPrefix(AntXMLContext context) { |
| String configuredValue = getCurrentTargetPrefix(); |
| if (configuredValue != null && configuredValue.isEmpty()) { |
| configuredValue = null; |
| } |
| if (configuredValue != null) { |
| return configuredValue; |
| } |
| |
| String projectName = context.getCurrentProjectName(); |
| if ("".equals(projectName)) { |
| projectName = null; |
| } |
| |
| return projectName; |
| } |
| |
| } |
| |
| } |