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