Merge "Update old links in code to deprecated DataChangeListener"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / connection / ConnectionContextImpl.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
9 package org.opendaylight.openflowplugin.impl.connection;
10
11 import com.google.common.base.Preconditions;
12 import java.math.BigInteger;
13 import java.net.InetSocketAddress;
14 import java.util.Objects;
15 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
16 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
17 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
18 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
19 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
20 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
21 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
22 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
23 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
24 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
25 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
30 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  *
36  */
37 public class ConnectionContextImpl implements ConnectionContext {
38
39     private final ConnectionAdapter connectionAdapter;
40     private volatile CONNECTION_STATE connectionState;
41     private FeaturesReply featuresReply;
42     private NodeId nodeId;
43     private DeviceDisconnectedHandler deviceDisconnectedHandler;
44     private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
45     private OutboundQueueProvider outboundQueueProvider;
46     private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
47     private HandshakeContext handshakeContext;
48     private DeviceInfo deviceInfo;
49
50     /**
51      * @param connectionAdapter
52      */
53     public ConnectionContextImpl(final ConnectionAdapter connectionAdapter) {
54         this.connectionAdapter = connectionAdapter;
55     }
56
57     @Override
58     public ConnectionAdapter getConnectionAdapter() {
59         return connectionAdapter;
60     }
61
62     @Override
63     public OutboundQueue getOutboundQueueProvider() {
64         return this.outboundQueueProvider;
65     }
66
67     @Override
68     public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
69         this.outboundQueueProvider = outboundQueueProvider;
70         ((DeviceInfoImpl)this.deviceInfo).setOutboundQueueProvider(this.outboundQueueProvider);
71     }
72
73     @Override
74     public CONNECTION_STATE getConnectionState() {
75         return connectionState;
76     }
77
78     @Override
79     public NodeId getNodeId() {
80         return nodeId;
81     }
82
83     @Override
84     public void setNodeId(final NodeId nodeId) {
85         this.nodeId = nodeId;
86     }
87
88     @Override
89     public FeaturesReply getFeatures() {
90         return featuresReply;
91     }
92
93     @Override
94     public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
95         this.deviceDisconnectedHandler = deviceDisconnectedHandler;
96     }
97
98     @Override
99     public void setFeatures(final FeaturesReply featuresReply) {
100         this.featuresReply = featuresReply;
101     }
102
103     @Override
104     public void closeConnection(final boolean propagate) {
105         if (Objects.isNull(nodeId)){
106             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
107         } else {
108             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
109         }
110         final BigInteger datapathId = Objects.nonNull(featuresReply) ? featuresReply.getDatapathId() : BigInteger.ZERO;
111         if (LOG.isDebugEnabled()) {
112             LOG.debug("Actively closing connection: {}, datapathId: {}",
113                     connectionAdapter.getRemoteAddress(), datapathId);
114         }
115         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
116
117         unregisterOutboundQueue();
118         closeHandshakeContext();
119
120         if (getConnectionAdapter().isAlive()) {
121             getConnectionAdapter().disconnect();
122         }
123
124         if (propagate) {
125             propagateDeviceDisconnectedEvent();
126         }
127     }
128
129     private void closeHandshakeContext() {
130         LOG.debug("Trying closing handshake context for node {}", getSafeNodeIdForLOG());
131         if (handshakeContext != null) {
132             try {
133                 handshakeContext.close();
134             } catch (Exception e) {
135                 LOG.error("handshake context closing failed:{} ", e);
136             } finally {
137                 handshakeContext = null;
138             }
139         }
140     }
141
142     @Override
143     public void onConnectionClosed() {
144
145         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
146
147         if (null == nodeId){
148             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
149         } else {
150             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
151         }
152
153         final InetSocketAddress remoteAddress = connectionAdapter.getRemoteAddress();
154         final Short auxiliaryId;
155         if (null != getFeatures() && null != getFeatures().getAuxiliaryId()) {
156             auxiliaryId = getFeatures().getAuxiliaryId();
157         } else {
158             auxiliaryId = 0;
159         }
160
161         LOG.debug("disconnecting: node={}|auxId={}|connection state = {}",
162                 remoteAddress,
163                 auxiliaryId,
164                 getConnectionState());
165
166         unregisterOutboundQueue();
167         closeHandshakeContext();
168         propagateDeviceDisconnectedEvent();
169     }
170
171     private void propagateDeviceDisconnectedEvent() {
172         if (Objects.nonNull(deviceDisconnectedHandler)) {
173             final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
174             if (LOG.isDebugEnabled()) {
175                 LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
176                         connectionAdapter.getRemoteAddress(), datapathId);
177             }
178             deviceDisconnectedHandler.onDeviceDisconnected(this);
179         }
180     }
181
182     /**
183      * This method returns safe nodeId for logging
184      * @return string value od nodeId or string "null"
185      */
186     @Override
187     public String getSafeNodeIdForLOG() {
188         return Objects.nonNull(nodeId) ? nodeId.getValue() : "null";
189     }
190
191     @Override
192     public void setOutboundQueueHandleRegistration(OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration) {
193         this.outboundQueueHandlerRegistration = outboundQueueHandlerRegistration;
194     }
195
196     private void unregisterOutboundQueue() {
197         if (LOG.isDebugEnabled()) {
198             LOG.debug("Trying unregister outbound queue handler registration for node {}", nodeId);
199         }
200         if (outboundQueueHandlerRegistration != null) {
201             outboundQueueHandlerRegistration.close();
202             outboundQueueHandlerRegistration = null;
203         }
204     }
205
206     @Override
207     public synchronized void changeStateToHandshaking() {
208         connectionState = CONNECTION_STATE.HANDSHAKING;
209     }
210
211     @Override
212     public synchronized void changeStateToTimeouting() {
213         connectionState = CONNECTION_STATE.TIMEOUTING;
214     }
215
216     @Override
217     public synchronized void changeStateToWorking() {
218         connectionState = CONNECTION_STATE.WORKING;
219     }
220
221     @Override
222     public DeviceInfo getDeviceInfo() {
223         return this.deviceInfo;
224     }
225
226     @Override
227     public void handshakeSuccessful() {
228         Preconditions.checkNotNull(nodeId, "Cannot create DeviceInfo if 'NodeId' is not set!");
229         Preconditions.checkNotNull(featuresReply, "Cannot create DeviceInfo if 'features' is not set!");
230         this.deviceInfo = new DeviceInfoImpl(
231                 nodeId,
232                 DeviceStateUtil.createNodeInstanceIdentifier(nodeId),
233                 featuresReply.getVersion(),
234                 featuresReply.getDatapathId(),
235                 outboundQueueProvider);
236     }
237
238     @Override
239     public void setHandshakeContext(HandshakeContext handshakeContext) {
240         this.handshakeContext = handshakeContext;
241     }
242
243     @Override
244     public boolean equals(Object o) {
245         if (this == o) {
246             return true;
247         }
248
249         if (o == null || getClass() != o.getClass()) {
250             return false;
251         }
252
253         ConnectionContextImpl that = (ConnectionContextImpl) o;
254
255         if (!connectionAdapter.equals(that.connectionAdapter)) {
256             return false;
257         }
258
259         if (featuresReply != null ? !featuresReply.equals(that.featuresReply) : that.featuresReply != null) {
260             return false;
261         }
262
263         return nodeId != null ? nodeId.equals(that.nodeId) : that.nodeId == null;
264
265     }
266
267     @Override
268     public int hashCode() {
269         int result = connectionAdapter.hashCode();
270         result = 31 * result + (featuresReply != null ? featuresReply.hashCode() : 0);
271         result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0);
272         return result;
273     }
274
275     private class DeviceInfoImpl implements DeviceInfo {
276
277         private final NodeId nodeId;
278         private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
279         private final Short version;
280         private final BigInteger datapathId;
281         private final ServiceGroupIdentifier serviceGroupIdentifier;
282         private OutboundQueue outboundQueueProvider;
283
284         DeviceInfoImpl(
285                 final NodeId nodeId,
286                 final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
287                 final Short version,
288                 final BigInteger datapathId,
289                 final OutboundQueue outboundQueueProvider) {
290             this.nodeId = nodeId;
291             this.nodeII = nodeII;
292             this.version = version;
293             this.datapathId = datapathId;
294             this.outboundQueueProvider = outboundQueueProvider;
295             this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.nodeId.getValue());
296         }
297
298         @Override
299         public NodeId getNodeId() {
300             return nodeId;
301         }
302
303         @Override
304         public KeyedInstanceIdentifier<Node, NodeKey> getNodeInstanceIdentifier() {
305             return nodeII;
306         }
307
308         @Override
309         public short getVersion() {
310             return version;
311         }
312
313         @Override
314         public BigInteger getDatapathId() {
315             return datapathId;
316         }
317
318         @Override
319         public ServiceGroupIdentifier getServiceIdentifier() {
320             return this.serviceGroupIdentifier;
321         }
322
323         @Override
324         public boolean equals(Object o) {
325             if (this == o) {
326                 return true;
327             }
328
329             if (o == null || getClass() != o.getClass()) {
330                 return false;
331             }
332
333             DeviceInfoImpl that = (DeviceInfoImpl) o;
334
335             return  (nodeId.equals(that.nodeId) &&
336                     nodeII.equals(that.nodeII) &&
337                     version.equals(that.version) &&
338                     datapathId.equals(that.datapathId));
339
340         }
341
342         @Override
343         public int hashCode() {
344             int result = nodeId.hashCode();
345             result = 31 * result + nodeII.hashCode();
346             result = 31 * result + version.hashCode();
347             result = 31 * result + datapathId.hashCode();
348             return result;
349         }
350
351         public void setOutboundQueueProvider(final OutboundQueue outboundQueueProvider) {
352             this.outboundQueueProvider = outboundQueueProvider;
353         }
354
355         @Override
356         public Long reserveXidForDeviceMessage() {
357             return outboundQueueProvider.reserveEntry();
358         }
359     }
360 }