From d9c6ec672befe0c8f74ff9f88377f8dbd927829b Mon Sep 17 00:00:00 2001 From: Can Gencer Date: Wed, 17 Aug 2016 17:01:21 +0200 Subject: [PATCH] Fix for GetDistributedObjects() When GetDistributedObjects() is called with existing objects created from other clients, there would be an exception thrown if the proxy had generic type arguments. Now, proxies created through GetDistributedObjects() will have parameters of type "Object", but can be recreated when asked for with a specific generic type. --- .../Hazelcast.Client.Spi/ProxyManager.cs | 75 ++++++++++++++----- .../ClientDistributedObjectTest.cs | 23 +++++- 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/Hazelcast.Net/Hazelcast.Client.Spi/ProxyManager.cs b/Hazelcast.Net/Hazelcast.Client.Spi/ProxyManager.cs index 2cfb0c691f..b6e6215b60 100644 --- a/Hazelcast.Net/Hazelcast.Client.Spi/ProxyManager.cs +++ b/Hazelcast.Net/Hazelcast.Client.Spi/ProxyManager.cs @@ -108,25 +108,58 @@ public ICollection GetDistributedObjects() return new ReadOnlyCollection(_proxies.Values.ToList()); } - public ClientProxy GetOrCreateProxy(string service, string id) + public ClientProxy GetOrCreateProxy(string service, string id) where T : IDistributedObject { var ns = new ObjectNamespace(service, id); ClientProxy proxy; _proxies.TryGetValue(ns, out proxy); + var requestedInterface = typeof (T); if (proxy != null) { - return proxy; + // only return the existing proxy, if the requested type args match + var proxyInterface = proxy.GetType().GetInterface(requestedInterface.Name); + var proxyArgs = proxyInterface.GetGenericArguments(); + var requestedArgs = requestedInterface.GetGenericArguments(); + if (proxyArgs.SequenceEqual(requestedArgs)) + { + // the proxy we found matches what we were looking for + return proxy; + } + + // create a new proxy, which matches the interface requested + proxy = makeProxy(service, id, requestedInterface); } - ClientProxyFactory factory; + else + { + // create a new proxy, which needs initialization on server. + proxy = makeProxy(service, id, requestedInterface); + InitializeWithRetry(proxy); + } + + proxy.SetContext(new ClientContext(_client.GetSerializationService(), + _client.GetClientClusterService(), + _client.GetClientPartitionService(), _client.GetInvocationService(), _client.GetClientExecutionService(), + _client.GetListenerService(), + this, _client.GetClientConfig())); + proxy.PostInit(); + + _proxies.AddOrUpdate(ns, n => proxy, (n, oldProxy) => { + Logger.Warning("Replacing old proxy for " + oldProxy.GetName() + " of type " + oldProxy.GetType() + " with " + proxy.GetType()); + return proxy; + }); + return proxy; + } + private ClientProxy makeProxy(string service, string id, Type requestedInterface) + { + ClientProxyFactory factory; _proxyFactories.TryGetValue(service, out factory); if (factory == null) { throw new ArgumentException("No factory registered for service: " + service); } - var clientProxy = factory(typeof (T), id); - InitializeWithRetry(clientProxy); - return _proxies.GetOrAdd(ns, clientProxy); + var clientProxy = factory(requestedInterface, id); + return clientProxy; } public ClientProxy GetProxy(string service, string id) @@ -225,9 +258,8 @@ internal static ClientProxy ProxyFactory(Type proxyType, Type interfaceType, str { if (proxyType.ContainsGenericParameters) { - var genericTypeArguments = interfaceType.GetGenericArguments(); - var mgType = proxyType.MakeGenericType(genericTypeArguments); - return Activator.CreateInstance(mgType, name, id) as ClientProxy; + var typeWithParams = GetTypeWithParameters(proxyType, interfaceType); + return Activator.CreateInstance(typeWithParams, name, id) as ClientProxy; } return Activator.CreateInstance(proxyType, name, id) as ClientProxy; } @@ -253,7 +285,22 @@ private Address FindNextAddressToCreateARequest() return liteMember != null ? liteMember.GetAddress() : null; } - private void Initialize(ClientProxy clientProxy) + private static Type GetTypeWithParameters(Type proxyType, Type interfaceType) + { + var genericTypeArguments = interfaceType.GetGenericArguments(); + if (genericTypeArguments.Length == proxyType.GetGenericArguments().Length) + { + return proxyType.MakeGenericType(genericTypeArguments); + } + var types = new Type[proxyType.GetGenericArguments().Length]; + for (var i = 0; i < types.Length; i++) + { + types[i] = typeof (object); + } + return proxyType.MakeGenericType(types); + } + + private void InitializeOnServer(ClientProxy clientProxy) { var initializationTarget = FindNextAddressToCreateARequest(); var invocationTarget = initializationTarget; @@ -278,12 +325,6 @@ private void Initialize(ClientProxy clientProxy) { throw ExceptionUtil.Rethrow(e); } - clientProxy.SetContext(new ClientContext(_client.GetSerializationService(), - _client.GetClientClusterService(), - _client.GetClientPartitionService(), _client.GetInvocationService(), _client.GetClientExecutionService(), - _client.GetListenerService(), - this, _client.GetClientConfig())); - clientProxy.PostInit(); } private void InitializeWithRetry(ClientProxy clientProxy) @@ -294,7 +335,7 @@ private void InitializeWithRetry(ClientProxy clientProxy) { try { - Initialize(clientProxy); + InitializeOnServer(clientProxy); return; } catch (Exception e) diff --git a/Hazelcast.Test/Hazelcast.Client.Test/ClientDistributedObjectTest.cs b/Hazelcast.Test/Hazelcast.Client.Test/ClientDistributedObjectTest.cs index 7bf647bd25..ffd036b6be 100644 --- a/Hazelcast.Test/Hazelcast.Client.Test/ClientDistributedObjectTest.cs +++ b/Hazelcast.Test/Hazelcast.Client.Test/ClientDistributedObjectTest.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System; using System.Threading; using Hazelcast.Core; using NUnit.Framework; @@ -40,19 +41,37 @@ public void TestDistributedObjectListener() [Test] public void TestGetDistributedObjects() { - var queue = Client.GetMap(TestSupport.RandomString()); + var map = Client.GetMap(TestSupport.RandomString()); var topic = Client.GetTopic(TestSupport.RandomString()); var semaphore = Client.GetSemaphore(TestSupport.RandomString()); + Assert.AreEqual(3, Client.GetDistributedObjects().Count); - queue.Destroy(); + map.Destroy(); topic.Destroy(); semaphore.Destroy(); Assert.AreEqual(0, Client.GetDistributedObjects().Count); } + [Test] + public void TestGetDistributedObjectsFromAnotherClient() + { + String mapName = TestSupport.RandomString(); + var map = Client.GetMap(mapName); + Client.GetTopic(TestSupport.RandomString()); + Client.GetSemaphore(TestSupport.RandomString()); + + map.Put(1, 1); + var client2 = CreateClient(); + + Assert.AreEqual(3, client2.GetDistributedObjects().Count); + + var map2 = client2.GetMap(mapName); + Assert.AreEqual(1, map2.Get(1)); + } + private class DistributedObjectListener : IDistributedObjectListener { private readonly CountdownEvent _createdLatch;