2009-12-04 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                         State = MessageState.Written;
166                 }
167
168                 public void WriteMessage (XmlDictionaryWriter writer)
169                 {
170                         if (State != MessageState.Created)
171                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
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)
184                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
185
186                         OnWriteStartBody (writer);
187                 }
188
189                 public void WriteStartBody (XmlWriter writer)
190                 {
191                         WriteStartBody (
192                                 XmlDictionaryWriter.CreateDictionaryWriter (writer));
193                 }
194
195                 public void WriteStartEnvelope (XmlDictionaryWriter writer)
196                 {
197                         if (State != MessageState.Created)
198                                 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
199
200                         OnWriteStartEnvelope (writer);
201                 }
202
203                 [MonoTODO]
204                 protected virtual void OnBodyToString (
205                         XmlDictionaryWriter writer)
206                 {
207                         throw new NotImplementedException ();
208                 }
209
210                 protected virtual void OnClose ()
211                 {
212                 }
213
214                 [MonoTODO ("use maxBufferSize")]
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 ()), 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                         writer.WriteStartElement ("s", "Body", Version.Envelope.Namespace);
274                         if (BodyId != null)
275                                 writer.WriteAttributeString ("u", "Id", Constants.WsuNamespace, BodyId);
276                 }
277
278                 protected virtual void OnWriteStartEnvelope (
279                         XmlDictionaryWriter writer)
280                 {
281                         writer.WriteStartElement ("s", "Envelope", Version.Envelope.Namespace);
282                         if (Headers.Action != null && Version.Addressing.Namespace != MessageVersion.None.Addressing.Namespace)
283                                 writer.WriteXmlnsAttribute ("a", Version.Addressing.Namespace);
284                         foreach (MessageHeaderInfo h in Headers)
285                                 if (h.Id != null) {
286                                         writer.WriteXmlnsAttribute ("u", Constants.WsuNamespace);
287                                         break;
288                                 }
289                 }
290
291                 protected virtual void OnWriteStartHeaders (
292                         XmlDictionaryWriter writer)
293                 {
294                         writer.WriteStartElement ("s", "Header", Version.Envelope.Namespace);
295                 }
296
297                 #region factory methods
298
299                 //  1) fault -> 4
300                 //  2) action -> 5
301                 //  3) fault, action -> 10
302                 //  4) version, fault -> 10
303                 //  5) version, action -> EmptyMessage
304                 //  6) action, body -> 12
305                 //  7) action, xmlReader -> 8
306                 //  8) action, reader -> 16
307                 // 10) version, fault, action -> 20
308                 // 11) version, action, body -> 14
309                 // 12) action, body, formatter -> 14
310                 // 13) version, action, body -> 14
311                 // 14) version, action, body, formatter -> 20
312                 // 15) version, action, xmlReader -> 16
313                 // 16) version, action, reader -> 20
314                 // 17) xmlReader, maxSizeOfHeaders, version -> 18
315                 // 18) reader, maxSizeOfHeaders, version -> ForwardingMessage
316                 // 19) action, bodyWriter -> 20
317                 // 20) version, action, bodyWriter -> SimpleMessage
318
319                 public static Message CreateMessage (MessageVersion version,
320                         FaultCode code, string reason, string action)
321                 {
322                         MessageFault fault = MessageFault.CreateFault (code, reason);
323                         return CreateMessage (version, fault, action);
324                 }
325
326                 public static Message CreateMessage (MessageVersion version,
327                         FaultCode code, string reason, object detail,
328                         string action)
329                 {
330                         MessageFault fault = MessageFault.CreateFault (
331                                 code, new FaultReason (reason), detail);
332                         return CreateMessage (version, fault, action);
333                 }
334
335                 public static Message CreateMessage (MessageVersion version,
336                         MessageFault fault, string action)
337                 {
338                         return new SimpleMessage (version, action,
339                                 new MessageFaultBodyWriter (fault, version), true);
340                 }
341
342                 public static Message CreateMessage (MessageVersion version,
343                         string action, object body)
344                 {
345                         return body == null ?
346                                 CreateMessage (version, action) :
347                                 CreateMessage (version, action, body, new DataContractSerializer (body.GetType ()));
348                 }
349
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                 public static Message CreateMessage (MessageVersion version,
361                         string action, XmlReader body)
362                 {
363                         return CreateMessage (version, action,
364                                 XmlDictionaryReader.CreateDictionaryReader (body));
365                 }
366
367                 public static Message CreateMessage (MessageVersion version,
368                         string action, XmlDictionaryReader body)
369                 {
370                         return CreateMessage (version, action,
371                                 new XmlReaderBodyWriter (body));
372                 }
373
374                 public static Message CreateMessage (XmlReader envelopeReader,
375                         int maxSizeOfHeaders, MessageVersion version)
376                 {
377                         return CreateMessage (
378                                 XmlDictionaryReader.CreateDictionaryReader (envelopeReader),
379                                 maxSizeOfHeaders,
380                                 version);
381                 }
382
383                 // Core implementations of CreateMessage.
384
385                 public static Message CreateMessage (MessageVersion version,
386                         string action, BodyWriter body)
387                 {
388                         if (version == null)
389                                 throw new ArgumentNullException ("version");
390                         if (body == null)
391                                 throw new ArgumentNullException ("body");
392                         return new SimpleMessage (version, action, body, false);
393                 }
394
395                 public static Message CreateMessage (MessageVersion version,
396                         string action)
397                 {
398                         if (version == null)
399                                 throw new ArgumentNullException ("version");
400                         return new EmptyMessage (version, action);
401                 }
402
403                 public static Message CreateMessage (
404                         XmlDictionaryReader envelopeReader,
405                         int maxSizeOfHeaders,
406                         MessageVersion version)
407                 {
408                         if (envelopeReader == null)
409                                 throw new ArgumentNullException ("envelopeReader");
410                         if (version == null)
411                                 throw new ArgumentNullException ("version");
412                         return new XmlReaderMessage (version,
413                                 envelopeReader, maxSizeOfHeaders);
414                 }
415
416                 #endregion
417         }
418 }