From 6990bb0fe2e30c0d3985b8a53d5e13a35e01fa0a Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Thu, 27 Oct 2016 14:35:19 +0200 Subject: [PATCH] Implement SalExperimenterMpMessageService Add missing implementation for experimenter multipart message RPC service and register it as routed RPC implementation Resolves: bug 6820 Change-Id: I5646f93dd6375b729e995a9e60e6d688f1508559 Signed-off-by: Tomas Slusny (cherry picked from commit cf84afd05137e68dcda33f88ae30312b649d79a9) --- .../SalExperimenterMpMessageServiceImpl.java | 98 +++++++++++++++++ .../impl/util/MdSalRegistrationUtils.java | 41 ++----- ...lExperimenterMpMessageServiceImplTest.java | 101 ++++++++++++++++++ .../impl/services/ServiceMocking.java | 1 + .../impl/util/MdSalRegistrationUtilsTest.java | 2 +- 5 files changed, 210 insertions(+), 33 deletions(-) create mode 100644 openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImpl.java create mode 100644 openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImplTest.java diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImpl.java new file mode 100644 index 0000000000..9797ece901 --- /dev/null +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImpl.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.impl.services; + +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Future; +import javax.annotation.Nullable; +import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; +import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack; +import org.opendaylight.openflowplugin.api.openflow.device.Xid; +import org.opendaylight.openflowplugin.extension.api.ConvertorMessageToOFJava; +import org.opendaylight.openflowplugin.extension.api.TypeVersionKey; +import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider; +import org.opendaylight.openflowplugin.extension.api.exception.ConversionException; +import org.opendaylight.openflowplugin.extension.api.exception.ConverterNotFoundException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SalExperimenterMpMessageService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.experimenter.core.ExperimenterDataOfChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestExperimenterCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.experimenter._case.MultipartRequestExperimenterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.experimenter.types.rev151020.experimenter.core.message.ExperimenterMessageOfChoice; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +public class SalExperimenterMpMessageServiceImpl extends AbstractMultipartService implements SalExperimenterMpMessageService { + private final ExtensionConverterProvider extensionConverterProvider; + + public SalExperimenterMpMessageServiceImpl(final RequestContextStack requestContextStack, + final DeviceContext deviceContext, + final ExtensionConverterProvider extensionConverterProvider) { + super(requestContextStack, deviceContext); + this.extensionConverterProvider = extensionConverterProvider; + } + + @Override + public Future> sendExperimenterMpRequest(SendExperimenterMpRequestInput input) { + return Futures.lazyTransform(handleServiceCall(input), new Function>, RpcResult>() { + @Nullable + @Override + public RpcResult apply(final RpcResult> result) { + return result.isSuccessful() + ? RpcResultBuilder + .success(new SendExperimenterMpRequestOutputBuilder() + .setExperimenterMessageOfChoice(input.getExperimenterMessageOfChoice())) + .build() + : RpcResultBuilder + .failed() + .withRpcErrors(result.getErrors()) + .build(); + } + }); + } + + @Override + @SuppressWarnings("unchecked") + protected OfHeader buildRequest(Xid xid, SendExperimenterMpRequestInput input) throws ServiceException { + final TypeVersionKey key = new TypeVersionKey( + input.getExperimenterMessageOfChoice().getImplementedInterface(), + getVersion()); + + final ConvertorMessageToOFJava messageConverter = + extensionConverterProvider.getMessageConverter(key); + + if (Objects.isNull(messageConverter)) { + throw new ServiceException(new ConverterNotFoundException(key.toString())); + } + + try { + return RequestInputUtils + .createMultipartHeader(MultipartType.OFPMPEXPERIMENTER, xid.getValue(), getVersion()) + .setMultipartRequestBody(new MultipartRequestExperimenterCaseBuilder() + .setMultipartRequestExperimenter(new MultipartRequestExperimenterBuilder() + .setExperimenter(messageConverter.getExperimenterId()) + .setExpType(messageConverter.getType()) + .setExperimenterDataOfChoice(messageConverter + .convert(input.getExperimenterMessageOfChoice())) + .build()) + .build()) + .build(); + } catch (final ConversionException e) { + throw new ServiceException(e); + } + } +} diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java index a1ea39d2dd..781776ad70 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java @@ -21,6 +21,7 @@ import org.opendaylight.openflowplugin.impl.services.NodeConfigServiceImpl; import org.opendaylight.openflowplugin.impl.services.PacketProcessingServiceImpl; import org.opendaylight.openflowplugin.impl.services.SalEchoServiceImpl; import org.opendaylight.openflowplugin.impl.services.SalExperimenterMessageServiceImpl; +import org.opendaylight.openflowplugin.impl.services.SalExperimenterMpMessageServiceImpl; import org.opendaylight.openflowplugin.impl.services.SalFlatBatchServiceImpl; import org.opendaylight.openflowplugin.impl.services.SalFlowServiceImpl; import org.opendaylight.openflowplugin.impl.services.SalFlowsBatchServiceImpl; @@ -48,6 +49,7 @@ import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorE import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.echo.service.rev150305.SalEchoService; import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.message.service.rev151020.SalExperimenterMessageService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SalExperimenterMpMessageService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; @@ -64,7 +66,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.O import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService; -import org.opendaylight.yangtools.yang.binding.RpcService; public class MdSalRegistrationUtils { @@ -101,7 +102,6 @@ public class MdSalRegistrationUtils { // register routed service instances rpcContext.registerRpcServiceImplementation(SalEchoService.class, new SalEchoServiceImpl(rpcContext, deviceContext)); rpcContext.registerRpcServiceImplementation(SalFlowService.class, salFlowService); - //TODO: add constructors with rcpContext and deviceContext to meter, group, table constructors rpcContext.registerRpcServiceImplementation(FlowCapableTransactionService.class, flowCapableTransactionService); rpcContext.registerRpcServiceImplementation(SalMeterService.class, salMeterService); rpcContext.registerRpcServiceImplementation(SalGroupService.class, salGroupService); @@ -111,7 +111,7 @@ public class MdSalRegistrationUtils { rpcContext.registerRpcServiceImplementation(NodeConfigService.class, new NodeConfigServiceImpl(rpcContext, deviceContext)); rpcContext.registerRpcServiceImplementation(OpendaylightFlowStatisticsService.class, OpendaylightFlowStatisticsServiceImpl.createWithOook(rpcContext, deviceContext, convertorExecutor)); - // Direct statistics gathering + // register direct statistics gathering services final OpendaylightDirectStatisticsServiceProvider statisticsProvider = new OpendaylightDirectStatisticsServiceProvider(); statisticsProvider.register(FlowDirectStatisticsService.class, new FlowDirectStatisticsService(rpcContext, deviceContext, convertorExecutor)); statisticsProvider.register(GroupDirectStatisticsService.class, new GroupDirectStatisticsService(rpcContext, deviceContext, convertorExecutor)); @@ -120,41 +120,18 @@ public class MdSalRegistrationUtils { statisticsProvider.register(QueueDirectStatisticsService.class, new QueueDirectStatisticsService(rpcContext, deviceContext, convertorExecutor)); rpcContext.registerRpcServiceImplementation(OpendaylightDirectStatisticsService.class, new OpendaylightDirectStatisticsServiceImpl(statisticsProvider)); - final SalFlatBatchServiceImpl salFlatBatchService = new SalFlatBatchServiceImpl( + // register flat batch services + rpcContext.registerRpcServiceImplementation(SalFlatBatchService.class, new SalFlatBatchServiceImpl( new SalFlowsBatchServiceImpl(salFlowService, flowCapableTransactionService), new SalGroupsBatchServiceImpl(salGroupService, flowCapableTransactionService), new SalMetersBatchServiceImpl(salMeterService, flowCapableTransactionService) - ); - rpcContext.registerRpcServiceImplementation(SalFlatBatchService.class, salFlatBatchService); + )); - // TODO: experimenter symmetric and multipart message services + // register experimenter services rpcContext.registerRpcServiceImplementation(SalExperimenterMessageService.class, new SalExperimenterMessageServiceImpl(rpcContext, deviceContext, extensionConverterProvider)); - } - - /** - * Method unregisters all OF services. - * - * @param rpcContext - unregistration processing is implemented in {@link RpcContext} - */ - public static void unregisterServices(@CheckForNull final RpcContext rpcContext) { - Preconditions.checkArgument(rpcContext != null); - - rpcContext.unregisterRpcServiceImplementation(SalEchoService.class); - rpcContext.unregisterRpcServiceImplementation(SalFlowService.class); - //TODO: add constructors with rcpContext and deviceContext to meter, group, table constructors - rpcContext.unregisterRpcServiceImplementation(FlowCapableTransactionService.class); - rpcContext.unregisterRpcServiceImplementation(SalMeterService.class); - rpcContext.unregisterRpcServiceImplementation(SalGroupService.class); - rpcContext.unregisterRpcServiceImplementation(SalTableService.class); - rpcContext.unregisterRpcServiceImplementation(SalPortService.class); - rpcContext.unregisterRpcServiceImplementation(PacketProcessingService.class); - rpcContext.unregisterRpcServiceImplementation(NodeConfigService.class); - rpcContext.unregisterRpcServiceImplementation(OpendaylightFlowStatisticsService.class); - rpcContext.unregisterRpcServiceImplementation(SalFlatBatchService.class); - // TODO: experimenter symmetric and multipart message services - rpcContext.unregisterRpcServiceImplementation(SalExperimenterMessageService.class); - rpcContext.unregisterRpcServiceImplementation(OpendaylightDirectStatisticsService.class); + rpcContext.registerRpcServiceImplementation(SalExperimenterMpMessageService.class, + new SalExperimenterMpMessageServiceImpl(rpcContext, deviceContext, extensionConverterProvider)); } /** diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImplTest.java new file mode 100644 index 0000000000..cf1d4601ff --- /dev/null +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImplTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.impl.services; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.opendaylight.openflowplugin.api.openflow.device.Xid; +import org.opendaylight.openflowplugin.extension.api.ConvertorMessageToOFJava; +import org.opendaylight.openflowplugin.extension.api.TypeVersionKey; +import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ExperimenterId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestExperimenterCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.experimenter._case.MultipartRequestExperimenter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.experimenter.types.rev151020.experimenter.core.message.ExperimenterMessageOfChoice; +import org.opendaylight.yangtools.yang.binding.DataContainer; + +public class SalExperimenterMpMessageServiceImplTest extends ServiceMocking { + private static final long DUMMY_ID = 42L; + private SalExperimenterMpMessageServiceImpl salExperimenterMpMessageService; + + @Mock + private ExtensionConverterProvider mockedExtensionConverterProvider; + + @Mock + private ConvertorMessageToOFJava mockedExtensionConverter; + + @Override + protected void setup() { + when(mockedExtensionConverterProvider.getMessageConverter(Matchers.any())) + .thenReturn(mockedExtensionConverter); + + when(mockedExtensionConverter.getExperimenterId()) + .thenReturn(new ExperimenterId(DUMMY_ID)); + + when(mockedExtensionConverter.getType()) + .thenReturn((long) MultipartType.OFPMPEXPERIMENTER.getIntValue()); + + salExperimenterMpMessageService = new SalExperimenterMpMessageServiceImpl( + mockedRequestContextStack, + mockedDeviceContext, + mockedExtensionConverterProvider); + } + + @Test + public void sendExperimenterMpRequest() throws Exception { + salExperimenterMpMessageService.sendExperimenterMpRequest(new SendExperimenterMpRequestInputBuilder() + .setExperimenterMessageOfChoice(new DummyExperimenter()) + .setNode(new NodeRef(mockedDeviceInfo.getNodeInstanceIdentifier())) + .build()); + + verify(mockedRequestContextStack).createRequestContext(); + } + + @Test + public void buildRequest() throws Exception { + final SendExperimenterMpRequestInput data = new SendExperimenterMpRequestInputBuilder() + .setExperimenterMessageOfChoice(new DummyExperimenter()) + .setNode(new NodeRef(mockedDeviceInfo.getNodeInstanceIdentifier())) + .build(); + + final OfHeader ofHeader = salExperimenterMpMessageService.buildRequest(new Xid(DUMMY_ID), data); + verify(mockedExtensionConverter).convert(data.getExperimenterMessageOfChoice()); + assertEquals(DUMMY_ID, (long) ofHeader.getXid()); + assertEquals(mockedDeviceInfo.getVersion(), (short) ofHeader.getVersion()); + assertEquals(MultipartRequestInput.class, ofHeader.getImplementedInterface()); + + final MultipartRequestInput input = MultipartRequestInput.class.cast(ofHeader); + assertEquals(MultipartRequestExperimenterCase.class, input.getMultipartRequestBody().getImplementedInterface()); + + final MultipartRequestExperimenter multipartRequestExperimenter = + MultipartRequestExperimenterCase.class.cast(input.getMultipartRequestBody()) + .getMultipartRequestExperimenter(); + + assertEquals(DUMMY_ID, (long) multipartRequestExperimenter.getExperimenter().getValue()); + assertEquals(MultipartType.OFPMPEXPERIMENTER.getIntValue(), (long) multipartRequestExperimenter.getExpType()); + } + + private static class DummyExperimenter implements ExperimenterMessageOfChoice { + @Override + public Class getImplementedInterface() { + return DummyExperimenter.class; + } + } +} \ No newline at end of file diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/ServiceMocking.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/ServiceMocking.java index 05f8c9c2e1..fafa4df3f8 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/ServiceMocking.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/ServiceMocking.java @@ -87,6 +87,7 @@ public abstract class ServiceMocking { public void initialization() { when(mockedRequestContextStack.createRequestContext()).thenReturn(mockedRequestContext); when(mockedRequestContext.getXid()).thenReturn(DUMMY_XID); + when(mockedRequestContext.getFuture()).thenReturn(Futures.immediateFuture(null)); when(mockedFeatures.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID); when(mockedFeatures.getVersion()).thenReturn(DUMMY_VERSION); diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java index 33f544b022..61f994824b 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java @@ -35,7 +35,7 @@ public class MdSalRegistrationUtilsTest { * Number of currently registrated services (can be changed) * (RpcContext, DeviceContext)} */ - private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 13; + private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 14; @Test public void registerServiceTest() { -- 2.36.6