2003-10-22 Todd Berman <tberman@gentoo.org>
authorTodd Berman <tberman@mono-cvs.ximian.com>
Wed, 22 Oct 2003 18:12:23 +0000 (18:12 -0000)
committerTodd Berman <tberman@mono-cvs.ximian.com>
Wed, 22 Oct 2003 18:12:23 +0000 (18:12 -0000)
        * SoapPort.cs: Implemented.
        * MessagingConfiguration.cs: Inital implementation, missing
Load ()
        * SoapTransport.cs: Implemented.
        * SoapChannelCollection.cs: Implemented.
        * SoapChannel.cs: Implemented.
        * SoapPlainFormatter.cs: Implemented.
        * SoapTcpChannel.cs: Implemented.
        * SoapTcpListener.cs: Implemented.
        * SoapTcpTransport.cs: Implemented.
        * SoapReceiver.cs: Initial implementation.
        * SoapReceivers.cs: Initial implementation.
        * SoapSender.cs: Initial implementation.
        * SoapDimeFormatter.cs: basic stubs.
        * ChangeLog: Added.

svn path=/trunk/mcs/; revision=19306

15 files changed:
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/ChangeLog [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/ISoapTransport.cs
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/MessagingConfiguration.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannel.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannelCollection.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapDimeFormatter.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapPlainFormatter.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapPort.cs
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapReceiver.cs
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapReceivers.cs
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapSender.cs
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpChannel.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpListener.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpTransport.cs [new file with mode: 0644]
mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTransport.cs [new file with mode: 0644]

diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/ChangeLog b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/ChangeLog
new file mode 100644 (file)
index 0000000..3d247aa
--- /dev/null
@@ -0,0 +1,16 @@
+2003-10-22  Todd Berman <tberman@gentoo.org>
+
+       * SoapPort.cs: Implemented.
+       * MessagingConfiguration.cs: Inital implementation, missing Load ()
+       * SoapTransport.cs: Implemented.
+       * SoapChannelCollection.cs: Implemented.
+       * SoapChannel.cs: Implemented.
+       * SoapPlainFormatter.cs: Implemented.
+       * SoapTcpChannel.cs: Implemented.
+       * SoapTcpListener.cs: Implemented.
+       * SoapTcpTransport.cs: Implemented.
+       * SoapReceiver.cs: Initial implementation.
+       * SoapReceivers.cs: Initial implementation.
+       * SoapSender.cs: Initial implementation.
+       * SoapDimeFormatter.cs: basic stubs.
+       * ChangeLog: Added.
index 096fc9557370930749119cc9362e3fb1c461217a..bd15fae6116c9a1259a52390c2dcd45dba0ff43b 100755 (executable)
@@ -19,7 +19,7 @@ namespace Microsoft.Web.Services.Messaging {
 \r
                int IdleTimeout { get; set; }\r
                \r
-               string Scheme { get; }\r
+               //string Scheme { get; }\r
                \r
                IAsyncResult BeginSend ( \r
                        SoapEnvelope envelope,\r
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/MessagingConfiguration.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/MessagingConfiguration.cs
new file mode 100644 (file)
index 0000000..1f679a6
--- /dev/null
@@ -0,0 +1,70 @@
+//
+// Microsoft.Web.Services.Messaging.Configuration.MessagingConfiguration.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Xml;
+using System.Collections;
+using Microsoft.Web.Services.Messaging;
+using Microsoft.Web.Services.Configuration;
+
+namespace Microsoft.Web.Services.Messaging.Configuration
+{
+       public class MessagingConfiguration : ConfigurationBase
+       {
+               
+               private static Hashtable _transports;
+
+               static MessagingConfiguration ()
+               {
+                       _transports = new Hashtable ();
+               }
+
+               public MessagingConfiguration () : base ()
+               {
+                       //Add transports here
+                       AddTransport ("soap.tcp", new SoapTcpTransport ());
+               }
+
+               public void AddTransport (string scheme, ISoapTransport trans)
+               {
+                       if(scheme == null || scheme.Length == 0) {
+                               throw new ArgumentNullException ("scheme");
+                       }
+                       if(trans == null) {
+                               throw new ArgumentNullException ("transport");
+                       }
+                       _transports[scheme] = trans;
+               }
+
+               public ISoapTransport GetTransport (string scheme)
+               {
+                       if(scheme == null || scheme.Length == 0) {
+                               throw new ArgumentNullException ("scheme");
+                       }
+                       return (ISoapTransport)_transports[scheme];
+               }
+
+               public void RemoveTransport (string scheme)
+               {
+                       if(scheme == null || scheme.Length == 0) {
+                               throw new ArgumentNullException ("scheme");
+                       }
+                       _transports.Remove (scheme);
+               }
+
+               [MonoTODO]
+               public void Load (XmlNode node) 
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public ICollection Transports {
+                       get { return _transports.Values; }
+               }
+               
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannel.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannel.cs
new file mode 100644 (file)
index 0000000..83ae17e
--- /dev/null
@@ -0,0 +1,155 @@
+//
+// Microsoft.Web.Services.Messaging.SoapChannel.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public abstract class SoapChannel
+       {
+               
+               private ISoapFormatter _formatter;
+               private object _sync_obj = new object ();
+
+               public SoapChannel (ISoapFormatter format)
+               {
+                       if(format == null) {
+                               throw new ArgumentNullException ("formatter");
+                       }
+                       _formatter = format;
+               }
+
+               public abstract void Close ();
+
+               public SoapEnvelope DeserializeMessage (Stream stream)
+               {
+                       return _formatter.Deserialize (stream);
+               }
+
+               public void SerializeMessage (SoapEnvelope envelope, Stream stream)
+               {
+                       _formatter.Serialize (envelope, stream);
+               }
+
+               public abstract SoapEnvelope Receive ();
+               public abstract void Send (SoapEnvelope envelope);
+
+               public abstract bool Active {
+                       get;
+               }
+               
+               public abstract string Scheme {
+                       get;
+               }
+
+               public object SyncRoot {
+                       get { return _sync_obj; }
+               }
+               
+               public IAsyncResult BeginReceive (AsyncCallback callback, object state)
+               {
+                       return new ReceiveAsyncResult (this, callback, state);
+               }
+
+               public SoapEnvelope EndReceive (IAsyncResult result)
+               {
+                       if(result == null) {
+                               throw new ArgumentNullException ("result");
+                       }
+
+                       ReceiveAsyncResult res = result as ReceiveAsyncResult;
+                       
+                       if(res != null) {
+                               ReceiveAsyncResult.End (result);
+                               return res.Envelope;
+                       }
+                       
+                       throw new InvalidOperationException ("Invalid IAsyncResult type");
+               }
+
+               public IAsyncResult BeginSend (SoapEnvelope env, AsyncCallback callback, object state)
+               {
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       return new SendAsyncResult (this, env, callback, state);
+               }
+
+               public void EndSend (IAsyncResult result)
+               {
+                       if(result == null) {
+                               throw new ArgumentNullException ("result");
+                       }
+                       SendAsyncResult a_res = result as SendAsyncResult;
+
+                       if(a_res != null) {
+                               AsyncResult.End (result);
+                       }
+                       throw new InvalidOperationException ("Invalid IAsyncResult type");
+               }
+               
+               protected class ReceiveAsyncResult : AsyncResult
+               {
+                       private SoapEnvelope _envelope;
+
+                       private delegate SoapEnvelope Receive ();
+
+                       public ReceiveAsyncResult (SoapChannel channel,
+                                                  AsyncCallback callback,
+                                                  object state) : base (callback, state)
+                       {
+                               Receive rec = new Receive (channel.Receive);
+                               
+                               rec.BeginInvoke (new AsyncCallback (OnReceiveComplete), rec);
+                       }
+
+                       private void OnReceiveComplete (IAsyncResult result)
+                       {
+                               Receive rec = (Receive) result.AsyncState;
+
+                               try {
+                                       _envelope = rec.EndInvoke (result);
+                                       Complete (result.CompletedSynchronously);
+                               } catch (Exception e) {
+                                       Complete (result.CompletedSynchronously, e);
+                               }
+                       }
+
+                       public SoapEnvelope Envelope {
+                               get { return _envelope; }
+                       }
+               }
+
+               protected class SendAsyncResult : AsyncResult
+               {
+                       private delegate void Send (SoapEnvelope e);
+                       
+                       public SendAsyncResult (SoapChannel channel,
+                                               SoapEnvelope env,
+                                               AsyncCallback callback,
+                                               object state) : base (callback, state)
+                       {
+                               Send send_delegate = new Send (channel.Send);
+                               send_delegate.BeginInvoke (env, new AsyncCallback (OnSendComplete), send_delegate);
+                       }
+
+                       private void OnSendComplete (IAsyncResult result)
+                       {
+                               Send s_del = result.AsyncState as Send;
+
+                               try {
+                                       s_del.EndInvoke (result);
+                                       this.Complete (result.CompletedSynchronously);
+                               } catch (Exception e) {
+                                       Complete (result.CompletedSynchronously, e);
+                               }
+                       }
+               }
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannelCollection.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapChannelCollection.cs
new file mode 100644 (file)
index 0000000..c05f454
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// Microsoft.Web.Services.Messaging.SoapChannelCollection.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Collections;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public class SoapChannelCollection
+       {
+
+               private Hashtable _channels = new Hashtable ();
+
+               public void Add (string to, SoapChannel channel)
+               {
+                       if(to == null || to.Length == 0) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       if(channel == null) {
+                               throw new ArgumentNullException ("channel");
+                       }
+
+                       _channels[to] = channel;
+               }
+
+               public void Clear ()
+               {
+                       _channels.Clear ();
+               }
+
+               public bool Contains (string to)
+               {
+                       if(to == null || to.Length == 0) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       return _channels.Contains (to);
+               }
+
+               public IEnumerator GetEnumerator ()
+               {
+                       return _channels.Values.GetEnumerator ();
+               }
+
+               public void Remove (string to)
+               {
+                       if(to == null || to.Length == 0) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       _channels.Remove (to);
+               }
+
+               public int Count {
+                       get { return _channels.Values.Count; }
+               }
+
+               public SoapChannel this [string index] {
+                       get { return (SoapChannel) _channels[index]; }
+               }
+
+               public ICollection Keys {
+                       get { return _channels.Keys; }
+               }
+
+               public object SyncRoot {
+                       get { return _channels.SyncRoot; }
+               }
+
+               public ICollection Values {
+                       get { return _channels.Values; }
+               }
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapDimeFormatter.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapDimeFormatter.cs
new file mode 100644 (file)
index 0000000..0ee0d9a
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// Microsoft.Web.Services.Messaging.SoapDimeFormatter.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public class SoapDimeFormatter : ISoapFormatter
+       {
+
+               [MonoTODO]
+               public SoapEnvelope Deserialize (Stream stream)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO]
+               public void Serialize (SoapEnvelope envelope, Stream stream)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapPlainFormatter.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapPlainFormatter.cs
new file mode 100644 (file)
index 0000000..b56b022
--- /dev/null
@@ -0,0 +1,59 @@
+//
+// Microsoft.Web.Services.Messaging.SoapPlainFormatter.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+
+//FIXME: Can be removed when workaround is removed.
+using System.Text;
+using System.Net.Sockets;
+
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public class SoapPlainFormatter : ISoapFormatter
+       {
+               public SoapEnvelope Deserialize (Stream stream)
+               {
+                       if(stream == null) {
+                               throw new ArgumentNullException ("stream");
+                       }
+                       SoapEnvelope env = new SoapEnvelope ();
+                       //env.Load (stream);
+                       
+
+                       //FIXME: Workaround for XmlDocument.Load's love of stream closing
+                       byte[] buf = new byte[1024];
+                       String msg = "";
+                       int numRead = 0;
+                       
+                       do {
+                               numRead = stream.Read(buf, 0, buf.Length);
+                               msg = String.Concat (msg, Encoding.ASCII.GetString (buf, 0, numRead));
+                       } while(((NetworkStream)stream).DataAvailable);
+                       
+                       env.LoadXml (msg);
+                       
+                       return env;
+               }
+
+               [MonoTODO("Should error if envelope has DimeAttachments")]
+               public void Serialize (SoapEnvelope env, Stream stream)
+               {
+                       if(stream == null) {
+                               throw new ArgumentNullException ("stream");
+                       }
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       
+                       env.Save (stream);
+                       stream.Flush();
+               }
+       }
+}
index ffdc064f8852c04b9ba4e69f4ce3a633e241aed3..d3f7137d82be2f9474db31c15f4a9b0317fb69c4 100755 (executable)
@@ -1,6 +1,34 @@
-namespace Microsoft.Web.Services.Messaging {
+//
+// Microsoft.Web.Services.Messaging.SoapPort.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging 
+{
 
         public abstract class SoapPort
         {
+               private Pipeline _pipeline;
+
+               public SoapPort () : base ()
+               {
+                       _pipeline = null;
+               }
+
+               protected abstract void FilterMessage (SoapEnvelope env);
+
+               public Pipeline Pipeline {
+                       get {
+                               if(_pipeline == null) {
+                                       _pipeline = new Pipeline ();
+                               }
+                               return _pipeline;
+                       }
+                       set { _pipeline = value; }
+               }
         }
 }
index c0250e0e2e13d1c239beb8ac0218b6eca6e1fbdc..6a45024ce225247b691743814d2824848909f4b1 100755 (executable)
+//
+// Microsoft.Web.Services.Messaging.SoapReceiver.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
 using System;
 using System.Web;
 using Microsoft.Web.Services;
+using Microsoft.Web.Services.Addressing;
+using Microsoft.Web.Services.Configuration;
 
 namespace Microsoft.Web.Services.Messaging {
 
         public abstract class SoapReceiver : SoapPort, IHttpHandler
         {
 
+               private static Pipeline _defPipe = new Pipeline ();
+
                protected abstract void Receive (SoapEnvelope envelope);
 
-               [MonoTODO]
-                public bool IsReusable {
+               public SoapReceiver () : base ()
+               {
+               }
+
+               protected void Receive (SoapEnvelope envelope, Exception e)
+               {
+               }
+
+               public static void DispatchMessage (SoapEnvelope env)
+               {
+                       DispatchMessage (env, null);
+               }
+
+               public static void DispatchMessage (SoapEnvelope env, RelatesTo relation)
+               {
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       SoapReceiver rec = null;
+                       AddressingHeaders header = null;
+
+                       try {
+
+                               header = env.Context.Addressing;
+
+                               header.Load (env);
+
+                               if(header.RelatesTo != null || header.To != null || relation != null)
+                               {
+                                       object to = null;
+                                       if(header.RelatesTo != null) {
+                                               if(WebServicesConfiguration.MessagingConfiguration.GetTransport (header.RelatesTo.Value.Scheme) == null) {
+                                                       //FIXME: Incorrect exception here, should be using something in Routing.
+                                                       throw new ArgumentException ("Transport " + header.RelatesTo.Value.Scheme + " is not supported");
+                                               }
+                                               to = SoapReceivers.Receiver (header.RelatesTo.Value);
+                                               env.Context.SetActor (header.RelatesTo);
+                                       }
+                                       if(to == null && header.To != null) {
+                                               if(env.Context.Channel.Scheme != header.To.Value.Scheme) {
+                                                       //FIXME: Incorrect exception again.
+                                                       throw new ArgumentException ("Channel's Scheme and To's Scheme are not the same.");
+                                               }
+                                               to = SoapReceivers.Receiver (header.To.Value);
+                                               env.Context.SetActor (header.RelatesTo);
+                                       }
+                                       if(to == null && relation != null) {
+                                               to = SoapReceivers.Receiver (relation.Value);
+                                               env.Context.Addressing.RelatesTo = relation;
+                                               env.Context.SetActor (relation);
+                                       }
+                                       if(to != null) {
+                                               rec = to as SoapReceiver;
+                                               if(rec == null) {
+                                                       rec = (SoapReceiver) Activator.CreateInstance (to as Type);
+                                               }
+                                               if(rec != null) {
+                                                       Exception excep = null;
+                                                       try {
+                                                               env.Context.SetIsInbound (true);
+                                                               rec.FilterMessage (env);
+                                                       } catch (Exception e) {
+                                                               excep = e;
+                                                       }
+                                                       if(excep != null) {
+                                                               //FIXME: again, wrong exception type, should be throwing something XmlElement like
+                                                               rec.Receive (env, excep);
+                                                       } else {
+                                                               rec.Receive (env);
+                                                       }
+                                               } else {
+                                                       //FIXME: same thing
+                                                       throw new InvalidOperationException ("no receiver found");
+                                               }
+                                       } else {
+                                               //FIXME: same
+                                               throw new InvalidOperationException ("no receiver found pt 2");
+                                       }
+                               }
+                       } catch (Exception e) {
+                               if(rec == null) {
+                                       DispatchMessageFault (env, e);
+                               } else {
+                                       DispatchMessageFault (env, e, rec.Pipeline);
+                               }
+                       }
+               }
+               
+                public static void DispatchMessageFault (SoapEnvelope env, Exception e)
+               {
+                       DispatchMessageFault (env, e, _defPipe);
+               }
+
+               public static void DispatchMessageFault (SoapEnvelope env, Exception e, Pipeline pipe)
+               {
+               }
+               
+               public bool IsReusable {
                         get {
-                                throw new NotImplementedException ();
-                        }
+                               return true;
+                       }
                 }
 
-                [MonoTODO]
+               protected override void FilterMessage (SoapEnvelope env)
+               {
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       Pipeline.ProcessInputMessage (env);
+               }
+
+               public void ProcessSoapRequest (HttpContext context)
+               {
+                       
+               }
+
+               public void ProcessNonSoapRequest (HttpContext context)
+               {
+                       
+               }
+
                 public void ProcessRequest (HttpContext context)
                 {
-                        throw new NotImplementedException ();
-                }
+                       if(context.Request.HttpMethod == "POST" || context.Request.Headers["SOAPAction"] != null) {
+                               ProcessSoapRequest (context);
+                       }
+                       ProcessNonSoapRequest (context);
+               }
         }
 }
index edeb11201316c62fca0a6103520ca75d2f5c433b..6853f17918e3369c48b11688894278187dcd75a1 100644 (file)
@@ -6,6 +6,8 @@
 // (C) 2003 Todd Berman
 
 using System;
+using System.Collections;
+using Microsoft.Web.Services.Configuration;
 
 namespace Microsoft.Web.Services.Messaging
 {
@@ -13,18 +15,130 @@ namespace Microsoft.Web.Services.Messaging
        public class SoapReceivers
        {
 
-               [MonoTODO]
+               private static Hashtable _receivers = new Hashtable ();
+       
+               private SoapReceivers () { }
+
                public static void Add (Uri uri, SoapReceiver receiver)
                {
-                       throw new NotImplementedException ();
+                       Add (uri, receiver, false);
+               }
+
+               public static void Add (Uri uri, Type type)
+               {
+                       Add (uri, type, false);
+               }
+
+               public static void Add (Uri uri, SoapReceiver receiver, bool passive)
+               {
+                       if(uri == null) {
+                               throw new ArgumentNullException ("uri");
+                       }
+                       if(receiver == null) {
+                               throw new ArgumentNullException ("receiver");
+                       }
+                       
+                       lock(SyncRoot) {
+                               if(_receivers.Contains (uri)) {
+                                       throw new ArgumentException ("An item with this key already exists");
+                               }
+                               
+                               if(passive == false) {
+                                       ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (uri.Scheme);
+                                       
+                                       if(trans != null) {
+                                               trans.RegisterPort (uri, receiver);
+                                       } else {
+                                               throw new NotSupportedException ("Transport " + uri.Scheme + " not supported.");
+                                       }
+                               }
+
+                               _receivers.Add (uri, receiver);
+                       }
+               }
+
+               public static void Add (Uri uri, Type type, bool passive)
+               {
+                       if(uri == null) {
+                               throw new ArgumentNullException ("uri");
+                       }
+                       if(type == null) {
+                               throw new ArgumentNullException ("type");
+                       }
+                       lock(SyncRoot) {
+                               if(_receivers.Contains (uri)) {
+                                       throw new ArgumentException ("An item with this key already exists");
+                               }
+
+                               if(passive == false) {
+                                       ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (uri.Scheme);
+
+                                       if(trans != null) {
+                                               trans.RegisterPort (uri, type);
+                                       } else {
+                                               throw new NotSupportedException ("Transport " + uri.Scheme + " is not supported");
+                                       }
+                               }
+
+                               _receivers.Add (uri, type);
+                       }
+               }
+
+               public static void Clear ()
+               {
+                       lock(SyncRoot) {
+                               foreach(ISoapTransport trans in WebServicesConfiguration.MessagingConfiguration.Transports) {
+                                       trans.UnregisterAll ();
+                               }
+                               _receivers.Clear ();
+                       }
+               }
+
+               public static bool Contains (Uri to)
+               {
+                       if(to == null) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       bool retVal = false;
+                       lock(SyncRoot) {
+                               retVal = _receivers.Contains (to);
+                       }
+                       return retVal;
+               }
+
+               public static IDictionaryEnumerator GetEnumerator ()
+               {
+                       return _receivers.GetEnumerator ();
+               }
+
+               public static object Receiver (Uri to)
+               {
+                       return _receivers[to];
                }
 
-               [MonoTODO]
                public static void Remove (Uri to)
                {
-                       throw new NotImplementedException ();
+                       if(to == null) {
+                               throw new ArgumentNullException ("to");
+                       }
+
+                       lock(SyncRoot) {
+                               if(_receivers.Contains (to) == false) {
+                                       ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (to.Scheme);
+                                       if(trans != null) {
+                                               trans.UnregisterPort (to);
+                                               _receivers.Remove (to);
+                                       }
+                               }
+                       }
                }
 
-       }
+               public static int Count {
+                       get { return _receivers.Values.Count; }
+               }
 
+               public static object SyncRoot {
+                       get { return _receivers.SyncRoot; }
+               }
+       }
 }
index e27b32f2684c9bbfb491f918b360ebc2d0ca9d6c..485c021051004a0b2cea6f0e812e0ecea3c478cb 100644 (file)
@@ -9,35 +9,95 @@ using System;
 using System.Web;
 using Microsoft.Web.Services;
 using Microsoft.Web.Services.Addressing;
+using Microsoft.Web.Services.Configuration;
 
 namespace Microsoft.Web.Services.Messaging {
 
         public class SoapSender : SoapPort
         {
 
-               [MonoTODO]
-               public SoapSender ()
+               private EndpointReference _destination = null;
+               private ISoapTransport _transport = null;
+               
+               public SoapSender () : base ()
                {
-                       throw new NotImplementedException ();
                }
 
-               [MonoTODO]
-               public SoapSender (EndpointReference destination)
+               public SoapSender (EndpointReference dest) : base ()
                {
-                       throw new NotImplementedException ();
+                       if(dest == null) {
+                               throw new ArgumentNullException ("destination");
+                       }
+                       Destination = dest;
+               }
+
+               public SoapSender (Uri destination) : this (new EndpointReference (destination))
+               {
+               }
+
+               protected override void FilterMessage (SoapEnvelope env)
+               {
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       Pipeline.ProcessOutputMessage (env);
+               }
+
+               public void Send (SoapEnvelope env)
+               {
+                       if(env == null) {
+                               throw new ArgumentNullException ("envelope");
+                       }
+                       if(env.Context.Action == null) {
+                               throw new ArgumentException ("Action not set");
+                       }
+                       if(env.Processed == true || env.Context.Processed == true) {
+                               throw new ArgumentException ("Attempting to re-process an envelope");
+                       }
+                       
+                       if(_destination == null) {
+                               throw new ArgumentException ("Destination is not set, cant send");
+                       }
+                       if(_transport == null) {
+                               throw new ArgumentException ("Transport is not set, cant send");
+                       }
+
+                       env.Context.SetTo(_destination.Address);
+
+                       FilterMessage (env);
+
+                       _transport.Send (env, _destination);
                }
 
                [MonoTODO]
-               public SoapSender (Uri destination)
+               public IAsyncResult BeginSend (SoapEnvelope env, AsyncCallback callback, object state)
                {
                        throw new NotImplementedException ();
-               } 
+               }
 
                [MonoTODO]
-               public void Send (SoapEnvelope env)
+               public void EndSend (IAsyncResult result)
                {
                        throw new NotImplementedException ();
                }
-       
+
+               public ISoapTransport Transport {
+                       get { return _transport; }
+               }
+
+               public EndpointReference Destination {
+                       get { return _destination; }
+                       set {
+                               if(value == null || value.Address == null || value.Address.Value == null) {
+                                       throw new ArgumentNullException ("destination");
+                               }
+                               ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (value.Address.Value.Scheme);
+                               if(trans == null) {
+                                       throw new ArgumentException ("Transport " + value.Address.Value.Scheme + " is not supported");
+                               }
+                               _destination = value;
+                               _transport = trans;
+                       }
+               }
         }
 }
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpChannel.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpChannel.cs
new file mode 100644 (file)
index 0000000..65d6ab8
--- /dev/null
@@ -0,0 +1,188 @@
+//
+// Microsoft.Web.Services.Messaging.SoapTcpChannel.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Microsoft.Web.Services.Messaging
+{
+
+       public class SoapTcpChannel : SoapChannel
+       {
+
+               private bool _active = false;
+               private bool _disposed = false;
+               private AddressFamily _addrFam = AddressFamily.InterNetwork;
+               private DateTime _lastActivity = DateTime.Now;
+               private int _port = 0;
+               private Socket _socket = null;
+               private NetworkStream _stream = null;
+               private Uri _destination = null;
+               private string _hostname = null;
+
+               public SoapTcpChannel (Socket sock, ISoapFormatter format) : base (format)
+               {
+                       _socket = sock;
+                       _stream = new NetworkStream (sock, false);
+                       _active = true;
+
+                       IPEndPoint ep = sock.RemoteEndPoint as IPEndPoint;
+
+                       _destination = new Uri ("soap.tcp://" + ep.Address.ToString () + ":" + ep.Port);
+               }
+
+               public SoapTcpChannel (Uri uri, ISoapFormatter format) : base (format)
+               {
+                       if(uri == null) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       if(uri.Scheme != "soap.tcp") {
+                               throw new ArgumentException ("Invalid Scheme");
+                       }
+                       _hostname = uri.Host;
+                       _port = uri.Port < 0 ? 8081 : uri.Port;
+               }
+
+               public new void Close ()
+               {
+                       lock(SyncRoot) {
+                               try {
+                                       _active = false;
+                                       if(_socket != null || !_socket.Connected) {
+                                               _socket.Close ();
+                                       }
+                               } catch {
+                                       _socket = null;
+                               }
+                       }
+               }
+               
+               public void Connect ()
+               {
+                       if(_disposed) {
+                               throw new ObjectDisposedException (GetType ().FullName);
+                       }
+                       if(_active) {
+                               return;
+                       }
+                       lock(SyncRoot) {
+                               if(_active) {
+                                       return;
+                               }
+                               IPHostEntry host = Dns.Resolve (_hostname);
+
+                               IPAddress[] ip_addrs = host.AddressList;
+
+                               Exception exception = null;
+
+                               for (int i = 0; i < ip_addrs.Length; i++) {
+                                       IPAddress addy = ip_addrs[i];
+
+                                       _addrFam = addy.AddressFamily;
+                                       _socket = new Socket (_addrFam, SocketType.Stream, ProtocolType.Tcp);
+                                       _active = false;
+
+                                       try {
+                                               Connect ( new IPEndPoint (addy, _port) );
+                                               break;
+                                       } catch (Exception e) {
+                                               _socket.Close ();
+                                               _socket = null;
+                                               exception = e;
+                                       }
+                               }
+
+                               if(_active == false) {
+                                       if(exception != null) {
+                                               throw exception;
+                                       }
+
+                                       throw new Exception ("Not Connected");
+                               }
+                               _stream = new NetworkStream (_socket, false);
+                       }
+               }
+
+               public void Connect (IPEndPoint endpoint)
+               {
+                       if(_disposed) {
+                               throw new ObjectDisposedException (GetType ().FullName);
+                       }
+                       if(endpoint == null) {
+                               throw new ArgumentNullException ("endpoint");
+                       }
+
+                       _socket.Connect (endpoint);
+                       _active = true;
+                       UpdateLastActivity ();
+               }
+
+
+               ~SoapTcpChannel ()
+               {
+                       if(_active == false) {
+                               Close ();
+                               _disposed = true;
+                       }
+               }
+
+
+               public new SoapEnvelope Receive ()
+               {
+                       if(!_active) {
+                               Connect ();
+                       }
+
+                       SoapEnvelope env = DeserializeMessage (_stream);
+
+                       if(env != null) {
+                               env.Context.Channel = this;
+                       }
+
+                       UpdateLastActivity ();
+                       
+                       return env;
+               }
+
+               public new void Send (SoapEnvelope env)
+               {
+                       lock(SyncRoot) {
+                               if(!_active) {
+                                       Connect ();
+                               }
+                               SerializeMessage (env, _stream);
+                               UpdateLastActivity ();
+                       }
+               }
+
+               public void UpdateLastActivity ()
+               {
+                       lock (SyncRoot) {
+                               _lastActivity = DateTime.Now;
+                       }
+               }
+
+               public new bool Active {
+                       get { return _active; }
+               }
+
+               public Uri Destination {
+                       get { return _destination; }
+               }
+
+               public DateTime LastActivity {
+                       get { return _lastActivity; }
+               }
+
+               public new string Scheme {
+                       get { return "soap.tcp"; }
+               }
+               
+       }
+
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpListener.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpListener.cs
new file mode 100644 (file)
index 0000000..c454d88
--- /dev/null
@@ -0,0 +1,71 @@
+//
+// Microsoft.Web.Services.Messaging.SoapTcpListener.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public class SoapTcpListener : TcpListener
+       {
+
+               private int _refs = 0;
+
+               private delegate Socket AcceptSocket ();
+
+               private AcceptSocket _acceptSocket;
+       
+               public SoapTcpListener (IPEndPoint endpoint) : base (endpoint)
+               {
+                       if(Server == null) {
+                               Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+                       }
+               }
+
+               public SoapTcpListener (IPAddress address, int port) : base (address, port)
+               {
+                       if(Server == null) {
+                               Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+                       }
+               }
+
+               public SoapTcpListener (int port) : base (port)
+               {
+                       if(Server == null) {
+                               Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+                       }
+               }
+
+               public void AddReference ()
+               {
+                       _refs++;
+               }
+
+               public int ReleaseReference ()
+               {
+                       return --_refs;
+               }
+
+               public IAsyncResult BeginAcceptSocket (AsyncCallback callback, object state)
+               {
+                       if(_acceptSocket == null) {
+                               _acceptSocket = new AcceptSocket (base.AcceptSocket);
+                       }
+                       return _acceptSocket.BeginInvoke (callback, state);
+               }
+
+               public Socket EndAcceptSocket (IAsyncResult result)
+               {
+                       return _acceptSocket.EndInvoke (result);
+               }
+
+               public bool IsListening {
+                       get { return Active; }
+               }
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpTransport.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTcpTransport.cs
new file mode 100644 (file)
index 0000000..f42d5f3
--- /dev/null
@@ -0,0 +1,228 @@
+//
+// Microsoft.Web.Services.Messaging.SoapTcpTransport.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Collections;
+using Microsoft.Web.Services;
+using Microsoft.Web.Services.Addressing;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public class SoapTcpTransport : SoapTransport, ISoapTransport
+       {
+               
+               public static string Scheme = "soap.tcp";
+               
+               private Hashtable _listeners = new Hashtable ();
+               private Hashtable _receivers = new Hashtable ();
+
+               public SoapTcpChannel GetTcpChannel (Uri to)
+               {
+                       SoapTcpChannel chan = null;
+                       lock (Channels.SyncRoot) {
+                               int port = (to.Port == -1) ? 8081 : to.Port;
+
+                               Uri uri = new Uri (String.Format("{0}://{1}:{2}", Scheme, to.Host, port));
+
+                               chan = Channels[uri.AbsoluteUri] as SoapTcpChannel;
+
+                               if(chan == null) {
+                                       SoapTcpChannel newChan = new SoapTcpChannel (uri, Formatter);
+                                       Channels.Add (uri.AbsoluteUri, newChan);
+                               
+                                       newChan.BeginReceive(new AsyncCallback (OnReceive), newChan);
+                                       chan = newChan;
+                               
+                               }
+                       }
+                       return chan;
+               }
+
+               public IAsyncResult BeginSend (SoapEnvelope env,
+                                               Uri dest,
+                                               AsyncCallback callback,
+                                               object state)
+               {
+                       SoapTcpChannel chan = GetTcpChannel (dest);
+
+                       return new SendAsyncResult (chan, env, callback, state);
+               }
+
+               public void EndSend (IAsyncResult result)
+               {
+                       if(result == null) {
+                               throw new ArgumentNullException ("result");
+                       }
+
+                       if(result is SendAsyncResult) {
+                               AsyncResult.End (result);
+                       } else {
+                               throw new InvalidOperationException ("Invalid IAsyncResult Type");
+                       }
+               }
+
+               public void RegisterPort (Uri to, Type rType)
+               {
+                       GenericRegister (to, rType);
+               }
+
+               public void RegisterPort (Uri to, SoapReceiver rec)
+               {
+                       GenericRegister (to, rec);
+               }
+
+               private void GenericRegister (Uri to, object rType)
+               {
+                       if(to == null) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       if(Scheme != to.Scheme) {
+                               throw new ArgumentException ("invalid Scheme");
+                       }
+                       //if(to.Host != "localhost") {
+                       //      throw new ArgumentException ("Host name " + to.Host + " does not equal " + Dns.GetHostName() );
+                       //}
+
+                       lock(Channels.SyncRoot) {
+                               if(Receivers.Contains (to) == true) {
+                                       throw new ArgumentException ("URI has already been registered");
+                               }
+                               int port = to.Port <= -1 ? 8081 : to.Port;
+                               Uri to_with_port = new Uri (Scheme + "://" + to.Host + ":" + port);
+                               SoapTcpListener tcp = (SoapTcpListener) _listeners[to_with_port];
+
+                               if(tcp == null) {
+                                       
+                                       //This is what Hervey says it does, not WSE2 TP tested.
+                                       
+                                       if(to.Host == "localhost") {
+                                               tcp = new SoapTcpListener (IPAddress.Loopback, port);
+                                       } else {
+                                               tcp = new SoapTcpListener (IPAddress.Any, port);
+                                       }
+
+                                       tcp.Start ();
+                                       tcp.AddReference ();
+
+                                       tcp.BeginAcceptSocket (new AsyncCallback (OnAcceptSocket), tcp);
+
+                                       _listeners[to_with_port] = tcp;
+                               } else {
+                                       tcp.AddReference ();
+                               }
+
+                               Receivers[to] = rType;
+                       }
+               }
+
+               public void Send (SoapEnvelope env, Uri to)
+               {
+                       SoapTcpChannel tcp = GetTcpChannel (to);
+
+                       tcp.Send (env);
+               }
+
+               public void UnregisterAll ()
+               {
+                       lock (Channels.SyncRoot) {
+
+                               Receivers.Clear ();
+                               foreach(SoapTcpListener tcp in _listeners.Values) {
+                                       tcp.Stop ();
+                               }
+                               _listeners.Clear ();
+                       }
+               }
+
+               public void UnregisterPort (Uri to)
+               {
+                       if(to == null) {
+                               throw new ArgumentNullException ("to");
+                       }
+                       lock(Channels.SyncRoot) {
+                               int port = to.Port < 0 ? 8081 : to.Port;
+
+                               Uri newTo = new Uri (Scheme + "://" + to.Host + ":" + port);
+                               SoapTcpListener tcp = _listeners[newTo] as SoapTcpListener;
+
+                               if(tcp != null) {
+                                       if(tcp.ReleaseReference () == 0) {
+                                               _listeners.Remove(newTo);
+                                               tcp.Stop();
+                                       }
+                                       Receivers.Remove(to);
+                               }
+                       }
+               }
+
+               //private string Scheme {
+               //      get { return "soap.tcp"; }
+               //}
+
+               private void OnAcceptSocket (IAsyncResult result)
+               {
+                       try {
+                               SoapTcpListener tcp = (SoapTcpListener) result.AsyncState;
+
+                               if(tcp != null) {
+                                       Socket sock = tcp.EndAcceptSocket (result);
+                                       if(tcp.IsListening != true) {
+                                               tcp.BeginAcceptSocket (new AsyncCallback (OnAcceptSocket), result);
+                                       }
+                                       if(sock != null) {
+                                               SoapTcpChannel chan = new SoapTcpChannel (sock, Formatter);
+                                               lock (Channels.SyncRoot) {
+                                                       Channels.Add (chan.Destination.AbsoluteUri, chan);
+                                               }
+                                               chan.BeginReceive (new AsyncCallback (OnReceive), chan);
+                                       }
+                               }
+                       } catch (Exception)
+                       {
+                       }
+               }
+
+               private void OnReceive (IAsyncResult result)
+               {
+                       SoapTcpChannel tcp = result.AsyncState as SoapTcpChannel;
+                       SoapEnvelope env = null;
+
+                       try {
+                               env = tcp.EndReceive (result);
+                               tcp.BeginReceive (new AsyncCallback (OnReceive), result);
+                       } catch (Exception e) {
+                               lock (Channels.SyncRoot) {
+                                       Channels.Remove (tcp.Destination.AbsoluteUri);
+                                       tcp.Close ();
+                               }
+                       }
+                       
+                       if(env != null) {
+                               env.Context.Channel = tcp;
+
+                               AddressingHeaders header = env.Context.Addressing;
+
+                               header.Load (env);
+
+                               //FIXME: There is a lot more checking to do here for a valid message.
+                               if(header.To != null) {
+                                       if(header.To.Value.Scheme != "soap.tcp") {
+                                               SoapReceiver.DispatchMessageFault (env, new ArgumentException ("soap error"));
+                                       }
+                               }
+                               SoapReceiver.DispatchMessage (env);
+                       }
+               }
+               
+               protected IDictionary Receivers {
+                       get { return _receivers; }
+               }
+               
+       }
+}
diff --git a/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTransport.cs b/mcs/class/Microsoft.Web.Services/Microsoft.Web.Services.Messaging/SoapTransport.cs
new file mode 100644 (file)
index 0000000..a9d8433
--- /dev/null
@@ -0,0 +1,88 @@
+//
+// Microsoft.Web.Services.Messaging.SoapTransport.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+
+namespace Microsoft.Web.Services.Messaging
+{
+       public abstract class SoapTransport
+       {
+               private SoapChannelCollection _channels;
+               private ICredentials _credentials;
+               private ISoapFormatter _formatter;
+               private int _timeout;
+
+               [MonoTODO("DimeFormatter is the default here, but not impl yet")]
+               protected SoapTransport () : base ()
+               {
+                       _credentials = null;
+                       _formatter = new SoapPlainFormatter ();
+                       _channels = new SoapChannelCollection ();
+                       _timeout = 120000;
+               }
+
+               public SoapChannelCollection Channels {
+                       get { return _channels; }
+               }
+
+               public ICredentials Credentials {
+                       get { return _credentials; }
+                       set { _credentials = value; }
+               }
+
+               public ISoapFormatter Formatter {
+                       get { return _formatter; }
+                       set {
+                               if(value == null) {
+                                       throw new ArgumentNullException ("formatter");
+                               }
+                               _formatter = value;
+                       }
+               }
+
+               public int IdleTimeout {
+                       get { return _timeout; }
+                       set {
+                               if(value < 0) {
+                                       throw new ArgumentNullException ("Timeout");
+                               }
+                               _timeout = value;
+                       }
+               }
+
+               protected class SendAsyncResult : AsyncResult
+               {
+                       private delegate void Send (SoapEnvelope env);
+
+                       private SoapChannel _channel;
+
+                       public SendAsyncResult (SoapChannel chan,
+                                               SoapEnvelope env,
+                                               AsyncCallback callback,
+                                               object state) : base (callback, state)
+                       {
+                               _channel = chan;
+                               chan.BeginSend (env, new AsyncCallback (OnSendComplete), null);
+                       }
+
+                       public void OnSendComplete (IAsyncResult result)
+                       {
+                               try {
+                                       _channel.EndSend (result);
+                                       Complete (result.CompletedSynchronously);
+                               } catch (Exception e) {
+                                       Complete (result.CompletedSynchronously, e);
+                               }
+                       }
+
+                       public SoapChannel Channel {
+                               get { return _channel; }
+                       }
+               }
+       }
+}