linux-packaging-mono/mcs/class/System.ServiceModel/System.ServiceModel.Description/DataContractSerializerMessageContractImporter.cs
Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

414 lines
12 KiB
C#

//
// DataContractSerializerMessageContractImporter.cs
//
// Author: Atsushi Enomoto (atsushi@ximian.com)
// Ankit Jain (jankit@novell.com)
//
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using QName = System.Xml.XmlQualifiedName;
using WSDL = System.Web.Services.Description.ServiceDescription;
using Message = System.Web.Services.Description.Message;
namespace System.ServiceModel.Description
{
public class DataContractSerializerMessageContractImporter
: IWsdlImportExtension
{
MessageContractImporterInternal impl = new DataContractMessageContractImporterInternal ();
bool enabled = true;
public bool Enabled {
get { return enabled; }
set { enabled = value; }
}
void IWsdlImportExtension.BeforeImport (
ServiceDescriptionCollection wsdlDocuments,
XmlSchemaSet xmlSchemas,
ICollection<XmlElement> policy)
{
if (!Enabled)
return;
impl.BeforeImport (wsdlDocuments, xmlSchemas, policy);
}
void IWsdlImportExtension.ImportContract (WsdlImporter importer,
WsdlContractConversionContext context)
{
if (!Enabled)
return;
impl.ImportContract (importer, context);
}
void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
WsdlEndpointConversionContext context)
{
if (!Enabled)
return;
impl.ImportEndpoint (importer, context);
}
}
abstract class MessageContractImporterInternal : IWsdlImportExtension
{
protected abstract void Init (WsdlImporter importer);
public void ImportContract (WsdlImporter importer,
WsdlContractConversionContext context)
{
if (importer == null)
throw new ArgumentNullException ("importer");
if (context == null)
throw new ArgumentNullException ("context");
if (this.importer != null || this.context != null)
throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
Init (importer);
schema_set_in_use = new XmlSchemaSet ();
schema_set_in_use.Add (importer.XmlSchemas);
foreach (WSDL wsdl in importer.WsdlDocuments)
foreach (XmlSchema xs in wsdl.Types.Schemas)
schema_set_in_use.Add (xs);
schema_set_in_use.Compile ();
this.importer = importer;
this.context = context;
try {
DoImportContract ();
} finally {
this.importer = null;
this.context = null;
}
}
internal WsdlImporter importer;
WsdlContractConversionContext context;
internal XmlSchemaSet schema_set_in_use;
public void BeforeImport (
ServiceDescriptionCollection wsdlDocuments,
XmlSchemaSet xmlSchemas,
ICollection<XmlElement> policy)
{
}
void DoImportContract ()
{
PortType port_type = context.WsdlPortType;
ContractDescription contract = context.Contract;
int i, j;
List<MessagePartDescription> parts = new List<MessagePartDescription> ();
i = 0;
foreach (Operation op in port_type.Operations) {
OperationDescription opdescr = contract.Operations [i];
if (IsOperationImported (port_type, op))
continue;
if (!CanImportOperation (port_type, op))
continue;
j = 0;
foreach (OperationMessage opmsg in op.Messages) {
//SM.MessageDescription
MessageDescription msgdescr = opdescr.Messages [j];
//OpMsg's corresponding WSMessage
Message msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
msgdescr.Body.WrapperNamespace = port_type.ServiceDescription.TargetNamespace;
if (opmsg is OperationOutput) {
//ReturnValue
msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
resolveMessage (msg, msgdescr.Body, parts);
if (parts.Count > 0) {
msgdescr.Body.ReturnValue = parts [0];
parts.Clear ();
}
continue;
}
/* OperationInput */
/* Parts, MessagePartDescription */
resolveMessage (msg, msgdescr.Body, parts);
foreach (MessagePartDescription p in parts)
msgdescr.Body.Parts.Add (p);
parts.Clear ();
j ++;
}
OnOperationImported (opdescr);
i ++;
}
}
bool IsOperationImported (PortType pt, Operation op)
{
foreach (OperationMessage opmsg in op.Messages) {
var opdsc = context.GetMessageDescription (opmsg);
var parts = opdsc.Body.Parts;
var ret = opdsc.Body.ReturnValue;
if ((ret != null) &&
(ret.DataContractImporter != null || ret.XmlSerializationImporter != null))
return true;
foreach (var part in opdsc.Body.Parts)
if (part.DataContractImporter != null || part.XmlSerializationImporter != null)
return true;
}
return false;
}
void resolveMessage (Message msg, MessageBodyDescription body, List<MessagePartDescription> parts)
{
foreach (MessagePart part in msg.Parts) {
if (part.Name == "parameters") {
if (!part.Element.IsEmpty) {
body.WrapperName = part.Element.Name;
ImportPartsBySchemaElement (part.Element, parts, msg, part);
} else {
body.WrapperName = part.Type.Name;
ResolveType (part.Type, parts, body.WrapperNamespace);
}
}
else
throw new InvalidOperationException ("Only 'parameters' element in message part is supported"); // this should have been rejected by CanImportOperation().
}
}
public void ImportEndpoint (WsdlImporter importer,
WsdlEndpointConversionContext context)
{
}
protected abstract void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part);
protected abstract void ResolveType (QName qname, List<MessagePartDescription> parts, string ns);
protected abstract bool CanImportOperation (PortType portType, Operation op);
protected abstract void OnOperationImported (OperationDescription od);
}
class DataContractMessageContractImporterInternal : MessageContractImporterInternal
{
XsdDataContractImporter dc_importer;
protected override void Init (WsdlImporter importer)
{
if (dc_importer == null)
dc_importer = importer.GetState<XsdDataContractImporter> ();
}
protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part)
{
XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
if (element == null)
throw new InvalidOperationException ("Could not resolve : " + qname.ToString ()); // this should have been rejected by CanImportOperation().
var ct = element.ElementSchemaType as XmlSchemaComplexType;
if (ct == null) // simple type
parts.Add (CreateMessagePart (element, msg, part));
else // complex type
foreach (var elem in GetElementsInParticle (ct.ContentTypeParticle))
parts.Add (CreateMessagePart (elem, msg, part));
}
IEnumerable<XmlSchemaElement> GetElementsInParticle (XmlSchemaParticle p)
{
if (p is XmlSchemaElement) {
yield return (XmlSchemaElement) p;
} else {
var gb = p as XmlSchemaGroupBase;
if (gb != null)
foreach (XmlSchemaParticle pp in gb.Items)
foreach (var e in GetElementsInParticle (pp))
yield return e;
}
}
MessagePartDescription CreateMessagePart (XmlSchemaElement elem, Message msg, MessagePart msgPart)
{
var part = new MessagePartDescription (elem.QualifiedName.Name, elem.QualifiedName.Namespace);
part.DataContractImporter = dc_importer;
if (dc_importer.CanImport (schema_set_in_use, elem)) {
var typeQName = dc_importer.Import (schema_set_in_use, elem);
part.CodeTypeReference = dc_importer.GetCodeTypeReference (elem.ElementSchemaType.QualifiedName, elem);
}
return part;
}
protected override void ResolveType (QName qname, List<MessagePartDescription> parts, string ns)
{
/*foreach (XmlSchema xs in importer.Schemas)
if (xs.Types [qname] != null)
return resolveParameters ((XmlSchemaElement) xs.Types [qname]., msgdescr, importer);
//FIXME: What to do here?
throw new Exception ("Could not resolve : " + qname.ToString ());*/
throw new NotImplementedException ();
}
Message FindMessage (OperationMessage om)
{
foreach (WSDL sd in importer.WsdlDocuments)
if (sd.TargetNamespace == om.Message.Namespace)
foreach (Message msg in sd.Messages)
if (msg.Name == om.Message.Name)
return msg;
return null;
}
protected override bool CanImportOperation (PortType portType, Operation op)
{
foreach (OperationMessage om in op.Messages) {
var msg = FindMessage (om);
if (msg == null)
return false;
foreach (MessagePart part in msg.Parts) {
if (part.Name == "parameters" && !part.Element.IsEmpty) {
var xe = schema_set_in_use.GlobalElements [part.Element] as XmlSchemaElement;
if (xe == null || !dc_importer.CanImport (schema_set_in_use, xe))
return false;
}
else
return false;
}
}
return true;
}
protected override void OnOperationImported (OperationDescription od)
{
// do nothing
}
}
class XmlSerializerMessageContractImporterInternal : MessageContractImporterInternal
{
CodeCompileUnit ccu;
XmlSchemaSet schema_set_cache;
XmlSchemaImporter schema_importer;
XmlCodeExporter code_exporter;
public CodeCompileUnit CodeCompileUnit {
get { return ccu; }
}
protected override void Init (WsdlImporter importer)
{
if (ccu == null)
ccu = importer.GetState<CodeCompileUnit> ();
}
protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart msgPart)
{
if (schema_set_cache != schema_set_in_use) {
schema_set_cache = schema_set_in_use;
var xss = new XmlSchemas ();
foreach (XmlSchema xs in schema_set_cache.Schemas ())
xss.Add (xs);
schema_importer = new XmlSchemaImporter (xss);
if (ccu.Namespaces.Count == 0)
ccu.Namespaces.Add (new CodeNamespace ());
var cns = ccu.Namespaces [0];
code_exporter = new XmlCodeExporter (cns, ccu);
}
var part = new MessagePartDescription (qname.Name, qname.Namespace);
part.XmlSerializationImporter = this;
var mbrNS = msg.ServiceDescription.TargetNamespace;
var xmm = schema_importer.ImportMembersMapping (qname);
code_exporter.ExportMembersMapping (xmm);
// FIXME: use of ElementName is a hack!
part.CodeTypeReference = new CodeTypeReference (xmm.ElementName);
parts.Add (part);
}
protected override void ResolveType (QName qname, List<MessagePartDescription> parts, string ns)
{
throw new NotImplementedException ();
}
protected override bool CanImportOperation (PortType portType, Operation op)
{
// FIXME: implement
return true;
}
protected override void OnOperationImported (OperationDescription od)
{
od.Behaviors.Add (new XmlSerializerMappingBehavior ());
}
}
// just a marker behavior
class XmlSerializerMappingBehavior : IOperationBehavior
{
public void AddBindingParameters (OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior (OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior (OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
}
public void Validate (OperationDescription operationDescription)
{
}
}
}