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