Bug 624 - Separate netty and exi specific classes from netconf-util.
[controller.git] / opendaylight / netconf / netconf-netty-util / src / main / java / org / opendaylight / controller / netconf / nettyutil / AbstractNetconfSession.java
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.controller.netconf.nettyutil;
9
10 import io.netty.channel.Channel;
11 import io.netty.channel.ChannelFuture;
12 import io.netty.channel.ChannelHandler;
13 import java.io.IOException;
14 import org.opendaylight.controller.netconf.api.NetconfExiSession;
15 import org.opendaylight.controller.netconf.api.NetconfMessage;
16 import org.opendaylight.controller.netconf.api.NetconfSession;
17 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
18 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
19 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
20 import org.opendaylight.controller.netconf.nettyutil.handler.exi.EXIParameters;
21 import org.opendaylight.controller.netconf.util.xml.XmlElement;
22 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
23 import org.opendaylight.protocol.framework.AbstractProtocolSession;
24 import org.openexi.proc.common.EXIOptionsException;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 public abstract class AbstractNetconfSession<S extends NetconfSession, L extends NetconfSessionListener<S>> extends AbstractProtocolSession<NetconfMessage> implements NetconfSession, NetconfExiSession {
29     private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class);
30     private final L sessionListener;
31     private final long sessionId;
32     private boolean up = false;
33
34     private ChannelHandler delayedEncoder;
35
36     private final Channel channel;
37
38     protected AbstractNetconfSession(final L sessionListener, final Channel channel, final long sessionId) {
39         this.sessionListener = sessionListener;
40         this.channel = channel;
41         this.sessionId = sessionId;
42         logger.debug("Session {} created", sessionId);
43     }
44
45     protected abstract S thisInstance();
46
47     @Override
48     public void close() {
49         channel.close();
50         up = false;
51         sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed"));
52     }
53
54     @Override
55     protected void handleMessage(final NetconfMessage netconfMessage) {
56         logger.debug("handling incoming message");
57         sessionListener.onMessage(thisInstance(), netconfMessage);
58     }
59
60     @Override
61     public ChannelFuture sendMessage(final NetconfMessage netconfMessage) {
62         final ChannelFuture future = channel.writeAndFlush(netconfMessage);
63         if (delayedEncoder != null) {
64                 replaceMessageEncoder(delayedEncoder);
65                 delayedEncoder = null;
66         }
67
68         return future;
69     }
70
71     @Override
72     protected void endOfInput() {
73         logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
74                 : "initialized");
75         if (isUp()) {
76             this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session."));
77         }
78     }
79
80     @Override
81     protected void sessionUp() {
82         logger.debug("Session {} up", toString());
83         sessionListener.onSessionUp(thisInstance());
84         this.up = true;
85     }
86
87     @Override
88     public String toString() {
89         final StringBuffer sb = new StringBuffer(getClass().getSimpleName() + "{");
90         sb.append("sessionId=").append(sessionId);
91         sb.append('}');
92         return sb.toString();
93     }
94
95     protected final void replaceMessageDecoder(final ChannelHandler handler) {
96         replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, handler);
97     }
98
99     protected final void replaceMessageEncoder(final ChannelHandler handler) {
100         replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, handler);
101     }
102
103     protected final void replaceMessageEncoderAfterNextMessage(final ChannelHandler handler) {
104         this.delayedEncoder = handler;
105     }
106
107     protected final void replaceChannelHandler(final String handlerName, final ChannelHandler handler) {
108         channel.pipeline().replace(handlerName, handlerName, handler);
109     }
110
111     @Override
112     public final void startExiCommunication(final NetconfMessage startExiMessage) {
113         final EXIParameters exiParams;
114         try {
115             exiParams = EXIParameters.fromXmlElement(XmlElement.fromDomDocument(startExiMessage.getDocument()));
116         } catch (final EXIOptionsException e) {
117             logger.warn("Unable to parse EXI parameters from {} om session {}", XmlUtil.toString(startExiMessage.getDocument()), this, e);
118             throw new IllegalArgumentException(e);
119         }
120         final NetconfEXICodec exiCodec = new NetconfEXICodec(exiParams.getOptions());
121         addExiHandlers(exiCodec);
122         logger.debug("Session {} EXI handlers added to pipeline", this);
123     }
124
125     protected abstract void addExiHandlers(NetconfEXICodec exiCodec);
126
127     public final boolean isUp() {
128         return up;
129     }
130
131     public final long getSessionId() {
132         return sessionId;
133     }
134 }