2009-05-28 Atsushi Enomoto <atsushi@ximian.com>
[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 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                         writer.WriteStartElement ("z", "anyType", Constants.MSSerialization);
141                         writer.WriteAttributeString ("i", "nil", "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                                 OnWriteBodyContents (writer);
163                         else if (Version.Envelope == EnvelopeVersion.None)
164                                 WriteXsiNil (writer);
165                 }
166
167                 public void WriteMessage (XmlDictionaryWriter writer)
168                 {
169                         if (State != MessageState.Created)
170                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
171                         State = MessageState.Written;
172
173                         OnWriteMessage (writer);
174                 }
175
176                 public void WriteMessage (XmlWriter writer)
177                 {
178                         WriteMessage (XmlDictionaryWriter.CreateDictionaryWriter (writer));
179                 }
180
181                 public void WriteStartBody (XmlDictionaryWriter writer)
182                 {
183                         if (State != MessageState.Created && State != MessageState.Written)
184                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
185                         State = MessageState.Written;
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 && State != MessageState.Written)
199                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
200                         State = MessageState.Written;
201
202                         OnWriteStartEnvelope (writer);
203                 }
204
205                 [MonoTODO]
206                 protected virtual void OnBodyToString (
207                         XmlDictionaryWriter writer)
208                 {
209                         throw new NotImplementedException ();
210                 }
211
212                 protected virtual void OnClose ()
213                 {
214                 }
215
216                 protected virtual MessageBuffer OnCreateBufferedCopy (
217                         int maxBufferSize)
218                 {
219                         var s = new XmlWriterSettings ();
220                         s.OmitXmlDeclaration = true;
221                         s.ConformanceLevel = ConformanceLevel.Auto;
222                         StringWriter sw = new StringWriter ();
223                         using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, s)))
224                                 WriteBodyContents (w);
225                         var headers = new MessageHeaders (Headers);
226                         var props = new MessageProperties (Properties);
227                         return new DefaultMessageBuffer (maxBufferSize, headers, props, new XmlReaderBodyWriter (sw.ToString ()), false);
228                 }
229
230                 protected virtual string OnGetBodyAttribute (
231                         string localName, string ns)
232                 {
233                         // other than XmlReaderMessage it cannot return anything
234                         return null;
235                 }
236
237                 protected virtual XmlDictionaryReader OnGetReaderAtBodyContents ()
238                 {
239                         var ws = new XmlWriterSettings ();
240                         ws.ConformanceLevel = ConformanceLevel.Auto;
241                         StringWriter sw = new StringWriter ();
242                         using (XmlDictionaryWriter body = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, ws))) {
243                                 WriteBodyContents (body);
244                         }
245
246                         var rs = new XmlReaderSettings ();
247                         rs.ConformanceLevel = ConformanceLevel.Auto;
248                         return XmlDictionaryReader.CreateDictionaryReader (XmlReader.Create (new StringReader (sw.ToString ()), rs));
249                 }
250
251                 protected abstract void OnWriteBodyContents (
252                         XmlDictionaryWriter writer);
253
254                 protected virtual void OnWriteMessage (
255                         XmlDictionaryWriter writer)
256                 {
257                         if (Version.Envelope != EnvelopeVersion.None) {
258                                 WriteStartEnvelope (writer);
259                                 if (Headers.Count > 0) {
260                                         OnWriteStartHeaders (writer);
261                                         for (int i = 0, count = Headers.Count; i < count; i++)
262                                                 Headers.WriteHeader (i, writer);
263                                         writer.WriteEndElement ();
264                                 }
265                         }
266                         WriteBody (writer);
267                         if (Version.Envelope != EnvelopeVersion.None)
268                                 writer.WriteEndElement ();
269                 }
270
271                 protected virtual void OnWriteStartBody (
272                         XmlDictionaryWriter writer)
273                 {
274                         writer.WriteStartElement ("s", "Body", Version.Envelope.Namespace);
275                         if (BodyId != null)
276                                 writer.WriteAttributeString ("u", "Id", Constants.WsuNamespace, BodyId);
277                 }
278
279                 protected virtual void OnWriteStartEnvelope (
280                         XmlDictionaryWriter writer)
281                 {
282                         writer.WriteStartElement ("s", "Envelope", Version.Envelope.Namespace);
283                         if (Headers.Action != null && Version.Addressing.Namespace != MessageVersion.None.Addressing.Namespace)
284                                 writer.WriteXmlnsAttribute ("a", Version.Addressing.Namespace);
285                         foreach (MessageHeaderInfo h in Headers)
286                                 if (h.Id != null) {
287                                         writer.WriteXmlnsAttribute ("u", Constants.WsuNamespace);
288                                         break;
289                                 }
290                 }
291
292                 protected virtual void OnWriteStartHeaders (
293                         XmlDictionaryWriter writer)
294                 {
295                         writer.WriteStartElement ("s", "Header", Version.Envelope.Namespace);
296                 }
297
298                 #region factory methods
299
300                 //  1) fault -> 4
301                 //  2) action -> 5
302                 //  3) fault, action -> 10
303                 //  4) version, fault -> 10
304                 //  5) version, action -> EmptyMessage
305                 //  6) action, body -> 12
306                 //  7) action, xmlReader -> 8
307                 //  8) action, reader -> 16
308                 // 10) version, fault, action -> 20
309                 // 11) version, action, body -> 14
310                 // 12) action, body, formatter -> 14
311                 // 13) version, action, body -> 14
312                 // 14) version, action, body, formatter -> 20
313                 // 15) version, action, xmlReader -> 16
314                 // 16) version, action, reader -> 20
315                 // 17) xmlReader, maxSizeOfHeaders, version -> 18
316                 // 18) reader, maxSizeOfHeaders, version -> ForwardingMessage
317                 // 19) action, bodyWriter -> 20
318                 // 20) version, action, bodyWriter -> SimpleMessage
319
320                 public static Message CreateMessage (MessageVersion version,
321                         FaultCode code, string reason, string action)
322                 {
323                         MessageFault fault = MessageFault.CreateFault (code, reason);
324                         return CreateMessage (version, fault, action);
325                 }
326
327                 public static Message CreateMessage (MessageVersion version,
328                         FaultCode code, string reason, object detail,
329                         string action)
330                 {
331                         MessageFault fault = MessageFault.CreateFault (
332                                 code, new FaultReason (reason), detail);
333                         return CreateMessage (version, fault, action);
334                 }
335
336                 public static Message CreateMessage (MessageVersion version,
337                         MessageFault fault, string action)
338                 {
339                         return new SimpleMessage (version, action,
340                                 new MessageFaultBodyWriter (fault, version), true);
341                 }
342
343                 public static Message CreateMessage (MessageVersion version,
344                         string action, object body)
345                 {
346                         return body == null ?
347                                 CreateMessage (version, action) :
348                                 CreateMessage (version, action, body, new DataContractSerializer (body.GetType ()));
349                 }
350
351                 public static Message CreateMessage (MessageVersion version,
352                         string action, object body, XmlObjectSerializer xmlFormatter)
353                 {
354                         return body == null ?
355                                 CreateMessage (version, action) :
356                                 CreateMessage (
357                                         version, action,
358                                         new XmlObjectSerializerBodyWriter (body, xmlFormatter));
359                 }
360
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                 public static Message CreateMessage (MessageVersion version,
369                         string action, XmlDictionaryReader body)
370                 {
371                         return CreateMessage (version, action,
372                                 new XmlReaderBodyWriter (body));
373                 }
374
375                 public static Message CreateMessage (XmlReader envelopeReader,
376                         int maxSizeOfHeaders, MessageVersion version)
377                 {
378                         return CreateMessage (
379                                 XmlDictionaryReader.CreateDictionaryReader (envelopeReader),
380                                 maxSizeOfHeaders,
381                                 version);
382                 }
383
384                 // Core implementations of CreateMessage.
385
386                 public static Message CreateMessage (MessageVersion version,
387                         string action, BodyWriter body)
388                 {
389                         if (version == null)
390                                 throw new ArgumentNullException ("version");
391                         if (body == null)
392                                 throw new ArgumentNullException ("body");
393                         return new SimpleMessage (version, action, body, false);
394                 }
395
396                 public static Message CreateMessage (MessageVersion version,
397                         string action)
398                 {
399                         if (version == null)
400                                 throw new ArgumentNullException ("version");
401                         return new EmptyMessage (version, action);
402                 }
403
404                 public static Message CreateMessage (
405                         XmlDictionaryReader envelopeReader,
406                         int maxSizeOfHeaders,
407                         MessageVersion version)
408                 {
409                         if (envelopeReader == null)
410                                 throw new ArgumentNullException ("envelopeReader");
411                         if (version == null)
412                                 throw new ArgumentNullException ("version");
413                         return new XmlReaderMessage (version,
414                                 envelopeReader, maxSizeOfHeaders);
415                 }
416
417                 #endregion
418         }
419 }