1 //
2 // SyndicationElementExtension.cs
3 //
4 // Author:
5 //	Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.ObjectModel;
31 using System.IO;
32 using System.Runtime.Serialization;
33 using System.Text;
34 using System.Xml;
35 using System.Xml.Serialization;
36 
37 namespace System.ServiceModel.Syndication
38 {
39 	public class SyndicationElementExtension
40 	{
41 		ReadWriteHandler handler;
42 
SyndicationElementExtension(object dataContractExtension)43 		public SyndicationElementExtension (object dataContractExtension)
44 			: this (dataContractExtension, (XmlObjectSerializer) null)
45 		{
46 		}
47 
SyndicationElementExtension(object dataContractExtension, XmlObjectSerializer dataContractSerializer)48 		public SyndicationElementExtension (object dataContractExtension, XmlObjectSerializer dataContractSerializer)
49 			: this (null, null, dataContractExtension, dataContractSerializer)
50 		{
51 		}
52 
SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension)53 		public SyndicationElementExtension (string outerName, string outerNamespace, object dataContractExtension)
54 			: this (outerName, outerNamespace, dataContractExtension, null)
55 		{
56 		}
57 
SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension, XmlObjectSerializer dataContractSerializer)58 		public SyndicationElementExtension (string outerName, string outerNamespace, object dataContractExtension, XmlObjectSerializer dataContractSerializer)
59 		{
60 			if (dataContractExtension == null)
61 				throw new ArgumentNullException ("dataContractExtension");
62 			handler = new DataContractReadWriteHandler (outerName, outerNamespace, dataContractExtension, dataContractSerializer);
63 		}
64 
SyndicationElementExtension(object xmlSerializerExtension, XmlSerializer serializer)65 		public SyndicationElementExtension (object xmlSerializerExtension, XmlSerializer serializer)
66 		{
67 			if (xmlSerializerExtension == null)
68 				throw new ArgumentNullException ("xmlSerializerExtension");
69 			handler = new XmlSerializationReadWriteHandler (xmlSerializerExtension, serializer);
70 		}
71 
SyndicationElementExtension(XmlReader xmlReader)72 		public SyndicationElementExtension (XmlReader xmlReader)
73 		{
74 			if (xmlReader == null)
75 				throw new ArgumentNullException ("xmlReader");
76 			xmlReader.MoveToContent ();
77 			if (xmlReader.NodeType != XmlNodeType.Element)
78 				throw new XmlException ("Element node is expected on the argument xmlReader");
79 
80 			handler = new XmlReaderReadWriteHandler (xmlReader);
81 		}
82 
83 		public string OuterName {
84 			get { return handler != null ? handler.Name : null; }
85 		}
86 
87 		public string OuterNamespace {
88 			get { return handler != null ? handler.Namespace : null; }
89 		}
90 
GetObject()91 		public TExtension GetObject<TExtension> ()
92 		{
93 			return GetObject<TExtension> (new DataContractSerializer (typeof (TExtension)));
94 		}
95 
GetObject(XmlObjectSerializer serializer)96 		public TExtension GetObject<TExtension> (XmlObjectSerializer serializer)
97 		{
98 			if (serializer == null)
99 				throw new ArgumentNullException ("serializer");
100 			return (TExtension) serializer.ReadObject (GetReader (), false);
101 		}
102 
GetObject(XmlSerializer serializer)103 		public TExtension GetObject<TExtension> (XmlSerializer serializer)
104 		{
105 			if (serializer == null)
106 				throw new ArgumentNullException ("serializer");
107 			return (TExtension) serializer.Deserialize (GetReader ());
108 		}
109 
GetReader()110 		public XmlReader GetReader ()
111 		{
112 			var r = handler.GetReader ();
113 			r.MoveToContent ();
114 			return r;
115 		}
116 
WriteTo(XmlWriter writer)117 		public void WriteTo (XmlWriter writer)
118 		{
119 			if (writer == null)
120 				throw new ArgumentNullException ("writer");
121 
122 			handler.WriteTo (writer);
123 		}
124 
125 		abstract class ReadWriteHandler
126 		{
127 			public string Name { get; protected set; }
128 
129 			public string Namespace { get; protected set; }
130 
GetReader()131 			public virtual XmlReader GetReader ()
132 			{
133 				StringWriter sw = new StringWriter ();
134 				using (XmlWriter w = XmlWriter.Create (sw))
135 					WriteTo (w);
136 				return XmlReader.Create (new StringReader (sw.ToString ()));
137 			}
138 
WriteTo(XmlWriter writer)139 			public abstract void WriteTo (XmlWriter writer);
140 		}
141 
142 		class DataContractReadWriteHandler : ReadWriteHandler
143 		{
144 			object extension;
145 			XmlObjectSerializer serializer;
146 
DataContractReadWriteHandler(string name, string ns, object extension, XmlObjectSerializer serializer)147 			public DataContractReadWriteHandler (string name, string ns, object extension, XmlObjectSerializer serializer)
148 			{
149 				if (serializer == null)
150 					serializer = new DataContractSerializer (extension.GetType ());
151 				// FIXME: this is a nasty workaround that mcs somehow fails to resolve InternalVisibleTo(System.ServiceModel) in System.Runtime.Serialization.dll and thus rejects the use of KnownTypeCollection unlike NET_2_0 case (where System.ServiceModel.Web.dll is referenced).
152 				XmlQualifiedName qname = null;
153 				if (name == null || ns == null) {
154 					var ms = new MemoryStream ();
155 					using (var xw = XmlWriter.Create (ms))
156 						serializer.WriteStartObject (xw, extension);
157 					ms.Position = 0;
158 					var xr = XmlReader.Create (ms);
159 					xr.MoveToContent ();
160 					qname = new XmlQualifiedName (xr.LocalName, xr.NamespaceURI);
161 				}
162 				this.Name = name ?? qname.Name;
163 				this.Namespace = ns ?? qname.Namespace;
164 				this.extension = extension;
165 				this.serializer = serializer;
166 			}
167 
WriteTo(XmlWriter writer)168 			public override void WriteTo (XmlWriter writer)
169 			{
170 				if (Name != null) {
171 					writer.WriteStartElement (Name, Namespace);
172 					serializer.WriteObjectContent (writer, extension);
173 					writer.WriteFullEndElement ();
174 				}
175 				else
176 					serializer.WriteObject (writer, extension);
177 			}
178 		}
179 
180 		class XmlSerializationReadWriteHandler : ReadWriteHandler
181 		{
182 			object extension;
183 			XmlSerializer serializer;
184 
XmlSerializationReadWriteHandler(object extension, XmlSerializer serializer)185 			public XmlSerializationReadWriteHandler (object extension, XmlSerializer serializer)
186 			{
187 				this.extension = extension;
188 				this.serializer = serializer;
189 
190 				if (serializer == null)
191 					serializer = new XmlSerializer (extension.GetType ());
192 			}
193 
WriteTo(XmlWriter writer)194 			public override void WriteTo (XmlWriter writer)
195 			{
196 				serializer.Serialize (writer, extension);
197 			}
198 		}
199 
200 		class XmlReaderReadWriteHandler : ReadWriteHandler
201 		{
202 			string xml;
203 
XmlReaderReadWriteHandler(XmlReader reader)204 			public XmlReaderReadWriteHandler (XmlReader reader)
205 			{
206 				reader.MoveToContent ();
207 				Name = reader.LocalName;
208 				Namespace = reader.NamespaceURI;
209 				xml = reader.ReadOuterXml ();
210 			}
211 
GetReader()212 			public override XmlReader GetReader ()
213 			{
214 				var r = XmlReader.Create (new StringReader (xml));
215 				r.MoveToContent ();
216 				return r;
217 			}
218 
WriteTo(XmlWriter writer)219 			public override void WriteTo (XmlWriter writer)
220 			{
221 				writer.WriteNode (GetReader (), false);
222 			}
223 		}
224 	}
225 }
226