[WCF]: Implement missing WsdlImporter pieces.
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / Message.cs
1 //
2 // Message.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005-2006,2010 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.IO;
31 using System.Runtime.Serialization;
32 using System.Xml;
33 using System.Xml.Schema;
34 using Mono.Xml.XPath;
35
36 namespace System.ServiceModel.Channels
37 {
38         public abstract class Message : IDisposable
39         {
40                 bool disposed;
41                 string body_id;
42                 Message copied_message;
43                 string string_cache;
44
45                 protected Message () {
46                         State = MessageState.Created;
47                 }
48
49                 public abstract MessageHeaders Headers { get; }
50
51                 public virtual bool IsEmpty {
52                         get { return false; }
53                 }
54
55                 public virtual bool IsFault {
56                         get { return false; }
57                 }
58
59                 public abstract MessageProperties Properties { get; }
60
61                 public MessageState State { get; private set; }
62
63                 public abstract MessageVersion Version { get; }
64
65                 protected bool IsDisposed {
66                         get { return disposed; }
67                 }
68
69                 public void Close ()
70                 {
71                         if (!disposed)
72                                 OnClose ();
73                         State = MessageState.Closed;
74                         disposed = true;
75                 }
76
77                 public MessageBuffer CreateBufferedCopy (int maxBufferSize)
78                 {
79                         if (State != MessageState.Created)
80                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
81
82                         if (copied_message != null)
83                                 return copied_message.CreateBufferedCopy (maxBufferSize);
84
85                         try {
86                                 return OnCreateBufferedCopy (maxBufferSize);
87                         } finally {
88                                 State = MessageState.Copied;
89                         }
90                 }
91
92                 void IDisposable.Dispose ()
93                 {
94                         Close ();
95                 }
96
97                 public T GetBody<T> ()
98                 {
99                         return GetBody<T> (new DataContractSerializer (typeof (T)));
100                 }
101
102                 public T GetBody<T> (XmlObjectSerializer xmlFormatter)
103                 {
104                         return (T) xmlFormatter.ReadObject (GetReaderAtBodyContents ());
105                 }
106
107                 public string GetBodyAttribute (string localName, string ns)
108                 {
109                         return OnGetBodyAttribute (localName, ns);
110                 }
111
112                 public XmlDictionaryReader GetReaderAtBodyContents ()
113                 {
114                         if (copied_message != null)
115                                 return copied_message.GetReaderAtBodyContents ();
116
117                         return OnGetReaderAtBodyContents ();
118                 }
119
120                 public override string ToString ()
121                 {
122                         if (string_cache != null)
123                                 return string_cache;
124
125                         StringWriter sw = new StringWriter ();
126                         XmlWriterSettings settings = new XmlWriterSettings ();
127                         settings.Indent = true;
128                         settings.OmitXmlDeclaration = true;
129
130                         using (XmlWriter w = XmlWriter.Create (sw, settings)) {
131                                 OnBodyToString (XmlDictionaryWriter.CreateDictionaryWriter (w));
132                         }
133                         string_cache = sw.ToString ();
134                         return string_cache;
135                 }
136
137                 void WriteXsiNil (XmlDictionaryWriter writer)
138                 {
139                         var dic = Constants.SoapDictionary;
140                         writer.WriteStartElement ("z", dic.Add ("anyType"), dic.Add (Constants.MSSerialization));
141                         writer.WriteAttributeString ("i", dic.Add ("nil"), dic.Add ("http://www.w3.org/2001/XMLSchema-instance"), "true");
142                         writer.WriteEndElement ();
143                 }
144
145                 public void WriteBody (XmlDictionaryWriter writer)
146                 {
147                         if (Version.Envelope != EnvelopeVersion.None)
148                                 WriteStartBody (writer);
149                         WriteBodyContents (writer);
150                         if (Version.Envelope != EnvelopeVersion.None)
151                                 writer.WriteEndElement ();
152                 }
153
154                 public void WriteBody (XmlWriter writer)
155                 {
156                         WriteBody (XmlDictionaryWriter.CreateDictionaryWriter (writer));
157                 }
158
159                 public void WriteBodyContents (XmlDictionaryWriter writer)
160                 {
161                         if (!IsEmpty) {
162                                 if (copied_message != null)
163                                         copied_message.WriteBodyContents (writer);
164                                 OnWriteBodyContents (writer);
165                         }
166                         else if (Version.Envelope == EnvelopeVersion.None)
167                                 WriteXsiNil (writer);
168                         State = MessageState.Written;
169                 }
170
171                 public void WriteMessage (XmlDictionaryWriter writer)
172                 {
173                         if (State != MessageState.Created)
174                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
175
176                         OnWriteMessage (writer);
177                 }
178
179                 public void WriteMessage (XmlWriter writer)
180                 {
181                         WriteMessage (XmlDictionaryWriter.CreateDictionaryWriter (writer));
182                 }
183
184                 public void WriteStartBody (XmlDictionaryWriter writer)
185                 {
186                         if (State != MessageState.Created)
187                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
188
189                         OnWriteStartBody (writer);
190                 }
191
192                 public void WriteStartBody (XmlWriter writer)
193                 {
194                         WriteStartBody (
195                                 XmlDictionaryWriter.CreateDictionaryWriter (writer));
196                 }
197
198                 public void WriteStartEnvelope (XmlDictionaryWriter writer)
199                 {
200                         if (State != MessageState.Created)
201                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
202
203                         OnWriteStartEnvelope (writer);
204                 }
205
206                 protected virtual void OnBodyToString (
207                         XmlDictionaryWriter writer)
208                 {
209                         MessageState tempState = State;
210                         try {
211                                 var mb = CreateBufferedCopy (int.MaxValue);
212                                 copied_message = mb.CreateMessage ();
213                                 var msg = mb.CreateMessage ();
214                                 msg.WriteMessage (writer);
215                         }
216                         finally {
217                                 State = tempState;
218                         }
219                 }
220
221                 protected virtual void OnClose ()
222                 {
223                 }
224
225                 protected virtual MessageBuffer OnCreateBufferedCopy (
226                         int maxBufferSize)
227                 {
228                         var s = new XmlWriterSettings ();
229                         s.OmitXmlDeclaration = true;
230                         s.ConformanceLevel = ConformanceLevel.Auto;
231                         StringWriter sw = new StringWriter ();
232                         using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, s)))
233                                 WriteBodyContents (w);
234                         var headers = new MessageHeaders (Headers);
235                         var props = new MessageProperties (Properties);
236                         return new DefaultMessageBuffer (maxBufferSize, headers, props, new XmlReaderBodyWriter (sw.ToString (), maxBufferSize, null), false, new AttributeCollection ());
237                 }
238
239                 protected virtual string OnGetBodyAttribute (
240                         string localName, string ns)
241                 {
242                         return null;
243                 }
244
245                 protected virtual XmlDictionaryReader OnGetReaderAtBodyContents ()
246                 {
247                         var ws = new XmlWriterSettings ();
248                         ws.ConformanceLevel = ConformanceLevel.Auto;
249                         StringWriter sw = new StringWriter ();
250                         using (XmlDictionaryWriter body = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, ws))) {
251                                 WriteBodyContents (body);
252                         }
253
254                         var rs = new XmlReaderSettings ();
255                         rs.ConformanceLevel = ConformanceLevel.Auto;
256                         return XmlDictionaryReader.CreateDictionaryReader (XmlReader.Create (new StringReader (sw.ToString ()), rs));
257                 }
258
259                 protected abstract void OnWriteBodyContents (
260                         XmlDictionaryWriter writer);
261
262                 protected virtual void OnWriteMessage (
263                         XmlDictionaryWriter writer)
264                 {
265                         if (Version.Envelope != EnvelopeVersion.None) {
266                                 WriteStartEnvelope (writer);
267                                 if (Headers.Count > 0) {
268                                         OnWriteStartHeaders (writer);
269                                         for (int i = 0, count = Headers.Count; i < count; i++)
270                                                 Headers.WriteHeader (i, writer);
271                                         writer.WriteEndElement ();
272                                 }
273                         }
274                         WriteBody (writer);
275                         if (Version.Envelope != EnvelopeVersion.None)
276                                 writer.WriteEndElement ();
277                 }
278
279                 protected virtual void OnWriteStartBody (
280                         XmlDictionaryWriter writer)
281                 {
282                         var dic = Constants.SoapDictionary;
283                         writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
284                 }
285
286                 protected virtual void OnWriteStartEnvelope (
287                         XmlDictionaryWriter writer)
288                 {
289                         var dic = Constants.SoapDictionary;
290                         writer.WriteStartElement ("s", dic.Add ("Envelope"), dic.Add (Version.Envelope.Namespace));
291                         if (Headers.Action != null && Version.Addressing.Namespace != MessageVersion.None.Addressing.Namespace)
292                                 writer.WriteXmlnsAttribute ("a", dic.Add (Version.Addressing.Namespace));
293                         foreach (MessageHeaderInfo h in Headers)
294                                 if (h.Id != null && writer.LookupPrefix (Constants.WsuNamespace) != "u") {
295                                         writer.WriteXmlnsAttribute ("u", dic.Add (Constants.WsuNamespace));
296                                         break;
297                                 }
298                 }
299
300                 protected virtual void OnWriteStartHeaders (
301                         XmlDictionaryWriter writer)
302                 {
303                         var dic = Constants.SoapDictionary;
304                         writer.WriteStartElement ("s", dic.Add ("Header"), dic.Add (Version.Envelope.Namespace));
305                 }
306
307                 #region factory methods
308
309                 // 1) version, code, reason, action -> 3
310                 // 2) version, code, reason, detail, action -> 3
311                 // 3) version, fault, action -> SimpleMessage
312                 // 4) version, action, body -> 10 or 5
313                 // 5) version, action, body, formatter -> 10 or 9
314                 // 6) version, action, xmlReader -> 7
315                 // 7) version, action, reader -> 9
316                 // 8) xmlReader, maxSizeOfHeaders, version -> 11
317                 // 9) version, action, body -> SimpleMessage
318                 // 10) version, action -> EmptyMessage
319                 // 11) reader, maxSizeOfHeaders, version -> XmlReaderMessage
320
321                 // 1)
322                 public static Message CreateMessage (MessageVersion version,
323                         FaultCode code, string reason, string action)
324                 {
325                         MessageFault fault = MessageFault.CreateFault (code, reason);
326                         return CreateMessage (version, fault, action);
327                 }
328
329                 // 2)
330                 public static Message CreateMessage (MessageVersion version,
331                         FaultCode code, string reason, object detail,
332                         string action)
333                 {
334                         MessageFault fault = MessageFault.CreateFault (
335                                 code, new FaultReason (reason), detail);
336                         return CreateMessage (version, fault, action);
337                 }
338
339                 // 3)
340                 public static Message CreateMessage (MessageVersion version,
341                         MessageFault fault, string action)
342                 {
343                         return new SimpleMessage (version, action,
344                                 new MessageFaultBodyWriter (fault, version), true, empty_attributes);
345                 }
346
347                 // 4)
348                 public static Message CreateMessage (MessageVersion version,
349                         string action, object body)
350                 {
351                         return body == null ?
352                                 CreateMessage (version, action) :
353                                 CreateMessage (version, action, body, new DataContractSerializer (body.GetType ()));
354                 }
355
356                 // 5)
357                 public static Message CreateMessage (MessageVersion version,
358                         string action, object body, XmlObjectSerializer xmlFormatter)
359                 {
360                         return body == null ?
361                                 CreateMessage (version, action) :
362                                 CreateMessage (
363                                         version, action,
364                                         new XmlObjectSerializerBodyWriter (body, xmlFormatter));
365                 }
366
367                 // 6)
368                 public static Message CreateMessage (MessageVersion version,
369                         string action, XmlReader body)
370                 {
371                         return CreateMessage (version, action,
372                                 XmlDictionaryReader.CreateDictionaryReader (body));
373                 }
374
375                 // 7)
376                 public static Message CreateMessage (MessageVersion version,
377                         string action, XmlDictionaryReader body)
378                 {
379                         return CreateMessage (version, action,
380                                 new XmlReaderBodyWriter (body));
381                 }
382
383                 // 8)
384                 public static Message CreateMessage (XmlReader envelopeReader,
385                         int maxSizeOfHeaders, MessageVersion version)
386                 {
387                         return CreateMessage (
388                                 XmlDictionaryReader.CreateDictionaryReader (envelopeReader),
389                                 maxSizeOfHeaders,
390                                 version);
391                 }
392
393                 // Core implementations of CreateMessage.
394
395                 static readonly AttributeCollection empty_attributes = new AttributeCollection ();
396
397                 // 9)
398                 public static Message CreateMessage (MessageVersion version,
399                         string action, BodyWriter body)
400                 {
401                         if (version == null)
402                                 throw new ArgumentNullException ("version");
403                         if (body == null)
404                                 throw new ArgumentNullException ("body");
405                         return new SimpleMessage (version, action, body, false, empty_attributes);
406                 }
407
408                 // 10)
409                 public static Message CreateMessage (MessageVersion version,
410                         string action)
411                 {
412                         if (version == null)
413                                 throw new ArgumentNullException ("version");
414                         return new EmptyMessage (version, action);
415                 }
416
417                 // 11)
418                 public static Message CreateMessage (
419                         XmlDictionaryReader envelopeReader,
420                         int maxSizeOfHeaders,
421                         MessageVersion version)
422                 {
423                         if (envelopeReader == null)
424                                 throw new ArgumentNullException ("envelopeReader");
425                         if (version == null)
426                                 throw new ArgumentNullException ("version");
427                         return new XmlReaderMessage (version,
428                                 envelopeReader, maxSizeOfHeaders);
429                 }
430
431                 #endregion
432         }
433 }