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 ResponseMessage resp
= client
.Send (this);
172 // Add some nice syntactic sugar by throwing an
173 // exception if the response is an error.
174 ErrorResponse err
= resp
as ErrorResponse
;
177 throw new ResponseMessageException (err
);
184 public abstract class RequestMessageExecutor
{
185 public delegate void AsyncResponse (ResponseMessage response
);
186 public event AsyncResponse AsyncResponseEvent
;
188 public abstract ResponseMessage
Execute (RequestMessage req
);
190 protected void SendAsyncResponse (ResponseMessage response
)
192 if (this.AsyncResponseEvent
!= null)
193 this.AsyncResponseEvent (response
);
196 // Really only worth overriding if the request is a keepalive
197 public virtual void Cleanup () { }
200 [AttributeUsage (AttributeTargets
.Class
)]
201 public class RequestMessageAttribute
: Attribute
{
202 private Type message_type
;
204 public RequestMessageAttribute (Type message_type
)
206 this.message_type
= message_type
;
209 public Type MessageType
{
210 get { return this.message_type; }
214 public class ResponseWrapper
{
215 public ResponseMessage Message
;
217 // Needed by the XmlSerializer for deserialization
218 public ResponseWrapper () { }
220 public ResponseWrapper (ResponseMessage response
)
222 this.Message
= response
;
226 public abstract class ResponseMessage
: Message
{
227 private static Type
[] response_types
= null;
228 private static object type_lock
= new object ();
230 public static Type
[] Types
{
233 if (response_types
== null)
234 response_types
= GetTypes (typeof (ResponseMessage
));
237 return response_types
;
242 public class EmptyResponse
: ResponseMessage { }
244 public class ErrorResponse
: ResponseMessage
{
245 public string Message
;
246 public string Details
;
248 // Needed by the XmlSerializer for deserialization
249 public ErrorResponse () { }
251 public ErrorResponse (Exception e
)
253 this.Message
= e
.Message
;
254 this.Details
= e
.ToString ();
257 public ErrorResponse (string message
)
259 this.Message
= message
;
263 public class ResponseMessageException
: Exception
{
265 private string details
;
267 internal ResponseMessageException (ErrorResponse response
) : base (response
.Message
)
269 Log
.Debug ("Creating a ResponseMessageException from an ErrorResponse");
270 details
= response
.Details
;
273 internal ResponseMessageException (Exception e
) : base (e
.Message
, e
) { }
275 internal ResponseMessageException (Exception e
, string message
) : base (message
, e
) { }
277 internal ResponseMessageException (Exception e
, string message
, string details
) : base (message
, e
)
279 this.details
= details
;
282 internal ResponseMessageException (string message
) : base (message
) { }
284 public override string ToString ()
286 StringBuilder sb
= new StringBuilder ();
288 sb
.AppendFormat ("{0}: {1}", this.GetType (), this.Message
);
290 if (this.details
!= null)
291 sb
.AppendFormat ("\n Details: {0}", this.details
);
293 if (this.InnerException
!= null) {
294 sb
.Append ("\n Inner exception: ");
295 sb
.Append (this.InnerException
.ToString ());
298 return sb
.ToString ();