Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ChannelFactory.cs
index c2fab23ab37699f13305149e8c04b4a2a4f52abe..780c4a90b998437cfba78c8ee105418a55979d15 100644 (file)
@@ -43,22 +43,33 @@ namespace System.ServiceModel
                // instance members
 
                ServiceEndpoint service_endpoint;
+               IChannelFactory factory;
 
                protected ChannelFactory ()
                {
                }
 
-               internal IChannelFactory OpenedChannelFactory { get; private set; }
+               internal IChannelFactory OpenedChannelFactory {
+                       get {
+                               if (factory == null) {
+                                       factory = CreateFactory ();
+                                       factory.Open ();
+                               }
+
+                               return factory;
+                       }
+                       private set {
+                               factory = value;
+                       }
+               }
 
                public ServiceEndpoint Endpoint {
                        get { return service_endpoint; }
                }
 
-#if !NET_2_1
                public ClientCredentials Credentials {
                        get { return Endpoint.Behaviors.Find<ClientCredentials> (); }
                }
-#endif
 
                protected internal override TimeSpan DefaultCloseTimeout {
                        get { return Endpoint.Binding.CloseTimeout; }
@@ -99,7 +110,7 @@ namespace System.ServiceModel
 #else
 
                        string contractName = Endpoint.Contract.ConfigurationName;
-                       ClientSection client = (ClientSection) ConfigurationManager.GetSection ("system.serviceModel/client");
+                       ClientSection client = ConfigUtil.ClientSection;
                        ChannelEndpointElement res = null;
                        foreach (ChannelEndpointElement el in client.Endpoints) {
                                if (el.Contract == contractName && (endpointConfig == el.Name || endpointConfig == "*")) {
@@ -125,7 +136,7 @@ namespace System.ServiceModel
 #if !NET_2_1
                private void ApplyBehavior (string behaviorConfig)
                {
-                       BehaviorsSection behaviorsSection = (BehaviorsSection) ConfigurationManager.GetSection ("system.serviceModel/behaviors");
+                       BehaviorsSection behaviorsSection = ConfigUtil.BehaviorsSection;
                        EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
                        int i = 0;
                        foreach (BehaviorExtensionElement el in behaviorElement) {
@@ -138,10 +149,7 @@ namespace System.ServiceModel
 
                protected virtual IChannelFactory CreateFactory ()
                {
-                       bool session = false;
                        bool isOneWay = true; // check OperationDescription.IsOneWay
-                       bool isDuplex = Endpoint.Contract.CallbackContractType != null;
-
                        foreach (var od in Endpoint.Contract.Operations)
                                if (!od.IsOneWay) {
                                        isOneWay = false;
@@ -150,27 +158,37 @@ namespace System.ServiceModel
 
                        BindingParameterCollection pl = CreateBindingParameters ();
 
-                       if (isDuplex) {
-                               switch (Endpoint.Contract.SessionMode) {
-                               case SessionMode.Required:
-                                       if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
-                                               return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires session channel, but the binding does not support it.");
-                               case SessionMode.Allowed:
-                                       if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
-                                               return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
-                                       goto case SessionMode.Required;
-                               default:
-                                       if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
-                                               return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires non-session channel, but the binding does not support it.");
-                               }
-                       } else if (isOneWay) {
+                       // the assumption on the type of created channel could
+                       // be wrong, but would mostly fit the actual 
+                       // requirements. No books have explained how it is done.
+
+                       // try duplex
+                       switch (Endpoint.Contract.SessionMode) {
+                       case SessionMode.Required:
+                               if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
+                                       return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
+                               break;
+                       case SessionMode.Allowed:
+                               if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
+                                       return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
+                               if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
+                                       return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
+                               break;
+                       default:
+                               if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
+                                       return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
+                               break;
+                       }
+
+                       if (Endpoint.Contract.CallbackContractType != null)
+                               throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
+
+                       if (isOneWay) {
                                switch (Endpoint.Contract.SessionMode) {
                                case SessionMode.Required:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires session channel, but the binding does not support it.");
+                                       break;
                                case SessionMode.Allowed:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
@@ -178,24 +196,29 @@ namespace System.ServiceModel
                                default:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires non-session channel, but the binding does not support it.");
+                                       break;
                                }
-                       } else {
+                       }
+                       // both OneWay and non-OneWay contracts fall into here.
+                       {
                                switch (Endpoint.Contract.SessionMode) {
                                case SessionMode.Required:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires session channel, but the binding does not support it.");
+                                       break;
                                case SessionMode.Allowed:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
-                                       goto case SessionMode.Required;
+                                       if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
+                                               return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
+                                       break;
                                default:
                                        if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
                                                return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
-                                       throw new InvalidOperationException ("The contract requires non-session channel, but the binding does not support it.");
+                                       break;
                                }
                        }
+                       throw new InvalidOperationException (String.Format ("The binding does not support any of the channel types that the contract '{0}' allows.", Endpoint.Contract.Name));
                }
 
                BindingParameterCollection CreateBindingParameters ()
@@ -221,14 +244,24 @@ namespace System.ServiceModel
                        Close ();
                }
 
-               [MonoTODO]
                public T GetProperty<T> () where T : class
                {
-                       throw new NotImplementedException ();
+                       if (OpenedChannelFactory != null)
+                               OpenedChannelFactory.GetProperty<T> ();
+                       return null;
                }
 
                protected void EnsureOpened ()
                {
+                       if (Endpoint == null)
+                               throw new InvalidOperationException ("A service endpoint must be configured for this channel factory");
+                       if (Endpoint.Address == null)
+                               throw new InvalidOperationException ("An EndpointAddress must be configured for this channel factory");
+                       if (Endpoint.Contract == null)
+                               throw new InvalidOperationException ("A service Contract must be configured for this channel factory");
+                       if (Endpoint.Binding == null)
+                               throw new InvalidOperationException ("A Binding must be configured for this channel factory");
+
                        if (State != CommunicationState.Opened)
                                Open ();
                }
@@ -238,7 +271,8 @@ namespace System.ServiceModel
                        EndpointAddress remoteAddress)
                {
                        InitializeEndpoint (CreateDescription ());
-                       service_endpoint.Address = remoteAddress;
+                       if (remoteAddress != null)
+                               service_endpoint.Address = remoteAddress;
                        ApplyConfiguration (endpointConfigurationName);
                }
 
@@ -246,65 +280,79 @@ namespace System.ServiceModel
                        EndpointAddress remoteAddress)
                {
                        InitializeEndpoint (CreateDescription ());
-                       service_endpoint.Binding = binding;
-                       service_endpoint.Address = remoteAddress;
+                       if (binding != null)
+                               service_endpoint.Binding = binding;
+                       if (remoteAddress != null)
+                               service_endpoint.Address = remoteAddress;
                }
 
                protected void InitializeEndpoint (ServiceEndpoint endpoint)
                {
+                       if (endpoint == null)
+                               throw new ArgumentNullException ("endpoint");
                        service_endpoint = endpoint;
                }
 
-               [MonoTODO]
                protected override void OnAbort ()
                {
-                       throw new NotImplementedException ();
+                       if (OpenedChannelFactory != null)
+                               OpenedChannelFactory.Abort ();
                }
 
-               [MonoTODO]
+               Action<TimeSpan> close_delegate;
+               Action<TimeSpan> open_delegate;
+
+
                protected override IAsyncResult OnBeginClose (
                        TimeSpan timeout, AsyncCallback callback, object state)
                {
-                       throw new NotImplementedException ();
+                       if (close_delegate == null)
+                               close_delegate = new Action<TimeSpan> (OnClose);
+                       return close_delegate.BeginInvoke (timeout, callback, state);
                }
 
-               [MonoTODO]
                protected override IAsyncResult OnBeginOpen (
                        TimeSpan timeout, AsyncCallback callback, object state)
                {
-                       throw new NotImplementedException ();
+                       if (open_delegate == null)
+                               open_delegate = new Action<TimeSpan> (OnClose);
+                       return open_delegate.BeginInvoke (timeout, callback, state);
                }
 
-               [MonoTODO]
                protected override void OnEndClose (IAsyncResult result)
                {
-                       throw new NotImplementedException ();
+                       if (close_delegate == null)
+                               throw new InvalidOperationException ("Async close operation has not started");
+                       close_delegate.EndInvoke (result);
                }
 
-               [MonoTODO]
                protected override void OnEndOpen (IAsyncResult result)
                {
-                       throw new NotImplementedException ();
+                       if (open_delegate == null)
+                               throw new InvalidOperationException ("Async close operation has not started");
+                       open_delegate.EndInvoke (result);
                }
 
-               [MonoTODO]
                protected override void OnClose (TimeSpan timeout)
                {
+                       if (OpenedChannelFactory != null)
+                               OpenedChannelFactory.Close (timeout);
                }
 
-               [MonoTODO]
                protected override void OnOpen (TimeSpan timeout)
                {
                }
 
                protected override void OnOpening ()
                {
+                       base.OnOpening ();
                        OpenedChannelFactory = CreateFactory ();
-                       OpenedChannelFactory.Open ();
                }
 
                protected override void OnOpened ()
                {
+                       base.OnOpened ();
+                       OpenedChannelFactory.Open ();
                }
        }