From cf15612c619be80b5e4fbf059f5369f6ba37459f Mon Sep 17 00:00:00 2001 From: pkupczyk <pkupczyk> Date: Tue, 25 Sep 2012 07:26:43 +0000 Subject: [PATCH] BIS-185 / Make long-running method calls in IDataStoreService use service conversations BIS-196 / Make service conversations timeout configurable - junit tests and bugfixes SVN: 26781 --- .../client/ClientMessenger.java | 18 +- .../ServiceConversationServerManager.java | 8 +- .../systemtests/RmiConversationTest.java | 413 --------------- .../systemtests/ServiceConversationTest.java | 492 ++++++++++++++++++ .../systemtests/SystemTestCase.java | 19 - .../BaseServiceConversationServerManager.java | 16 +- .../ServiceConversationMethodInvocation.java | 22 +- .../cisd/common/spring/WaitAction.java | 8 +- .../ServiceConversationServerManager.java | 8 +- 9 files changed, 535 insertions(+), 469 deletions(-) delete mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/RmiConversationTest.java create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/ServiceConversationTest.java diff --git a/common/source/java/ch/systemsx/cisd/common/serviceconversation/client/ClientMessenger.java b/common/source/java/ch/systemsx/cisd/common/serviceconversation/client/ClientMessenger.java index 1c97fe7fe81..250da484235 100644 --- a/common/source/java/ch/systemsx/cisd/common/serviceconversation/client/ClientMessenger.java +++ b/common/source/java/ch/systemsx/cisd/common/serviceconversation/client/ClientMessenger.java @@ -46,16 +46,15 @@ class ClientMessenger implements IServiceConversation private final ClientResponseMessageMultiplexer responseMessageMultiplexer; private final int serviceMessageTimeoutMillis; - + private final int serverWorkQueueSizeAtStartup; private int outgoingMessageIdx; private final AtomicBoolean serviceExceptionSignaled = new AtomicBoolean(); - - private final static Logger operationLog = - LogFactory.getLogger(LogCategory.OPERATION, ClientMessenger.class); + private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + ClientMessenger.class); ClientMessenger(ServiceConversationDTO serviceConversationDTO, IServiceMessageTransport transportToService, @@ -151,9 +150,11 @@ class ClientMessenger implements IServiceConversation } } - private ServiceMessage getMessage(int timeout) throws InterruptedException { + private ServiceMessage getMessage(int timeout) throws InterruptedException + { ServiceMessage message = responseMessageQueue.poll(timeout); - while (message != null && message.getProgress() != null) { + while (message != null && message.getProgress() != null) + { operationLog.info(message.getProgress()); message = responseMessageQueue.poll(timeout); } @@ -186,9 +187,10 @@ class ClientMessenger implements IServiceConversation throw new ServiceExecutionException(message.getConversationId(), message.tryGetExceptionDescription()); } - + final Object payload = message.getPayload(); - if (messageClass != null && messageClass.isAssignableFrom(payload.getClass()) == false) + if (messageClass != null && payload != null + && messageClass.isAssignableFrom(payload.getClass()) == false) { throw new UnexpectedMessagePayloadException(payload.getClass(), messageClass); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ServiceConversationServerManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ServiceConversationServerManager.java index 045ab76f03d..e2a0389b6ae 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ServiceConversationServerManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ServiceConversationServerManager.java @@ -16,6 +16,8 @@ package ch.systemsx.cisd.openbis.dss.generic.server; +import org.springframework.beans.factory.InitializingBean; + import ch.systemsx.cisd.common.conversation.client.ServiceConversationClientDetails; import ch.systemsx.cisd.common.conversation.manager.BaseServiceConversationServerManager; import ch.systemsx.cisd.common.spring.PropertyPlaceholderUtils; @@ -27,7 +29,7 @@ import ch.systemsx.cisd.openbis.generic.shared.conversation.ServiceConversationA * @author pkupczyk */ public class ServiceConversationServerManager extends BaseServiceConversationServerManager - implements IServiceConversationServerManagerLocal + implements IServiceConversationServerManagerLocal, InitializingBean { private IDataStoreService dataStoreService; @@ -37,9 +39,9 @@ public class ServiceConversationServerManager extends BaseServiceConversationSer private int applicationServerTimeoutInMillis; @Override - protected void initializeServices() + public void afterPropertiesSet() throws Exception { - addService(IDataStoreService.class.getName(), dataStoreService); + addService(IDataStoreService.class, dataStoreService); } @Override diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/RmiConversationTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/RmiConversationTest.java deleted file mode 100644 index 3fc7a813d30..00000000000 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/RmiConversationTest.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright 2012 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.openbis.datastoreserver.systemtests; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -import java.util.Date; -import java.util.List; -import java.util.UUID; - -import javax.annotation.Resource; - -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.hibernate.Criteria; -import org.hibernate.SessionFactory; -import org.hibernate.criterion.Restrictions; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.GenericWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import ch.systemsx.cisd.base.exceptions.TimeoutExceptionUnchecked; -import ch.systemsx.cisd.common.conversation.manager.IServiceConversationClientManagerRemote; -import ch.systemsx.cisd.common.conversation.manager.IServiceConversationServerManagerRemote; -import ch.systemsx.cisd.common.conversation.progress.IServiceConversationProgressListener; -import ch.systemsx.cisd.common.logging.LogInitializer; -import ch.systemsx.cisd.common.server.ISessionTokenProvider; -import ch.systemsx.cisd.common.serviceconversation.ServiceConversationDTO; -import ch.systemsx.cisd.common.serviceconversation.ServiceMessage; -import ch.systemsx.cisd.common.serviceconversation.server.ServiceConversationServer; -import ch.systemsx.cisd.common.spring.HttpInvokerUtils; -import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.OpenBISSessionHolder; - -@Test(groups = - { "system test", "broken" }) -public class RmiConversationTest extends SystemTestCase -{ - /* - private static RmiConversationController cont; - - private EchoService echo; - - private Server conversationClient; - - @BeforeClass - public void beforeClass() throws Exception - { - LogInitializer.init(); - - conversationClient = new Server(); - Connector clientConnector = new SelectChannelConnector(); - clientConnector.setPort(8882); - conversationClient.addConnector(clientConnector); - DispatcherServlet clientDispatcherServlet = new DispatcherServlet() - { - private static final long serialVersionUID = 1L; - - @Override - protected WebApplicationContext findWebApplicationContext() - { - GenericWebApplicationContext ctx = new GenericWebApplicationContext(); - - GenericBeanDefinition definition = new GenericBeanDefinition(); - definition.setBeanClass(ClientBean.class); - ctx.registerBeanDefinition("client", definition); - - GenericBeanDefinition exporter = new GenericBeanDefinition(); - exporter.setBeanClass(ClientExporter.class); - ctx.registerBeanDefinition("clientExporter", exporter); - - ctx.refresh(); - - return ctx; - } - }; - ServletContextHandler clientSch = - new ServletContextHandler(conversationClient, "/", ServletContextHandler.SESSIONS); - clientSch.addServlet(new ServletHolder(clientDispatcherServlet), "/*"); - conversationClient.start(); - - } - - @BeforeMethod - public void beforeMethod() throws Exception - { - EchoService httpEcho = - HttpInvokerUtils.createServiceStub(EchoService.class, - "http://localhost:8888/openbis/rmi-echoservice", 5000); - cont = new RmiConversationController("http://localhost:8882"); - OpenBISSessionHolder sessionHolder = new OpenBISSessionHolder(); - sessionHolder.setSessionToken(""); - echo = cont.getConversationalReference(sessionHolder, httpEcho, EchoService.class); - } - - @AfterClass - public void afterClass() throws Exception - { - conversationClient.getGracefulShutdown(); - } - - @Test - public void callThroughRpcServiceConversationWorks() throws Exception - { - assertThat(echo.echo("echo", 0), is("echo")); - } - - @Test(expectedExceptions = TimeoutExceptionUnchecked.class) - public void clientTimeoutsIfNoProgressMade() - { - echo.echoWithoutProgress("echo", 5000); - } - - @Test - public void clientDoesNotTimeOutIfProgressIsReported() - { - assertThat(echo.echo("echo", 5000), is("echo")); - } - - // Disabled because I could not make transactions work with this test spring context. - @Test(enabled = false) - public void transactionIsRolledBackIfThereIsAnExceptionDuringRequestProcessing() - throws Exception - { - try - { - echo.echoWithStoreAndProcessingException("echo"); - assertThat(true, is(false)); - } catch (Exception e) - { - } - - assertThat(echo.exists("echo"), is(false)); - } - - // Disabled because I could not make transactions work with this test spring context. - @Test(enabled = false) - public void transactionIsCommitedAfterSuccessfulRequestProcessing() throws Exception - { - assertThat(echo.echoWithStore("stored"), is("stored")); - assertThat(echo.exists("stored"), is(true)); - } - - public interface EchoService extends IServiceConversationServerManagerRemote - { - @Transactional - public String echo(String input, Integer delayInMillis); - - @Transactional - public String echo(String input, Integer delayInMillis, - IServiceConversationProgressListener listener); - - @Transactional - public String echoWithoutProgress(String input, Integer delayInMillis); - - @Transactional - public String echoWithoutProgress(String input, Integer delayInMillis, - IServiceConversationProgressListener listener); - - @Transactional - public String echoWithStore(String input); - - @Transactional - public String echoWithStore(String input, IServiceConversationProgressListener listener); - - @Transactional - public String echoWithStoreAndProcessingException(String input); - - @Transactional - public String echoWithStoreAndProcessingException(String input, - IServiceConversationProgressListener listener); - - @Transactional - public boolean exists(String code); - - @Transactional - public boolean exists(String code, IServiceConversationProgressListener listener); - } - - public static class EchoServiceBean implements EchoService - { - - private ServiceConversationServer server; - - private SessionFactory sessionFactory; - - public EchoServiceBean() - { - } - - @Override - public ServiceConversationDTO startConversation(ISessionTokenProvider sessionTokenProvider, - String clientUrl, String typeId) - { - IServiceConversationClientManagerRemote client = - HttpInvokerUtils.createServiceStub( - IServiceConversationClientManagerRemote.class, - "http://localhost:8882/client", 5000); - server.addClientResponseTransport("test-client-id", client); - return this.server.startConversation(typeId, "test-client-id"); - } - - @Override - public void send(ServiceMessage message) - { - server.getIncomingMessageTransport().send(message); - } - - @Override - public String echo(String input, Integer delayInMillis) - { - return echo(input, delayInMillis, null); - } - - @Override - public String echo(String input, Integer delayInMillis, - IServiceConversationProgressListener progress) - { - - long startTime = System.currentTimeMillis(); - int total = 50; - int unit = delayInMillis / total; - int i = 0; - - progress.update("progress", total, i); - while (System.currentTimeMillis() - startTime < delayInMillis) - { - try - { - Thread.sleep(unit); - } catch (InterruptedException ex) - { - ex.printStackTrace(); - } - progress.update("progress", total, ++i); - - } - return input; - } - - @Override - public String echoWithoutProgress(String input, Integer delayInMillis) - { - return echoWithoutProgress(input, delayInMillis, null); - } - - @Override - public String echoWithoutProgress(String input, Integer delayInMillis, - IServiceConversationProgressListener progress) - { - try - { - Thread.sleep(delayInMillis); - } catch (InterruptedException ex) - { - ex.printStackTrace(); - } - return input; - } - - @Override - public String echoWithStore(String input) - { - return echoWithStore(input, null); - } - - @Override - public String echoWithStore(String input, IServiceConversationProgressListener progress) - { - - DatabaseInstancePE db = new DatabaseInstancePE(); - db.setCode(input); - db.setOriginalSource(false); - db.setRegistrationDate(new Date()); - db.setUuid(UUID.randomUUID().toString()); - sessionFactory.getCurrentSession().persist(db); - return input; - } - - @Override - public String echoWithStoreAndProcessingException(String input) - { - return echoWithStoreAndProcessingException(input, null); - } - - @Override - public String echoWithStoreAndProcessingException(String input, - IServiceConversationProgressListener progress) - { - - DatabaseInstancePE db = new DatabaseInstancePE(); - db.setCode(input); - db.setOriginalSource(false); - db.setRegistrationDate(new Date()); - db.setUuid(UUID.randomUUID().toString()); - sessionFactory.getCurrentSession().persist(db); - - throw new NullPointerException("Exception"); - } - - @Override - public boolean exists(String code) - { - return exists(code, null); - } - - @Override - public boolean exists(String code, IServiceConversationProgressListener progress) - { - - Criteria criteria = - sessionFactory.getCurrentSession().createCriteria(DatabaseInstancePE.class); - criteria.add(Restrictions.eq("code", code)); - - @SuppressWarnings( - { "unchecked", "cast" }) - List<DatabaseInstancePE> list = (List<DatabaseInstancePE>) criteria.list(); - boolean result = list.size() > 0; - if (result) - { - sessionFactory.getCurrentSession().delete(list.get(0)); - } - return result; - } - - public void setSessionFactory(SessionFactory sessionFactory) - { - this.sessionFactory = sessionFactory; - } - - private EchoService echoService; - - private ServiceConversationServiceFactory<EchoService> rmiServiceFactory; - - public void setEchoService(EchoService echoService) - { - this.echoService = echoService; - this.server = new ServiceConversationServer(); - this.rmiServiceFactory = - new ServiceConversationServiceFactory<EchoService>(this.server, - this.echoService, EchoService.class, 1000); - this.server.addServiceType(rmiServiceFactory); - - } - } - - public static class ClientBean implements IServiceConversationClientManagerRemote - { - - @Override - public void send(ServiceMessage message) - { - cont.process(message); - } - } - - @RequestMapping( - { "/client" }) - public static class ClientExporter extends HttpInvokerServiceExporter - { - @Override - public void afterPropertiesSet() - { - setServiceInterface(IServiceConversationClientManagerRemote.class); - setService(new ClientBean()); - super.afterPropertiesSet(); - } - } - - @RequestMapping( - { "/openbis/rmi-echoservice" }) - public static class EchoServiceExporter extends HttpInvokerServiceExporter - { - - @Resource(name = "echoService") - private EchoService echoService; - - @Override - public void afterPropertiesSet() - { - setServiceInterface(EchoService.class); - setService(echoService); - super.afterPropertiesSet(); - } - } - */ -} diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/ServiceConversationTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/ServiceConversationTest.java new file mode 100644 index 00000000000..c762e993c8f --- /dev/null +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/ServiceConversationTest.java @@ -0,0 +1,492 @@ +/* + * Copyright 2012 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.datastoreserver.systemtests; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.base.exceptions.TimeoutExceptionUnchecked; +import ch.systemsx.cisd.common.conversation.annotation.Conversational; +import ch.systemsx.cisd.common.conversation.annotation.Progress; +import ch.systemsx.cisd.common.conversation.client.ServiceConversationClientDetails; +import ch.systemsx.cisd.common.conversation.manager.BaseServiceConversationClientManager; +import ch.systemsx.cisd.common.conversation.manager.BaseServiceConversationServerManager; +import ch.systemsx.cisd.common.conversation.manager.IServiceConversationClientManagerRemote; +import ch.systemsx.cisd.common.conversation.manager.IServiceConversationServerManagerRemote; +import ch.systemsx.cisd.common.logging.LogInitializer; +import ch.systemsx.cisd.common.serviceconversation.client.ServiceExecutionException; +import ch.systemsx.cisd.common.spring.WaitAction; + +@Test +public class ServiceConversationTest +{ + + private static final int SERVER_PORT = 9000; + + private static final String SERVER_PATH = "/conversationServer"; + + private static final String SERVER_URL = "http://localhost:" + SERVER_PORT + SERVER_PATH; + + private static final int CLIENT_PORT_1 = 9001; + + private static final int CLIENT_PORT_2 = 9002; + + private static final String CLIENT_PATH = "/conversationClient"; + + private static final String CLIENT_URL_1 = "http://localhost:" + CLIENT_PORT_1 + CLIENT_PATH; + + private static final String CLIENT_URL_2 = "http://localhost:" + CLIENT_PORT_2 + CLIENT_PATH; + + private static final String SESSION_TOKEN_1 = "test-session-token-1"; + + private static final String SESSION_TOKEN_2 = "test-session-token-2"; + + private static final int TIMEOUT = 500; + + private static final Integer CLIENT_ID_1 = Integer.valueOf(1); + + private static final Integer CLIENT_ID_2 = Integer.valueOf(2); + + private Mockery context; + + private TestServiceWrapper1 serviceOnServerSideWrapper1; + + private TestServiceWrapper2 serviceOnServerSideWrapper2; + + private BaseServiceConversationClientManager clientManager1; + + private BaseServiceConversationClientManager clientManager2; + + private BaseServiceConversationServerManager serverManager; + + private ServiceExporter<?> clientExporter1; + + private ServiceExporter<?> clientExporter2; + + private ServiceExporter<?> serverExporter; + + @BeforeClass(alwaysRun = true) + public void beforeClass() throws Exception + { + LogInitializer.init(); + + serviceOnServerSideWrapper1 = new TestServiceWrapper1(); + serviceOnServerSideWrapper2 = new TestServiceWrapper2(); + + clientManager1 = createClientManager(); + clientManager2 = createClientManager(); + serverManager = createServerManager(); + + clientExporter1 = createClientExporter(CLIENT_PORT_1, clientManager1); + clientExporter2 = createClientExporter(CLIENT_PORT_2, clientManager2); + serverExporter = createServerExporter(serverManager); + + clientExporter1.getServer().start(); + clientExporter2.getServer().start(); + serverExporter.getServer().start(); + } + + @AfterClass(alwaysRun = true) + public void afterClass() throws Exception + { + clientExporter1.getServer().stop(); + clientExporter2.getServer().stop(); + serverExporter.getServer().stop(); + } + + @BeforeMethod + public void beforeMethod() throws Exception + { + context = new Mockery(); + + serviceOnServerSideWrapper1.setService(context.mock(TestService1.class)); + serviceOnServerSideWrapper2.setService(context.mock(TestService2.class)); + } + + private <S> S getServiceOnClientSide1(Class<S> serviceInterface) + { + return clientManager1.getService(SERVER_URL, serviceInterface, SESSION_TOKEN_1, + CLIENT_ID_1, TIMEOUT); + } + + private <S> S getServiceOnClientSide2(Class<S> serviceInterface) + { + return clientManager2.getService(SERVER_URL, serviceInterface, SESSION_TOKEN_2, + CLIENT_ID_2, TIMEOUT); + } + + @Test(expectedExceptions = ServiceExecutionException.class) + public void testNonConversationalMethod() throws Exception + { + getServiceOnClientSide1(TestService1.class).nonConversationalMethod(); + } + + @Test + public void testConversationalMethodWithoutReturnValue() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper1.getService()).methodWithoutReturnValue(); + } + }); + getServiceOnClientSide1(TestService1.class).methodWithoutReturnValue(); + } + + @Test + public void testConversationalMethodWithPrimitiveReturnValue() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper1.getService()).methodWithPrimitiveReturnValue(); + will(returnValue(1)); + } + }); + + Assert.assertEquals(getServiceOnClientSide1(TestService1.class) + .methodWithPrimitiveReturnValue(), 1); + } + + @Test + public void testConversationalMethodWithSerializableReturnValue() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper1.getService()) + .methodWithSerializableReturnValue(); + will(returnValue("abc")); + + } + }); + Assert.assertEquals(getServiceOnClientSide1(TestService1.class) + .methodWithSerializableReturnValue(), "abc"); + } + + @Test(expectedExceptions = TimeoutExceptionUnchecked.class) + public void testTimeout() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper1.getService()).methodWithoutReturnValue(); + will(new WaitAction(2 * TIMEOUT)); + } + }); + getServiceOnClientSide1(TestService1.class).methodWithoutReturnValue(); + } + + @Test + public void testMultipleClientsWithSameService() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper2.getService()).methodWithPrimitiveParameter(1); + will(returnValue(1)); + + one(serviceOnServerSideWrapper2.getService()).methodWithPrimitiveParameter(2); + will(returnValue(2)); + + one(serviceOnServerSideWrapper2.getService()).methodWithPrimitiveParameter(3); + will(returnValue(3)); + + one(serviceOnServerSideWrapper2.getService()).methodWithPrimitiveParameter(4); + will(returnValue(4)); + } + }); + Assert.assertEquals(getServiceOnClientSide1(TestService2.class) + .methodWithPrimitiveParameter(1), 1); + Assert.assertEquals(getServiceOnClientSide2(TestService2.class) + .methodWithPrimitiveParameter(2), 2); + Assert.assertEquals(getServiceOnClientSide2(TestService2.class) + .methodWithPrimitiveParameter(3), 3); + Assert.assertEquals(getServiceOnClientSide1(TestService2.class) + .methodWithPrimitiveParameter(4), 4); + } + + @Test + public void testMultipleClientsWithDifferentService() + { + context.checking(new Expectations() + { + { + one(serviceOnServerSideWrapper1.getService()).methodWithPrimitiveReturnValue(); + will(returnValue(1)); + + one(serviceOnServerSideWrapper2.getService()).methodWithPrimitiveParameter(2); + will(returnValue(2)); + } + }); + Assert.assertEquals(getServiceOnClientSide1(TestService1.class) + .methodWithPrimitiveReturnValue(), 1); + Assert.assertEquals(getServiceOnClientSide2(TestService2.class) + .methodWithPrimitiveParameter(2), 2); + } + + private BaseServiceConversationClientManager createClientManager() + { + return new BaseServiceConversationClientManager(); + } + + private BaseServiceConversationServerManager createServerManager() + { + return new BaseServiceConversationServerManager() + { + { + addService(TestService1.class, serviceOnServerSideWrapper1); + addService(TestService2.class, serviceOnServerSideWrapper2); + } + + @Override + protected ServiceConversationClientDetails getClientDetailsForClientId( + Object clientId) + { + if (clientId.equals(CLIENT_ID_1)) + { + return new ServiceConversationClientDetails(CLIENT_URL_1, TIMEOUT); + } else if (clientId.equals(CLIENT_ID_2)) + { + return new ServiceConversationClientDetails(CLIENT_URL_2, TIMEOUT); + } else + { + throw new IllegalArgumentException("Unknown client"); + } + } + }; + } + + private ServiceExporter<IServiceConversationClientManagerRemote> createClientExporter(int port, + BaseServiceConversationClientManager manager) + { + try + { + ServiceExporter<IServiceConversationClientManagerRemote> exporter = + new ServiceExporter<IServiceConversationClientManagerRemote>(port, CLIENT_PATH, + IServiceConversationClientManagerRemote.class, manager); + return exporter; + } catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private ServiceExporter<IServiceConversationServerManagerRemote> createServerExporter( + BaseServiceConversationServerManager manager) + { + try + { + ServiceExporter<IServiceConversationServerManagerRemote> exporter = + new ServiceExporter<IServiceConversationServerManagerRemote>(SERVER_PORT, + SERVER_PATH, IServiceConversationServerManagerRemote.class, manager); + return exporter; + } catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private class ServiceExporter<S> + { + + private Server server; + + public ServiceExporter(final int port, final String path, final Class<?> serviceInterface, + final S service) + { + SelectChannelConnector connector = new SelectChannelConnector(); + connector.setPort(port); + + this.server = new Server(); + this.server.addConnector(connector); + + DispatcherServlet dispatcher = new DispatcherServlet() + { + private static final long serialVersionUID = 1L; + + @Override + protected WebApplicationContext findWebApplicationContext() + { + GenericWebApplicationContext ctx = new GenericWebApplicationContext(); + + GenericBeanDefinition exporterBean = new GenericBeanDefinition(); + exporterBean.setBeanClass(HttpInvokerServiceExporter.class); + MutablePropertyValues exporterProperties = new MutablePropertyValues(); + exporterProperties.addPropertyValue("service", service); + exporterProperties.addPropertyValue("serviceInterface", serviceInterface); + exporterBean.setPropertyValues(exporterProperties); + ctx.registerBeanDefinition("serviceExporter", exporterBean); + + GenericBeanDefinition mappingBean = new GenericBeanDefinition(); + mappingBean.setBeanClass(SimpleUrlHandlerMapping.class); + Map<String, String> urlMap = new HashMap<String, String>(); + urlMap.put(path, "serviceExporter"); + MutablePropertyValues mappingProperties = new MutablePropertyValues(); + mappingProperties.addPropertyValue("urlMap", urlMap); + mappingBean.setPropertyValues(mappingProperties); + ctx.registerBeanDefinition("mapping", mappingBean); + + ctx.refresh(); + return ctx; + } + }; + + ServletContextHandler servletCtx = + new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); + servletCtx.addServlet(new ServletHolder(dispatcher), "/*"); + } + + public Server getServer() + { + return server; + } + + } + + public static interface TestService1 + { + + public void nonConversationalMethod(); + + @Conversational(progress = Progress.MANUAL) + public void methodWithoutReturnValue(); + + @Conversational(progress = Progress.MANUAL) + public int methodWithPrimitiveReturnValue(); + + @Conversational(progress = Progress.MANUAL) + public Serializable methodWithSerializableReturnValue(); + + } + + public static interface TestService2 + { + @Conversational(progress = Progress.MANUAL) + public int methodWithPrimitiveParameter(int parameter); + + @Conversational(progress = Progress.MANUAL) + public Serializable methodWithSerializableParameter(Serializable parameter); + + } + + public static interface TestServiceLocal + { + public void someLocalMethod(); + } + + public static class TestServiceWrapper1 implements TestServiceLocal, TestService1 + { + + private TestService1 service; + + @Override + public void nonConversationalMethod() + { + service.nonConversationalMethod(); + } + + @Override + public void methodWithoutReturnValue() + { + service.methodWithoutReturnValue(); + } + + @Override + public int methodWithPrimitiveReturnValue() + { + return service.methodWithPrimitiveReturnValue(); + } + + @Override + public Serializable methodWithSerializableReturnValue() + { + return service.methodWithSerializableReturnValue(); + } + + @Override + public void someLocalMethod() + { + } + + public TestService1 getService() + { + return service; + } + + public void setService(TestService1 service) + { + this.service = service; + } + + } + + public static class TestServiceWrapper2 implements TestServiceLocal, TestService2 + { + + private TestService2 service; + + @Override + public int methodWithPrimitiveParameter(int parameter) + { + return service.methodWithPrimitiveParameter(parameter); + } + + @Override + public Serializable methodWithSerializableParameter(Serializable parameter) + { + return service.methodWithSerializableParameter(parameter); + } + + @Override + public void someLocalMethod() + { + } + + public TestService2 getService() + { + return service; + } + + public void setService(TestService2 service) + { + this.service = service; + } + + } + +} diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java index 6721f7c77cc..843f16877aa 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/SystemTestCase.java @@ -147,25 +147,6 @@ public abstract class SystemTestCase extends AssertJUnit applicationContext = new GenericWebApplicationContext(f); applicationContext.setParent(new ClassPathXmlApplicationContext( getApplicationContextLocation())); - - /* Needed for RmiConversationTest */ - /* - * GenericBeanDefinition definition = new GenericBeanDefinition(); - * MutablePropertyValues values = new MutablePropertyValues(); - * values.addPropertyValue("sessionFactory", new RuntimeBeanReference( - * "hibernate-session-factory")); values.addPropertyValue("echoService", new - * RuntimeBeanReference( "echoService")); definition.setPropertyValues(values); - * definition.setBeanClass(EchoServiceBean.class); - * applicationContext.registerBeanDefinition("echoService", definition); - */ - - /* Needed for RmiConversationTest */ - /* - * GenericBeanDefinition exporter = new GenericBeanDefinition(); - * exporter.setBeanClass(EchoServiceExporter.class); - * applicationContext.registerBeanDefinition("echoServiceExporter", exporter); - */ - applicationContext.refresh(); return applicationContext; } diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/conversation/manager/BaseServiceConversationServerManager.java b/openbis-common/source/java/ch/systemsx/cisd/common/conversation/manager/BaseServiceConversationServerManager.java index 2e340d8923e..06895711641 100644 --- a/openbis-common/source/java/ch/systemsx/cisd/common/conversation/manager/BaseServiceConversationServerManager.java +++ b/openbis-common/source/java/ch/systemsx/cisd/common/conversation/manager/BaseServiceConversationServerManager.java @@ -19,8 +19,6 @@ package ch.systemsx.cisd.common.conversation.manager; import java.util.HashMap; import java.util.Map; -import org.springframework.beans.factory.InitializingBean; - import ch.systemsx.cisd.common.conversation.client.ServiceConversationClientDetails; import ch.systemsx.cisd.common.serviceconversation.ServiceConversationDTO; import ch.systemsx.cisd.common.serviceconversation.ServiceMessage; @@ -32,7 +30,7 @@ import ch.systemsx.cisd.common.spring.HttpInvokerUtils; * @author pkupczyk */ public abstract class BaseServiceConversationServerManager implements - IServiceConversationServerManagerRemote, InitializingBean + IServiceConversationServerManagerRemote { private ServiceConversationServer server; @@ -48,18 +46,10 @@ public abstract class BaseServiceConversationServerManager implements server = new ServiceConversationServer(); } - @Override - public void afterPropertiesSet() throws Exception - { - initializeServices(); - } - - protected abstract void initializeServices(); - - protected void addService(String serviceName, Object service) + protected void addService(Class<?> serviceInterface, Object service) { ServiceConversationServiceFactory serviceFactory = - new ServiceConversationServiceFactory(server, serviceName, service) + new ServiceConversationServiceFactory(server, serviceInterface.getName(), service) { @Override protected int getProgressInterval(String conversationId) diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/conversation/message/ServiceConversationMethodInvocation.java b/openbis-common/source/java/ch/systemsx/cisd/common/conversation/message/ServiceConversationMethodInvocation.java index ff31ff734c4..47a293bb4d9 100644 --- a/openbis-common/source/java/ch/systemsx/cisd/common/conversation/message/ServiceConversationMethodInvocation.java +++ b/openbis-common/source/java/ch/systemsx/cisd/common/conversation/message/ServiceConversationMethodInvocation.java @@ -19,6 +19,7 @@ package ch.systemsx.cisd.common.conversation.message; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; import org.springframework.remoting.support.RemoteInvocation; @@ -100,19 +101,30 @@ public class ServiceConversationMethodInvocation implements Serializable private Method findMethodOn(Object o) throws SecurityException, NoSuchMethodException { - Method method = null; + Method methodFound = null; for (Class<?> inter : o.getClass().getInterfaces()) { - method = inter.getMethod(invocation.getMethodName(), invocation.getParameterTypes()); + Method[] methods = inter.getMethods(); - if (method != null && method.isAnnotationPresent(Conversational.class)) + for (Method method : methods) { - return method; + if (method.getName().equals(invocation.getMethodName()) + && Arrays + .equals(method.getParameterTypes(), invocation.getParameterTypes())) + { + methodFound = method; + break; + } + } + + if (methodFound != null && methodFound.isAnnotationPresent(Conversational.class)) + { + return methodFound; } } - if (method == null) + if (methodFound == null) { throw new NoSuchMethodException( "No method found for the service conversation invocation: " + invocation); diff --git a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/spring/WaitAction.java b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/spring/WaitAction.java index 8ec19e11fe8..4e273b301e2 100644 --- a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/spring/WaitAction.java +++ b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/spring/WaitAction.java @@ -5,19 +5,17 @@ import org.jmock.api.Action; import org.jmock.api.Invocation; /** - * - * * @author Franz-Josef Elmer */ -final class WaitAction implements Action +public final class WaitAction implements Action { private final long waitingTime; - WaitAction(long waitingTime) + public WaitAction(long waitingTime) { this.waitingTime = waitingTime; } - + @Override public Object invoke(Invocation inv) throws Throwable { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceConversationServerManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceConversationServerManager.java index 42784d6fb38..a3e51731a48 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceConversationServerManager.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceConversationServerManager.java @@ -19,6 +19,8 @@ package ch.systemsx.cisd.openbis.generic.server; import java.util.HashMap; import java.util.Map; +import org.springframework.beans.factory.InitializingBean; + import ch.systemsx.cisd.common.conversation.client.ServiceConversationClientDetails; import ch.systemsx.cisd.common.conversation.manager.BaseServiceConversationServerManager; import ch.systemsx.cisd.openbis.generic.server.business.IServiceConversationServerManagerLocal; @@ -31,7 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.conversation.ServiceConversationD */ public class ServiceConversationServerManager extends BaseServiceConversationServerManager - implements IServiceConversationServerManagerLocal + implements IServiceConversationServerManagerLocal, InitializingBean { private Map<Object, ServiceConversationClientDetails> dataStoreIdToDataStoreDetailsMap = @@ -40,9 +42,9 @@ public class ServiceConversationServerManager extends BaseServiceConversationSer private IETLLIMSService etlService; @Override - protected void initializeServices() + public void afterPropertiesSet() throws Exception { - addService(IETLLIMSService.class.getName(), etlService); + addService(IETLLIMSService.class, etlService); } @Override -- GitLab