// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Schema;
namespace Ringtoets.Common.IO.Readers
{
///
/// Container for one or more related/nested schema definitions, representing a combined
/// XML Schema Definition (XSD).
///
public class CombinedXmlSchemaDefinition
{
private readonly XmlSchemaSet xmlSchemaSet;
///
/// Creates a new instance of .
///
/// A string representing the main schema definition.
/// A containing
/// one or more nested schema definitions; the keys should represent unique file names by which
/// the schema definitions can be referenced from , the
/// values should represent the corresponding schema definition strings.
/// Thrown when
/// is null.
/// Thrown when:
///
/// - is invalid.
/// - contains invalid schema definition values.
/// - , all together with its referenced
/// , contains an invalid schema definition.
/// - contains schema definitions that are not
/// referenced by .
///
///
public CombinedXmlSchemaDefinition(string mainSchemaDefinition, IDictionary nestedSchemaDefinitions)
{
CheckSchemaDefinitions(mainSchemaDefinition, nestedSchemaDefinitions);
var nestedSchemaDefinitionsResolver = new NestedSchemaDefinitionsResolver(nestedSchemaDefinitions);
xmlSchemaSet = new XmlSchemaSet
{
XmlResolver = nestedSchemaDefinitionsResolver
};
CompileSchemaSet(mainSchemaDefinition);
if (!nestedSchemaDefinitionsResolver.AllNestedSchemaDefinitionsReferenced)
{
throw new ArgumentException($"'{nameof(nestedSchemaDefinitions)}' contains one or more schema definitions that are not referenced.");
}
}
///
/// Check the provided schema definitions for not being null, empty or only containing white spaces.
///
/// A string representing the main schema definition.
/// A containing
/// one or more nested schema definitions.
/// Thrown when
/// is null.
/// Thrown when:
///
/// - is invalid.
/// - contains invalid schema definition values.
///
///
private static void CheckSchemaDefinitions(string mainSchemaDefinition, IDictionary nestedSchemaDefinitions)
{
if (string.IsNullOrWhiteSpace(mainSchemaDefinition))
{
throw new ArgumentException($"'{nameof(mainSchemaDefinition)}' null, empty or only containing white spaces.");
}
if (nestedSchemaDefinitions == null)
{
throw new ArgumentNullException(nameof(nestedSchemaDefinitions));
}
if (nestedSchemaDefinitions.Values.Any(string.IsNullOrWhiteSpace))
{
throw new ArgumentException($"'{nameof(nestedSchemaDefinitions)}' holds a nested schema definition value that equals null, is empty or only contains white spaces.");
}
}
///
/// Compiles the based on the provided main schema definition string.
///
/// A string representing the main schema definition.
/// Thrown when ,
/// all together with its referenced nested schema definitions, contains an invalid schema
/// definition.
private void CompileSchemaSet(string mainSchemaDefinition)
{
try
{
xmlSchemaSet.Add(XmlSchema.Read(new StringReader(mainSchemaDefinition), null));
xmlSchemaSet.Compile();
}
catch (Exception exception) when (exception is XmlException
|| exception is XmlSchemaException)
{
throw new ArgumentException($"'{nameof(mainSchemaDefinition)}' containing invalid schema definition: {exception.Message}", exception);
}
}
///
/// Resolver for nested schema definitions.
///
private class NestedSchemaDefinitionsResolver : XmlResolver
{
private readonly IDictionary nestedSchemaDefinitions;
private readonly IDictionary nestedSchemaDefinitionsUsage;
///
/// Creates a new instance of .
///
/// A containing
/// one or more nested schema definitions.
public NestedSchemaDefinitionsResolver(IDictionary nestedSchemaDefinitions)
{
this.nestedSchemaDefinitions = nestedSchemaDefinitions;
nestedSchemaDefinitionsUsage = nestedSchemaDefinitions.Keys.ToDictionary(k => k, k => false);
}
public override ICredentials Credentials
{
set
{
throw new NotImplementedException();
}
}
///
/// Gets whether or not all nested schema definitions are used.
///
public bool AllNestedSchemaDefinitionsReferenced
{
get
{
return nestedSchemaDefinitionsUsage.Values.All(v => v);
}
}
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
string fileName = Path.GetFileName(absoluteUri.ToString());
if (nestedSchemaDefinitions.ContainsKey(fileName))
{
nestedSchemaDefinitionsUsage[fileName] = true;
return new MemoryStream(Encoding.UTF8.GetBytes(nestedSchemaDefinitions[fileName]));
}
return null;
}
}
}
}