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