2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.PeerResolvers / CustomPeerResolverService.cs
1 // 
2 // CustomPeerResolverService.cs
3 // 
4 // Author: 
5 //     Marcos Cobena (marcoscobena@gmail.com)
6 //      Atsushi Enomoto  <atsushi@ximian.com>
7 // 
8 // Copyright 2007 Marcos Cobena (http://www.youcannoteatbits.org/)
9 //
10 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections.Generic;
33 using System.Linq;
34 using System.Transactions;
35 using System.Timers;
36
37 namespace System.ServiceModel.PeerResolvers
38 {
39         [MonoTODO ("Implement cleanup and refresh")]
40         // FIXME: TransactionTimeout must be null by-default.
41         [ServiceBehavior (AutomaticSessionShutdown = true, ConcurrencyMode = ConcurrencyMode.Multiple, 
42                           InstanceContextMode = InstanceContextMode.Single, ReleaseServiceInstanceOnTransactionComplete = true, 
43                           TransactionIsolationLevel = IsolationLevel.Unspecified, /*TransactionTimeout = null, */
44                           UseSynchronizationContext = false, ValidateMustUnderstand = true)]
45         public class CustomPeerResolverService : IPeerResolverContract
46         {
47                 bool control_shape;
48                 bool opened;
49                 // Maybe it's worth to change List<T> for a better distributed and faster collection.
50                 List<Node> mesh = new List<Node> ();
51                 object mesh_lock = new object ();
52                 Timer refresh_timer, cleanup_timer;
53                 DateTime last_refresh_time = DateTime.Now;
54
55                 public CustomPeerResolverService ()
56                 {
57                         refresh_timer = new Timer () { AutoReset = true };
58                         RefreshInterval = new TimeSpan (0, 10, 0);
59                         refresh_timer.Elapsed += delegate {
60                                         // FIXME: implement
61                                 };
62                         cleanup_timer = new Timer () { AutoReset = true };
63                         CleanupInterval = new TimeSpan (0, 1, 0);
64                         cleanup_timer.Elapsed += delegate {
65                                         // FIXME: implement
66                                 };
67                         control_shape = false;
68                         opened = false;
69                 }
70
71                 public TimeSpan CleanupInterval {
72                         get { return TimeSpan.FromMilliseconds ((int) cleanup_timer.Interval); }
73                         set {
74                                 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
75                                         throw new ArgumentOutOfRangeException (
76                                         "The interval is either zero or greater than max value.");
77                                 if (opened)
78                                         throw new InvalidOperationException ("The interval must be set before it is opened");
79
80                                 cleanup_timer.Interval = value.TotalMilliseconds;
81                         }
82                 }
83
84                 public bool ControlShape {
85                         get { return control_shape; }
86                         set { control_shape = value; }
87                 }
88
89                 public TimeSpan RefreshInterval {
90                         get { return TimeSpan.FromMilliseconds ((int) refresh_timer.Interval); }
91                         set {
92                                 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
93                                         throw new ArgumentOutOfRangeException (
94                                         "The interval is either zero or greater than max value.");
95                                 if (opened)
96                                         throw new InvalidOperationException ("The interval must be set before it is opened");
97
98                                 refresh_timer.Interval = value.TotalMilliseconds;
99                         }
100                 }
101
102                 [MonoTODO ("Do we have to unregister nodes here?")]
103                 public virtual void Close ()
104                 {
105                         if (! opened)
106                                 throw new InvalidOperationException ("The service has never been opened or it was closed by a previous call to this method.");
107                         refresh_timer.Stop ();
108                         cleanup_timer.Stop ();
109                 }
110
111                 [MonoTODO]
112                 public virtual ServiceSettingsResponseInfo GetServiceSettings ()
113                 {
114                         if (! opened)
115                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
116                 
117 //                      return new ServiceSettingsResponseInfo ();
118                         throw new NotImplementedException ();
119                 }
120
121                 public virtual void Open ()
122                 {
123                         if ((CleanupInterval == TimeSpan.Zero) || (RefreshInterval == TimeSpan.Zero))
124                                 throw new ArgumentException ("Cleanup interval or refresh interval are set to a time span interval of zero.");
125
126                         if (opened)
127                                 throw new InvalidOperationException ("The service has been started by a previous call to this method.");
128                         
129                         opened = true;
130
131                         refresh_timer.Start ();
132                         cleanup_timer.Start ();
133                 }
134
135                 [MonoTODO]
136                 public virtual RefreshResponseInfo Refresh (RefreshInfo refreshInfo)
137                 {
138                         if (refreshInfo == null)
139                                 throw new ArgumentException ("Refresh info cannot be null.");
140                         
141                         if (! opened)
142                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
143
144                         var node = mesh.FirstOrDefault (n => n.MeshId == refreshInfo.MeshId && n.RegistrationId.Equals (refreshInfo.RegistrationId));
145                         if (node == null)
146                                 return new RefreshResponseInfo (TimeSpan.Zero, RefreshResult.RegistrationNotFound);
147
148                         // FIXME: implement actual refresh.
149                         last_refresh_time = DateTime.Now;
150
151                         return new RefreshResponseInfo (RefreshInterval - (DateTime.Now - last_refresh_time), RefreshResult.Success);
152                 }
153
154                 public virtual RegisterResponseInfo Register (RegisterInfo registerInfo)
155                 {
156                         if (registerInfo == null)
157                                 throw new ArgumentException ("Register info cannot be null.");
158                         
159                         if (! opened)
160                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
161                         
162                         return Register (registerInfo.ClientId, registerInfo.MeshId, registerInfo.NodeAddress);
163                 }
164
165                 public virtual RegisterResponseInfo Register (Guid clientId, string meshId, PeerNodeAddress address)
166                 {
167                         Node n = new Node () { RegistrationId = Guid.NewGuid (), MeshId = meshId, ClientId = clientId, NodeAddress = address };
168                         RegisterResponseInfo rri = new RegisterResponseInfo ();
169                         rri.RegistrationId = n.RegistrationId;
170                         lock (mesh_lock)
171                                 mesh.Add (n);
172                         
173                         return rri;
174                 }
175
176                 public virtual ResolveResponseInfo Resolve (ResolveInfo resolveInfo)
177                 {
178                         ResolveResponseInfo rri = new ResolveResponseInfo ();
179                         if (resolveInfo == null)
180                                 throw new ArgumentException ("Resolve info cannot be null.");
181                         
182                         if (! opened)
183                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
184                         
185                         foreach (var node in mesh)
186                                 if (node.MeshId == resolveInfo.MeshId &&
187                                     node.ClientId == resolveInfo.ClientId)
188                                         rri.Addresses.Add (node.NodeAddress);
189                         
190                         return rri;
191                 }
192
193                 public virtual void Unregister (UnregisterInfo unregisterInfo)
194                 {
195                         if (unregisterInfo == null)
196                                 throw new ArgumentException ("Unregister info cannot be null.");
197                         
198                         if (! opened)
199                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
200                         
201                         lock (mesh_lock)
202                                 foreach (var node in mesh)
203                                         if (node.MeshId == unregisterInfo.MeshId &&
204                                             node.RegistrationId == unregisterInfo.RegistrationId) {
205                                                 mesh.Remove (node);
206                                                 break;
207                                         }
208                 }
209
210                 [MonoTODO]
211                 public virtual RegisterResponseInfo Update (UpdateInfo updateInfo)
212                 {
213                         if (updateInfo == null)
214                                 throw new ArgumentException ("Update info cannot be null.");
215                         
216                         if (! opened)
217                                 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
218                         
219 //                      return new RegisterResponseInfo ();
220                         throw new NotImplementedException ();
221                 }
222         }
223         
224         internal class Node
225         {
226                 public Guid ClientId { get; set; }
227                 public string MeshId { get; set; }
228                 public Guid RegistrationId { get; set; }
229                 public PeerNodeAddress NodeAddress { get; set; }
230         }
231 }