2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.protocol.bmp.impl.session;
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;
31 public final class BmpSessionImpl extends SimpleChannelInboundHandler<Notification> implements BmpSession {
33 private static final Logger LOG = LoggerFactory.getLogger(BmpSessionImpl.class);
35 private final BmpSessionListener listener;
37 private Channel channel;
41 public BmpSessionImpl(@Nonnull final BmpSessionListener listener) {
42 this.listener = Preconditions.checkNotNull(listener);
43 this.state = State.IDLE;
47 protected void channelRead0(final ChannelHandlerContext channelHandlerContext, final Notification msg) throws Exception {
48 this.handleMessage(msg);
52 public void channelInactive(final ChannelHandlerContext ctx) {
53 LOG.debug("Channel {} inactive.", ctx.channel());
57 super.channelInactive(ctx);
58 } catch (final Exception e) {
59 throw new IllegalStateException("Failed to delegate channel inactive event on channel " + ctx.channel(), e);
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());
71 public synchronized void close() {
72 LOG.info("Closing session: {}", this);
73 if (this.channel != null) {
76 this.state = State.IDLE;
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();
87 public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
88 LOG.error("Exception caught in BMP Session.", cause);
90 this.listener.onSessionDown(new IllegalStateException(cause));
94 public String toString() {
95 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
98 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
99 toStringHelper.add("channel", this.channel);
100 return toStringHelper;
103 private synchronized void handleMessage(final Notification msg) {
104 switch (this.state) {
106 if (msg instanceof InitiationMessage) {
107 this.state = State.INITIATED;
108 this.listener.onMessage(msg);
110 LOG.warn("Unexpected message received {}, expected was BMP Initiation Message. Closing session.", msg);
115 if (msg instanceof TerminationMessage) {
116 LOG.info("Session {} terminated by remote with reason: {}", this, getTerminationReason((TerminationMessage) msg));
119 this.listener.onMessage(msg);
123 new IllegalStateException("Received message " + msg + " while BMP Session " + this + " was not active.");
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();
138 private void endOfInput() {
139 this.listener.onSessionDown(new IOException("End of input detected. Closing the session."));
142 private void sessionUp() {
143 Preconditions.checkArgument(State.IDLE == this.state);
144 this.listener.onSessionUp(this);
145 this.state = State.UP;
148 protected enum State {
150 * Waiting for connection to be established.
154 * The connection has been established. Waiting for Initiation Message.
158 * The Initiation Messages has been received. Pass incoming messages to session listener.