//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Data.Mapping;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Collections.ObjectModel;
using System.Runtime.Versioning;
namespace System.Data.Metadata.Edm
{
///
/// This class represents a collection of artifact files to be loaded from one
/// filesystem folder.
///
internal class MetadataArtifactLoaderCompositeFile : MetadataArtifactLoader
{
private ReadOnlyCollection _csdlChildren;
private ReadOnlyCollection _ssdlChildren;
private ReadOnlyCollection _mslChildren;
private readonly string _path;
private readonly ICollection _uriRegistry;
///
/// Constructor - loads all resources into the _children collection
///
/// The path to the (collection of) resources
/// The global registry of URIs
[ResourceExposure(ResourceScope.Machine)] //Exposes the file path which is a Machine resource
public MetadataArtifactLoaderCompositeFile(string path, ICollection uriRegistry)
{
_path = path;
_uriRegistry = uriRegistry;
}
public override string Path
{
get { return _path; }
}
[ResourceExposure(ResourceScope.Machine)] //Exposes the file paths which are a Machine resource
public override void CollectFilePermissionPaths(List paths, DataSpace spaceToGet)
{
IList files;
if(TryGetListForSpace(spaceToGet, out files))
{
foreach(var loader in files)
{
loader.CollectFilePermissionPaths(paths, spaceToGet);
}
}
}
public override bool IsComposite
{
get
{
return true;
}
}
internal ReadOnlyCollection CsdlChildren
{
get
{
LoadCollections();
return _csdlChildren;
}
}
internal ReadOnlyCollection SsdlChildren
{
get
{
LoadCollections();
return _ssdlChildren;
}
}
internal ReadOnlyCollection MslChildren
{
get
{
LoadCollections();
return _mslChildren;
}
}
///
/// Load all the collections at once so we have a "fairly" matched in time set of files
/// otherwise we may end up loading the csdl files, and then not loading the ssdl, and msl
/// files for sometime later.
///
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //For GetArtifactsInDirectory method call. We pick the paths from class variable.
//so this method does not expose any resource.
void LoadCollections()
{
if (_csdlChildren == null)
{
ReadOnlyCollection csdlChildren = GetArtifactsInDirectory(_path, XmlConstants.CSpaceSchemaExtension, _uriRegistry).AsReadOnly();
Interlocked.CompareExchange(ref _csdlChildren, csdlChildren, null);
}
if (_ssdlChildren == null)
{
ReadOnlyCollection ssdlChildren = GetArtifactsInDirectory(_path, XmlConstants.SSpaceSchemaExtension, _uriRegistry).AsReadOnly();
Interlocked.CompareExchange(ref _ssdlChildren, ssdlChildren, null);
}
if (_mslChildren == null)
{
ReadOnlyCollection mslChildren = GetArtifactsInDirectory(_path, XmlConstants.CSSpaceSchemaExtension, _uriRegistry).AsReadOnly();
Interlocked.CompareExchange(ref _mslChildren, mslChildren, null);
}
}
///
/// Get paths to artifacts for a specific DataSpace, in the original, unexpanded
/// form.
///
/// A filesystem folder can contain any kind of artifact, so we simply
/// ignore the parameter and return the original path to the folder.
/// The DataSpace for the artifacts of interest
/// A List of strings identifying paths to all artifacts for a specific DataSpace
public override List GetOriginalPaths(DataSpace spaceToGet)
{
return GetOriginalPaths();
}
///
/// Get paths to artifacts for a specific DataSpace.
///
/// The DataSpace for the artifacts of interest
/// A List of strings identifying paths to all artifacts for a specific DataSpace
public override List GetPaths(DataSpace spaceToGet)
{
List list = new List();
IList files;
if (!TryGetListForSpace(spaceToGet, out files))
{
return list;
}
foreach (MetadataArtifactLoaderFile file in files)
{
list.AddRange(file.GetPaths(spaceToGet));
}
return list;
}
private bool TryGetListForSpace(DataSpace spaceToGet, out IList files)
{
switch (spaceToGet)
{
case DataSpace.CSpace:
files = CsdlChildren;
return true;
case DataSpace.SSpace:
files = SsdlChildren;
return true;
case DataSpace.CSSpace:
files = MslChildren;
return true;
default:
Debug.Assert(false, "Invalid DataSpace value.");
files = null;
return false;
}
}
///
/// Get paths to all artifacts
///
/// A List of strings identifying paths to all resources
public override List GetPaths()
{
List list = new List();
foreach (MetadataArtifactLoaderFile resource in CsdlChildren)
{
list.AddRange(resource.GetPaths());
}
foreach (MetadataArtifactLoaderFile resource in SsdlChildren)
{
list.AddRange(resource.GetPaths());
}
foreach (MetadataArtifactLoaderFile resource in MslChildren)
{
list.AddRange(resource.GetPaths());
}
return list;
}
///
/// Aggregates all resource streams from the _children collection
///
/// A List of XmlReader objects; cannot be null
public override List GetReaders(Dictionary sourceDictionary)
{
List list = new List();
foreach (MetadataArtifactLoaderFile resource in CsdlChildren)
{
list.AddRange(resource.GetReaders(sourceDictionary));
}
foreach (MetadataArtifactLoaderFile resource in SsdlChildren)
{
list.AddRange(resource.GetReaders(sourceDictionary));
}
foreach (MetadataArtifactLoaderFile resource in MslChildren)
{
list.AddRange(resource.GetReaders(sourceDictionary));
}
return list;
}
///
/// Get XmlReaders for a specific DataSpace.
///
/// The DataSpace corresponding to the requested artifacts
/// A List of XmlReader objects
public override List CreateReaders(DataSpace spaceToGet)
{
List list = new List();
IList files;
if (!TryGetListForSpace(spaceToGet, out files))
{
return list;
}
foreach (MetadataArtifactLoaderFile file in files)
{
list.AddRange(file.CreateReaders(spaceToGet));
}
return list;
}
[ResourceExposure(ResourceScope.Machine)] //Exposes the directory name which is a Machine resource
[ResourceConsumption(ResourceScope.Machine)] //For Directory.GetFiles method call but we do not create the directory name in this method
private static List GetArtifactsInDirectory(string directory, string extension, ICollection uriRegistry)
{
List loaders = new List();
string[] fileNames = Directory.GetFiles(
directory,
MetadataArtifactLoader.wildcard + extension,
SearchOption.TopDirectoryOnly
);
foreach (string fileName in fileNames)
{
string fullPath = System.IO.Path.Combine(directory, fileName);
if (uriRegistry.Contains(fullPath))
continue;
// We need a second filter on the file names verifying the right extension because
// a file name with an extension longer than 3 characters might still match the
// given extension. For example, if we look for *.msl, abc.msl_something would match
// because the 8.3 name format matches it.
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
{
loaders.Add(new MetadataArtifactLoaderFile(fullPath, uriRegistry));
// the file is added to the registry in the MetadataArtifactLoaderFile ctor
}
}
return loaders;
}
}
}