// NAnt - A .NET build tool // Copyright (C) 2002-2003 Scott Hernandez // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Scott Hernandez (ScottHernandez@hotmail.com) using System; using System.Collections; using System.Collections.Specialized; using System.Globalization; using System.Reflection; using System.Xml; using NAnt.Core.Attributes; using NAnt.Core.Tasks; using NAnt.Core.Types; using NAnt.Core.Util; namespace NAnt.Core { /// /// Executes embedded tasks in the order in which they are defined. /// public class TaskContainer : Task { #region Private Instance Fields private StringCollection _subXMLElements; #endregion Private Instance Fields #region Override implementation of Element /// /// Gets a value indicating whether the element is performing additional /// processing using the that was use to /// initialize the element. /// /// /// , as a is /// responsable for creating tasks from the nested build elements. /// protected override bool CustomXmlProcessing { get { return true;} } #endregion Override implementation of Element #region Override implementation of Task /// /// Automatically exclude build elements that are defined on the task /// from things that get executed, as they are evaluated normally during /// XML task initialization. /// /// used to initialize the container. protected override void InitializeTask(XmlNode taskNode) { base.InitializeTask(taskNode); // Exclude any BuildElements (like FileSets, etc.) from our execution elements. // These build elements will be handled during the xml init of the task container (Element xmlinit code) _subXMLElements = new StringCollection(); foreach (MemberInfo memInfo in this.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public)) { if(memInfo.DeclaringType.Equals(typeof(object))) { continue; } BuildElementAttribute buildElemAttr = (BuildElementAttribute) Attribute.GetCustomAttribute(memInfo, typeof(BuildElementAttribute), true); if (buildElemAttr != null) { _subXMLElements.Add(buildElemAttr.Name); } } } protected override void ExecuteTask() { ExecuteChildTasks(); } #endregion Override implementation of Task #region Protected Instance Methods /// /// Creates and executes the embedded (child XML nodes) elements. /// /// /// Skips any element defined by the host that has /// a defined. /// protected virtual void ExecuteChildTasks() { foreach (XmlNode childNode in XmlNode) { //we only care about xmlnodes (elements) that are of the right namespace. if (!(childNode.NodeType == XmlNodeType.Element) || !childNode.NamespaceURI.Equals(NamespaceManager.LookupNamespace("nant"))) { continue; } // ignore any private xml elements (by def. this includes any property with a BuildElementAttribute (name). if (IsPrivateXmlElement(childNode)) { continue; } if (TypeFactory.TaskBuilders.Contains(childNode.Name)) { // create task instance Task task = CreateChildTask(childNode); // for now, we should assume null tasks are because of // incomplete metadata about the XML if (task != null) { task.Parent = this; // execute task task.Execute(); } } else if (TypeFactory.DataTypeBuilders.Contains(childNode.Name)) { // we are an datatype declaration DataTypeBase dataType = CreateChildDataTypeBase(childNode); Log(Level.Debug, "Adding a {0} reference with id '{1}'.", childNode.Name, dataType.ID); if (!Project.DataTypeReferences.Contains(dataType.ID)) { Project.DataTypeReferences.Add(dataType.ID, dataType); } else { Project.DataTypeReferences[dataType.ID] = dataType; // overwrite with the new reference. } } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, ResourceUtils.GetString("NA1071"), childNode.Name), Project.LocationMap.GetLocation(childNode)); } } } protected virtual Task CreateChildTask(XmlNode node) { return Project.CreateTask(node); } protected virtual DataTypeBase CreateChildDataTypeBase(XmlNode node) { return Project.CreateDataTypeBase(node); } protected virtual bool IsPrivateXmlElement(XmlNode node) { return (_subXMLElements != null && _subXMLElements.Contains(node.Name)); } protected virtual void AddPrivateXmlElementName(string name) { if (_subXMLElements == null) { _subXMLElements = new StringCollection(); } if (!_subXMLElements.Contains(name)) { _subXMLElements.Add(name); } } #endregion Protected Instance Methods } }