2203b65b313b7c47f8705d224683cc5c6555eff5
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / DeviceContextImpl.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.device;
9
10 import java.math.BigInteger;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.concurrent.Future;
15
16 import javax.annotation.Nonnull;
17
18 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
25 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
26 import org.opendaylight.openflowplugin.api.openflow.device.*;
27 import org.opendaylight.openflowplugin.api.openflow.device.exception.DeviceDataException;
28 import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher;
29 import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
30 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
31 import org.opendaylight.openflowplugin.impl.device.translator.PacketReceivedTranslator;
32 import org.opendaylight.openflowplugin.impl.device.translator.PortUpdateTranslator;
33 import org.opendaylight.openflowplugin.openflow.md.core.session.SwitchConnectionCookieOFImpl;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.*;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.Error;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableFeatures;
39 import org.opendaylight.yangtools.yang.binding.ChildOf;
40 import org.opendaylight.yangtools.yang.binding.DataObject;
41 import org.opendaylight.yangtools.yang.common.RpcError;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import com.google.common.annotations.VisibleForTesting;
48 import com.google.common.base.Preconditions;
49 import com.google.common.util.concurrent.SettableFuture;
50
51 /**
52  *
53  */
54 public class DeviceContextImpl implements DeviceContext, DeviceReplyProcessor, TransactionChainListener {
55
56     private static final Logger LOG = LoggerFactory.getLogger(DeviceContextImpl.class);
57
58     private final ConnectionContext primaryConnectionContext;
59     private final DeviceState deviceState;
60     private final DataBroker dataBroker;
61     private final XidGenerator xidGenerator;
62     private Map<Long, RequestContext> requests =
63             new HashMap<Long, RequestContext>();
64
65     private final Map<SwitchConnectionDistinguisher, ConnectionContext> auxiliaryConnectionContexts;
66     private BindingTransactionChain txChainFactory;
67     private TranslatorLibrary translatorLibrary;
68
69     @VisibleForTesting
70     DeviceContextImpl(@Nonnull final ConnectionContext primaryConnectionContext,
71                       @Nonnull final DeviceState deviceState, @Nonnull final DataBroker dataBroker) {
72         this.primaryConnectionContext = Preconditions.checkNotNull(primaryConnectionContext);
73         this.deviceState = Preconditions.checkNotNull(deviceState);
74         this.dataBroker = Preconditions.checkNotNull(dataBroker);
75         xidGenerator = new XidGenerator();
76         txChainFactory = dataBroker.createTransactionChain(DeviceContextImpl.this);
77         auxiliaryConnectionContexts = new HashMap<>();
78         requests = new HashMap<>();
79     }
80
81     @Override
82     public <M extends ChildOf<DataObject>> void onMessage(final M message, final RequestContext requestContext) {
83         // TODO Auto-generated method stub
84
85     }
86
87     @Override
88     public void addAuxiliaryConenctionContext(final ConnectionContext connectionContext) {
89         final SwitchConnectionDistinguisher connectionDistinguisher = new SwitchConnectionCookieOFImpl(connectionContext.getFeatures().getAuxiliaryId());
90         auxiliaryConnectionContexts.put(connectionDistinguisher, connectionContext);
91     }
92
93     @Override
94     public void removeAuxiliaryConenctionContext(final ConnectionContext connectionContext) {
95         // TODO Auto-generated method stub
96
97     }
98
99     @Override
100     public DeviceState getDeviceState() {
101         return deviceState;
102     }
103
104     @Override
105     public ReadTransaction getReadTransaction() {
106         return dataBroker.newReadOnlyTransaction();
107     }
108
109     @Override
110     public WriteTransaction getWriteTransaction() {
111         // FIXME : we wana to have only one WriteTransaction exposed in one time
112         // so thing about blocking notification mechanism for wait to new transaction
113         return txChainFactory.newWriteOnlyTransaction();
114     }
115
116     @Override
117     public TableFeatures getCapabilities() {
118         // TODO Auto-generated method stub
119         return null;
120     }
121
122     @Override
123     public ConnectionContext getPrimaryConnectionContext() {
124         return primaryConnectionContext;
125     }
126
127     @Override
128     public ConnectionContext getAuxiliaryConnectiobContexts(final BigInteger cookie) {
129         return auxiliaryConnectionContexts.get(new SwitchConnectionCookieOFImpl(cookie.longValue()));
130     }
131
132     @Override
133     public Xid getNextXid() {
134         return xidGenerator.generate();
135     }
136
137     public Map<Long, RequestContext> getRequests() {
138         return requests;
139     }
140
141     @Override
142     public void hookRequestCtx(Xid xid, RequestContext requestFutureContext) {
143         // TODO Auto-generated method stub
144         requests.put(xid.getValue(), requestFutureContext);
145     }
146
147     @Override
148     public void processReply(OfHeader ofHeader) {
149         RequestContext requestContext = getRequests().get(ofHeader.getXid());
150         SettableFuture replyFuture = requestContext.getFuture();
151         getRequests().remove(ofHeader.getXid());
152         RpcResult<OfHeader> rpcResult;
153
154         if(ofHeader instanceof Error) {
155             Error error = (Error) ofHeader;
156             String message = "Operation on device failed";
157             rpcResult= RpcResultBuilder
158                     .<OfHeader>failed()
159                     .withError(RpcError.ErrorType.APPLICATION, message, new DeviceDataException(message, error))
160                     .build();
161         } else {
162             rpcResult= RpcResultBuilder
163                     .<OfHeader>success()
164                     .withResult(ofHeader)
165                     .build();
166         }
167
168         replyFuture.set(rpcResult);
169         try {
170             requestContext.close();
171         } catch (Exception e) {
172             LOG.error("Closing RequestContext failed: ", e);
173         }
174     }
175
176     @Override
177     public void processReply(Xid xid, List<OfHeader> ofHeaderList) {
178         RequestContext requestContext = getRequests().get(xid.getValue());
179         SettableFuture replyFuture = requestContext.getFuture();
180         getRequests().remove(xid.getValue());
181         RpcResult<List<OfHeader>> rpcResult= RpcResultBuilder
182                                                 .<List<OfHeader>>success()
183                                                 .withResult(ofHeaderList)
184                                                 .build();
185         replyFuture.set(rpcResult);
186         try {
187             requestContext.close();
188         } catch (Exception e) {
189             LOG.error("Closing RequestContext failed: ", e);
190         }
191     }
192
193     @Override
194     public void processException(Xid xid, DeviceDataException deviceDataException) {
195         RequestContext requestContext = getRequests().get(xid.getValue());
196
197         SettableFuture replyFuture = requestContext.getFuture();
198         getRequests().remove(xid.getValue());
199         RpcResult<List<OfHeader>> rpcResult= RpcResultBuilder
200                 .<List<OfHeader>>failed()
201                 .withError(RpcError.ErrorType.APPLICATION, "Message processing failed", deviceDataException)
202                 .build();
203         replyFuture.set(rpcResult);
204         try {
205             requestContext.close();
206         } catch (Exception e) {
207             LOG.error("Closing RequestContext failed: ", e);
208         }
209     }
210
211     @Override
212     public void processFlowRemovedMessage(FlowRemoved flowRemoved) {
213         //TODO: will be defined later
214     }
215
216     @Override
217     public void processPortStatusMessage(PortStatusMessage portStatus) {
218         TranslatorKey translatorKey = new TranslatorKey(portStatus.getVersion(), PortUpdateTranslator.class.getName());
219         MessageTranslator<PortStatusMessage, FlowCapableNodeConnector> messageTranslator = translatorLibrary.lookupTranslator(translatorKey);
220         FlowCapableNodeConnector nodeConnector = messageTranslator.translate(portStatus, this, null);
221         //TODO write into datastore
222     }
223
224     @Override
225     public void processPacketInMessage(PacketInMessage packetInMessage) {
226         TranslatorKey translatorKey = new TranslatorKey(packetInMessage.getVersion(), PacketReceivedTranslator.class.getName());
227         MessageTranslator<PacketInMessage, PacketReceived> messageTranslator = translatorLibrary.lookupTranslator(translatorKey);
228         PacketReceived packetReceived = messageTranslator.translate(packetInMessage, this, null);
229         //TODO publish to MD-SAL
230     }
231
232     @Override
233     public void onTransactionChainFailed(TransactionChain<?, ?> chain,
234             AsyncTransaction<?, ?> transaction, Throwable cause) {
235         txChainFactory.close();
236         txChainFactory = dataBroker.createTransactionChain(DeviceContextImpl.this);
237
238     }
239
240     @Override
241     public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
242      // NOOP - only yet, here is probably place for notification to get new WriteTransaction
243
244     }
245
246     public void setTranslatorLibrary(TranslatorLibrary translatorLibrary) {
247         this.translatorLibrary = translatorLibrary;
248     }
249 }