PageRenderTime 69ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Tum.CollabXT.TFS/Processors/TemplateProcessor.cs

#
C# | 306 lines | 210 code | 38 blank | 58 comment | 29 complexity | ff2249d798b94da906b27fc9ef9ca60e MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Resources;
  7. using System.Xml;
  8. using Tum.CollabXT.TFS.Resources;
  9. using System.Collections;
  10. namespace Tum.CollabXT.TFS
  11. {
  12. internal class TemplateProcessor
  13. {
  14. /// <summary>
  15. /// Dictionary to resolve the translation from a template processor type name to its type.
  16. /// </summary>
  17. internal static readonly Dictionary<string, ProcessorType> ProcessorNameToTypeDictionary = new Dictionary<string, ProcessorType>();
  18. /// <summary>
  19. /// Gets the used TFS tool provider.
  20. /// </summary>
  21. public TFSToolProvider ToolProvider
  22. {
  23. get;
  24. private set;
  25. }
  26. /// <summary>
  27. /// Gets the belonging process provider.
  28. /// </summary>
  29. public IProcessProvider ProcessProvider
  30. {
  31. get
  32. {
  33. return ToolProvider.ProcessProvider;
  34. }
  35. }
  36. /// <summary>
  37. /// Gets a dictionary of localized strings to be used within the provider.
  38. /// </summary>
  39. public Dictionary<string, string> LanguageDictionary
  40. {
  41. get;
  42. private set;
  43. }
  44. /// <summary>
  45. /// Gets or sets the name of the resource file that contains the template localizations.
  46. /// </summary>
  47. public string LanguageFileName
  48. {
  49. get;
  50. internal set;
  51. }
  52. /// <summary>
  53. /// Gets or sets the name of the TFS template folder contained in the provider's template.
  54. /// </summary>
  55. public string InnerTemplateFolder
  56. {
  57. get;
  58. internal set;
  59. }
  60. /// <summary>
  61. /// Name of the TFS process template configuration file.
  62. /// </summary>
  63. const string ProcessTemplateFile = "ProcessTemplate.xml";
  64. /// <summary>
  65. /// Gets the configuration document for the template.
  66. /// </summary>
  67. public XmlDocument TemplateConfigDocument
  68. {
  69. get;
  70. private set;
  71. }
  72. /// <summary>
  73. /// Static constructor. Builds the processor name to type dictionary.
  74. /// </summary>
  75. static TemplateProcessor()
  76. {
  77. ProcessorNameToTypeDictionary.Add("classification", ProcessorType.Classification);
  78. ProcessorNameToTypeDictionary.Add("groups", ProcessorType.Groups);
  79. ProcessorNameToTypeDictionary.Add("portal", ProcessorType.Portal);
  80. ProcessorNameToTypeDictionary.Add("workitemtracking", ProcessorType.WorkItemTracking);
  81. }
  82. /// <summary>
  83. /// Constructor.
  84. /// </summary>
  85. /// <param name="tfsTP">Tool provider to be used. TFSToolProvider.TemplatePath must end with \\ or /.</param>
  86. public TemplateProcessor(TFSToolProvider tfsTP)
  87. {
  88. if (tfsTP == null)
  89. throw new ArgumentNullException("tfsTP");
  90. ToolProvider = tfsTP;
  91. }
  92. /// <summary>
  93. /// Checks if all data specified by the tool provider is valid.
  94. /// </summary>
  95. private void CheckProviderData()
  96. {
  97. if (!Directory.Exists(ToolProvider.TemplatePath))
  98. throw new DirectoryNotFoundException("TemplatePath");
  99. if (!File.Exists(ToolProvider.TemplatePath + LanguageFileName))
  100. throw new FileNotFoundException(LanguageFileName);
  101. if (!Directory.Exists(ToolProvider.TemplatePath + InnerTemplateFolder))
  102. throw new DirectoryNotFoundException("InnerTemplateFolder");
  103. if (!File.Exists(ToolProvider.TemplatePath + InnerTemplateFolder + "/" + ProcessTemplateFile))
  104. throw new FileNotFoundException(ProcessTemplateFile);
  105. }
  106. /// <summary>
  107. /// Creates the final TFS process template.
  108. /// </summary>
  109. /// <param name="templateConfigDocument">Config document used for this template.</param>
  110. public void Process(XmlDocument templateConfigDocument)
  111. {
  112. if (templateConfigDocument == null)
  113. throw new ArgumentNullException("templateConfigDocument");
  114. TemplateConfigDocument = templateConfigDocument;
  115. //Check input data
  116. CheckProviderData();
  117. //Load language file
  118. LanguageDictionary = LoadLanguageDictionary(ToolProvider.TemplatePath + LanguageFileName);
  119. //Create output dictionary
  120. Directory.CreateDirectory(ToolProvider.OutputPath);
  121. #region Copy template
  122. ToolProvider.ProcessLog.AddEntry(Language.Processing_OutputDirectory);
  123. //Clean output directory
  124. try
  125. {
  126. Helper.DeleteDirectory(ToolProvider.OutputPath);
  127. }
  128. catch
  129. {
  130. ToolProvider.ProcessLog.AddEntry(Language.Error_DeletingOutputDirectory, LogEntryType.Error);
  131. return;
  132. }
  133. try
  134. {
  135. //Copy template data to output directory
  136. Helper.CopyDirectory(ToolProvider.TemplatePath + "tpl/", ToolProvider.OutputPath);
  137. }
  138. catch (FileCopyException e)
  139. {
  140. ToolProvider.ProcessLog.AddEntry(string.Format(Language.Template_FileCopyFailed, e.SourcePath, e.DestinationPath), LogEntryType.Error);
  141. return;
  142. }
  143. catch (Exception e)
  144. {
  145. throw new TFSException(string.Format(Language.Error_Unexpected, e.Message, e.StackTrace));
  146. }
  147. #endregion
  148. //Build template processors list
  149. List<IProcessor> templateProcessors = new List<IProcessor>();
  150. var templateProcessorNodes = templateConfigDocument.SelectNodes("//Tasks/Task");
  151. //Order list (e.g. workitems must be before classification)
  152. var orderedTemplateProcessorNodesList = new SortedList<ProcessorType, XmlNode>(new ProcessorOrderComparer());
  153. foreach (XmlNode curProcessorNode in templateProcessorNodes)
  154. {
  155. string curProcessorType = curProcessorNode.Attributes["type"].Value.ToLower();
  156. if (!ProcessorNameToTypeDictionary.ContainsKey(curProcessorType))
  157. throw new TemplateConfigInvalidException("Unknown Task type");
  158. orderedTemplateProcessorNodesList.Add(ProcessorNameToTypeDictionary[curProcessorType], curProcessorNode);
  159. }
  160. //First processor is the process template processor
  161. templateProcessors.Add(new ProcessTemplate());
  162. //Create processor instance list
  163. WorkItems workItemProcessor = null;
  164. foreach (var curProcessorEntry in orderedTemplateProcessorNodesList)
  165. {
  166. IProcessor curProcessor = null;
  167. switch (curProcessorEntry.Key)
  168. {
  169. case ProcessorType.WorkItemTracking:
  170. workItemProcessor = new WorkItems();
  171. curProcessor = workItemProcessor; // save work item processor for classification
  172. break;
  173. case ProcessorType.Portal:
  174. curProcessor = new WSS();
  175. break;
  176. case ProcessorType.Groups:
  177. curProcessor = new GroupsAndPermissions();
  178. break;
  179. case ProcessorType.Classification:
  180. if (workItemProcessor == null)
  181. throw new TFSException("Internal error");
  182. curProcessor = new Classification(workItemProcessor);
  183. break;
  184. }
  185. if (curProcessor == null)
  186. throw new TFSException("Internal error"); //No processor created. Must not happen
  187. //Complete processor initialization and add it to list
  188. curProcessor.TaskFileName = curProcessorEntry.Value.Attributes["file"].Value;
  189. curProcessor.TaskFileFolder = curProcessorEntry.Value.Attributes["folder"].Value;
  190. templateProcessors.Add(curProcessor);
  191. }
  192. try
  193. {
  194. //Run processors
  195. foreach (IProcessor curProcessor in templateProcessors)
  196. {
  197. ToolProvider.ProcessLog.AddSeparator();
  198. if (!curProcessor.Process(this))
  199. {
  200. //Processing failed
  201. if (ToolProvider.ProcessLog.ErrorCount == 0)
  202. {
  203. //Error not set by processor. Add it.
  204. ToolProvider.ProcessLog.AddEntry(string.Format(Language.Error_Unexpected, curProcessor.GetType()), LogEntryType.Error);
  205. return;
  206. }
  207. }
  208. }
  209. ToolProvider.ProcessLog.AddSeparator();
  210. ToolProvider.ProcessLog.AddEntry(Language.Processing_CompletedSuccessfully);
  211. }
  212. catch (Exception e)
  213. {
  214. throw new TFSException(string.Format(Language.Error_Unexpected, e.Message, e.StackTrace));
  215. }
  216. }
  217. /// <summary>
  218. /// Loads a dictionary from a language resource file.
  219. /// </summary>
  220. /// <param name="languageResourceFile">The .resources file's path.</param>
  221. /// <returns>Dictionary with all language ent</returns>
  222. private static Dictionary<string, string> LoadLanguageDictionary(string languageResourceFile)
  223. {
  224. try
  225. {
  226. using (ResourceReader reader = new ResourceReader(languageResourceFile))
  227. {
  228. var dict = new Dictionary<string, string>();
  229. foreach (DictionaryEntry entry in reader)
  230. {
  231. string key = entry.Key as string;
  232. if (key == null)
  233. continue;
  234. dict.Add(key, entry.Value as string);
  235. }
  236. return dict;
  237. }
  238. }
  239. catch (Exception)
  240. {
  241. return null;
  242. }
  243. }
  244. }
  245. internal class ProcessorOrderComparer : IComparer<ProcessorType>
  246. {
  247. public int Compare(ProcessorType x, ProcessorType y)
  248. {
  249. if(x == y)
  250. return 0;
  251. //WorkItemTracking must always be first, classification must always be last
  252. if (x == ProcessorType.WorkItemTracking || y == ProcessorType.Classification)
  253. return -1;
  254. if (y == ProcessorType.WorkItemTracking || x == ProcessorType.Classification)
  255. return 1;
  256. //In all other cases order does not matter
  257. return x.CompareTo(y);
  258. }
  259. }
  260. internal enum ProcessorType
  261. {
  262. ProcessTemplate,
  263. Classification,
  264. Groups,
  265. Portal,
  266. WorkItemTracking,
  267. }
  268. }