Implement SalExperimenterMpMessageService 33/47733/2
authorTomas Slusny <tomas.slusny@pantheon.tech>
Thu, 27 Oct 2016 12:35:19 +0000 (14:35 +0200)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Mon, 7 Nov 2016 12:16:45 +0000 (12:16 +0000)
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 <tomas.slusny@pantheon.tech>
(cherry picked from commit cf84afd05137e68dcda33f88ae30312b649d79a9)

openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImpl.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/SalExperimenterMpMessageServiceImplTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/ServiceMocking.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.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 (file)
index 0000000..9797ece
--- /dev/null
@@ -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<SendExperimenterMpRequestInput> 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<RpcResult<SendExperimenterMpRequestOutput>> sendExperimenterMpRequest(SendExperimenterMpRequestInput input) {
+        return Futures.lazyTransform(handleServiceCall(input), new Function<RpcResult<List<MultipartReply>>, RpcResult<SendExperimenterMpRequestOutput>>() {
+            @Nullable
+            @Override
+            public RpcResult<SendExperimenterMpRequestOutput> apply(final RpcResult<List<MultipartReply>> result) {
+                return result.isSuccessful()
+                        ? RpcResultBuilder
+                                .success(new SendExperimenterMpRequestOutputBuilder()
+                                        .setExperimenterMessageOfChoice(input.getExperimenterMessageOfChoice()))
+                                .build()
+                        : RpcResultBuilder
+                                .<SendExperimenterMpRequestOutput>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<ExperimenterMessageOfChoice, ExperimenterDataOfChoice> 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);
+        }
+    }
+}
index a1ea39d2dde8603c0ad9ee4694f69d305cbffb70..781776ad70eed29cc02fbe3d5369600ecac3b761 100644 (file)
@@ -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 (file)
index 0000000..cf1d460
--- /dev/null
@@ -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<ExperimenterMessageOfChoice, DataContainer> mockedExtensionConverter;
+
+    @Override
+    protected void setup() {
+        when(mockedExtensionConverterProvider.getMessageConverter(Matchers.<TypeVersionKey>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<? extends DataContainer> getImplementedInterface() {
+            return DummyExperimenter.class;
+        }
+    }
+}
\ No newline at end of file
index 05f8c9c2e1a447fb8174a30fdfa79e20d57e59dd..fafa4df3f810fa407fd820673d42c508a7f54764 100644 (file)
@@ -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);
index 33f544b022d63d34dd63beca6ef00dda0ea8bee3..61f994824b4b75094d552d6385157c07d5df0af9 100644 (file)
@@ -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() {