Initial code drop of netconf protocol implementation
[controller.git] / opendaylight / netconf / netconf-client / src / main / java / org / opendaylight / controller / netconf / client / NetconfClient.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
9 package org.opendaylight.controller.netconf.client;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.Sets;
14 import io.netty.util.concurrent.Future;
15 import io.netty.util.concurrent.GlobalEventExecutor;
16 import org.opendaylight.controller.netconf.api.NetconfMessage;
17 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
18 import org.opendaylight.protocol.framework.ReconnectStrategy;
19 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import javax.net.ssl.SSLContext;
24 import java.io.Closeable;
25 import java.io.IOException;
26 import java.net.InetSocketAddress;
27 import java.util.Set;
28 import java.util.concurrent.CancellationException;
29 import java.util.concurrent.ExecutionException;
30
31 public class NetconfClient implements Closeable {
32
33     private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
34
35     public static final int DEFAULT_CONNECT_TIMEOUT = 5000;
36     private final NetconfClientDispatcher dispatch;
37     private final String label;
38     private final NetconfClientSession clientSession;
39     private final NetconfClientSessionListener sessionListener;
40     private final long sessionId;
41     private final InetSocketAddress address;
42
43     // TODO test reconnecting constructor
44     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectionAttempts,
45             int attemptMsTimeout) {
46         this(clientLabelForLogging, address, getReconnectStrategy(connectionAttempts, attemptMsTimeout), Optional
47                 .<SSLContext> absent());
48     }
49
50     private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat,
51             Optional<SSLContext> maybeSSLContext) {
52         this.label = clientLabelForLogging;
53         dispatch = new NetconfClientDispatcher(maybeSSLContext);
54
55         sessionListener = new NetconfClientSessionListener();
56         Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
57         this.address = address;
58         clientSession = get(clientFuture);
59         this.sessionId = clientSession.getSessionId();
60     }
61
62     private NetconfClientSession get(Future<NetconfClientSession> clientFuture) {
63         try {
64             return clientFuture.get();
65         } catch (InterruptedException | CancellationException e) {
66             throw new RuntimeException("Netconf client interrupted", e);
67         } catch (ExecutionException e) {
68             throw new IllegalStateException("Unable to create netconf client", e);
69         }
70     }
71
72     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
73             Optional<SSLContext> maybeSSLContext) {
74         this(clientLabelForLogging, address,
75                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), maybeSSLContext);
76     }
77
78     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs) {
79         this(clientLabelForLogging, address,
80                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), Optional
81                         .<SSLContext> absent());
82     }
83
84     public NetconfClient(String clientLabelForLogging, InetSocketAddress address) {
85         this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
86                 DEFAULT_CONNECT_TIMEOUT), Optional.<SSLContext> absent());
87     }
88
89     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, Optional<SSLContext> maybeSSLContext) {
90         this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
91                 DEFAULT_CONNECT_TIMEOUT), maybeSSLContext);
92     }
93
94     public NetconfMessage sendMessage(NetconfMessage message) {
95         return sendMessage(message, 5, 1000);
96     }
97
98     public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
99         Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
100         clientSession.sendMessage(message);
101         try {
102             return sessionListener.getLastMessage(attempts, attemptMsDelay);
103         } catch (InterruptedException e) {
104             throw new RuntimeException(this + " Cannot read message from " + address, e);
105         } catch (IllegalStateException e) {
106             throw new IllegalStateException(this + " Cannot read message from " + address, e);
107         }
108     }
109
110     @Override
111     public void close() throws IOException {
112         clientSession.close();
113         dispatch.close();
114     }
115
116     private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
117         return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
118                 Long.valueOf(connectionAttempts), null);
119     }
120
121     @Override
122     public String toString() {
123         final StringBuffer sb = new StringBuffer("NetconfClient{");
124         sb.append("label=").append(label);
125         sb.append(", sessionId=").append(sessionId);
126         sb.append('}');
127         return sb.toString();
128     }
129
130     public long getSessionId() {
131         return sessionId;
132     }
133
134     public Set<String> getCapabilities() {
135         Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
136         return Sets.newHashSet(clientSession.getServerCapabilities());
137     }
138 }