Пример #1
0
 /// <summary>
 /// Gets the template manifest for this template. Can optionally parse an entire template manifest spanning tree.
 /// See <see cref="ManifestParseFlags"/> for details.
 /// </summary>
 /// <param name="parseFlags">See <see cref="ManifestParseFlags"/>.</param>
 /// <returns></returns>
 public TemplateManifest GetManifest(ManifestParseFlags parseFlags)
 {
     return(TemplateManifest.ParseManifest(FileName, Location, parseFlags));
 }
        /// <summary>
        /// <c>ParseManifest</c> parses the XML template manifest indicated by <paramref name="fileName"/>
        /// and <paramref name="location"/>, and creates a corresponding instance of <c>TemplateManifest</c>.
        /// </summary>
        /// <param name="fileName">The file name of the template</param>
        /// <param name="location">The location of the template, such as a file system folder, a package file, a database, etc.</param>
        /// <param name="parseFlags">Specifies settings related to template manifest creation</param>
        /// <returns>a reference to the newly created <c>TemplateManifest</c></returns>
        public static TemplateManifest ParseManifest(string fileName, TemplateLocation location, ManifestParseFlags parseFlags)
        {
            TemplateManifest     templateManifest = new TemplateManifest();
            TemplateFileLocation baseTemplateLoc  = new TemplateFileLocation(fileName, location);

            HashSet <VariableInfo>   variables       = GetHashSet <VariableInfo>(parseFlags, ManifestParseFlags.ParseVariables);
            HashSet <Dependency>     dependencies    = GetHashSet <Dependency>(parseFlags, ManifestParseFlags.ParseDependencies);
            HashSet <AdditionalFile> additionalFiles = GetHashSet <AdditionalFile>(parseFlags, ManifestParseFlags.ParseAdditionalFiles);
            HashSet <DataSource>     dataSources     = GetHashSet <DataSource>(parseFlags, ManifestParseFlags.ParseDataSources);

            Queue <TemplateFileLocation>   templateQueue      = new Queue <TemplateFileLocation>();
            HashSet <TemplateFileLocation> processedTemplates = new HashSet <TemplateFileLocation>();

            // Add the base template to the queue
            templateQueue.Enqueue(baseTemplateLoc);

            while (templateQueue.Count > 0)
            {
                TemplateFileLocation templateFileLoc = templateQueue.Dequeue();
                if (!processedTemplates.Contains(templateFileLoc))
                {
                    try
                    {
                        // TODO: Condider re-writing this using an XmlReader so that the entire document does not need to be allocated in a DOM. Doing so
                        // should make processing template manifest files faster. For now using an XDocument to just get things done fast.
                        XDocument manifest;
                        using (Stream manifestStream = templateFileLoc.FileLocation.GetFile(GetManifestName(templateFileLoc.FileName)))
                        {
                            // Read the template manifest so that it can be parsed.
                            manifest = XDocument.Load(manifestStream, LoadOptions.None);
                        }

                        if (templateFileLoc.Equals(baseTemplateLoc))
                        {
                            // Process the root templateManifest element.
                            templateManifest.HotDocsVersion       = manifest.Root.Attribute("hotdocsVersion").Value;
                            templateManifest.TemplateId           = manifest.Root.Attribute("templateId").Value;
                            templateManifest.FileName             = manifest.Root.Attribute("fileName").Value;
                            templateManifest.EffectiveCmpFileName = manifest.Root.Attribute("effectiveCmpFile").Value;

                            if (manifest.Root.Attribute("expirationDate") != null)
                            {
                                templateManifest.ExpirationDate = DateTime.Parse(manifest.Root.Attribute("expirationDate").Value);

                                if (manifest.Root.Attribute("warningDays") != null)
                                {
                                    templateManifest.WarningDays = int.Parse(manifest.Root.Attribute("warningDays").Value);
                                }

                                if (manifest.Root.Attribute("extensionDays") != null)
                                {
                                    templateManifest.ExtensionDays = int.Parse(manifest.Root.Attribute("extensionDays").Value);
                                }
                            }

                            var titleElem = manifest.Root.Element(s_namespace + "title");
                            templateManifest.Title = (titleElem != null) ? titleElem.Value.Trim() : string.Empty;

                            var descriptionElem = manifest.Root.Element(s_namespace + "description");
                            templateManifest.Description = (descriptionElem != null) ? descriptionElem.Value.Trim() : string.Empty;
                        }

                        if (variables != null)
                        {
                            // Process the variables element.
                            var variablesElem = manifest.Root.Element(s_namespace + "variables");
                            if (variablesElem != null)
                            {
                                // Add any not yet encountered variable to the variables collection.
                                foreach (var variableElem in variablesElem.Elements(s_namespace + "variable"))
                                {
                                    ValueType valueType;
                                    switch (variableElem.Attribute("type").Value)
                                    {
                                    case "text":
                                        valueType = ValueType.Text;
                                        break;

                                    case "number":
                                        valueType = ValueType.Number;
                                        break;

                                    case "date":
                                        valueType = ValueType.Date;
                                        break;

                                    case "trueFalse":
                                        valueType = ValueType.TrueFalse;
                                        break;

                                    case "multipleChoice":
                                        valueType = ValueType.MultipleChoice;
                                        break;

                                    default:
                                        valueType = ValueType.Unknown;
                                        break;
                                    }
                                    variables.Add(new VariableInfo(variableElem.Attribute("name").Value, valueType));
                                }
                            }
                        }

                        if (dependencies != null)
                        {
                            // Process the dependencies element.
                            var dependenciesElem = manifest.Root.Element(s_namespace + "dependencies");
                            if (dependenciesElem != null)
                            {
                                // Add any not yet encountered dependency to the dependencies collection.
                                foreach (var dependencyElem in dependenciesElem.Elements(s_namespace + "dependency"))
                                {
                                    string hintPath = (dependencyElem.Attribute("hintPath") != null) ? dependencyElem.Attribute("hintPath").Value : null;

                                    DependencyType dependencyType;
                                    switch (dependencyElem.Attribute("type").Value)
                                    {
                                    case "baseCmpFile":
                                        dependencyType = DependencyType.BaseCmpFile;
                                        break;

                                    case "pointedToCmpFile":
                                        dependencyType = DependencyType.PointedToCmpFile;
                                        break;

                                    case "templateInsert":
                                        dependencyType = DependencyType.TemplateInsert;
                                        break;

                                    case "clauseInsert":
                                        dependencyType = DependencyType.ClauseInsert;
                                        break;

                                    case "clauseLibraryInsert":
                                        dependencyType = DependencyType.ClauseLibraryInsert;
                                        break;

                                    case "imageInsert":
                                        dependencyType = DependencyType.ImageInsert;
                                        break;

                                    case "interviewImage":
                                        dependencyType = DependencyType.InterviewImage;
                                        break;

                                    case "assemble":
                                        dependencyType = DependencyType.Assemble;
                                        break;

                                    case "publisherMapFile":
                                        dependencyType = DependencyType.PublisherMapFile;
                                        break;

                                    case "userMapFile":
                                        dependencyType = DependencyType.UserMapFile;
                                        break;

                                    case "additionalTemplate":
                                        dependencyType = DependencyType.AdditionalTemplate;
                                        break;

                                    default:
                                        throw new Exception(string.Format("Invalid dependency type '{0}'.", dependencyElem.Attribute("type").Value));
                                    }
                                    dependencies.Add(new Dependency(dependencyElem.Attribute("fileName").Value, hintPath, dependencyType));
                                }
                            }
                        }

                        if (additionalFiles != null)
                        {
                            // Process the additionalFiles element.
                            var additionalFilesElem = manifest.Root.Element(s_namespace + "additionalFiles");
                            if (additionalFilesElem != null)
                            {
                                // Add any not yet encountered additionalFile to the additionalFiles collection.
                                foreach (var fileElem in additionalFilesElem.Elements(s_namespace + "file"))
                                {
                                    additionalFiles.Add(new AdditionalFile(fileElem.Attribute("fileName").Value));
                                }
                            }
                        }

                        if (dataSources != null)
                        {
                            // Process the dataSources element.
                            var dataSourcesElem = manifest.Root.Element(s_namespace + "dataSources");
                            if (dataSourcesElem != null)
                            {
                                // Add any not yet encountered dataSource to the dataSources collection.
                                foreach (var dataSourceElem in dataSourcesElem.Elements(s_namespace + "dataSource"))
                                {
                                    DataSourceType dataSourceType;
                                    switch (dataSourceElem.Attribute("type").Value)
                                    {
                                    case "currentAnswerFile":
                                        dataSourceType = DataSourceType.CurrentAnswerFile;
                                        break;

                                    case "answerFile":
                                        dataSourceType = DataSourceType.AnswerFile;
                                        break;

                                    case "databaseComponent":
                                        dataSourceType = DataSourceType.DatabaseComponent;
                                        break;

                                    case "custom":
                                        dataSourceType = DataSourceType.Custom;
                                        break;

                                    default:
                                        throw new Exception(string.Format("Invalid data source type '{0}'.", dataSourceElem.Attribute("type").Value));
                                    }

                                    List <DataSourceField> dataSourceFields = new List <DataSourceField>();
                                    foreach (var dataSourceFieldElem in dataSourceElem.Elements(s_namespace + "dataSourceField"))
                                    {
                                        DataSourceFieldType fieldType;
                                        switch (dataSourceFieldElem.Attribute("type").Value)
                                        {
                                        case "text":
                                            fieldType = DataSourceFieldType.Text;
                                            break;

                                        case "number":
                                            fieldType = DataSourceFieldType.Number;
                                            break;

                                        case "date":
                                            fieldType = DataSourceFieldType.Date;
                                            break;

                                        case "trueFalse":
                                            fieldType = DataSourceFieldType.TrueFalse;
                                            break;

                                        default:
                                            throw new Exception(string.Format("Invalid data source field type '{0}'.", dataSourceFieldElem.Attribute("type").Value));
                                        }

                                        DataSourceBackfillType backfillType;
                                        switch (dataSourceFieldElem.Attribute("backfill").Value)
                                        {
                                        case "never":
                                            backfillType = DataSourceBackfillType.Never;
                                            break;

                                        case "always":
                                            backfillType = DataSourceBackfillType.Always;
                                            break;

                                        case "prompt":
                                            backfillType = DataSourceBackfillType.Prompt;
                                            break;

                                        case "doNotAllow":
                                            backfillType = DataSourceBackfillType.DoNotAllow;
                                            break;

                                        default:
                                            throw new Exception(string.Format("Invalid data source backfill type '{0}'.", dataSourceFieldElem.Attribute("backfill").Value));
                                        }

                                        bool isKey = (dataSourceFieldElem.Attribute("isKey") != null) ? Convert.ToBoolean(dataSourceFieldElem.Attribute("isKey").Value) : false;

                                        dataSourceFields.Add(new DataSourceField(dataSourceFieldElem.Attribute("sourceName").Value, fieldType, backfillType, isKey));
                                    }
                                    dataSources.Add(new DataSource(dataSourceElem.Attribute("id").Value, dataSourceElem.Attribute("name").Value,
                                                                   dataSourceType, dataSourceFields.ToArray()));
                                }
                            }
                        }

                        if ((parseFlags & ManifestParseFlags.ParseRecursively) == ManifestParseFlags.ParseRecursively)
                        {
                            // Add any referenced templates to the template queue.
                            var dependenciesElem = manifest.Root.Element(s_namespace + "dependencies");
                            if (dependenciesElem != null)
                            {
                                var templateDependencies = from d in dependenciesElem.Elements(s_namespace + "dependency")
                                                           let type = d.Attribute("type").Value
                                                                      where type == "templateInsert" || type == "additionalTemplate"
                                                                      select d;

                                foreach (var templateDependency in templateDependencies)
                                {
                                    templateQueue.Enqueue(GetDependencyFileLocation(baseTemplateLoc,
                                                                                    (templateDependency.Attribute("hintPath") != null) ? templateDependency.Attribute("hintPath").Value : null,
                                                                                    templateDependency.Attribute("fileName").Value));
                                }
                            }

                            // Mark the template as processed so that its manifest will not get processed again.
                            processedTemplates.Add(templateFileLoc);
                        }
                    }
                    catch (Exception e)
                    {
                        string errorText = String.Format("Failed to read the manifest file for the template:\r\n\r\n     {0}     \r\n\r\n" +
                                                         "The following error occurred:\r\n\r\n     {1}     ", templateFileLoc.FileName, e.Message);
                        throw new Exception(errorText, e);
                    }
                }
            }

            if (variables != null)
            {
                templateManifest.Variables = variables.ToArray();
            }

            if (dependencies != null)
            {
                templateManifest.Dependencies = dependencies.ToArray();
            }

            if (additionalFiles != null)
            {
                templateManifest.AdditionalFiles = additionalFiles.ToArray();
            }

            if (dataSources != null)
            {
                templateManifest.DataSources = dataSources.ToArray();
            }

            return(templateManifest);
        }