2010-02-23 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Description / MetadataExchangeClient.cs
1 //
2 // MetadataExchangeClient.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //      Ankit Jain <jankit@novell.com>
7 //
8 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
35 using System.Web.Services.Description;
36 using System.Web.Services.Discovery;
37 using System.Web.Services.Protocols;
38 using System.Xml;
39 using System.Xml.Serialization;
40 using System.IO;
41 using System.Net;
42 using System.Text;
43
44 using SMBinding = System.ServiceModel.Channels.Binding;
45 using SMMessage = System.ServiceModel.Channels.Message;
46
47 namespace System.ServiceModel.Description
48 {
49         public class MetadataExchangeClient
50         {
51                 string scheme;
52
53                 EndpointAddress address;
54                 SMBinding binding;
55                 MetadataExchangeClientMode mode = MetadataExchangeClientMode.MetadataExchange;
56
57                 // constructors
58
59                 [MonoTODO ("use empty configuration")]
60                 public MetadataExchangeClient ()
61                 {
62                 }
63
64                 public MetadataExchangeClient (SMBinding mexBinding)
65                 {
66                         binding = mexBinding;
67                 }
68
69                 public MetadataExchangeClient (EndpointAddress address)
70                 {
71                         this.address = address;
72                 }
73
74                 public MetadataExchangeClient (string endpointConfigurationName)
75                 {
76                         throw new NotImplementedException ();
77                 }
78
79                 [MonoTODO ("MetadataExchangeClientMode is not considered")]
80                 public MetadataExchangeClient (Uri address, MetadataExchangeClientMode mode)
81                 {
82                         this.address = new EndpointAddress (address.AbsoluteUri);
83                         this.mode = mode;
84                 }
85
86                 [MonoTODO]
87                 public ICredentials HttpCredentials { get; set; }
88                 [MonoTODO]
89                 public int MaximumResolvedReferences { get; set; }
90
91                 public TimeSpan OperationTimeout { get; set; }
92
93                 [MonoTODO]
94                 public bool ResolveMetadataReferences { get; set; }
95
96                 public ClientCredentials SoapCredentials { get; set; }
97
98                 [MonoTODO ("use dialect and identifier (but how?)")]
99                 protected internal virtual ChannelFactory<IMetadataExchange> GetChannelFactory (EndpointAddress metadataAddress, string dialect, string identifier)
100                 {
101                         var se = new ServiceEndpoint (ContractDescription.GetContract (typeof (IMetadataExchange)), CreateBinding (metadataAddress), metadataAddress);
102                         if (SoapCredentials != null) {
103                                 se.Behaviors.RemoveAll<ClientCredentials> ();
104                                 se.Behaviors.Add (SoapCredentials);
105                         }
106                         return new ChannelFactory<IMetadataExchange> (se);
107                 }
108
109                 [MonoTODO]
110                 protected internal virtual HttpWebRequest GetWebRequest (Uri location, string dialect, string identifier)
111                 {
112                         throw new NotImplementedException ();
113                 }
114
115                 SMBinding CreateBinding (EndpointAddress address)
116                 {
117                         return address.Uri.Scheme == Uri.UriSchemeHttps ?
118                                 MetadataExchangeBindings.CreateMexHttpsBinding () :
119                                 MetadataExchangeBindings.CreateMexHttpBinding ();
120                 }
121
122                 // sync methods
123
124                 public MetadataSet GetMetadata ()
125                 {
126                         return GetMetadata (address);
127                 }
128
129                 public MetadataSet GetMetadata (EndpointAddress address)
130                 {
131                         //FIXME: default mode?
132                         return GetMetadataInternal (address, mode);
133                 }
134
135                 public MetadataSet GetMetadata (Uri address, MetadataExchangeClientMode mode)
136                 {
137                         return GetMetadataInternal (new EndpointAddress (address.AbsoluteUri), mode);
138                 }
139
140                 internal MetadataSet GetMetadataInternal (EndpointAddress address, MetadataExchangeClientMode mode)
141                 {
142                         // FIXME: give dialect and identifier
143                         var cf = GetChannelFactory (address, null, null);
144                         cf.Open ();
145                         var proxy = cf.CreateChannel ();
146                         var asClientChannel = proxy as IClientChannel;
147                         if (asClientChannel == null)
148                                 throw new InvalidOperationException ("The channel factory must return an IClientChannel implementation");
149                         asClientChannel.OperationTimeout = OperationTimeout;
150                         asClientChannel.Open ();
151
152                         SMMessage msg = SMMessage.CreateMessage ( 
153                                         MessageVersion.Soap12WSAddressing10, 
154                                         "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get");
155
156                         msg.Headers.ReplyTo = new EndpointAddress (
157                                         "http://www.w3.org/2005/08/addressing/anonymous");
158                         //msg.Headers.From = new EndpointAddress ("http://localhost");
159                         msg.Headers.To = address.Uri;
160                         msg.Headers.MessageId = new UniqueId ();
161
162                         SMMessage ret;
163                         try {
164                                 ret = proxy.Get (msg);
165                         } catch (Exception e) {
166                                 throw new InvalidOperationException (
167                                                 "Metadata contains a reference that cannot be resolved : " + address.Uri.AbsoluteUri, e);
168                         }
169
170                         return MetadataSet.ReadFrom (ret.GetReaderAtBodyContents ());
171                 }
172
173                 // async methods
174
175                 Func<Func<MetadataSet>,MetadataSet> getter;
176
177                 void PrepareGetter ()
178                 {
179                         if (getter == null)
180                                 getter = new Func<Func<MetadataSet>,MetadataSet> (GetMetadata);
181                 }
182
183                 public MetadataSet EndGetMetadata (IAsyncResult result)
184                 {
185                         return getter.EndInvoke (result);
186                 }
187
188                 MetadataSet GetMetadata (Func<MetadataSet> func)
189                 {
190                         return func ();
191                 }
192
193                 public IAsyncResult BeginGetMetadata (AsyncCallback callback, object asyncState)
194                 {
195                         PrepareGetter ();
196                         return getter.BeginInvoke (() => GetMetadata (), callback, asyncState);
197                 }
198
199                 public IAsyncResult BeginGetMetadata (EndpointAddress address, AsyncCallback callback, object asyncState)
200                 {
201                         PrepareGetter ();
202                         return getter.BeginInvoke (() => GetMetadata (address), callback, asyncState);
203                 }
204
205                 public IAsyncResult BeginGetMetadata (Uri address, MetadataExchangeClientMode mode, AsyncCallback callback, object asyncState)
206                 {
207                         PrepareGetter ();
208                         return getter.BeginInvoke (() => GetMetadata (address, mode), callback, asyncState);
209                 }
210         }
211
212         interface IMetadataExchangeClient : IMetadataExchange, IClientChannel
213         {
214         }
215 }