4 // Copyright (C) 2005 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
28 using System
.Collections
;
29 using System
.Reflection
;
31 using System
.Xml
.Serialization
;
37 public abstract class Message
{
38 protected static Type
[] GetTypes (Type parent_type
)
40 ArrayList types
= new ArrayList ();
42 foreach (Assembly ass
in AppDomain
.CurrentDomain
.GetAssemblies ())
43 types
.AddRange (ReflectionFu
.ScanAssemblyForClass (ass
, parent_type
));
45 return (Type
[]) types
.ToArray (typeof (Type
));
49 public class RequestWrapper
{
50 public RequestMessage Message
;
52 // Needed by the XmlSerializer for deserialization
53 public RequestWrapper () { }
55 public RequestWrapper (RequestMessage request
)
57 this.Message
= request
;
61 public abstract class RequestMessage
: Message
{
62 private static Type
[] request_types
= null;
63 private static object type_lock
= new object ();
65 private Hashtable handlers
= new Hashtable ();
66 private string client_name
;
67 private Client client
;
70 public bool Keepalive
;
72 public delegate void AsyncResponseHandler (ResponseMessage response
);
74 public delegate void Closed ();
75 public event Closed ClosedEvent
;
77 // This is why names arguments (like in python) are a good idea.
79 public RequestMessage (bool keepalive
, string client_name
)
81 this.Keepalive
= keepalive
;
82 this.client_name
= client_name
;
85 public RequestMessage (bool keepalive
) : this (keepalive
, null)
90 public RequestMessage (string client_name
) : this (false, client_name
)
95 public RequestMessage () : this (false, null)
100 public static Type
[] Types
{
103 if (request_types
== null)
104 request_types
= GetTypes (typeof (RequestMessage
));
107 return request_types
;
113 if (this.client
!= null)
114 this.client
.Close ();
117 public void RegisterAsyncResponseHandler (Type t
, AsyncResponseHandler handler
)
119 if (!t
.IsSubclassOf (typeof (ResponseMessage
)))
120 throw new ArgumentException ("Type must be a subclass of ResponsePayload");
122 this.handlers
[t
] = handler
;
125 public void UnregisterAsyncResponseHandler (Type t
)
127 if (!t
.IsSubclassOf (typeof (ResponseMessage
)))
128 throw new ArgumentException ("Type must be a subclass of ResponsePayload");
130 this.handlers
.Remove (t
);
133 private void OnClosedEvent ()
135 if (this.ClosedEvent
!= null)
139 private void OnAsyncResponse (ResponseMessage response
)
141 AsyncResponseHandler async_response
= (AsyncResponseHandler
) this.handlers
[response
.GetType ()];
143 if (async_response
!= null) {
144 async_response (response
);
148 public void SendAsync ()
150 if (this.client
!= null)
151 this.client
.Close ();
152 this.client
= new Client (this.client_name
);
153 this.client
.AsyncResponseEvent
+= OnAsyncResponse
;
154 this.client
.ClosedEvent
+= OnClosedEvent
;
155 this.client
.SendAsync (this);
158 public void SendAsyncBlocking ()
160 this.client
= new Client (this.client_name
);
161 this.client
.AsyncResponseEvent
+= OnAsyncResponse
;
162 this.client
.ClosedEvent
+= OnClosedEvent
;
163 this.client
.SendAsyncBlocking (this);
166 public ResponseMessage
Send ()
168 Client client
= new Client (this.client_name
);
169 //Logger.Log.Debug ("Sending message");
170 ResponseMessage resp
= client
.Send (this);
171 //Logger.Log.Debug ("Got reply");
173 //Logger.Log.Debug ("Closed client");
175 // Add some nice syntactic sugar by throwing an
176 // exception if the response is an error.
177 ErrorResponse err
= resp
as ErrorResponse
;
180 throw new ResponseMessageException (err
);
187 public abstract class RequestMessageExecutor
{
188 public delegate void AsyncResponse (ResponseMessage response
);
189 public event AsyncResponse AsyncResponseEvent
;
191 public abstract ResponseMessage
Execute (RequestMessage req
);
193 protected void SendAsyncResponse (ResponseMessage response
)
195 if (this.AsyncResponseEvent
!= null)
196 this.AsyncResponseEvent (response
);
199 // Really only worth overriding if the request is a keepalive
200 public virtual void Cleanup () { }
203 [AttributeUsage (AttributeTargets
.Class
)]
204 public class RequestMessageAttribute
: Attribute
{
205 private Type message_type
;
207 public RequestMessageAttribute (Type message_type
)
209 this.message_type
= message_type
;
212 public Type MessageType
{
213 get { return this.message_type; }
217 public class ResponseWrapper
{
218 public ResponseMessage Message
;
220 // Needed by the XmlSerializer for deserialization
221 public ResponseWrapper () { }
223 public ResponseWrapper (ResponseMessage response
)
225 this.Message
= response
;
229 public abstract class ResponseMessage
: Message
{
230 private static Type
[] response_types
= null;
231 private static object type_lock
= new object ();
233 public static Type
[] Types
{
236 if (response_types
== null)
237 response_types
= GetTypes (typeof (ResponseMessage
));
240 return response_types
;
245 public class EmptyResponse
: ResponseMessage { }
247 public class ErrorResponse
: ResponseMessage
{
248 public string Message
;
249 public string Details
;
251 // Needed by the XmlSerializer for deserialization
252 public ErrorResponse () { }
254 public ErrorResponse (Exception e
)
256 this.Message
= e
.Message
;
257 this.Details
= e
.ToString ();
260 public ErrorResponse (string message
)
262 this.Message
= message
;
266 public class ResponseMessageException
: Exception
{
268 private string details
;
270 internal ResponseMessageException (ErrorResponse response
) : base (response
.Message
)
272 details
= response
.Details
;
275 internal ResponseMessageException (Exception e
) : base (e
.Message
, e
) { }
277 public override string ToString ()
279 if (details
!= null) {
280 StringBuilder sb
= new StringBuilder ();
282 sb
.AppendFormat ("{0}: {1}\n", this.GetType (), this.Message
);
283 sb
.Append (this.details
);
285 return sb
.ToString ();
287 return base.ToString ();