2009-05-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / MessageHeader.cs
1 //
2 // System.ServiceModel.MessageHeader.cs
3 //
4 // Author: Duncan Mak (duncan@novell.com)
5 //         Atsushi Enomoto (atsushi@ximian.com)
6 //
7 // Copyright (C) 2005 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
29 using System;
30 using System.IO;
31 using System.Runtime.Serialization;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.Text;
35 using System.Xml;
36
37 namespace System.ServiceModel.Channels
38 {
39         public abstract class MessageHeader : MessageHeaderInfo
40         {
41                 static readonly XmlWriterSettings writer_settings;
42
43                 static MessageHeader ()
44                 {
45                         writer_settings = new XmlWriterSettings ();
46                         writer_settings.OmitXmlDeclaration = true;
47                         writer_settings.Indent = true;
48                 }
49
50                 protected MessageHeader () {}
51
52                 static string default_actor = String.Empty;
53                 static bool default_is_ref = false;
54                 static bool default_must_understand = false;
55                 static bool default_relay = false;
56                 static Type [] knownTypes = new Type [1] {typeof (EndpointAddress10)};
57
58                 public static MessageHeader CreateHeader (string name, string ns, object value)
59                 {
60                         return CreateHeader (name, ns, value, default_must_understand);
61                 }
62
63                 public static MessageHeader CreateHeader (string name, string ns, object value, bool must_understand)
64                 {
65                         return CreateHeader (name, ns, value, must_understand, default_actor);
66                 }
67
68                 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer formatter)
69                 {
70                         return CreateHeader (name, ns, value, formatter, default_must_understand, 
71                                              default_actor, default_relay);
72                 }
73
74                 public static MessageHeader CreateHeader (string name, string ns, object value, 
75                                                    bool must_understand, string actor)
76                 {
77                         return CreateHeader (name, ns, value, must_understand, actor, default_relay);
78                 }
79
80                 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer formatter, 
81                                                    bool must_understand)
82                 {
83                         return CreateHeader (name, ns, value, formatter, must_understand, default_actor, default_relay);
84                 }
85                 
86                 public static MessageHeader CreateHeader (string name, string ns, object value, 
87                                                    bool must_understand, string actor, bool relay)
88                 {
89                         return CreateHeader (name, ns, value, new DataContractSerializer (value.GetType (), knownTypes),
90                                         must_understand, actor, relay);
91                 }
92
93                 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer formatter,
94                                                    bool must_understand, string actor)
95                 {
96                         return CreateHeader (name, ns, value, formatter, must_understand, actor, default_relay);
97                 }
98                 
99                 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer formatter,
100                                                    bool must_understand, string actor, bool relay)
101                 {
102                         // FIXME: how to get IsReferenceParameter ?
103                         return new DefaultMessageHeader (name, ns, value, formatter, default_is_ref, must_understand, actor, relay);
104                 }
105
106                 public virtual bool IsMessageVersionSupported (MessageVersion version)
107                 {
108                         if (version.Envelope == EnvelopeVersion.Soap12)
109                                 if (Actor == EnvelopeVersion.Soap11.NextDestinationActorValue)
110                                         return false;
111
112                         if (version.Envelope == EnvelopeVersion.Soap11)
113                                 if (Actor == EnvelopeVersion.Soap12.NextDestinationActorValue ||
114                                     Actor == EnvelopeVersion.Soap12UltimateReceiver)
115                                         return false;
116
117                         // by default, it's always supported
118                         return true;
119                 }
120
121                 protected abstract void OnWriteHeaderContents (XmlDictionaryWriter writer, MessageVersion version);
122
123                 protected virtual void OnWriteStartHeader (XmlDictionaryWriter writer, MessageVersion version)
124                 {
125                         writer.WriteStartElement (this.Name, this.Namespace);
126                         WriteHeaderAttributes (writer, version);
127                 }
128
129                 public override string ToString ()
130                 {
131                         StringBuilder sb = new StringBuilder ();
132
133                         XmlWriter w = XmlWriter.Create (sb, writer_settings);
134
135                         WriteHeader (w, MessageVersion.Default);
136                         w.Close ();
137
138                         return sb.ToString ();
139                 }
140
141                 public void WriteHeader (XmlDictionaryWriter writer, MessageVersion version)
142                 {
143                         if (writer == null)
144                                 throw new ArgumentNullException ("writer is null.");
145
146                         if (version == null)
147                                 throw new ArgumentNullException ("version is null.");
148
149                         if (version.Envelope == EnvelopeVersion.None)
150                                 return;
151
152                         WriteStartHeader (writer, version);
153                         WriteHeaderContents (writer, version);
154
155                         writer.WriteEndElement ();
156                 }
157
158                 public void WriteHeader (XmlWriter writer, MessageVersion version)
159                 {
160                         WriteHeader (XmlDictionaryWriter.CreateDictionaryWriter (writer), version);
161                 }
162
163                 protected void WriteHeaderAttributes (XmlDictionaryWriter writer, MessageVersion version)
164                 {
165                         if (Id != null)
166                                 writer.WriteAttributeString ("u", "Id", Constants.WsuNamespace, Id);
167                         if (Actor != String.Empty) {
168                                 if (version.Envelope == EnvelopeVersion.Soap11) 
169                                         writer.WriteAttributeString ("s", "actor", version.Envelope.Namespace, Actor);
170
171                                 if (version.Envelope == EnvelopeVersion.Soap12) 
172                                         writer.WriteAttributeString ("s", "role", version.Envelope.Namespace, Actor);
173                         }
174
175                         // mustUnderstand is the same across SOAP 1.1 and 1.2
176                         if (MustUnderstand == true)
177                                 writer.WriteAttributeString ("s", "mustUnderstand", version.Envelope.Namespace, "1");
178
179                         // relay is only available on SOAP 1.2
180                         if (Relay == true && version.Envelope == EnvelopeVersion.Soap12)
181                                 writer.WriteAttributeString ("s", "relay", version.Envelope.Namespace, "true");
182                 }
183
184                 public void WriteHeaderContents (XmlDictionaryWriter writer, MessageVersion version)
185                 {
186                         this.OnWriteHeaderContents (writer, version);
187                 }
188
189                 public void WriteStartHeader (XmlDictionaryWriter writer, MessageVersion version)
190                 {
191                         this.OnWriteStartHeader (writer, version);
192                 }
193
194                 public override string Actor { get { return default_actor; }}
195
196                 public override bool IsReferenceParameter { get { return default_is_ref; }}
197
198                 public override bool MustUnderstand { get { return default_must_understand; }}
199
200                 public override bool Relay { get { return default_relay; }}
201
202                 internal class RawMessageHeader : MessageHeader
203                 {
204                         string soap_ns;
205                         bool is_ref, must_understand, relay;
206                         string actor;
207                         string body;
208                         string local_name;
209                         string namespace_uri;
210
211                         public RawMessageHeader (XmlReader reader, string soap_ns)
212                         {
213                                 Id = reader.GetAttribute ("Id", Constants.WsuNamespace);
214
215                                 // FIXME: fill is_ref
216                                 string s = reader.GetAttribute ("relay", soap_ns);
217                                 relay = s != null ? XmlConvert.ToBoolean (s) : false;
218                                 s = reader.GetAttribute ("mustUnderstand", soap_ns);
219                                 must_understand = s != null ? XmlConvert.ToBoolean (s) : false;
220                                 actor = reader.GetAttribute ("actor", soap_ns) ?? String.Empty;
221                                 local_name = reader.LocalName;
222                                 namespace_uri = reader.NamespaceURI;
223                                 body = reader.ReadOuterXml ();
224                         }
225
226                         public XmlReader CreateReader ()
227                         {
228                                 var reader = XmlReader.Create (new StringReader (body));
229                                 reader.MoveToContent ();
230                                 return reader;
231                         }
232
233                         protected override void OnWriteHeaderContents (
234                                 XmlDictionaryWriter writer, MessageVersion version)
235                         {
236                                 var r = CreateReader ();
237                                 r.MoveToContent ();
238                                 if (r.IsEmptyElement)
239                                         return; // write nothing
240                                 for (r.Read (); r.NodeType != XmlNodeType.EndElement;)
241                                         writer.WriteNode (r, false);
242                         }
243
244                         public override string Actor { get { return actor; }}
245
246                         public override bool IsReferenceParameter { get { return is_ref; }}
247
248                         public override bool MustUnderstand { get { return must_understand; }}
249
250                         public override string Name { get { return local_name; }}
251
252                         public override string Namespace { get { return namespace_uri; }}
253
254                         public override bool Relay { get { return relay; }}
255                 }
256
257                 internal class DefaultMessageHeader : MessageHeader
258                 {
259                         string actor, name, ns;
260                         object value;
261                         XmlObjectSerializer formatter;
262                         bool is_ref, must_understand, relay;
263                         
264                         internal DefaultMessageHeader (string name, string ns, object value, XmlObjectSerializer formatter, 
265                                                        bool isReferenceParameter,
266                                                        bool mustUnderstand, string actor, bool relay)
267                         {
268                                 this.name = name;
269                                 this.ns = ns;
270                                 this.value = value;
271                                 this.formatter = formatter;
272                                 this.is_ref = isReferenceParameter;
273                                 this.must_understand = mustUnderstand;
274                                 this.actor = actor;
275                                 this.relay = relay;
276                         }
277
278                         protected override void OnWriteHeaderContents (XmlDictionaryWriter writer,
279                                                                        MessageVersion version)
280                         {
281                                 if (value is EndpointAddress)
282                                         ((EndpointAddress) value).WriteTo (version.Addressing, writer, name, ns);
283                                 else
284                                         this.formatter.WriteObjectContent (writer, value);
285                         }
286
287                         public override string Actor { get { return actor; }}
288
289                         public override bool IsReferenceParameter { get { return is_ref; }}
290
291                         public override bool MustUnderstand { get { return must_understand; }}
292
293                         public override string Name { get { return name; }}
294
295                         public override string Namespace { get { return ns; }}
296
297                         public override bool Relay { get { return relay; }}
298                 }
299         }
300 }