Merge "Spec: OFPGC_ADD_OR_MOD support in openflowplugin"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / services / multilayer / MultiLayerExperimenterMultipartService.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.impl.services.multilayer;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import com.google.common.util.concurrent.SettableFuture;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.concurrent.Future;
21 import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
22 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
23 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
24 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
25 import org.opendaylight.openflowplugin.extension.api.ConverterMessageToOFJava;
26 import org.opendaylight.openflowplugin.extension.api.ConvertorMessageFromOFJava;
27 import org.opendaylight.openflowplugin.extension.api.TypeVersionKey;
28 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider;
29 import org.opendaylight.openflowplugin.extension.api.exception.ConversionException;
30 import org.opendaylight.openflowplugin.extension.api.exception.ConverterNotFoundException;
31 import org.opendaylight.openflowplugin.extension.api.path.MessagePath;
32 import org.opendaylight.openflowplugin.impl.services.AbstractExperimenterMultipartService;
33 import org.opendaylight.openflowplugin.impl.services.util.RequestInputUtils;
34 import org.opendaylight.openflowplugin.impl.services.util.ServiceException;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.SendExperimenterMpRequestOutputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.send.experimenter.mp.request.output.ExperimenterCoreMessageItem;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.mp.message.service.rev151020.send.experimenter.mp.request.output.ExperimenterCoreMessageItemBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.experimenter.core.ExperimenterDataOfChoice;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyExperimenterCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.experimenter._case.MultipartReplyExperimenter;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestExperimenterCaseBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.experimenter._case.MultipartRequestExperimenterBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.experimenter.types.rev151020.experimenter.core.message.ExperimenterMessageOfChoice;
49 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
50 import org.opendaylight.yangtools.yang.common.RpcResult;
51 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
52 import org.slf4j.Logger;
53
54 public class MultiLayerExperimenterMultipartService extends AbstractExperimenterMultipartService<MultipartReply> {
55
56     private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(MultiLayerExperimenterMultipartService.class);
57
58     public MultiLayerExperimenterMultipartService(RequestContextStack requestContextStack, DeviceContext deviceContext,
59                                                   ExtensionConverterProvider extensionConverterProvider) {
60         super(requestContextStack, deviceContext, extensionConverterProvider);
61     }
62
63     @Override
64     @SuppressWarnings("unchecked")
65     protected OfHeader buildRequest(Xid xid, SendExperimenterMpRequestInput input) throws ServiceException {
66         final TypeVersionKey key = new TypeVersionKey<>(
67             input.getExperimenterMessageOfChoice().getImplementedInterface(),
68             getVersion());
69
70         final ConverterMessageToOFJava<ExperimenterMessageOfChoice, ExperimenterDataOfChoice> messageConverter =
71             getExtensionConverterProvider().getMessageConverter(key);
72
73         if (Objects.isNull(messageConverter)) {
74             throw new ServiceException(new ConverterNotFoundException(key.toString()));
75         }
76
77         try {
78             return RequestInputUtils
79                 .createMultipartHeader(MultipartType.OFPMPEXPERIMENTER, xid.getValue(), getVersion())
80                 .setMultipartRequestBody(new MultipartRequestExperimenterCaseBuilder()
81                     .setMultipartRequestExperimenter(new MultipartRequestExperimenterBuilder()
82                         .setExperimenter(messageConverter.getExperimenterId())
83                         .setExpType(messageConverter.getType())
84                         .setExperimenterDataOfChoice(messageConverter
85                             .convert(input.getExperimenterMessageOfChoice()))
86                         .build())
87                     .build())
88                 .build();
89         } catch (final ConversionException e) {
90             throw new ServiceException(e);
91         }
92     }
93
94     @Override
95     @SuppressWarnings("unchecked")
96     public Future<RpcResult<SendExperimenterMpRequestOutput>> handleAndReply(SendExperimenterMpRequestInput input) {
97         final ListenableFuture<RpcResult<List<MultipartReply>>> multipartFuture = handleServiceCall(input);
98         final SettableFuture<RpcResult<SendExperimenterMpRequestOutput>> finalFuture = SettableFuture.create();
99
100         class CallBackImpl implements FutureCallback<RpcResult<List<MultipartReply>>> {
101             @Override
102             public void onSuccess(final RpcResult<List<MultipartReply>> result) {
103                 if (result.isSuccessful()) {
104                     final List<MultipartReply> multipartReplies = result.getResult();
105                     if (multipartReplies.isEmpty()) {
106                         LOG.warn("Multipart reply to Experimenter-Mp request shouldn't be empty list.");
107                         finalFuture.set(RpcResultBuilder.<SendExperimenterMpRequestOutput>failed()
108                                 .withError(ErrorType.RPC, "Multipart reply list is empty.").build());
109                     } else {
110                         LOG.debug(
111                                 "OnSuccess, rpc result successful,"
112                                         + " multipart response for rpc sendExperimenterMpRequest with xid {} obtained.",
113                                 multipartReplies.get(0).getXid());
114                         final SendExperimenterMpRequestOutputBuilder sendExpMpReqOutputBuilder =
115                                 new SendExperimenterMpRequestOutputBuilder();
116                         final List<ExperimenterCoreMessageItem> expCoreMessageItem = new ArrayList<>();
117                         for (MultipartReply multipartReply : multipartReplies) {
118                             final MultipartReplyExperimenterCase caseBody =
119                                     (MultipartReplyExperimenterCase)multipartReply.getMultipartReplyBody();
120                             final MultipartReplyExperimenter replyBody = caseBody.getMultipartReplyExperimenter();
121                             final ExperimenterDataOfChoice vendorData = replyBody.getExperimenterDataOfChoice();
122                             final MessageTypeKey<? extends ExperimenterDataOfChoice> key = new MessageTypeKey<>(
123                                     getVersion(),
124                                     (Class<? extends ExperimenterDataOfChoice>) vendorData.getImplementedInterface());
125                             final ConvertorMessageFromOFJava<ExperimenterDataOfChoice, MessagePath> messageConverter =
126                                     getExtensionConverterProvider().getMessageConverter(key);
127                             if (messageConverter == null) {
128                                 LOG.warn("Custom converter for {}[OF:{}] not found",
129                                         vendorData.getImplementedInterface(),
130                                         getVersion());
131                                 finalFuture.set(RpcResultBuilder.<SendExperimenterMpRequestOutput>failed()
132                                         .withError(ErrorType.RPC, "Custom converter not found.").build());
133                                 return;
134                             }
135                             try {
136                                 final ExperimenterMessageOfChoice messageOfChoice =
137                                         messageConverter.convert(vendorData, MessagePath.MPMESSAGE_RPC_OUTPUT);
138                                 final ExperimenterCoreMessageItemBuilder expCoreMessageItemBuilder =
139                                         new ExperimenterCoreMessageItemBuilder();
140                                 expCoreMessageItemBuilder.setExperimenterMessageOfChoice(messageOfChoice);
141                                 expCoreMessageItem.add(expCoreMessageItemBuilder.build());
142                             } catch (final ConversionException e) {
143                                 LOG.error("Conversion of experimenter message reply failed. Exception: {}", e);
144                                 finalFuture.set(RpcResultBuilder.<SendExperimenterMpRequestOutput>failed()
145                                         .withError(ErrorType.RPC,
146                                                    "Conversion of experimenter rpc output failed.").build());
147                                 return;
148                             }
149                         }
150                         sendExpMpReqOutputBuilder.setExperimenterCoreMessageItem(expCoreMessageItem);
151                         finalFuture.set(RpcResultBuilder.success(sendExpMpReqOutputBuilder.build()).build());
152                     }
153                 } else {
154                     LOG.warn("OnSuccess, rpc result unsuccessful,"
155                             + " multipart response for rpc sendExperimenterMpRequest was unsuccessful.");
156                     finalFuture.set(RpcResultBuilder.<SendExperimenterMpRequestOutput>failed()
157                             .withRpcErrors(result.getErrors()).build());
158                 }
159             }
160
161             @Override
162             public void onFailure(final Throwable throwable) {
163                 LOG.warn("Failure multipart response for Experimenter-Mp request. Exception: {}", throwable);
164                 finalFuture.set(RpcResultBuilder.<SendExperimenterMpRequestOutput>failed()
165                         .withError(ErrorType.RPC, "Future error", throwable).build());
166             }
167         }
168
169         Futures.addCallback(multipartFuture, new CallBackImpl(), MoreExecutors.directExecutor());
170
171         return finalFuture;
172     }
173
174     @VisibleForTesting
175     OfHeader buildRequestTest(Xid xid, SendExperimenterMpRequestInput input) throws ServiceException {
176         return buildRequest(xid, input);
177     }
178 }
179