/src/Tum.CollabXT.TFS/Processors/TemplateProcessor.cs
C# | 306 lines | 210 code | 38 blank | 58 comment | 29 complexity | ff2249d798b94da906b27fc9ef9ca60e MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.IO;
- using System.Resources;
- using System.Xml;
- using Tum.CollabXT.TFS.Resources;
- using System.Collections;
-
- namespace Tum.CollabXT.TFS
- {
- internal class TemplateProcessor
- {
- /// <summary>
- /// Dictionary to resolve the translation from a template processor type name to its type.
- /// </summary>
- internal static readonly Dictionary<string, ProcessorType> ProcessorNameToTypeDictionary = new Dictionary<string, ProcessorType>();
-
- /// <summary>
- /// Gets the used TFS tool provider.
- /// </summary>
- public TFSToolProvider ToolProvider
- {
- get;
- private set;
- }
-
- /// <summary>
- /// Gets the belonging process provider.
- /// </summary>
- public IProcessProvider ProcessProvider
- {
- get
- {
- return ToolProvider.ProcessProvider;
- }
- }
-
- /// <summary>
- /// Gets a dictionary of localized strings to be used within the provider.
- /// </summary>
- public Dictionary<string, string> LanguageDictionary
- {
- get;
- private set;
- }
-
-
- /// <summary>
- /// Gets or sets the name of the resource file that contains the template localizations.
- /// </summary>
- public string LanguageFileName
- {
- get;
- internal set;
- }
-
- /// <summary>
- /// Gets or sets the name of the TFS template folder contained in the provider's template.
- /// </summary>
- public string InnerTemplateFolder
- {
- get;
- internal set;
- }
-
- /// <summary>
- /// Name of the TFS process template configuration file.
- /// </summary>
- const string ProcessTemplateFile = "ProcessTemplate.xml";
-
- /// <summary>
- /// Gets the configuration document for the template.
- /// </summary>
- public XmlDocument TemplateConfigDocument
- {
- get;
- private set;
- }
-
- /// <summary>
- /// Static constructor. Builds the processor name to type dictionary.
- /// </summary>
- static TemplateProcessor()
- {
- ProcessorNameToTypeDictionary.Add("classification", ProcessorType.Classification);
- ProcessorNameToTypeDictionary.Add("groups", ProcessorType.Groups);
- ProcessorNameToTypeDictionary.Add("portal", ProcessorType.Portal);
- ProcessorNameToTypeDictionary.Add("workitemtracking", ProcessorType.WorkItemTracking);
- }
-
- /// <summary>
- /// Constructor.
- /// </summary>
- /// <param name="tfsTP">Tool provider to be used. TFSToolProvider.TemplatePath must end with \\ or /.</param>
- public TemplateProcessor(TFSToolProvider tfsTP)
- {
- if (tfsTP == null)
- throw new ArgumentNullException("tfsTP");
- ToolProvider = tfsTP;
- }
-
- /// <summary>
- /// Checks if all data specified by the tool provider is valid.
- /// </summary>
- private void CheckProviderData()
- {
- if (!Directory.Exists(ToolProvider.TemplatePath))
- throw new DirectoryNotFoundException("TemplatePath");
- if (!File.Exists(ToolProvider.TemplatePath + LanguageFileName))
- throw new FileNotFoundException(LanguageFileName);
- if (!Directory.Exists(ToolProvider.TemplatePath + InnerTemplateFolder))
- throw new DirectoryNotFoundException("InnerTemplateFolder");
- if (!File.Exists(ToolProvider.TemplatePath + InnerTemplateFolder + "/" + ProcessTemplateFile))
- throw new FileNotFoundException(ProcessTemplateFile);
- }
-
- /// <summary>
- /// Creates the final TFS process template.
- /// </summary>
- /// <param name="templateConfigDocument">Config document used for this template.</param>
- public void Process(XmlDocument templateConfigDocument)
- {
- if (templateConfigDocument == null)
- throw new ArgumentNullException("templateConfigDocument");
- TemplateConfigDocument = templateConfigDocument;
-
- //Check input data
- CheckProviderData();
-
-
- //Load language file
- LanguageDictionary = LoadLanguageDictionary(ToolProvider.TemplatePath + LanguageFileName);
-
- //Create output dictionary
- Directory.CreateDirectory(ToolProvider.OutputPath);
-
-
- #region Copy template
- ToolProvider.ProcessLog.AddEntry(Language.Processing_OutputDirectory);
- //Clean output directory
- try
- {
- Helper.DeleteDirectory(ToolProvider.OutputPath);
- }
- catch
- {
- ToolProvider.ProcessLog.AddEntry(Language.Error_DeletingOutputDirectory, LogEntryType.Error);
- return;
- }
-
- try
- {
- //Copy template data to output directory
- Helper.CopyDirectory(ToolProvider.TemplatePath + "tpl/", ToolProvider.OutputPath);
- }
- catch (FileCopyException e)
- {
- ToolProvider.ProcessLog.AddEntry(string.Format(Language.Template_FileCopyFailed, e.SourcePath, e.DestinationPath), LogEntryType.Error);
- return;
- }
- catch (Exception e)
- {
- throw new TFSException(string.Format(Language.Error_Unexpected, e.Message, e.StackTrace));
- }
- #endregion
-
- //Build template processors list
- List<IProcessor> templateProcessors = new List<IProcessor>();
- var templateProcessorNodes = templateConfigDocument.SelectNodes("//Tasks/Task");
-
- //Order list (e.g. workitems must be before classification)
- var orderedTemplateProcessorNodesList = new SortedList<ProcessorType, XmlNode>(new ProcessorOrderComparer());
- foreach (XmlNode curProcessorNode in templateProcessorNodes)
- {
- string curProcessorType = curProcessorNode.Attributes["type"].Value.ToLower();
- if (!ProcessorNameToTypeDictionary.ContainsKey(curProcessorType))
- throw new TemplateConfigInvalidException("Unknown Task type");
- orderedTemplateProcessorNodesList.Add(ProcessorNameToTypeDictionary[curProcessorType], curProcessorNode);
- }
-
- //First processor is the process template processor
- templateProcessors.Add(new ProcessTemplate());
-
- //Create processor instance list
- WorkItems workItemProcessor = null;
- foreach (var curProcessorEntry in orderedTemplateProcessorNodesList)
- {
- IProcessor curProcessor = null;
-
- switch (curProcessorEntry.Key)
- {
- case ProcessorType.WorkItemTracking:
- workItemProcessor = new WorkItems();
- curProcessor = workItemProcessor; // save work item processor for classification
- break;
-
- case ProcessorType.Portal:
- curProcessor = new WSS();
- break;
-
- case ProcessorType.Groups:
- curProcessor = new GroupsAndPermissions();
- break;
-
- case ProcessorType.Classification:
- if (workItemProcessor == null)
- throw new TFSException("Internal error");
- curProcessor = new Classification(workItemProcessor);
- break;
- }
- if (curProcessor == null)
- throw new TFSException("Internal error"); //No processor created. Must not happen
-
- //Complete processor initialization and add it to list
- curProcessor.TaskFileName = curProcessorEntry.Value.Attributes["file"].Value;
- curProcessor.TaskFileFolder = curProcessorEntry.Value.Attributes["folder"].Value;
-
- templateProcessors.Add(curProcessor);
- }
-
- try
- {
- //Run processors
- foreach (IProcessor curProcessor in templateProcessors)
- {
- ToolProvider.ProcessLog.AddSeparator();
- if (!curProcessor.Process(this))
- {
- //Processing failed
- if (ToolProvider.ProcessLog.ErrorCount == 0)
- {
- //Error not set by processor. Add it.
- ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_Unexpected, curProcessor.GetType()), LogEntryType.Error);
- return;
- }
- }
- }
-
- ToolProvider.ProcessLog.AddSeparator();
- ToolProvider.ProcessLog.AddEntry(Language.Processing_CompletedSuccessfully);
- }
- catch (Exception e)
- {
- throw new TFSException(string.Format(Language.Error_Unexpected, e.Message, e.StackTrace));
- }
- }
-
-
- /// <summary>
- /// Loads a dictionary from a language resource file.
- /// </summary>
- /// <param name="languageResourceFile">The .resources file's path.</param>
- /// <returns>Dictionary with all language ent</returns>
- private static Dictionary<string, string> LoadLanguageDictionary(string languageResourceFile)
- {
- try
- {
- using (ResourceReader reader = new ResourceReader(languageResourceFile))
- {
- var dict = new Dictionary<string, string>();
- foreach (DictionaryEntry entry in reader)
- {
- string key = entry.Key as string;
- if (key == null)
- continue;
- dict.Add(key, entry.Value as string);
- }
- return dict;
- }
- }
- catch (Exception)
- {
- return null;
- }
- }
- }
-
- internal class ProcessorOrderComparer : IComparer<ProcessorType>
- {
- public int Compare(ProcessorType x, ProcessorType y)
- {
- if(x == y)
- return 0;
-
- //WorkItemTracking must always be first, classification must always be last
- if (x == ProcessorType.WorkItemTracking || y == ProcessorType.Classification)
- return -1;
- if (y == ProcessorType.WorkItemTracking || x == ProcessorType.Classification)
- return 1;
-
- //In all other cases order does not matter
- return x.CompareTo(y);
- }
- }
-
- internal enum ProcessorType
- {
- ProcessTemplate,
- Classification,
- Groups,
- Portal,
- WorkItemTracking,
- }
- }