Merge "Adding ofplugin-config classifier to poms"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / services / SalFlowServiceImpl.java
1 /**
2  * Copyright (c) 2015 Cisco Systems, Inc. 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 package org.opendaylight.openflowplugin.impl.services;
9
10 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
11 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
12 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
13 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
14 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.SettableFuture;
17 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
18 import org.opendaylight.yangtools.yang.binding.DataObject;
19 import com.google.common.base.Function;
20 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.JdkFutureAdapters;
22 import com.google.common.util.concurrent.ListenableFuture;
23 import java.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.concurrent.Future;
27 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
28 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.FlowConvertor;
29 import org.opendaylight.openflowplugin.openflow.md.util.FlowCreatorUtil;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.slf4j.Logger;
44
45 public class SalFlowServiceImpl extends CommonService implements SalFlowService {
46
47     private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(SalFlowServiceImpl.class);
48
49
50     public SalFlowServiceImpl(final RequestContextStack requestContextStack, final DeviceContext deviceContext) {
51         super(requestContextStack, deviceContext);
52     }
53
54     <T extends DataObject, F> ListenableFuture<RpcResult<T>> handleServiceCall(final BigInteger connectionID,
55             final FlowModInputBuilder flowModInputBuilder, final Function<DataCrate<T>, Future<RpcResult<F>>> function) {
56         LOG.debug("Calling the FlowMod RPC method on MessageDispatchService");
57
58         final RequestContext<T> requestContext = requestContextStack.createRequestContext();
59         final SettableFuture<RpcResult<T>> result = requestContextStack.storeOrFail(requestContext);
60         final DataCrate<T> dataCrate = DataCrateBuilder.<T> builder().setiDConnection(connectionID)
61                 .setRequestContext(requestContext).setFlowModInputBuilder(flowModInputBuilder).build();
62
63         if (!result.isDone()) {
64             final Future<RpcResult<F>> resultFromOFLib = function.apply(dataCrate);
65
66             final RpcResultConvertor<T> rpcResultConvertor = new RpcResultConvertor<>(requestContext, deviceContext);
67             rpcResultConvertor.processResultFromOfJava(resultFromOFLib);
68
69         } else {
70             RequestContextUtil.closeRequstContext(requestContext);
71         }
72         return result;
73     }
74
75     @Override
76     public Future<RpcResult<AddFlowOutput>> addFlow(final AddFlowInput input) {
77         final List<FlowModInputBuilder> ofFlowModInputs = FlowConvertor.toFlowModInputs(input, version, datapathId);
78         return processFlowModInputBuilders(ofFlowModInputs);
79     }
80
81     @Override
82     public Future<RpcResult<RemoveFlowOutput>> removeFlow(final RemoveFlowInput input) {
83
84         return this.<RemoveFlowOutput, Void> handleServiceCall(PRIMARY_CONNECTION,
85                 new Function<DataCrate<RemoveFlowOutput>, Future<RpcResult<Void>>>() {
86                     @Override
87                     public Future<RpcResult<Void>> apply(final DataCrate<RemoveFlowOutput> data) {
88                         final FlowModInputBuilder ofFlowModInput = FlowConvertor.toFlowModInput(input, version,
89                                 datapathId);
90                         return createResultForFlowMod(data, ofFlowModInput);
91                     }
92                 });
93     }
94
95     @Override
96     public Future<RpcResult<UpdateFlowOutput>> updateFlow(final UpdateFlowInput input) {
97         final UpdateFlowInput in = input;
98         final UpdatedFlow updated = in.getUpdatedFlow();
99         final OriginalFlow original = in.getOriginalFlow();
100
101         final List<FlowModInputBuilder> allFlowMods = new ArrayList<>();
102         List<FlowModInputBuilder> ofFlowModInputs;
103
104         if (!FlowCreatorUtil.canModifyFlow(original, updated, version)) {
105             // We would need to remove original and add updated.
106
107             // remove flow
108             final RemoveFlowInputBuilder removeflow = new RemoveFlowInputBuilder(original);
109             final List<FlowModInputBuilder> ofFlowRemoveInput = FlowConvertor.toFlowModInputs(removeflow.build(),
110                     version, datapathId);
111             // remove flow should be the first
112             allFlowMods.addAll(ofFlowRemoveInput);
113             final AddFlowInputBuilder addFlowInputBuilder = new AddFlowInputBuilder(updated);
114             ofFlowModInputs = FlowConvertor.toFlowModInputs(addFlowInputBuilder.build(), version, datapathId);
115         } else {
116             ofFlowModInputs = FlowConvertor.toFlowModInputs(updated, version, datapathId);
117         }
118
119         allFlowMods.addAll(ofFlowModInputs);
120         return processFlowModInputBuilders(allFlowMods);
121     }
122
123     private <T extends DataObject> Future<RpcResult<T>> processFlowModInputBuilders(
124             final List<FlowModInputBuilder> ofFlowModInputs) {
125         final List<ListenableFuture<RpcResult<T>>> partialFutures = new ArrayList<>();
126         for (FlowModInputBuilder flowModInputBuilder : ofFlowModInputs) {
127             ListenableFuture<RpcResult<T>> partialFuture = handleServiceCall(PRIMARY_CONNECTION, flowModInputBuilder,
128                     new Function<DataCrate<T>, Future<RpcResult<Void>>>() {
129                         @Override
130                         public ListenableFuture<RpcResult<Void>> apply(final DataCrate<T> data) {
131                             return createResultForFlowMod(data);
132                         }
133                     });
134             partialFutures.add(partialFuture);
135         }
136
137         ListenableFuture<List<RpcResult<T>>> allFutures = Futures.allAsList(partialFutures);
138         final SettableFuture<RpcResult<T>> finalFuture = SettableFuture.create();
139         Futures.addCallback(allFutures, new FutureCallback<List<RpcResult<T>>>() {
140             @Override
141             public void onSuccess(List<RpcResult<T>> result) {
142                 for (RpcResult<T> rpcResult : result) {
143                     if (rpcResult.isSuccessful()) {
144                         // TODO: AddFlowOutput has getTransactionId() - shouldn't it have some value?
145                         finalFuture.set(RpcResultBuilder.<T> success().build());
146                     }
147                 }
148             }
149
150             @Override
151             public void onFailure(Throwable t) {
152                 finalFuture.set(RpcResultBuilder.<T> failed().withError(ErrorType.APPLICATION, "", t.getMessage())
153                         .build());
154             }
155         });
156
157         return finalFuture;
158     }
159
160     protected <T extends DataObject> ListenableFuture<RpcResult<Void>> createResultForFlowMod(final DataCrate<T> data) {
161         return createResultForFlowMod(data, data.getFlowModInputBuilder()) ;
162     }
163
164     protected <T extends DataObject> ListenableFuture<RpcResult<Void>> createResultForFlowMod(final DataCrate<T> data, final FlowModInputBuilder flowModInput) {
165         final Xid xId = deviceContext.getNextXid();
166         flowModInput.setXid(xId.getValue());
167         data.getRequestContext().setXid(xId);
168         Future<RpcResult<Void>> flowModResult = provideConnectionAdapter(data.getiDConnection()).flowMod(
169                 flowModInput.build());
170         return JdkFutureAdapters.listenInPoolThread(flowModResult);
171     }
172
173 }