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 static java.util.Objects.requireNonNull;
13 import com.google.common.base.MoreObjects;
14 import com.google.common.base.MoreObjects.ToStringHelper;
15 import com.google.common.base.Preconditions;
16 import io.netty.channel.Channel;
17 import io.netty.channel.ChannelHandlerContext;
18 import io.netty.channel.SimpleChannelInboundHandler;
19 import java.io.IOException;
20 import java.net.InetAddress;
21 import java.net.InetSocketAddress;
22 import javax.annotation.Nonnull;
23 import org.opendaylight.protocol.bmp.api.BmpSession;
24 import org.opendaylight.protocol.bmp.api.BmpSessionListener;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.InitiationMessage;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.Reason;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.TerminationMessage;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.termination.Tlvs;
29 import org.opendaylight.yangtools.yang.binding.Notification;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 public final class BmpSessionImpl extends SimpleChannelInboundHandler<Notification> implements BmpSession {
35 private static final Logger LOG = LoggerFactory.getLogger(BmpSessionImpl.class);
37 private final BmpSessionListener listener;
39 private Channel channel;
43 public BmpSessionImpl(@Nonnull final BmpSessionListener listener) {
44 this.listener = requireNonNull(listener);
45 this.state = State.IDLE;
49 protected void channelRead0(final ChannelHandlerContext channelHandlerContext, final Notification msg) throws Exception {
50 this.handleMessage(msg);
54 public void channelInactive(final ChannelHandlerContext ctx) {
55 LOG.debug("Channel {} inactive.", ctx.channel());
59 super.channelInactive(ctx);
60 } catch (final Exception e) {
61 throw new IllegalStateException("Failed to delegate channel inactive event on channel " + ctx.channel(), e);
66 public void channelActive(final ChannelHandlerContext ctx) throws Exception {
67 this.channel = ctx.channel();
68 LOG.info("Starting session {} <-> {}.", this.channel.localAddress(), this.channel.remoteAddress());
73 public synchronized void close() {
74 LOG.info("Closing session: {}", this);
75 if (this.channel != null) {
78 this.state = State.IDLE;
83 public InetAddress getRemoteAddress() {
84 requireNonNull(this.channel.remoteAddress(), "BMP Channel doesn't have a valid remote address.");
85 return ((InetSocketAddress) this.channel.remoteAddress()).getAddress();
89 public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
90 LOG.error("Exception caught in BMP Session.", cause);
92 this.listener.onSessionDown(new IllegalStateException(cause));
96 public String toString() {
97 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
100 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
101 toStringHelper.add("channel", this.channel);
102 return toStringHelper;
105 private synchronized void handleMessage(final Notification msg) {
106 switch (this.state) {
108 if (msg instanceof InitiationMessage) {
109 this.state = State.INITIATED;
110 this.listener.onMessage(msg);
112 LOG.warn("Unexpected message received {}, expected was BMP Initiation Message. Closing session.", msg);
117 if (msg instanceof TerminationMessage) {
118 LOG.info("Session {} terminated by remote with reason: {}", this, getTerminationReason((TerminationMessage) msg));
121 this.listener.onMessage(msg);
125 throw new IllegalStateException("Received message " + msg + " while BMP Session " + this + " was not active.");
131 private static Reason getTerminationReason(final TerminationMessage terminationMessage) {
132 final Tlvs tlvs = terminationMessage.getTlvs();
133 if (tlvs != null && tlvs.getReasonTlv() != null) {
134 return tlvs.getReasonTlv().getReason();
139 private void endOfInput() {
140 this.listener.onSessionDown(new IOException("End of input detected. Closing the session."));
143 private void sessionUp() {
144 Preconditions.checkArgument(State.IDLE == this.state);
145 this.listener.onSessionUp(this);
146 this.state = State.UP;
149 protected enum State {
151 * Waiting for connection to be established.
155 * The connection has been established. Waiting for Initiation Message.
159 * The Initiation Messages has been received. Pass incoming messages to session listener.