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 javax.annotation.concurrent.GuardedBy;
24 import org.opendaylight.protocol.bmp.api.BmpSession;
25 import org.opendaylight.protocol.bmp.api.BmpSessionListener;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev180329.InitiationMessage;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev180329.Reason;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev180329.TerminationMessage;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev180329.termination.Tlvs;
30 import org.opendaylight.yangtools.yang.binding.Notification;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 public final class BmpSessionImpl extends SimpleChannelInboundHandler<Notification> implements BmpSession {
36 private static final Logger LOG = LoggerFactory.getLogger(BmpSessionImpl.class);
38 private final BmpSessionListener listener;
40 private Channel channel;
44 public BmpSessionImpl(@Nonnull final BmpSessionListener listener) {
45 this.listener = requireNonNull(listener);
46 this.state = State.IDLE;
50 protected void channelRead0(final ChannelHandlerContext channelHandlerContext, final Notification msg) {
51 this.handleMessage(msg);
55 @SuppressWarnings("checkstyle:IllegalCatch")
56 public void channelInactive(final ChannelHandlerContext ctx) {
57 LOG.debug("Channel {} inactive.", ctx.channel());
61 super.channelInactive(ctx);
62 } catch (final Exception e) {
63 throw new IllegalStateException("Failed to delegate channel inactive event on channel " + ctx.channel(), e);
68 public synchronized void channelActive(final ChannelHandlerContext ctx) {
69 this.channel = ctx.channel();
70 LOG.info("Starting session {} <-> {}.", this.channel.localAddress(), this.channel.remoteAddress());
71 Preconditions.checkArgument(State.IDLE == this.state);
72 this.listener.onSessionUp(this);
73 this.state = State.UP;
77 public synchronized void close() {
78 LOG.info("Closing session: {}", this);
79 if (this.channel != null) {
82 this.state = State.IDLE;
87 public synchronized InetAddress getRemoteAddress() {
88 final InetSocketAddress address = (InetSocketAddress) this.channel.remoteAddress();
89 requireNonNull(address, "BMP Channel doesn't have a valid remote address.");
90 return address.getAddress();
94 public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
95 LOG.error("Exception caught in BMP Session.", cause);
97 this.listener.onSessionDown(new IllegalStateException(cause));
101 public String toString() {
102 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
105 private synchronized ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
106 toStringHelper.add("channel", this.channel);
107 return toStringHelper;
110 private synchronized void handleMessage(final Notification msg) {
111 switch (this.state) {
113 if (msg instanceof InitiationMessage) {
114 this.state = State.INITIATED;
115 this.listener.onMessage(msg);
117 LOG.warn("Unexpected message received {}, "
118 + "expected was BMP Initiation Message. Closing session.", msg);
123 if (msg instanceof TerminationMessage) {
124 LOG.info("Session {} terminated by remote with reason: {}",
125 this, getTerminationReason((TerminationMessage) msg));
128 this.listener.onMessage(msg);
132 throw new IllegalStateException("Received message " + msg
133 + " while BMP Session " + this + " was not active.");
139 private static Reason getTerminationReason(final TerminationMessage terminationMessage) {
140 final Tlvs tlvs = terminationMessage.getTlvs();
141 if (tlvs != null && tlvs.getReasonTlv() != null) {
142 return tlvs.getReasonTlv().getReason();
147 private void endOfInput() {
148 this.listener.onSessionDown(new IOException("End of input detected. Closing the session."));
151 protected enum State {
153 * Waiting for connection to be established.
157 * The connection has been established. Waiting for Initiation Message.
161 * The Initiation Messages has been received. Pass incoming messages to session listener.