/// <summary> /// Generate a list of artifact summary information from a resource input stream, /// using the default <see cref="ConformanceHarvesters"/>. /// <para> /// If the target resource represents a <see cref="Bundle"/> instance, then the generator /// returns a list of summaries for all resource entries contained in the bundle. /// </para> /// </summary> /// <param name="navStream">An <see cref="INavigatorStream"/> instance.</param> /// <param name="initProperties"> /// An optional summary properties initialization method, or <c>null</c>. /// If specified, the generator will call this method for each generated summary, /// allowing the caller to modify or enrich the set of generated summary properties. /// </param> /// <param name="harvesters"> /// A list of <see cref="ArtifactSummaryHarvester"/> delegates that the /// generator calls to harvest summary information from each artifact. /// If the harvester list equals <c>null</c> or empty, then the generator will /// harvest only the common default summary properties. /// </param> /// <returns>A list of new <see cref="ArtifactSummary"/> instances.</returns> /// <remarks> /// The generator catches all runtime exceptions that occur during harvesting and returns /// them as <see cref="ArtifactSummary"/> instances with <see cref="ArtifactSummary.IsFaulted"/> /// equal to <c>true</c> and <see cref="ArtifactSummary.Error"/> returning the exception. /// </remarks> public static List <ArtifactSummary> Generate( INavigatorStream navStream, Action <ArtifactSummaryPropertyBag> initProperties, params ArtifactSummaryHarvester[] harvesters) { var result = new List <ArtifactSummary>(); // Factory returns null for unknown file formats if (navStream == null) { return(result); } try { // Run default or specified (custom) harvesters if (harvesters == null || harvesters.Length == 0) { harvesters = ConformanceHarvesters; } while (navStream.MoveNext()) { var current = navStream.Current; if (current != null) { var properties = new ArtifactSummaryPropertyBag(); // Initialize default summary information // Note: not exposed by IElementNavigator, cannot use harvester properties.SetPosition(navStream.Position); properties.SetTypeName(current.Type); properties.SetResourceUri(navStream.Position); // Allow caller to modify/enrich harvested properties initProperties?.Invoke(properties); // Generate the final (immutable) ArtifactSummary instance var summary = generate(properties, current, harvesters); result.Add(summary); } } } // TODO Catch specific exceptions // catch (System.IO.FileNotFoundException) // catch (UnauthorizedAccessException) // catch (System.Security.SecurityException) // catch (FormatException) catch (Exception ex) { result.Add(ArtifactSummary.FromException(ex)); } finally { navStream?.Dispose(); } return(result); }
// Generate summary for a single artifact static ArtifactSummary generate( ArtifactSummaryPropertyBag props, ISourceNode nav, ArtifactSummaryHarvester[] harvesters) { Exception error = null; // [WMR 20180419] Support empty harvester list (harvest only default props, no custom props) if (harvesters != null && harvesters.Length > 0) { try { // Harvest summary information via specified harvesters // Top-level harvesters receive navigator positioned on the first child element level // Catch individual exceptions inside loop, return as AggregateException var errors = new List <Exception>(); if (nav.Children().Any()) { foreach (var harvester in harvesters) { try { if (harvester != null && harvester.Invoke(nav, props)) { break; } } // TODO Catch specific exceptions // catch (FormatException) catch (Exception ex) { errors.Add(ex); } } } // Combine all errors into single AggregateException error = errors.Count > 0 ? new AggregateException(errors) : null; } // TODO Catch specific exceptions // catch (FormatException) // catch (NotSupportedException) catch (Exception ex) { // Error in summary factory? // Make sure we always return a valid summary error = ex; } } // Create final summary from harvested properties and optional error return(new ArtifactSummary(props, error)); }