/// <summary> /// Loads the current <see cref="ArtifactsConfiguration"/> from file and uses it to build the updated <see cref="ArtifactsConfiguration"/> using the <see cref="ArtifactsConfigurationBuilder"/>. /// </summary> /// <param name="types">The discovered artifact types from the bounded context's assemblies.</param> /// <param name="topology">The <see cref="Applications.Configuration.Topology"/> that's used for building the <see cref="ArtifactsConfiguration"/>.</param> /// <param name="configuration">Current <see cref="BuildTaskConfiguration"/>.</param> /// <returns>The built <see cref="ArtifactsConfiguration"/>.</returns> public ArtifactsConfiguration Build(IEnumerable <Type> types, Applications.Configuration.Topology topology, BuildTaskConfiguration configuration) { var artifactsConfiguration = _configurationManager.Load(); var boundedContextTopology = new BoundedContextTopology(topology, configuration.UseModules, configuration.NamespaceSegmentsToStrip); return(new ArtifactsConfigurationBuilder(types, artifactsConfiguration, _artifactTypes, _buildMessages).Build(boundedContextTopology)); }
/// <summary> /// Loads the current <see cref="ArtifactsConfiguration"/> from file and uses it to build the updated <see cref="ArtifactsConfiguration"/> using the <see cref="ArtifactsConfigurationBuilder"/> /// </summary> /// <param name="types">The discovered artifact types from the bounded context's assemblies</param> /// <param name="topology">The <see cref="Applications.Configuration.Topology"/> that's used for building the <see cref="ArtifactsConfiguration"/></param> /// <param name="parsingResults"></param> public ArtifactsConfiguration Build(Type[] types, Applications.Configuration.Topology topology, ArgumentsParsingResult parsingResults) { var artifactsConfiguration = _configurationManager.Load(); var boundedContextTopology = new BoundedContextTopology(topology, parsingResults.UseModules, parsingResults.NamespaceSegmentsToStrip); return(new ArtifactsConfigurationBuilder(types, artifactsConfiguration, _artifactTypes, _logger).Build(boundedContextTopology)); }
/// <summary> /// Returns a <see cref="Dictionary{Feature, FeatureName}"/> where Key is the Feature (id) and Value is the FeatureName of all <see cref="FeatureDefinition"/> in <see cref="Applications.Configuration.Topology"/> /// </summary> public static Dictionary <Feature, FeatureName> RetrieveAllFeatureIds(this BoundedContextTopology configuration) { var featureMap = new Dictionary <Feature, FeatureName>(); AddAllFeaturesToMap(RetrieveFeatures(configuration), featureMap); return(featureMap); }
/// <summary> /// Validates the <see cref="ArtifactsConfiguration"/> based on the bounded context's topology and the discoved artifact types in the assemblies of the bounded context. /// </summary> /// <param name="configuration">The <see cref="ArtifactsConfiguration"/> being extended.</param> /// <param name="boundedContextTopology"><see cref="BoundedContextTopology"/> to validate against.</param> /// <param name="types">All <see cref="Type">types</see> to validate.</param> /// <param name="buildMessages"><see cref="IBuildMessages"/> for outputting build messages.</param> public static void ValidateArtifacts( this ArtifactsConfiguration configuration, BoundedContextTopology boundedContextTopology, IEnumerable <Type> types, IBuildMessages buildMessages) { ThrowIfDuplicateArtifacts(configuration, buildMessages); WarnIfFeatureMissingFromTopology(configuration, boundedContextTopology, buildMessages); WarnIfArtifactNoLongerInStructure(configuration, types, buildMessages); }
int HandleArtifactOfType(ArtifactType artifactType, BoundedContextTopology boundedContextConfiguration, MutableAritfactsDictionary artifactsDictionary, List <string> nonMatchingArtifacts) { var targetProperty = artifactType.TargetPropertyExpression.GetPropertyInfo(); var newArtifacts = 0; var artifacts = _artifacts.Where(_ => artifactType.Type.IsAssignableFrom(_)); foreach (var artifact in artifacts) { var feature = boundedContextConfiguration.FindMatchingFeature(artifact.Namespace, nonMatchingArtifacts); if (feature.Value != null) { MutableArtifactsByTypeDictionary artifactsByType; if (!artifactsDictionary.TryGetValue(feature.Key, out artifactsByType)) { artifactsByType = artifactsDictionary[feature.Key] = new Dictionary <PropertyInfo, Dictionary <ArtifactId, ArtifactDefinition> >(); } Dictionary <ArtifactId, ArtifactDefinition> mutableArtifacts; if (!artifactsByType.TryGetValue(targetProperty, out mutableArtifacts)) { mutableArtifacts = artifactsByType[targetProperty] = new Dictionary <ArtifactId, ArtifactDefinition>(); } if (!mutableArtifacts.Any(_ => _.Value.Type.GetActualType() == artifact)) { var artifactObject = new Dolittle.Artifacts.Artifact(ArtifactId.New(), ArtifactGeneration.First); if (artifact.HasAttribute <ArtifactAttribute>()) { artifactObject = (artifact.GetTypeInfo().GetCustomAttributes(typeof(ArtifactAttribute), false).First() as ArtifactAttribute).Artifact; } AddNewArtifact(artifactObject, artifact, mutableArtifacts, artifactType.TypeName); newArtifacts++; } else { if (artifact.HasAttribute <ArtifactAttribute>()) { var artifactObject = (artifact.GetTypeInfo().GetCustomAttributes(typeof(ArtifactAttribute), false).First() as ArtifactAttribute).Artifact; var existingArtifact = mutableArtifacts.Single(_ => _.Value.Type.GetActualType() == artifact); if (!existingArtifact.Key.Value.Equals(artifactObject.Id.Value)) { mutableArtifacts.Remove(existingArtifact.Key); AddNewArtifact(artifactObject, artifact, mutableArtifacts, artifactType.TypeName); newArtifacts++; } } } } } return(newArtifacts); }
/// <summary> /// Returns a <see cref="FeatureDefinition"/> that matches the artifact with the given namespace based on the <see cref="BoundedContextTopology">BoundedContextConfiguration's </see> topology /// </summary> public static KeyValuePair <Feature, FeatureDefinition> FindMatchingFeature(this BoundedContextTopology boundedContextConfiguration, string @namespace) { var nonMatchingList = new List <string>(); var featureDef = boundedContextConfiguration.FindMatchingFeature(@namespace, nonMatchingList); if (featureDef.Key == null) { throw new NonMatchingArtifact(); } return(featureDef); }
/// <summary> /// Returns all <see cref="FeatureDefinition"/> from the <see cref="Applications.Configuration.Topology"/> /// </summary> public static IDictionary <Feature, FeatureDefinition> RetrieveFeatures(this BoundedContextTopology configuration) { if (configuration.UseModules) { return(configuration.Topology.Modules.SelectMany(_ => _.Value.Features).ToDictionary(_ => _.Key, _ => _.Value)); } else { return(configuration.Topology.Features); } }
/// <summary> /// Returns a <see cref="FeatureDefinition"/> that matches the artifact with the given namespace based on the <see cref="BoundedContextTopology">BoundedContextConfiguration's </see> topology. /// </summary> /// <param name="configuration"><see cref="BoundedContextTopology"/> to extend.</param> /// <param name="namespace">Namespace to find matching feature in.</param> /// <param name="artifactsWithoutMatch">The artifacts that was unmatched.</param> /// <returns>A <see cref="KeyValuePair{TKey, TValue}"/> of <see cref="Feature"/> to <see cref="FeatureDefinition"/>.</returns> public static KeyValuePair <Feature, FeatureDefinition> FindMatchingFeature( this BoundedContextTopology configuration, string @namespace, List <string> artifactsWithoutMatch) { var area = new Area() { Value = @namespace.Split('.').First() }; var segments = @namespace.Split('.').Skip(1).ToArray(); if (configuration.NamespaceSegmentsToStrip.ContainsKey(area)) { var newSegments = new List <string>(segments); foreach (var segment in configuration.NamespaceSegmentsToStrip[area]) { newSegments.Remove(segment); } segments = newSegments.ToArray(); } if (configuration.UseModules) { var matchingModule = configuration.Topology.Modules .SingleOrDefault(module => module.Value.Name.Value.Equals(segments[0], StringComparison.InvariantCulture)); try { return(FindMatchingFeature(segments.Skip(1).ToArray(), matchingModule.Value.Features)); } catch (Exception) { artifactsWithoutMatch.Add(@namespace); return(new KeyValuePair <Feature, FeatureDefinition>(null, null)); } } try { return(FindMatchingFeature(segments, configuration.Topology.Features)); } catch (Exception) { artifactsWithoutMatch.Add(@namespace); return(new KeyValuePair <Feature, FeatureDefinition>(null, null)); } }
static void WarnIfFeatureMissingFromTopology(ArtifactsConfiguration artifacts, BoundedContextTopology boundedContextTopology, IBuildMessages buildMessages) { Dictionary <Feature, FeatureName> featureMap = boundedContextTopology.RetrieveAllFeatureIds(); foreach (var artifact in artifacts) { if (!featureMap.ContainsKey(artifact.Key)) { buildMessages.Warning($"Found artifacts under a Feature that does not exist in the topology. Feature: '{artifact.Key}':"); buildMessages.Warning("Artifacts:"); var artifactDefinitions = artifacts.GetAllArtifactDefinitions(artifact.Key); foreach (var definitionEntry in artifactDefinitions) { buildMessages.Warning($"\tArtifact: '{definitionEntry.Key.Value}' - '{definitionEntry.Value.Type.TypeString} @{definitionEntry.Value.Generation.Value}'"); } } } }
/// <summary> /// Builds a valid <see cref="ArtifactsConfiguration"/> based on a <see cref="BoundedContextTopology"/> /// </summary> /// <param name="boundedContextTopology"></param> /// <returns></returns> public ArtifactsConfiguration Build(BoundedContextTopology boundedContextTopology) { var newArtifacts = 0; var artifactsDictionary = new MutableAritfactsDictionary(); foreach (var(feature, featureArtifactsByType) in _currentArtifactsConfiguration) { var featureArtifacts = artifactsDictionary[feature] = new Dictionary <PropertyInfo, Dictionary <ArtifactId, ArtifactDefinition> >(); foreach (var artifactType in featureArtifactsByType.GetType().GetProperties()) { var existingArtifactsForFeatureType = artifactType.GetValue(featureArtifactsByType) as IReadOnlyDictionary <ArtifactId, ArtifactDefinition>; featureArtifacts[artifactType] = new Dictionary <ArtifactId, ArtifactDefinition>(existingArtifactsForFeatureType); } } var nonMatchingArtifacts = new List <string>(); foreach (var artifactType in _artifactTypes.ArtifactTypes) { newArtifacts += HandleArtifactOfType( artifactType, boundedContextTopology, artifactsDictionary, nonMatchingArtifacts ); } if (nonMatchingArtifacts.Any()) { foreach (var artifactNamespace in nonMatchingArtifacts) { _logger.Warning($"An artifact with namespace: '{artifactNamespace}' could not be matched with any feature in the Bounded Context's topology"); } throw new NonMatchingArtifact(); } //new Dictionary<Feature, ArtifactsByTypeDefinition>() var artifactsByTypeDefinitionConstructor = typeof(ArtifactsByTypeDefinition).GetConstructors().Single(_ => _.GetParameters().All(p => p.ParameterType.Equals(typeof(IDictionary <ArtifactId, ArtifactDefinition>)))); var updatedArtifactsConfiguration = new ArtifactsConfiguration(new Dictionary <Feature, ArtifactsByTypeDefinition>( artifactsDictionary.Select(_ => { var feature = _.Key; var arguments = artifactsByTypeDefinitionConstructor.GetParameters().Select(arg => { return(_.Value.SingleOrDefault(prop => arg.Name.ToLower().Equals(prop.Key.Name.ToLower())).Value ?? new Dictionary <ArtifactId, ArtifactDefinition>()); }).ToArray(); var artifacts = artifactsByTypeDefinitionConstructor.Invoke(arguments) as ArtifactsByTypeDefinition; return(new KeyValuePair <Feature, ArtifactsByTypeDefinition>(feature, artifacts)); }) )); updatedArtifactsConfiguration.ValidateArtifacts(boundedContextTopology, _artifacts, _logger); if (newArtifacts > 0) { _logger.Information($"Added {newArtifacts} new artifacts to the map."); } else { _logger.Information($"No new artifacts added to the map."); } return(updatedArtifactsConfiguration); }