Code Clean Up
[bgpcep.git] / bgp / bmp-impl / src / main / java / org / opendaylight / protocol / bmp / impl / session / BmpSessionImpl.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.protocol.bmp.impl.session;
10
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Preconditions;
14 import io.netty.channel.Channel;
15 import io.netty.channel.ChannelHandlerContext;
16 import io.netty.channel.SimpleChannelInboundHandler;
17 import java.io.IOException;
18 import java.net.InetAddress;
19 import java.net.InetSocketAddress;
20 import javax.annotation.Nonnull;
21 import org.opendaylight.protocol.bmp.api.BmpSession;
22 import org.opendaylight.protocol.bmp.api.BmpSessionListener;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.InitiationMessage;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.Reason;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.TerminationMessage;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.termination.Tlvs;
27 import org.opendaylight.yangtools.yang.binding.Notification;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public final class BmpSessionImpl extends SimpleChannelInboundHandler<Notification> implements BmpSession {
32
33     private static final Logger LOG = LoggerFactory.getLogger(BmpSessionImpl.class);
34
35     private final BmpSessionListener listener;
36
37     private Channel channel;
38
39     private State state;
40
41     public BmpSessionImpl(@Nonnull final BmpSessionListener listener) {
42         this.listener = Preconditions.checkNotNull(listener);
43         this.state = State.IDLE;
44     }
45
46     @Override
47     protected void channelRead0(final ChannelHandlerContext channelHandlerContext, final Notification msg) throws Exception {
48         this.handleMessage(msg);
49     }
50
51     @Override
52     public void channelInactive(final ChannelHandlerContext ctx) {
53         LOG.debug("Channel {} inactive.", ctx.channel());
54         this.endOfInput();
55
56         try {
57             super.channelInactive(ctx);
58         } catch (final Exception e) {
59             throw new IllegalStateException("Failed to delegate channel inactive event on channel " + ctx.channel(), e);
60         }
61     }
62
63     @Override
64     public void channelActive(final ChannelHandlerContext ctx) throws Exception {
65         this.channel = ctx.channel();
66         LOG.info("Starting session {} <-> {}.", this.channel.localAddress(), this.channel.remoteAddress());
67         sessionUp();
68     }
69
70     @Override
71     public synchronized void close() {
72         LOG.info("Closing session: {}", this);
73         if (this.channel != null) {
74             this.channel.close();
75             this.channel = null;
76             this.state = State.IDLE;
77         }
78     }
79
80     @Override
81     public InetAddress getRemoteAddress() {
82         Preconditions.checkNotNull(this.channel.remoteAddress(), "BMP Channel doesn't have a valid remote address.");
83         return ((InetSocketAddress) this.channel.remoteAddress()).getAddress();
84     }
85
86     @Override
87     public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
88         LOG.error("Exception caught in BMP Session.", cause);
89         close();
90         this.listener.onSessionDown(new IllegalStateException(cause));
91     }
92
93     @Override
94     public String toString() {
95         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
96     }
97
98     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
99         toStringHelper.add("channel", this.channel);
100         return toStringHelper;
101     }
102
103     private synchronized void handleMessage(final Notification msg) {
104         switch (this.state) {
105         case UP:
106             if (msg instanceof InitiationMessage) {
107                 this.state = State.INITIATED;
108                 this.listener.onMessage(msg);
109             } else {
110                 LOG.warn("Unexpected message received {}, expected was BMP Initiation Message. Closing session.", msg);
111                 close();
112             }
113             break;
114         case INITIATED:
115             if (msg instanceof TerminationMessage) {
116                 LOG.info("Session {} terminated by remote with reason: {}", this, getTerminationReason((TerminationMessage) msg));
117                 close();
118             } else {
119                 this.listener.onMessage(msg);
120             }
121             break;
122         case IDLE:
123             new IllegalStateException("Received message " + msg + " while BMP Session " + this + " was not active.");
124             break;
125         default:
126             break;
127         }
128     }
129
130     private static Reason getTerminationReason(final TerminationMessage terminationMessage) {
131         final Tlvs tlvs = terminationMessage.getTlvs();
132         if (tlvs != null && tlvs.getReasonTlv() != null) {
133             return tlvs.getReasonTlv().getReason();
134         }
135         return null;
136     }
137
138     private void endOfInput() {
139         this.listener.onSessionDown(new IOException("End of input detected. Closing the session."));
140     }
141
142     private void sessionUp() {
143         Preconditions.checkArgument(State.IDLE == this.state);
144         this.listener.onSessionUp(this);
145         this.state = State.UP;
146     }
147
148     protected enum State {
149         /**
150          * Waiting for connection to be established.
151          */
152         IDLE,
153         /**
154          * The connection has been established. Waiting for Initiation Message.
155          */
156         UP,
157         /**
158          * The Initiation Messages has been received. Pass incoming messages to session listener.
159          */
160         INITIATED
161     }
162
163 }