in src/Editor/Core/Impl/ContentType/ContentTypeRegistryServiceImpl.cs [88:182]
private void BuildContentTypes()
{
var oldMaps = Volatile.Read(ref this.maps);
if (oldMaps == null)
{
var nameToContentTypeBuilder = MapCollection.Empty.NameToContentTypeMap.ToBuilder();
var mimeTypeToContentTypeBuilder = MapCollection.Empty.MimeTypeToContentTypeMap.ToBuilder();
// Add the singleton Unknown content type to the dictionary
nameToContentTypeBuilder.Add(ContentTypeRegistryImpl.UnknownContentTypeName, ContentTypeRegistryImpl.UnknownContentTypeImpl);
// For each content type provision, create an IContentType.
foreach (Lazy<ContentTypeDefinition, IContentTypeDefinitionMetadata> contentTypeDefinition in ContentTypeDefinitions)
{
AddContentTypeFromMetadata(contentTypeDefinition.Metadata.Name,
contentTypeDefinition.Metadata.MimeType,
contentTypeDefinition.Metadata.BaseDefinition, nameToContentTypeBuilder, mimeTypeToContentTypeBuilder);
}
// Now consider the external sources. This allows us to consider legacy content types together with MEF-defined
// content types.
foreach (IContentTypeDefinitionSource source in this.ExternalSources)
{
if (source.Definitions != null)
{
foreach (IContentTypeDefinition metadata in source.Definitions)
{
AddContentTypeFromMetadata(metadata.Name,
/* mimeType*/ null,
metadata.BaseDefinitions, nameToContentTypeBuilder, mimeTypeToContentTypeBuilder);
}
}
}
List<ContentTypeImpl> allTypes = new List<ContentTypeImpl>(nameToContentTypeBuilder.Count);
allTypes.AddRange(nameToContentTypeBuilder.Values);
foreach (var type in allTypes)
{
type.ProcessBaseTypes(nameToContentTypeBuilder, mimeTypeToContentTypeBuilder);
}
#if DEBUG
foreach (var type in nameToContentTypeBuilder.Values)
{
Debug.Assert(type.IsProcessed);
}
#endif
foreach (var type in nameToContentTypeBuilder.Values)
{
type.CheckForCycle(breakCycle: true);
}
var fileExtensionToContentTypeMapBuilder = MapCollection.Empty.FileExtensionToContentTypeMap.ToBuilder();
var fileNameToContentTypeMapBuilder = MapCollection.Empty.FileNameToContentTypeMap.ToBuilder();
foreach (var fileExtensionDefinition in this.FileToContentTypeProductions)
{
// MEF ensures that there will be at least one content type in the metadata. We take the first one.
// We prefer this over defining a different attribute from ContentType[] for this purpose.
var contentTypeName = fileExtensionDefinition.Metadata.ContentTypes.FirstOrDefault();
ContentTypeImpl contentType;
if ((contentTypeName != null) && nameToContentTypeBuilder.TryGetValue(contentTypeName, out contentType))
{
if (!string.IsNullOrEmpty(fileExtensionDefinition.Metadata.FileExtension))
{
foreach (var ext in fileExtensionDefinition.Metadata.FileExtension.Split(';'))
{
if (ext != null)
{
var extension = RemoveExtensionDot(ext);
if (!(string.IsNullOrWhiteSpace(extension) || fileExtensionToContentTypeMapBuilder.ContainsKey(extension)))
fileExtensionToContentTypeMapBuilder.Add(extension, contentType);
}
}
}
if (!string.IsNullOrEmpty(fileExtensionDefinition.Metadata.FileName))
{
foreach (var name in fileExtensionDefinition.Metadata.FileName.Split(';'))
{
if (!(string.IsNullOrWhiteSpace(name) || fileNameToContentTypeMapBuilder.ContainsKey(name)))
fileNameToContentTypeMapBuilder.Add(name, contentType);
}
}
}
}
var newMaps = new MapCollection(nameToContentTypeBuilder.ToImmutable(), mimeTypeToContentTypeBuilder.ToImmutable(), fileExtensionToContentTypeMapBuilder.ToImmutable(), fileNameToContentTypeMapBuilder.ToImmutable());
Interlocked.CompareExchange(ref this.maps, newMaps, oldMaps);
// We actually don't care whether or not the CompareExchange succeeded.
// Eitehr it succeeded (normally the case) or someone else successfully completed BuildContentTypes on another thread and we shouldn't do anything.
}
}