Drop this one too
[mono.git] / mcs / class / System.ServiceModel.Routing / System.ServiceModel.Routing / RoutingService.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.Linq;
5 using System.Reflection;
6 using System.ServiceModel;
7 using System.ServiceModel.Channels;
8 using System.ServiceModel.Description;
9 using System.ServiceModel.Dispatcher;
10
11 namespace System.ServiceModel.Routing
12 {
13         [ServiceBehavior (AddressFilterMode = AddressFilterMode.Any, InstanceContextMode = InstanceContextMode.PerSession, UseSynchronizationContext = false, ValidateMustUnderstand = false)]
14         public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter
15         {
16 /*
17                 class SimplexDatagramClient : ClientBase<ISimplexDatagramRouter>, ISimplexDatagramRouter
18                 {
19                         public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
20                         {
21                                 return Channel.BeginProcessMessage (message, callback, state);
22                         }
23
24                         public void EndProcessMessage (IAsyncResult result);
25                         {
26                                 Channel.EndProcessMessage (result);
27                         }
28                 }
29
30                 class SimplexSessionClient : ClientBase<ISimplexSessionRouter>, ISimplexSessionRouter
31                 {
32                         public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
33                         {
34                                 return Channel.BeginProcessMessage (message, callback, state);
35                         }
36
37                         public void EndProcessMessage (IAsyncResult result);
38                         {
39                                 Channel.EndProcessMessage (result);
40                         }
41                 }
42
43                 class DuplexSessionClient : ClientBase<IDuplexSessionRouter>, IDuplexSessionRouter
44                 {
45                         public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
46                         {
47                                 return Channel.BeginProcessMessage (message, callback, state);
48                         }
49
50                         public void EndProcessMessage (IAsyncResult result);
51                         {
52                                 Channel.EndProcessMessage (result);
53                         }
54                 }
55
56                 class RequestReplyClient : ClientBase<IRequestReplyRouter>, IRequestReplyRouter
57                 {
58                         public IAsyncResult BeginProcessRequest (Message message, AsyncCallback callback, object state)
59                         {
60                                 return Channel.BeginProcessRequest (message, callback, state);
61                         }
62
63                         public Message EndProcessRequest (IAsyncResult result);
64                         {
65                                 return Channel.EndProcessRequest (result);
66                         }
67                 }
68 */
69
70                 internal RoutingService ()
71                 {
72                 }
73
74                 internal RoutingConfiguration Configuration { get; set; }
75
76                 Action<Message> process_message_duplex_session_handler;
77                 Action<Message> process_message_simplex_datagram_handler;
78                 Action<Message> process_message_simplex_session_handler;
79                 //Func<Message,Message> process_request_handler;
80
81                 Dictionary<ServiceEndpoint,ChannelFactory> factories = new Dictionary<ServiceEndpoint,ChannelFactory> ();
82                 ChannelFactory<IRequestReplyRouter> request_reply_factory;
83                 IRequestReplyRouter request_reply_channel;
84                 //Dictionary<ServiceEndpoint,IChannel> sessions = new Dictionary<ServiceEndpoint,IChannel> ();
85
86                 IEnumerable<ServiceEndpoint> GetMatchingEndpoints (Message message)
87                 {
88                         IEnumerable<ServiceEndpoint> ret;
89                         if (!Configuration.FilterTable.GetMatchingValue (message, out ret))
90                                 throw new EndpointNotFoundException ();
91                         return ret;
92                 }
93
94                 static readonly MethodInfo create_factory_method = typeof (ChannelFactory).GetMethod ("CreateFactory", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
95
96                 void ProcessMessageDuplexSession (Message message)
97                 {
98                         var sel = GetMatchingEndpoints (message);
99                         foreach (var se in sel) {
100                                 ChannelFactory cf;
101                                 if (!factories.TryGetValue (se, out cf)) {
102                                         cf = new ChannelFactory<IDuplexSessionRouter> (se);
103                                         factories [se] = cf;
104                                 }
105                                 // FIXME: possibly reuse session channels, though I doubt saving session *at the router* makes sense...
106                                 var ch = ((ChannelFactory<IDuplexSessionRouter>) cf).CreateChannel ();
107                                 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
108                         }
109                 }
110
111                 void ProcessMessageSimplexDatagram (Message message)
112                 {
113                         var sel = GetMatchingEndpoints (message);
114                         foreach (var se in sel) {
115                                 ChannelFactory cf;
116                                 if (!factories.TryGetValue (se, out cf)) {
117                                         cf = new ChannelFactory<ISimplexDatagramRouter> (se);
118                                         factories [se] = cf;
119                                 }
120                                 var ch = ((ChannelFactory<ISimplexDatagramRouter>) cf).CreateChannel ();
121                                 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
122                         }
123                 }
124
125                 void ProcessMessageSimplexSession (Message message)
126                 {
127                         var sel = GetMatchingEndpoints (message);
128                         foreach (var se in sel) {
129                                 ChannelFactory cf;
130                                 if (!factories.TryGetValue (se, out cf)) {
131                                         cf = new ChannelFactory<ISimplexSessionRouter> (se);
132                                         factories [se] = cf;
133                                 }
134                                 // FIXME: possibly reuse session channels, though I doubt saving session *at the router* makes sense...
135                                 var ch = ((ChannelFactory<ISimplexSessionRouter>) cf).CreateChannel ();
136                                 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
137                         }
138                 }
139
140                 IAsyncResult IDuplexSessionRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
141                 {
142                         if (process_message_duplex_session_handler == null)
143                                 process_message_duplex_session_handler = new Action<Message> (ProcessMessageDuplexSession);
144                         return process_message_duplex_session_handler.BeginInvoke (message, callback, state);
145                 }
146
147                 void IDuplexSessionRouter.EndProcessMessage (IAsyncResult result)
148                 {
149                         if (process_message_duplex_session_handler == null)
150                                 throw new InvalidOperationException ("Async operation has not started");
151                         process_message_duplex_session_handler.EndInvoke (result);
152                 }
153
154                 IAsyncResult IRequestReplyRouter.BeginProcessRequest (Message message, AsyncCallback callback, object state)
155                 {
156                         if (request_reply_channel != null)
157                                 throw new InvalidOperationException ("Another async request operation is in progress");
158
159                         var sel = GetMatchingEndpoints (message);
160                         ServiceEndpoint se = null;
161                         foreach (var se_ in sel) {
162                                 if (se != null)
163                                         throw new InvalidOperationException ("Multiple endpoints cannot be specified for request-reply channel");
164                                 se = se_;
165                         }
166                         if (se == null)
167                                 throw new InvalidOperationException ("No service endpoint is registered to the request-reply channel");
168
169                         if (request_reply_factory == null)
170                                 request_reply_factory = new ChannelFactory<IRequestReplyRouter> (se);
171                         request_reply_channel = request_reply_factory.CreateChannel ();
172                         return request_reply_channel.BeginProcessRequest (message, null, null);
173                 }
174
175                 Message IRequestReplyRouter.EndProcessRequest (IAsyncResult result)
176                 {
177                         if (request_reply_channel == null)
178                                 throw new InvalidOperationException ("Async request has not started");
179                         var ch = request_reply_channel;
180                         request_reply_channel = null;
181                         return ch.EndProcessRequest (result);
182                 }
183
184                 IAsyncResult ISimplexDatagramRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
185                 {
186                         if (process_message_simplex_datagram_handler == null)
187                                 process_message_simplex_datagram_handler = new Action<Message> (ProcessMessageSimplexDatagram);
188                         return process_message_simplex_datagram_handler.BeginInvoke (message, callback, state);
189                 }
190
191                 void ISimplexDatagramRouter.EndProcessMessage (IAsyncResult result)
192                 {
193                         if (process_message_simplex_datagram_handler == null)
194                                 throw new InvalidOperationException ("Async operation has not started");
195                         process_message_simplex_datagram_handler.EndInvoke (result);
196                 }
197
198                 IAsyncResult ISimplexSessionRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
199                 {
200                         if (process_message_simplex_session_handler == null)
201                                 process_message_simplex_session_handler = new Action<Message> (ProcessMessageSimplexSession);
202                         return process_message_simplex_session_handler.BeginInvoke (message, callback, state);
203                 }
204
205                 void ISimplexSessionRouter.EndProcessMessage (IAsyncResult result)
206                 {
207                         if (process_message_simplex_session_handler == null)
208                                 throw new InvalidOperationException ("Async operation has not started");
209                         process_message_simplex_session_handler.EndInvoke (result);
210                 }
211         }
212 }