Update draft-ietf-client-server models
[netconf.git] / transport / transport-tcp / src / main / java / org / opendaylight / netconf / transport / tcp / NettyTransportSupport.java
1 /*
2  * Copyright (c) 2022 PANTHEON.tech, s.r.o. 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.netconf.transport.tcp;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.ThreadFactoryBuilder;
13 import io.netty.bootstrap.Bootstrap;
14 import io.netty.bootstrap.ServerBootstrap;
15 import io.netty.channel.EventLoopGroup;
16 import io.netty.channel.epoll.Epoll;
17 import io.netty.channel.socket.ServerSocketChannel;
18 import io.netty.channel.socket.SocketChannel;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.common.rev230417.tcp.common.grouping.Keepalives;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * Utility class providing indirection between various Netty transport implementations. An implementation is chosen
28  * based on run-time characteristics -- either {@code epoll(2)}-based or {@code java.nio}-based one.
29  */
30 @NonNullByDefault
31 public final class NettyTransportSupport {
32     private static final Logger LOG = LoggerFactory.getLogger(NettyTransportSupport.class);
33     private static final AbstractNettyImpl IMPL = Epoll.isAvailable() ? new EpollNettyImpl() : new NioNettyImpl();
34
35     static {
36         LOG.info("Netty transport backed by {}", IMPL);
37     }
38
39     private NettyTransportSupport() {
40         // Hidden on purpose
41     }
42
43     /**
44      * Return a new {@link Bootstrap} instance. The bootstrap has its {@link Bootstrap#channel(Class)} already
45      * initialized to the backing implementation's {@link SocketChannel} class.
46      *
47      * @return A new Bootstrap
48      */
49     public static Bootstrap newBootstrap() {
50         return new Bootstrap().channel(IMPL.channelClass());
51     }
52
53     /**
54      * Return a new {@link Bootstrap} instance. The bootstrap has its {@link ServerBootstrap#channel(Class)} already
55      * initialized to the backing implementation's {@link ServerSocketChannel} class.
56      *
57      * @return A new ServerBootstrap
58      */
59     public static ServerBootstrap newServerBootstrap() {
60         return new ServerBootstrap().channel(IMPL.serverChannelClass());
61     }
62
63     /**
64      * Create a new {@link EventLoopGroup} supporting the backing implementation with default number of threads. The
65      * default is twice the number of available processors, or controlled through the {@code io.netty.eventLoopThreads}
66      * system property.
67      *
68      * @param name Thread naming prefix
69      * @return An EventLoopGroup
70      */
71     public static EventLoopGroup newEventLoopGroup(final String name) {
72         return newEventLoopGroup(name, 0);
73     }
74
75     /**
76      * Create a new {@link EventLoopGroup} supporting the backing implementation with specified (or default) number of
77      * threads.
78      *
79      * @param name Thread naming prefix
80      * @param numThreads Number of threads in the group, must be non-negative. Zero selects the default.
81      * @return An EventLoopGroup
82      */
83     public static EventLoopGroup newEventLoopGroup(final String name, final int numThreads) {
84         return IMPL.newEventLoopGroup(numThreads, new ThreadFactoryBuilder()
85             .setNameFormat(requireNonNull(name) + "-%d")
86             .setUncaughtExceptionHandler(
87                 (thread, ex) -> LOG.error("Thread terminated due to uncaught exception: {}", thread.getName(), ex))
88             .build());
89     }
90
91     static boolean keepalivesSupported() {
92         return IMPL.supportsKeepalives();
93     }
94
95     static void configureKeepalives(final Bootstrap bootstrap, final @Nullable Keepalives keepalives)
96             throws UnsupportedConfigurationException {
97         if (keepalives != null) {
98             checkKeepalivesSupported();
99             IMPL.configureKeepalives(bootstrap, keepalives);
100         }
101     }
102
103     static void configureKeepalives(final ServerBootstrap bootstrap, final @Nullable Keepalives keepalives)
104             throws UnsupportedConfigurationException {
105         if (keepalives != null) {
106             checkKeepalivesSupported();
107             IMPL.configureKeepalives(bootstrap, keepalives);
108         }
109     }
110
111     private static void checkKeepalivesSupported() throws UnsupportedConfigurationException {
112         if (!keepalivesSupported()) {
113             throw new UnsupportedConfigurationException("Keepalives are not supported");
114         }
115     }
116 }