Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / EntityModel / SchemaObjectModel / Schema.cs / 4 / Schema.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Objects.DataClasses;
using System.Text;
using System.Data.Entity;
using System.Linq;
namespace System.Data.EntityModel.SchemaObjectModel
{
///
/// class representing the Schema element in the schema
///
[System.Diagnostics.DebuggerDisplay("Namespace={Namespace}, PublicKeyToken={PublicKeyToken}, Version={Version}")]
internal class Schema : SchemaElement
{
#region Instance Fields
private const int RootDepth = 2;
// if adding properties also add to InitializeObject()!
private List _errors = new List();
// We need to keep track of functions seperately, since we can't deduce the strong name of the function,
// until we have resolved the parameter names. Hence we keep track of functions seperately and add them
// to the schema types list, in the validate phase
private List _functions = null;
private AliasResolver _aliasResolver = null;
private string _location = null;
private string _alias = null;
protected string _namespaceName = null;
private string _schemaXmlNamespace = null;
private List _schemaTypes = null;
private int _depth = 0; // recursion depth in Parse used by *Handlers to know which hander set to set
private double _edmVersion = XmlConstants.EdmVersionForV1;
private SchemaManager _schemaManager;
#endregion
#region Static Fields
private static IList _emptyPathList = new List(0).AsReadOnly();
#endregion
#region Public Methods
public Schema(SchemaManager schemaManager)
: base(null)
{
Debug.Assert(schemaManager != null, "SchemaManager parameter should never be null");
_schemaManager = schemaManager;
_errors = new List();
}
internal IList Resolve()
{
ResolveTopLevelNames();
if (_errors.Count != 0)
{
return ResetErrors();
}
ResolveSecondLevelNames();
return ResetErrors();
}
internal IList ValidateSchema()
{
Validate();
return ResetErrors();
}
internal void AddError(EdmSchemaError error)
{
_errors.Add(error);
}
///
/// Populate the schema object from a schema
///
/// TextReader containing the schema xml definition
/// Uri containing path to a schema file (may be null)
/// list of errors
internal IList Parse(XmlReader sourceReader, string sourceLocation)
{
// We don't Assert (sourceReader != null) here any more because third-party
// providers that extend XmlEnabledProvidermanifest could hit this code. The
// following code eventually detects the anomaly and a ProviderIncompatible
// exception is thrown (which is the right thing to do in such cases).
XmlReader wrappedReader = null;
try
{
// user specified a stream to read from, read from it.
// The Uri is just used to identify the stream in errors.
XmlReaderSettings readerSettings = CreateXmlReaderSettings();
wrappedReader = XmlReader.Create(sourceReader, readerSettings);
return InternalParse(wrappedReader, sourceLocation);
}
catch (System.IO.IOException ex)
{
AddError(ErrorCode.IOException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
// do not close the reader here (SQLBUDT 522950)
return ResetErrors();
}
///
/// Populate the schema object from a schema
///
/// TextReader containing the schema xml definition
/// Uri containing path to a schema file (may be null)
/// list of errors
private IList InternalParse(XmlReader sourceReader, string sourceLocation)
{
Debug.Assert(sourceReader != null, "sourceReader parameter is null");
// these need to be set before any calls to AddError are made.
Schema = this;
Location = sourceLocation;
try
{
// to make life simpler, we skip down to the first/root element, unless we're
// already there
if (sourceReader.NodeType != XmlNodeType.Element)
{
while (sourceReader.Read() && sourceReader.NodeType != XmlNodeType.Element)
{
}
}
GetPositionInfo(sourceReader);
List expectedNamespaces = SomSchemaSetHelper.GetPrimarySchemaNamespaces(DataModel);
// the root element needs to be either TDL or Schema in our namespace
if (sourceReader.EOF)
{
if (sourceLocation != null)
{
AddError(ErrorCode.EmptyFile, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.EmptyFile(sourceLocation));
}
else
{
AddError(ErrorCode.EmptyFile, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.EmptySchemaTextReader);
}
}
else if (!expectedNamespaces.Contains(sourceReader.NamespaceURI))
{
Func messageFormat = Strings.UnexpectedRootElement;
if (string.IsNullOrEmpty(sourceReader.NamespaceURI))
messageFormat = Strings.UnexpectedRootElementNoNamespace;
String expectedNamespacesString = Helper.GetCommaDelimitedString(expectedNamespaces);
AddError(ErrorCode.UnexpectedXmlElement, EdmSchemaErrorSeverity.Error, messageFormat(sourceReader.NamespaceURI, sourceReader.LocalName, expectedNamespacesString));
}
else
{
this.SchemaXmlNamespace = sourceReader.NamespaceURI;
if (DataModel == SchemaDataModelOption.EntityDataModel)
{
if (this.SchemaXmlNamespace == XmlConstants.ModelNamespace)
{
EdmVersion = XmlConstants.EdmVersionForV1;
}
else
{
Debug.Assert(this.SchemaXmlNamespace == XmlConstants.ModelNamespace_1_1, "Unknown namespace in CSDL");
EdmVersion = XmlConstants.EdmVersionForV1_1;
}
}
switch (sourceReader.LocalName)
{
case "Schema":
case "ProviderManifest":
HandleTopLevelSchemaElement(sourceReader);
// this forces the reader to look beyond this top
// level element, and complain if there is another one.
sourceReader.Read();
break;
default:
AddError(ErrorCode.UnexpectedXmlElement, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.UnexpectedRootElement(sourceReader.NamespaceURI, sourceReader.LocalName, SchemaXmlNamespace));
break;
}
}
}
catch (InvalidOperationException ex)
{
AddError(ErrorCode.InternalError, EdmSchemaErrorSeverity.Error, ex.Message);
}
catch (System.UnauthorizedAccessException ex)
{
AddError(ErrorCode.UnauthorizedAccessException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (System.IO.IOException ex)
{
AddError(ErrorCode.IOException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (System.Security.SecurityException ex)
{
AddError(ErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (XmlException ex)
{
AddError(ErrorCode.XmlError, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
return ResetErrors();
}
internal static XmlReaderSettings CreateEdmStandardXmlReaderSettings()
{
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.CheckCharacters = true;
readerSettings.CloseInput = false;
readerSettings.IgnoreWhitespace = true;
readerSettings.ConformanceLevel = ConformanceLevel.Auto;
readerSettings.IgnoreComments = true;
readerSettings.IgnoreProcessingInstructions = true;
readerSettings.ProhibitDtd = true;
// remove flags
// the ProcessInlineSchema, and ProcessSchemaLocation flags must be removed for the same
// xsd schema to be used on multiple threads
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessIdentityConstraints;
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessSchemaLocation;
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessInlineSchema;
return readerSettings;
}
private XmlReaderSettings CreateXmlReaderSettings()
{
XmlReaderSettings readerSettings = CreateEdmStandardXmlReaderSettings();
// add flags
readerSettings.ValidationFlags |= System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
readerSettings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(OnSchemaValidationEvent);
readerSettings.ValidationType = ValidationType.Schema;
XmlSchemaSet schemaSet = SomSchemaSetHelper.GetSchemaSet(DataModel);
// Do not use readerSetting.Schemas.Add(schemaSet)
// you must use the line below for this to work in
// a multithread environment
readerSettings.Schemas = schemaSet;
return readerSettings;
}
///
/// Called by the validating reader when the schema is xsd invalid
///
/// the validating reader
/// information about the validation error
internal void OnSchemaValidationEvent(object sender, System.Xml.Schema.ValidationEventArgs e)
{
Debug.Assert(e != null);
XmlReader reader = sender as XmlReader;
if (reader != null && !IsValidateableXmlNamespace(reader.NamespaceURI, reader.NodeType == XmlNodeType.Attribute))
{
// we allow non known namespaces to do whatever they want
return;
}
EdmSchemaErrorSeverity severity = EdmSchemaErrorSeverity.Error;
if (e.Severity == System.Xml.Schema.XmlSeverityType.Warning)
severity = EdmSchemaErrorSeverity.Warning;
AddError(ErrorCode.XmlError, severity, e.Exception.LineNumber, e.Exception.LinePosition, e.Message);
}
public bool IsParseableXmlNamespace(string xmlNamespaceUri, bool isAttribute)
{
if (string.IsNullOrEmpty(xmlNamespaceUri) && isAttribute)
{
// we own the empty namespace for attributes
return true;
}
if (_parseableXmlNamespaces == null)
{
_parseableXmlNamespaces = new HashSet();
foreach (var schemaResource in SomSchemaSetHelper.GetSchemaResourceMap().Values)
{
_parseableXmlNamespaces.Add(schemaResource.NamespaceUri);
}
}
return _parseableXmlNamespaces.Contains(xmlNamespaceUri);
}
HashSet _validatableXmlNamespaces;
HashSet _parseableXmlNamespaces;
public bool IsValidateableXmlNamespace(string xmlNamespaceUri, bool isAttribute)
{
if (string.IsNullOrEmpty(xmlNamespaceUri) && isAttribute)
{
// we own the empty namespace for attributes
return true;
}
if(_validatableXmlNamespaces == null)
{
_validatableXmlNamespaces = new HashSet();
foreach(var schemaResource in SomSchemaSetHelper.GetSchemaResourceMap().Values)
{
AddAllSchemaResourceNamespaceNames(_validatableXmlNamespaces, schemaResource);
}
}
return _validatableXmlNamespaces.Contains(xmlNamespaceUri);
}
private static void AddAllSchemaResourceNamespaceNames(HashSet hashSet, SomSchemaSetHelper.XmlSchemaResource schemaResource)
{
hashSet.Add(schemaResource.NamespaceUri);
foreach(var import in schemaResource.ImportedSchemas)
{
AddAllSchemaResourceNamespaceNames(hashSet, import);
}
}
internal override void ResolveTopLevelNames()
{
base.ResolveTopLevelNames();
// Resolve all the referenced namespace to make sure that this namespace is valid
AliasResolver.ResolveNamespaces();
foreach (SchemaElement element in SchemaTypes)
{
element.ResolveTopLevelNames();
}
foreach (Function function in Functions)
{
function.ResolveTopLevelNames();
}
}
internal override void ResolveSecondLevelNames()
{
base.ResolveSecondLevelNames();
foreach (SchemaElement element in SchemaTypes)
{
element.ResolveSecondLevelNames();
}
foreach (Function function in Functions)
{
function.ResolveSecondLevelNames();
}
}
///
/// Vaidate the schema.
///
/// list of errors
internal override void Validate()
{
// Also check for alias to be system namespace
if (!String.IsNullOrEmpty(Alias) && EdmItemCollection.IsSystemNamespace(ProviderManifest, Alias))
{
AddError(ErrorCode.CannotUseSystemNamespaceAsAlias, EdmSchemaErrorSeverity.Error,
System.Data.Entity.Strings.CannotUseSystemNamespaceAsAlias(Alias));
}
// Check whether the schema namespace is a system namespace. We set the provider manifest to edm provider manifest
// if we need to check for system namespace. Otherwise, it will be set to null (if we are loading edm provider manifest)
if (ProviderManifest != null &&
EdmItemCollection.IsSystemNamespace(ProviderManifest, Namespace))
{
AddError(ErrorCode.SystemNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.SystemNamespaceEncountered(Namespace));
}
foreach (SchemaElement schemaType in this.SchemaTypes)
{
schemaType.Validate();
}
foreach (Function function in this.Functions)
{
AddFunctionType(function);
function.Validate();
}
}
#endregion
#region Public Properties
///
/// The namespaceUri of the winfs xml namespace
///
internal string SchemaXmlNamespace
{
get
{
return _schemaXmlNamespace;
}
private set
{
_schemaXmlNamespace = value;
}
}
internal DbProviderManifest ProviderManifest
{
get
{
return _schemaManager.GetProviderManifest((string message, ErrorCode code, EdmSchemaErrorSeverity severity)=>AddError(code, severity, message));
}
}
///
/// Version of the EDM that this schema represents.
///
internal double EdmVersion
{
get
{
return _edmVersion;
}
set
{
_edmVersion = value;
}
}
///
/// Alias for the schema (null if none)
///
internal virtual string Alias
{
get
{
return _alias;
}
private set
{
_alias = value;
}
}
///
/// Namespace of the schema
///
internal virtual string Namespace
{
get
{
return _namespaceName;
}
private set
{
_namespaceName = value;
}
}
// ISSUE: jthunter-03/14/05 - The [....] "schemas" don't follow the ".Store" assembly
// naming convention but need to have the right StoreNamespace reported.
//
private static readonly string[] ClientNamespaceOfSchemasMissingStoreSuffix =
{
"System.Storage.[....].Utility",
"System.Storage.[....].Services"
};
///
/// Uri containing the file that defines the schema
///
internal string Location
{
get
{
return _location;
}
private set
{
_location = value;
}
}
///
/// List of all types defined in the schema
///
internal List SchemaTypes
{
get
{
if (_schemaTypes == null)
{
_schemaTypes = new List();
}
return _schemaTypes;
}
}
///
/// Fully qualified name of the schema (same as the namespace name)
///
public override string FQName
{
get
{
return Namespace;
}
}
private List Functions
{
get
{
if (_functions == null)
{
_functions = new List();
}
return _functions;
}
}
#endregion
#region Protected Properties
protected override bool HandleElement(XmlReader reader)
{
if (base.HandleElement(reader))
{
return true;
}
else if (CanHandleElement(reader, XmlConstants.EntityType))
{
HandleEntityTypeElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.ComplexType))
{
HandleInlineTypeElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.Association))
{
HandleAssociationElement(reader);
return true;
}
// Using is only supported in EntityDataModel
if (DataModel == SchemaDataModelOption.EntityDataModel)
{
if (CanHandleElement(reader, XmlConstants.Using))
{
HandleUsingElement(reader);
return true;
}
}
if (DataModel == SchemaDataModelOption.EntityDataModel ||
DataModel == SchemaDataModelOption.ProviderDataModel)
{
if (CanHandleElement(reader, XmlConstants.EntityContainer))
{
HandleEntityContainerTypeElement(reader);
return true;
}
else if (DataModel == SchemaDataModelOption.ProviderDataModel)
{
if (CanHandleElement(reader, XmlConstants.Function))
{
HandleFunctionElement(reader);
return true;
}
}
}
else
{
Debug.Assert(DataModel == SchemaDataModelOption.ProviderManifestModel, "Did you add a new option?");
if (CanHandleElement(reader, XmlConstants.TypesElement))
{
SkipThroughElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.FunctionsElement))
{
SkipThroughElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.Function))
{
HandleFunctionElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.TypeElement))
{
HandleTypeInformationElement(reader);
return true;
}
}
return false;
}
protected override bool ProhibitAttribute(string namespaceUri, string localName)
{
if (base.ProhibitAttribute(namespaceUri, localName))
{
return true;
}
if (namespaceUri == null && localName == XmlConstants.Name)
{
return false;
}
return false;
}
protected override bool HandleAttribute(XmlReader reader)
{
Debug.Assert(_depth > 0);
if (_depth == 1)
{
return false;
}
else
{
if (base.HandleAttribute(reader))
{
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Alias))
{
HandleAliasAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Namespace))
{
HandleNamespaceAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Provider))
{
HandleProviderAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.ProviderManifestToken))
{
HandleProviderManifestTokenAttribute(reader);
return true;
}
}
return false;
}
#endregion
#region Internal Methods
///
/// Called when all attributes for the schema element have been handled
///
protected override void HandleAttributesComplete()
{
if (_depth < RootDepth)
{
return;
}
else if (_depth == RootDepth)
{
// only call when done with the root element
_schemaManager.EnsurePrimitiveSchemaIsLoaded();
}
base.HandleAttributesComplete();
}
protected override void SkipThroughElement(XmlReader reader)
{
try
{
_depth++;
base.SkipThroughElement(reader);
}
finally
{
_depth--;
}
}
///
/// Look up a fully qualified type name reference.
///
/// element containing the reference
/// the fully qualified type name
/// the referenced schema type
/// false if there was an error
internal bool ResolveTypeName(SchemaElement usingElement, string typeName, out SchemaType type)
{
Debug.Assert(usingElement != null);
Debug.Assert(typeName != null);
type = null;
// get the schema(s) that match the namespace/alias
string actualQualification;
string unqualifiedTypeName;
Utils.ExtractNamespaceAndName(DataModel, typeName, out actualQualification, out unqualifiedTypeName);
string definingQualification = actualQualification;
if (definingQualification == null)
{
definingQualification = this.ProviderManifest == null ? this._namespaceName : this.ProviderManifest.NamespaceName;
}
string namespaceName;
// First check if there is an alias defined by this name. For primitive type namespace, we do not need to resolve
// any alias, since that's a reserved keyword and we don't allow alias with that name
if (actualQualification == null || !AliasResolver.TryResolveAlias(definingQualification, out namespaceName))
{
namespaceName = definingQualification;
}
// Resolve the type name
if (!SchemaManager.TryResolveType(namespaceName, unqualifiedTypeName, out type))
{
// it must be an undefined type.
if (actualQualification == null)
{
// Every type except the primitive type must be qualified
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotNamespaceQualified(typeName));
}
else if (!SchemaManager.IsValidNamespaceName(namespaceName))
{
usingElement.AddError(ErrorCode.BadNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.BadNamespaceOrAlias(actualQualification));
}
else
{
// if the type name was alias qualified
if (namespaceName != definingQualification)
{
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotInNamespaceAlias(unqualifiedTypeName, namespaceName, definingQualification));
}
else
{
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotInNamespaceNoAlias(unqualifiedTypeName, namespaceName));
}
}
return false;
}
// For ssdl and provider manifest, make sure that the type is present in this schema or primitive schema
else if (this.DataModel != SchemaDataModelOption.EntityDataModel && type.Schema != this && type.Schema != this.SchemaManager.PrimitiveSchema)
{
if (type.Namespace != this.Namespace)
{
usingElement.AddError(ErrorCode.InvalidNamespaceOrAliasSpecified, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InvalidNamespaceOrAliasSpecified(actualQualification));
}
else
{
usingElement.AddError(ErrorCode.CannotReferTypeAcrossSchema, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.CannotReferTypeAcrossSchema(unqualifiedTypeName));
}
return false;
}
return true;
}
#endregion
#region Internal Properties
///
/// List containing the current schema and all referenced schemas. Used for alias and namespace lookup.
///
internal AliasResolver AliasResolver
{
get
{
if (_aliasResolver == null)
{
_aliasResolver = new AliasResolver(this);
}
return _aliasResolver;
}
}
///
/// The schema data model
///
internal SchemaDataModelOption DataModel
{
get
{
return SchemaManager.DataModel;
}
}
///
/// The schema data model
///
internal SchemaManager SchemaManager
{
get
{
return _schemaManager;
}
}
#endregion
#region Private Methods
///
/// Handler for the Namespace attribute
///
/// xml reader currently positioned at Namespace attribute
private void HandleNamespaceAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
ReturnValue returnValue = HandleDottedNameAttribute(reader, Namespace, Strings.AlreadyDefined);
if (!returnValue.Succeeded)
return;
Namespace = returnValue.Value;
}
///
/// Handler for the Alias attribute
///
/// xml reader currently positioned at Alias attribute
private void HandleAliasAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
Alias = HandleUndottedNameAttribute(reader, Alias);
}
///
/// Handler for the Provider attribute
///
/// xml reader currently positioned at Provider attribute
private void HandleProviderAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
string provider = reader.Value;
_schemaManager.ProviderNotification(provider,
(string message, ErrorCode code, EdmSchemaErrorSeverity severity) => AddError(code, severity, reader, message));
}
///
/// Handler for the ProviderManifestToken attribute
///
/// xml reader currently positioned at ProviderManifestToken attribute
private void HandleProviderManifestTokenAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
string providerManifestToken = reader.Value;
_schemaManager.ProviderManifestTokenNotification(providerManifestToken,
(string message, ErrorCode code, EdmSchemaErrorSeverity severity) => AddError(code, severity, reader, message));
}
///
/// Handler for the using element
///
///
private void HandleUsingElement(XmlReader reader)
{
UsingElement referencedNamespace = new UsingElement(this);
referencedNamespace.Parse(reader);
AliasResolver.Add(referencedNamespace);
}
///
/// Handler for the top level element
///
/// xml reader currently positioned at top level element
private void HandleTopLevelSchemaElement(XmlReader reader)
{
Debug.Assert(reader != null);
try
{
_depth += RootDepth;
Parse(reader);
}
finally
{
_depth -= RootDepth;
}
}
///
/// Handler for the EntityType element
///
/// xml reader currently positioned at EntityType element
private void HandleEntityTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
SchemaEntityType itemType = new SchemaEntityType(this);
itemType.Parse(reader);
TryAddType(itemType, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the TypeInformation element
///
/// xml reader currently positioned at EntityType element
private void HandleTypeInformationElement(XmlReader reader)
{
Debug.Assert(reader != null);
TypeElement type = new TypeElement(this);
type.Parse(reader);
TryAddType(type, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the Function element
///
/// xml reader currently positioned at EntityType element
private void HandleFunctionElement(XmlReader reader)
{
Debug.Assert(reader != null);
Function function = new Function(this);
function.Parse(reader);
this.Functions.Add(function);
}
///
/// Handler for the Association element
///
/// xml reader currently positioned at Association element
private void HandleAssociationElement(XmlReader reader)
{
Debug.Assert(reader != null);
Relationship relationship = new Relationship(this, RelationshipKind.Association);
relationship.Parse(reader);
TryAddType(relationship, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the InlineType element
///
/// xml reader currently positioned at InlineType element
private void HandleInlineTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
SchemaComplexType complexType = new SchemaComplexType(this);
complexType.Parse(reader);
TryAddType(complexType, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the EntityContainer element
///
/// xml reader currently positioned at EntityContainer element
private void HandleEntityContainerTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
EntityContainer type = new EntityContainer(this);
type.Parse(reader);
TryAddContainer(type, true/*doNotAddErrorForEmptyName*/);
}
///
/// reset the error collection
///
/// old error list
private List ResetErrors()
{
List errors = _errors;
_errors = new List();
return errors;
}
protected void TryAddType(SchemaType schemaType, bool doNotAddErrorForEmptyName)
{
this.SchemaManager.SchemaTypes.Add(schemaType, doNotAddErrorForEmptyName,
Strings.TypeNameAlreadyDefinedDuplicate);
this.SchemaTypes.Add(schemaType);
}
protected void TryAddContainer(SchemaType schemaType, bool doNotAddErrorForEmptyName)
{
this.SchemaManager.SchemaTypes.Add(schemaType, doNotAddErrorForEmptyName,
Strings.EntityContainerAlreadyExists);
this.SchemaTypes.Add(schemaType);
}
protected void AddFunctionType(Function function)
{
AddErrorKind error = this.SchemaManager.SchemaTypes.TryAdd(function);
Debug.Assert(error != AddErrorKind.MissingNameError, "Function identity can never be null while adding global functions");
if (error != AddErrorKind.Succeeded)
{
function.AddError(ErrorCode.AlreadyDefined, EdmSchemaErrorSeverity.Error,
System.Data.Entity.Strings.AmbiguousFunctionOverload(function.FQName));
}
else
{
this.SchemaTypes.Add(function);
}
}
#endregion
#region Private Properties
#endregion
private static class SomSchemaSetHelper
{
public struct XmlSchemaResource
{
private static XmlSchemaResource[] EmptyImportList = new XmlSchemaResource[0];
public XmlSchemaResource(string namespaceUri, string resourceName, XmlSchemaResource [] importedSchemas)
{
Debug.Assert(!string.IsNullOrEmpty(namespaceUri), "namespaceUri is null or empty");
Debug.Assert(!string.IsNullOrEmpty(resourceName), "resourceName is null or empty");
Debug.Assert(importedSchemas != null, "importedSchemas is null");
NamespaceUri = namespaceUri;
ResourceName = resourceName;
ImportedSchemas = importedSchemas;
}
public XmlSchemaResource(string namespaceUri, string resourceName)
{
Debug.Assert(!string.IsNullOrEmpty(namespaceUri), "namespaceUri is null or empty");
Debug.Assert(!string.IsNullOrEmpty(resourceName), "resourceName is null or empty");
NamespaceUri = namespaceUri;
ResourceName = resourceName;
ImportedSchemas = EmptyImportList;
}
public string NamespaceUri;
public string ResourceName;
public XmlSchemaResource [] ImportedSchemas;
}
private static Memoizer _cachedSchemaSets =
new Memoizer(ComputeSchemaSet, EqualityComparer.Default);
public static Dictionary GetSchemaResourceMap()
{
XmlSchemaResource[] csdlImports = { new XmlSchemaResource(XmlConstants.CodeGenerationSchemaNamespace, "System.Data.Resources.CodeGenerationSchema.xsd") };
Dictionary schemaResourceMap = new Dictionary(StringComparer.Ordinal);
XmlSchemaResource csdlSchema = new XmlSchemaResource(XmlConstants.ModelNamespace, "System.Data.Resources.CSDLSchema.xsd", csdlImports);
schemaResourceMap.Add(csdlSchema.NamespaceUri, csdlSchema);
XmlSchemaResource csdlSchema_1_1 = new XmlSchemaResource(XmlConstants.ModelNamespace_1_1, "System.Data.Resources.CSDLSchema_1_1.xsd", csdlImports);
schemaResourceMap.Add(csdlSchema_1_1.NamespaceUri, csdlSchema_1_1);
XmlSchemaResource[] ssdlImports = { new XmlSchemaResource(XmlConstants.EntityStoreSchemaGeneratorNamespace, "System.Data.Resources.EntityStoreSchemaGenerator.xsd") };
XmlSchemaResource ssdlSchema = new XmlSchemaResource(XmlConstants.TargetNamespace, "System.Data.Resources.SSDLSchema.xsd", ssdlImports);
schemaResourceMap.Add(ssdlSchema.NamespaceUri, ssdlSchema);
XmlSchemaResource providerManifest = new XmlSchemaResource(XmlConstants.ProviderManifestNamespace, "System.Data.Resources.ProviderServices.ProviderManifest.xsd");
schemaResourceMap.Add(providerManifest.NamespaceUri, providerManifest);
return schemaResourceMap;
}
internal static List GetPrimarySchemaNamespaces(SchemaDataModelOption dataModel)
{
List namespaces = new List();
if (dataModel == SchemaDataModelOption.EntityDataModel)
{
namespaces.Add(XmlConstants.ModelNamespace);
namespaces.Add(XmlConstants.ModelNamespace_1_1);
}
else if (dataModel == SchemaDataModelOption.ProviderDataModel)
{
namespaces.Add(XmlConstants.TargetNamespace);
}
else
{
Debug.Assert(dataModel == SchemaDataModelOption.ProviderManifestModel, "Unknown SchemaDataModelOption did you add one?");
namespaces.Add(XmlConstants.ProviderManifestNamespace);
}
return namespaces;
}
internal static XmlSchemaSet GetSchemaSet(SchemaDataModelOption dataModel)
{
return _cachedSchemaSets.Evaluate(dataModel);
}
private static XmlSchemaSet ComputeSchemaSet(SchemaDataModelOption dataModel)
{
List namespaceNames = GetPrimarySchemaNamespaces(dataModel);
Debug.Assert(namespaceNames.Count > 0, "Unknown Datamodel");
XmlSchemaSet schemaSet = new XmlSchemaSet();
var schemaResourceMap = GetSchemaResourceMap();
HashSet schemasAlreadyAdded = new HashSet();
foreach (string namespaceName in namespaceNames)
{
Debug.Assert(schemaResourceMap.ContainsKey(namespaceName), "the namespace name is not one we have a schema set for");
XmlSchemaResource schemaResource = schemaResourceMap[namespaceName];
AddXmlSchemaToSet(schemaSet, schemaResource, schemasAlreadyAdded);
}
schemaSet.Compile();
return schemaSet;
}
private static void AddXmlSchemaToSet(XmlSchemaSet schemaSet, XmlSchemaResource schemaResource, HashSet schemasAlreadyAdded)
{
// loop through the children to do a depth first load
foreach (var import in schemaResource.ImportedSchemas)
{
AddXmlSchemaToSet(schemaSet, import, schemasAlreadyAdded);
}
if (!schemasAlreadyAdded.Contains(schemaResource.NamespaceUri))
{
Stream xsdStream = GetResourceStream(schemaResource.ResourceName);
XmlSchema schema = XmlSchema.Read(xsdStream, null);
schemaSet.Add(schema);
schemasAlreadyAdded.Add(schemaResource.NamespaceUri);
}
}
private static Stream GetResourceStream(string resourceName)
{
Debug.Assert(resourceName != null, "resourceName cannot be null");
Stream resourceStream = null;
System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
if (executingAssembly != null)
{
resourceStream = executingAssembly.GetManifestResourceStream(resourceName);
}
if (resourceStream == null)
{
throw EntityUtil.Data(System.Data.Entity.Strings.MissingAssemblyResource(resourceName));
}
return resourceStream;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Objects.DataClasses;
using System.Text;
using System.Data.Entity;
using System.Linq;
namespace System.Data.EntityModel.SchemaObjectModel
{
///
/// class representing the Schema element in the schema
///
[System.Diagnostics.DebuggerDisplay("Namespace={Namespace}, PublicKeyToken={PublicKeyToken}, Version={Version}")]
internal class Schema : SchemaElement
{
#region Instance Fields
private const int RootDepth = 2;
// if adding properties also add to InitializeObject()!
private List _errors = new List();
// We need to keep track of functions seperately, since we can't deduce the strong name of the function,
// until we have resolved the parameter names. Hence we keep track of functions seperately and add them
// to the schema types list, in the validate phase
private List _functions = null;
private AliasResolver _aliasResolver = null;
private string _location = null;
private string _alias = null;
protected string _namespaceName = null;
private string _schemaXmlNamespace = null;
private List _schemaTypes = null;
private int _depth = 0; // recursion depth in Parse used by *Handlers to know which hander set to set
private double _edmVersion = XmlConstants.EdmVersionForV1;
private SchemaManager _schemaManager;
#endregion
#region Static Fields
private static IList _emptyPathList = new List(0).AsReadOnly();
#endregion
#region Public Methods
public Schema(SchemaManager schemaManager)
: base(null)
{
Debug.Assert(schemaManager != null, "SchemaManager parameter should never be null");
_schemaManager = schemaManager;
_errors = new List();
}
internal IList Resolve()
{
ResolveTopLevelNames();
if (_errors.Count != 0)
{
return ResetErrors();
}
ResolveSecondLevelNames();
return ResetErrors();
}
internal IList ValidateSchema()
{
Validate();
return ResetErrors();
}
internal void AddError(EdmSchemaError error)
{
_errors.Add(error);
}
///
/// Populate the schema object from a schema
///
/// TextReader containing the schema xml definition
/// Uri containing path to a schema file (may be null)
/// list of errors
internal IList Parse(XmlReader sourceReader, string sourceLocation)
{
// We don't Assert (sourceReader != null) here any more because third-party
// providers that extend XmlEnabledProvidermanifest could hit this code. The
// following code eventually detects the anomaly and a ProviderIncompatible
// exception is thrown (which is the right thing to do in such cases).
XmlReader wrappedReader = null;
try
{
// user specified a stream to read from, read from it.
// The Uri is just used to identify the stream in errors.
XmlReaderSettings readerSettings = CreateXmlReaderSettings();
wrappedReader = XmlReader.Create(sourceReader, readerSettings);
return InternalParse(wrappedReader, sourceLocation);
}
catch (System.IO.IOException ex)
{
AddError(ErrorCode.IOException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
// do not close the reader here (SQLBUDT 522950)
return ResetErrors();
}
///
/// Populate the schema object from a schema
///
/// TextReader containing the schema xml definition
/// Uri containing path to a schema file (may be null)
/// list of errors
private IList InternalParse(XmlReader sourceReader, string sourceLocation)
{
Debug.Assert(sourceReader != null, "sourceReader parameter is null");
// these need to be set before any calls to AddError are made.
Schema = this;
Location = sourceLocation;
try
{
// to make life simpler, we skip down to the first/root element, unless we're
// already there
if (sourceReader.NodeType != XmlNodeType.Element)
{
while (sourceReader.Read() && sourceReader.NodeType != XmlNodeType.Element)
{
}
}
GetPositionInfo(sourceReader);
List expectedNamespaces = SomSchemaSetHelper.GetPrimarySchemaNamespaces(DataModel);
// the root element needs to be either TDL or Schema in our namespace
if (sourceReader.EOF)
{
if (sourceLocation != null)
{
AddError(ErrorCode.EmptyFile, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.EmptyFile(sourceLocation));
}
else
{
AddError(ErrorCode.EmptyFile, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.EmptySchemaTextReader);
}
}
else if (!expectedNamespaces.Contains(sourceReader.NamespaceURI))
{
Func messageFormat = Strings.UnexpectedRootElement;
if (string.IsNullOrEmpty(sourceReader.NamespaceURI))
messageFormat = Strings.UnexpectedRootElementNoNamespace;
String expectedNamespacesString = Helper.GetCommaDelimitedString(expectedNamespaces);
AddError(ErrorCode.UnexpectedXmlElement, EdmSchemaErrorSeverity.Error, messageFormat(sourceReader.NamespaceURI, sourceReader.LocalName, expectedNamespacesString));
}
else
{
this.SchemaXmlNamespace = sourceReader.NamespaceURI;
if (DataModel == SchemaDataModelOption.EntityDataModel)
{
if (this.SchemaXmlNamespace == XmlConstants.ModelNamespace)
{
EdmVersion = XmlConstants.EdmVersionForV1;
}
else
{
Debug.Assert(this.SchemaXmlNamespace == XmlConstants.ModelNamespace_1_1, "Unknown namespace in CSDL");
EdmVersion = XmlConstants.EdmVersionForV1_1;
}
}
switch (sourceReader.LocalName)
{
case "Schema":
case "ProviderManifest":
HandleTopLevelSchemaElement(sourceReader);
// this forces the reader to look beyond this top
// level element, and complain if there is another one.
sourceReader.Read();
break;
default:
AddError(ErrorCode.UnexpectedXmlElement, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.UnexpectedRootElement(sourceReader.NamespaceURI, sourceReader.LocalName, SchemaXmlNamespace));
break;
}
}
}
catch (InvalidOperationException ex)
{
AddError(ErrorCode.InternalError, EdmSchemaErrorSeverity.Error, ex.Message);
}
catch (System.UnauthorizedAccessException ex)
{
AddError(ErrorCode.UnauthorizedAccessException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (System.IO.IOException ex)
{
AddError(ErrorCode.IOException, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (System.Security.SecurityException ex)
{
AddError(ErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
catch (XmlException ex)
{
AddError(ErrorCode.XmlError, EdmSchemaErrorSeverity.Error, sourceReader, ex);
}
return ResetErrors();
}
internal static XmlReaderSettings CreateEdmStandardXmlReaderSettings()
{
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.CheckCharacters = true;
readerSettings.CloseInput = false;
readerSettings.IgnoreWhitespace = true;
readerSettings.ConformanceLevel = ConformanceLevel.Auto;
readerSettings.IgnoreComments = true;
readerSettings.IgnoreProcessingInstructions = true;
readerSettings.ProhibitDtd = true;
// remove flags
// the ProcessInlineSchema, and ProcessSchemaLocation flags must be removed for the same
// xsd schema to be used on multiple threads
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessIdentityConstraints;
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessSchemaLocation;
readerSettings.ValidationFlags &= ~System.Xml.Schema.XmlSchemaValidationFlags.ProcessInlineSchema;
return readerSettings;
}
private XmlReaderSettings CreateXmlReaderSettings()
{
XmlReaderSettings readerSettings = CreateEdmStandardXmlReaderSettings();
// add flags
readerSettings.ValidationFlags |= System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
readerSettings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(OnSchemaValidationEvent);
readerSettings.ValidationType = ValidationType.Schema;
XmlSchemaSet schemaSet = SomSchemaSetHelper.GetSchemaSet(DataModel);
// Do not use readerSetting.Schemas.Add(schemaSet)
// you must use the line below for this to work in
// a multithread environment
readerSettings.Schemas = schemaSet;
return readerSettings;
}
///
/// Called by the validating reader when the schema is xsd invalid
///
/// the validating reader
/// information about the validation error
internal void OnSchemaValidationEvent(object sender, System.Xml.Schema.ValidationEventArgs e)
{
Debug.Assert(e != null);
XmlReader reader = sender as XmlReader;
if (reader != null && !IsValidateableXmlNamespace(reader.NamespaceURI, reader.NodeType == XmlNodeType.Attribute))
{
// we allow non known namespaces to do whatever they want
return;
}
EdmSchemaErrorSeverity severity = EdmSchemaErrorSeverity.Error;
if (e.Severity == System.Xml.Schema.XmlSeverityType.Warning)
severity = EdmSchemaErrorSeverity.Warning;
AddError(ErrorCode.XmlError, severity, e.Exception.LineNumber, e.Exception.LinePosition, e.Message);
}
public bool IsParseableXmlNamespace(string xmlNamespaceUri, bool isAttribute)
{
if (string.IsNullOrEmpty(xmlNamespaceUri) && isAttribute)
{
// we own the empty namespace for attributes
return true;
}
if (_parseableXmlNamespaces == null)
{
_parseableXmlNamespaces = new HashSet();
foreach (var schemaResource in SomSchemaSetHelper.GetSchemaResourceMap().Values)
{
_parseableXmlNamespaces.Add(schemaResource.NamespaceUri);
}
}
return _parseableXmlNamespaces.Contains(xmlNamespaceUri);
}
HashSet _validatableXmlNamespaces;
HashSet _parseableXmlNamespaces;
public bool IsValidateableXmlNamespace(string xmlNamespaceUri, bool isAttribute)
{
if (string.IsNullOrEmpty(xmlNamespaceUri) && isAttribute)
{
// we own the empty namespace for attributes
return true;
}
if(_validatableXmlNamespaces == null)
{
_validatableXmlNamespaces = new HashSet();
foreach(var schemaResource in SomSchemaSetHelper.GetSchemaResourceMap().Values)
{
AddAllSchemaResourceNamespaceNames(_validatableXmlNamespaces, schemaResource);
}
}
return _validatableXmlNamespaces.Contains(xmlNamespaceUri);
}
private static void AddAllSchemaResourceNamespaceNames(HashSet hashSet, SomSchemaSetHelper.XmlSchemaResource schemaResource)
{
hashSet.Add(schemaResource.NamespaceUri);
foreach(var import in schemaResource.ImportedSchemas)
{
AddAllSchemaResourceNamespaceNames(hashSet, import);
}
}
internal override void ResolveTopLevelNames()
{
base.ResolveTopLevelNames();
// Resolve all the referenced namespace to make sure that this namespace is valid
AliasResolver.ResolveNamespaces();
foreach (SchemaElement element in SchemaTypes)
{
element.ResolveTopLevelNames();
}
foreach (Function function in Functions)
{
function.ResolveTopLevelNames();
}
}
internal override void ResolveSecondLevelNames()
{
base.ResolveSecondLevelNames();
foreach (SchemaElement element in SchemaTypes)
{
element.ResolveSecondLevelNames();
}
foreach (Function function in Functions)
{
function.ResolveSecondLevelNames();
}
}
///
/// Vaidate the schema.
///
/// list of errors
internal override void Validate()
{
// Also check for alias to be system namespace
if (!String.IsNullOrEmpty(Alias) && EdmItemCollection.IsSystemNamespace(ProviderManifest, Alias))
{
AddError(ErrorCode.CannotUseSystemNamespaceAsAlias, EdmSchemaErrorSeverity.Error,
System.Data.Entity.Strings.CannotUseSystemNamespaceAsAlias(Alias));
}
// Check whether the schema namespace is a system namespace. We set the provider manifest to edm provider manifest
// if we need to check for system namespace. Otherwise, it will be set to null (if we are loading edm provider manifest)
if (ProviderManifest != null &&
EdmItemCollection.IsSystemNamespace(ProviderManifest, Namespace))
{
AddError(ErrorCode.SystemNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.SystemNamespaceEncountered(Namespace));
}
foreach (SchemaElement schemaType in this.SchemaTypes)
{
schemaType.Validate();
}
foreach (Function function in this.Functions)
{
AddFunctionType(function);
function.Validate();
}
}
#endregion
#region Public Properties
///
/// The namespaceUri of the winfs xml namespace
///
internal string SchemaXmlNamespace
{
get
{
return _schemaXmlNamespace;
}
private set
{
_schemaXmlNamespace = value;
}
}
internal DbProviderManifest ProviderManifest
{
get
{
return _schemaManager.GetProviderManifest((string message, ErrorCode code, EdmSchemaErrorSeverity severity)=>AddError(code, severity, message));
}
}
///
/// Version of the EDM that this schema represents.
///
internal double EdmVersion
{
get
{
return _edmVersion;
}
set
{
_edmVersion = value;
}
}
///
/// Alias for the schema (null if none)
///
internal virtual string Alias
{
get
{
return _alias;
}
private set
{
_alias = value;
}
}
///
/// Namespace of the schema
///
internal virtual string Namespace
{
get
{
return _namespaceName;
}
private set
{
_namespaceName = value;
}
}
// ISSUE: jthunter-03/14/05 - The [....] "schemas" don't follow the ".Store" assembly
// naming convention but need to have the right StoreNamespace reported.
//
private static readonly string[] ClientNamespaceOfSchemasMissingStoreSuffix =
{
"System.Storage.[....].Utility",
"System.Storage.[....].Services"
};
///
/// Uri containing the file that defines the schema
///
internal string Location
{
get
{
return _location;
}
private set
{
_location = value;
}
}
///
/// List of all types defined in the schema
///
internal List SchemaTypes
{
get
{
if (_schemaTypes == null)
{
_schemaTypes = new List();
}
return _schemaTypes;
}
}
///
/// Fully qualified name of the schema (same as the namespace name)
///
public override string FQName
{
get
{
return Namespace;
}
}
private List Functions
{
get
{
if (_functions == null)
{
_functions = new List();
}
return _functions;
}
}
#endregion
#region Protected Properties
protected override bool HandleElement(XmlReader reader)
{
if (base.HandleElement(reader))
{
return true;
}
else if (CanHandleElement(reader, XmlConstants.EntityType))
{
HandleEntityTypeElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.ComplexType))
{
HandleInlineTypeElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.Association))
{
HandleAssociationElement(reader);
return true;
}
// Using is only supported in EntityDataModel
if (DataModel == SchemaDataModelOption.EntityDataModel)
{
if (CanHandleElement(reader, XmlConstants.Using))
{
HandleUsingElement(reader);
return true;
}
}
if (DataModel == SchemaDataModelOption.EntityDataModel ||
DataModel == SchemaDataModelOption.ProviderDataModel)
{
if (CanHandleElement(reader, XmlConstants.EntityContainer))
{
HandleEntityContainerTypeElement(reader);
return true;
}
else if (DataModel == SchemaDataModelOption.ProviderDataModel)
{
if (CanHandleElement(reader, XmlConstants.Function))
{
HandleFunctionElement(reader);
return true;
}
}
}
else
{
Debug.Assert(DataModel == SchemaDataModelOption.ProviderManifestModel, "Did you add a new option?");
if (CanHandleElement(reader, XmlConstants.TypesElement))
{
SkipThroughElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.FunctionsElement))
{
SkipThroughElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.Function))
{
HandleFunctionElement(reader);
return true;
}
else if (CanHandleElement(reader, XmlConstants.TypeElement))
{
HandleTypeInformationElement(reader);
return true;
}
}
return false;
}
protected override bool ProhibitAttribute(string namespaceUri, string localName)
{
if (base.ProhibitAttribute(namespaceUri, localName))
{
return true;
}
if (namespaceUri == null && localName == XmlConstants.Name)
{
return false;
}
return false;
}
protected override bool HandleAttribute(XmlReader reader)
{
Debug.Assert(_depth > 0);
if (_depth == 1)
{
return false;
}
else
{
if (base.HandleAttribute(reader))
{
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Alias))
{
HandleAliasAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Namespace))
{
HandleNamespaceAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.Provider))
{
HandleProviderAttribute(reader);
return true;
}
else if (CanHandleAttribute(reader, XmlConstants.ProviderManifestToken))
{
HandleProviderManifestTokenAttribute(reader);
return true;
}
}
return false;
}
#endregion
#region Internal Methods
///
/// Called when all attributes for the schema element have been handled
///
protected override void HandleAttributesComplete()
{
if (_depth < RootDepth)
{
return;
}
else if (_depth == RootDepth)
{
// only call when done with the root element
_schemaManager.EnsurePrimitiveSchemaIsLoaded();
}
base.HandleAttributesComplete();
}
protected override void SkipThroughElement(XmlReader reader)
{
try
{
_depth++;
base.SkipThroughElement(reader);
}
finally
{
_depth--;
}
}
///
/// Look up a fully qualified type name reference.
///
/// element containing the reference
/// the fully qualified type name
/// the referenced schema type
/// false if there was an error
internal bool ResolveTypeName(SchemaElement usingElement, string typeName, out SchemaType type)
{
Debug.Assert(usingElement != null);
Debug.Assert(typeName != null);
type = null;
// get the schema(s) that match the namespace/alias
string actualQualification;
string unqualifiedTypeName;
Utils.ExtractNamespaceAndName(DataModel, typeName, out actualQualification, out unqualifiedTypeName);
string definingQualification = actualQualification;
if (definingQualification == null)
{
definingQualification = this.ProviderManifest == null ? this._namespaceName : this.ProviderManifest.NamespaceName;
}
string namespaceName;
// First check if there is an alias defined by this name. For primitive type namespace, we do not need to resolve
// any alias, since that's a reserved keyword and we don't allow alias with that name
if (actualQualification == null || !AliasResolver.TryResolveAlias(definingQualification, out namespaceName))
{
namespaceName = definingQualification;
}
// Resolve the type name
if (!SchemaManager.TryResolveType(namespaceName, unqualifiedTypeName, out type))
{
// it must be an undefined type.
if (actualQualification == null)
{
// Every type except the primitive type must be qualified
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotNamespaceQualified(typeName));
}
else if (!SchemaManager.IsValidNamespaceName(namespaceName))
{
usingElement.AddError(ErrorCode.BadNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.BadNamespaceOrAlias(actualQualification));
}
else
{
// if the type name was alias qualified
if (namespaceName != definingQualification)
{
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotInNamespaceAlias(unqualifiedTypeName, namespaceName, definingQualification));
}
else
{
usingElement.AddError(ErrorCode.NotInNamespace, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.NotInNamespaceNoAlias(unqualifiedTypeName, namespaceName));
}
}
return false;
}
// For ssdl and provider manifest, make sure that the type is present in this schema or primitive schema
else if (this.DataModel != SchemaDataModelOption.EntityDataModel && type.Schema != this && type.Schema != this.SchemaManager.PrimitiveSchema)
{
if (type.Namespace != this.Namespace)
{
usingElement.AddError(ErrorCode.InvalidNamespaceOrAliasSpecified, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InvalidNamespaceOrAliasSpecified(actualQualification));
}
else
{
usingElement.AddError(ErrorCode.CannotReferTypeAcrossSchema, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.CannotReferTypeAcrossSchema(unqualifiedTypeName));
}
return false;
}
return true;
}
#endregion
#region Internal Properties
///
/// List containing the current schema and all referenced schemas. Used for alias and namespace lookup.
///
internal AliasResolver AliasResolver
{
get
{
if (_aliasResolver == null)
{
_aliasResolver = new AliasResolver(this);
}
return _aliasResolver;
}
}
///
/// The schema data model
///
internal SchemaDataModelOption DataModel
{
get
{
return SchemaManager.DataModel;
}
}
///
/// The schema data model
///
internal SchemaManager SchemaManager
{
get
{
return _schemaManager;
}
}
#endregion
#region Private Methods
///
/// Handler for the Namespace attribute
///
/// xml reader currently positioned at Namespace attribute
private void HandleNamespaceAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
ReturnValue returnValue = HandleDottedNameAttribute(reader, Namespace, Strings.AlreadyDefined);
if (!returnValue.Succeeded)
return;
Namespace = returnValue.Value;
}
///
/// Handler for the Alias attribute
///
/// xml reader currently positioned at Alias attribute
private void HandleAliasAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
Alias = HandleUndottedNameAttribute(reader, Alias);
}
///
/// Handler for the Provider attribute
///
/// xml reader currently positioned at Provider attribute
private void HandleProviderAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
string provider = reader.Value;
_schemaManager.ProviderNotification(provider,
(string message, ErrorCode code, EdmSchemaErrorSeverity severity) => AddError(code, severity, reader, message));
}
///
/// Handler for the ProviderManifestToken attribute
///
/// xml reader currently positioned at ProviderManifestToken attribute
private void HandleProviderManifestTokenAttribute(XmlReader reader)
{
Debug.Assert(reader != null);
string providerManifestToken = reader.Value;
_schemaManager.ProviderManifestTokenNotification(providerManifestToken,
(string message, ErrorCode code, EdmSchemaErrorSeverity severity) => AddError(code, severity, reader, message));
}
///
/// Handler for the using element
///
///
private void HandleUsingElement(XmlReader reader)
{
UsingElement referencedNamespace = new UsingElement(this);
referencedNamespace.Parse(reader);
AliasResolver.Add(referencedNamespace);
}
///
/// Handler for the top level element
///
/// xml reader currently positioned at top level element
private void HandleTopLevelSchemaElement(XmlReader reader)
{
Debug.Assert(reader != null);
try
{
_depth += RootDepth;
Parse(reader);
}
finally
{
_depth -= RootDepth;
}
}
///
/// Handler for the EntityType element
///
/// xml reader currently positioned at EntityType element
private void HandleEntityTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
SchemaEntityType itemType = new SchemaEntityType(this);
itemType.Parse(reader);
TryAddType(itemType, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the TypeInformation element
///
/// xml reader currently positioned at EntityType element
private void HandleTypeInformationElement(XmlReader reader)
{
Debug.Assert(reader != null);
TypeElement type = new TypeElement(this);
type.Parse(reader);
TryAddType(type, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the Function element
///
/// xml reader currently positioned at EntityType element
private void HandleFunctionElement(XmlReader reader)
{
Debug.Assert(reader != null);
Function function = new Function(this);
function.Parse(reader);
this.Functions.Add(function);
}
///
/// Handler for the Association element
///
/// xml reader currently positioned at Association element
private void HandleAssociationElement(XmlReader reader)
{
Debug.Assert(reader != null);
Relationship relationship = new Relationship(this, RelationshipKind.Association);
relationship.Parse(reader);
TryAddType(relationship, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the InlineType element
///
/// xml reader currently positioned at InlineType element
private void HandleInlineTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
SchemaComplexType complexType = new SchemaComplexType(this);
complexType.Parse(reader);
TryAddType(complexType, true/*doNotAddErrorForEmptyName*/);
}
///
/// Handler for the EntityContainer element
///
/// xml reader currently positioned at EntityContainer element
private void HandleEntityContainerTypeElement(XmlReader reader)
{
Debug.Assert(reader != null);
EntityContainer type = new EntityContainer(this);
type.Parse(reader);
TryAddContainer(type, true/*doNotAddErrorForEmptyName*/);
}
///
/// reset the error collection
///
/// old error list
private List ResetErrors()
{
List errors = _errors;
_errors = new List();
return errors;
}
protected void TryAddType(SchemaType schemaType, bool doNotAddErrorForEmptyName)
{
this.SchemaManager.SchemaTypes.Add(schemaType, doNotAddErrorForEmptyName,
Strings.TypeNameAlreadyDefinedDuplicate);
this.SchemaTypes.Add(schemaType);
}
protected void TryAddContainer(SchemaType schemaType, bool doNotAddErrorForEmptyName)
{
this.SchemaManager.SchemaTypes.Add(schemaType, doNotAddErrorForEmptyName,
Strings.EntityContainerAlreadyExists);
this.SchemaTypes.Add(schemaType);
}
protected void AddFunctionType(Function function)
{
AddErrorKind error = this.SchemaManager.SchemaTypes.TryAdd(function);
Debug.Assert(error != AddErrorKind.MissingNameError, "Function identity can never be null while adding global functions");
if (error != AddErrorKind.Succeeded)
{
function.AddError(ErrorCode.AlreadyDefined, EdmSchemaErrorSeverity.Error,
System.Data.Entity.Strings.AmbiguousFunctionOverload(function.FQName));
}
else
{
this.SchemaTypes.Add(function);
}
}
#endregion
#region Private Properties
#endregion
private static class SomSchemaSetHelper
{
public struct XmlSchemaResource
{
private static XmlSchemaResource[] EmptyImportList = new XmlSchemaResource[0];
public XmlSchemaResource(string namespaceUri, string resourceName, XmlSchemaResource [] importedSchemas)
{
Debug.Assert(!string.IsNullOrEmpty(namespaceUri), "namespaceUri is null or empty");
Debug.Assert(!string.IsNullOrEmpty(resourceName), "resourceName is null or empty");
Debug.Assert(importedSchemas != null, "importedSchemas is null");
NamespaceUri = namespaceUri;
ResourceName = resourceName;
ImportedSchemas = importedSchemas;
}
public XmlSchemaResource(string namespaceUri, string resourceName)
{
Debug.Assert(!string.IsNullOrEmpty(namespaceUri), "namespaceUri is null or empty");
Debug.Assert(!string.IsNullOrEmpty(resourceName), "resourceName is null or empty");
NamespaceUri = namespaceUri;
ResourceName = resourceName;
ImportedSchemas = EmptyImportList;
}
public string NamespaceUri;
public string ResourceName;
public XmlSchemaResource [] ImportedSchemas;
}
private static Memoizer _cachedSchemaSets =
new Memoizer(ComputeSchemaSet, EqualityComparer.Default);
public static Dictionary GetSchemaResourceMap()
{
XmlSchemaResource[] csdlImports = { new XmlSchemaResource(XmlConstants.CodeGenerationSchemaNamespace, "System.Data.Resources.CodeGenerationSchema.xsd") };
Dictionary schemaResourceMap = new Dictionary(StringComparer.Ordinal);
XmlSchemaResource csdlSchema = new XmlSchemaResource(XmlConstants.ModelNamespace, "System.Data.Resources.CSDLSchema.xsd", csdlImports);
schemaResourceMap.Add(csdlSchema.NamespaceUri, csdlSchema);
XmlSchemaResource csdlSchema_1_1 = new XmlSchemaResource(XmlConstants.ModelNamespace_1_1, "System.Data.Resources.CSDLSchema_1_1.xsd", csdlImports);
schemaResourceMap.Add(csdlSchema_1_1.NamespaceUri, csdlSchema_1_1);
XmlSchemaResource[] ssdlImports = { new XmlSchemaResource(XmlConstants.EntityStoreSchemaGeneratorNamespace, "System.Data.Resources.EntityStoreSchemaGenerator.xsd") };
XmlSchemaResource ssdlSchema = new XmlSchemaResource(XmlConstants.TargetNamespace, "System.Data.Resources.SSDLSchema.xsd", ssdlImports);
schemaResourceMap.Add(ssdlSchema.NamespaceUri, ssdlSchema);
XmlSchemaResource providerManifest = new XmlSchemaResource(XmlConstants.ProviderManifestNamespace, "System.Data.Resources.ProviderServices.ProviderManifest.xsd");
schemaResourceMap.Add(providerManifest.NamespaceUri, providerManifest);
return schemaResourceMap;
}
internal static List GetPrimarySchemaNamespaces(SchemaDataModelOption dataModel)
{
List namespaces = new List();
if (dataModel == SchemaDataModelOption.EntityDataModel)
{
namespaces.Add(XmlConstants.ModelNamespace);
namespaces.Add(XmlConstants.ModelNamespace_1_1);
}
else if (dataModel == SchemaDataModelOption.ProviderDataModel)
{
namespaces.Add(XmlConstants.TargetNamespace);
}
else
{
Debug.Assert(dataModel == SchemaDataModelOption.ProviderManifestModel, "Unknown SchemaDataModelOption did you add one?");
namespaces.Add(XmlConstants.ProviderManifestNamespace);
}
return namespaces;
}
internal static XmlSchemaSet GetSchemaSet(SchemaDataModelOption dataModel)
{
return _cachedSchemaSets.Evaluate(dataModel);
}
private static XmlSchemaSet ComputeSchemaSet(SchemaDataModelOption dataModel)
{
List namespaceNames = GetPrimarySchemaNamespaces(dataModel);
Debug.Assert(namespaceNames.Count > 0, "Unknown Datamodel");
XmlSchemaSet schemaSet = new XmlSchemaSet();
var schemaResourceMap = GetSchemaResourceMap();
HashSet schemasAlreadyAdded = new HashSet();
foreach (string namespaceName in namespaceNames)
{
Debug.Assert(schemaResourceMap.ContainsKey(namespaceName), "the namespace name is not one we have a schema set for");
XmlSchemaResource schemaResource = schemaResourceMap[namespaceName];
AddXmlSchemaToSet(schemaSet, schemaResource, schemasAlreadyAdded);
}
schemaSet.Compile();
return schemaSet;
}
private static void AddXmlSchemaToSet(XmlSchemaSet schemaSet, XmlSchemaResource schemaResource, HashSet schemasAlreadyAdded)
{
// loop through the children to do a depth first load
foreach (var import in schemaResource.ImportedSchemas)
{
AddXmlSchemaToSet(schemaSet, import, schemasAlreadyAdded);
}
if (!schemasAlreadyAdded.Contains(schemaResource.NamespaceUri))
{
Stream xsdStream = GetResourceStream(schemaResource.ResourceName);
XmlSchema schema = XmlSchema.Read(xsdStream, null);
schemaSet.Add(schema);
schemasAlreadyAdded.Add(schemaResource.NamespaceUri);
}
}
private static Stream GetResourceStream(string resourceName)
{
Debug.Assert(resourceName != null, "resourceName cannot be null");
Stream resourceStream = null;
System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
if (executingAssembly != null)
{
resourceStream = executingAssembly.GetManifestResourceStream(resourceName);
}
if (resourceStream == null)
{
throw EntityUtil.Data(System.Data.Entity.Strings.MissingAssemblyResource(resourceName));
}
return resourceStream;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.