a27c260100ac06fb99411b7bcf66fa8213285228
[netconf.git] / protocol / netconf-server / src / main / java / org / opendaylight / netconf / server / NetconfServerFactoryImpl.java
1 /*
2  * Copyright (c) 2023 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.server;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.ListenableFuture;
13 import io.netty.bootstrap.ServerBootstrap;
14 import io.netty.channel.EventLoopGroup;
15 import io.netty.util.concurrent.DefaultPromise;
16 import io.netty.util.concurrent.EventExecutor;
17 import io.netty.util.concurrent.GlobalEventExecutor;
18 import java.util.List;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.netconf.server.api.NetconfServerFactory;
22 import org.opendaylight.netconf.shaded.sshd.server.SshServer;
23 import org.opendaylight.netconf.transport.api.TransportChannel;
24 import org.opendaylight.netconf.transport.api.TransportChannelListener;
25 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
26 import org.opendaylight.netconf.transport.ssh.SSHServer;
27 import org.opendaylight.netconf.transport.ssh.ServerFactoryManagerConfigurator;
28 import org.opendaylight.netconf.transport.tcp.NettyTransportSupport;
29 import org.opendaylight.netconf.transport.tcp.TCPServer;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.server.rev230417.SshServerGrouping;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev230417.TcpServerGrouping;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public final class NetconfServerFactoryImpl implements NetconfServerFactory {
36     private static final Logger LOG = LoggerFactory.getLogger(NetconfServerFactoryImpl.class);
37     private static final TransportChannelListener EMPTY_LISTENER =  new ChannelInitializerListener(null, null);
38
39     private final EventLoopGroup parentGroup;
40     private final EventLoopGroup workerGroup;
41     private final ServerChannelInitializer channelInitializer;
42     private final TransportChannelListener transportChannelListener;
43
44     public NetconfServerFactoryImpl(final ServerChannelInitializer channelInitializer, final EventLoopGroup bossGroup,
45             final EventLoopGroup workerGroup) {
46         this(channelInitializer, bossGroup, workerGroup, GlobalEventExecutor.INSTANCE);
47     }
48
49     public NetconfServerFactoryImpl(final ServerChannelInitializer channelInitializer,
50             final EventLoopGroup parentGroup, final EventLoopGroup workerGroup, final EventExecutor executor) {
51         this.parentGroup = requireNonNull(parentGroup);
52         this.workerGroup = requireNonNull(workerGroup);
53         this.channelInitializer = channelInitializer;
54         transportChannelListener = new ChannelInitializerListener(channelInitializer, executor);
55     }
56
57     @NonNull protected ServerBootstrap createBootstrap() {
58         return NettyTransportSupport.newServerBootstrap().group(parentGroup, workerGroup);
59     }
60
61     @Override
62     public ListenableFuture<TCPServer> createTcpServer(final TcpServerGrouping params)
63             throws UnsupportedConfigurationException {
64         return TCPServer.listen(transportChannelListener, createBootstrap(), params);
65     }
66
67     @Override
68     public ListenableFuture<SSHServer> createSshServer(final TcpServerGrouping tcpParams,
69             final SshServerGrouping sshParams) throws UnsupportedConfigurationException {
70         return SSHServer.listen(EMPTY_LISTENER, createBootstrap(), tcpParams, sshParams);
71     }
72
73     @Override
74     public ListenableFuture<SSHServer> createSshServer(final TcpServerGrouping tcpParams,
75             final SshServerGrouping sshParams, final ServerFactoryManagerConfigurator configurator)
76                 throws UnsupportedConfigurationException {
77         final var initializer = requireNonNull(channelInitializer);
78
79         return SSHServer.listen(EMPTY_LISTENER, createBootstrap(), tcpParams, sshParams, factoryManager -> {
80             if (configurator != null) {
81                 configurator.configureServerFactoryManager(factoryManager);
82             }
83             if (factoryManager instanceof SshServer server) {
84                 server.setSubsystemFactories(List.of(new NetconfSubsystemFactory(initializer)));
85             }
86         });
87     }
88
89     private record ChannelInitializerListener(
90             @Nullable ServerChannelInitializer channelInitializer,
91             @Nullable EventExecutor executor) implements TransportChannelListener {
92         @Override
93         public void onTransportChannelEstablished(final TransportChannel channel) {
94             LOG.debug("Transport channel {} established", channel);
95             if (channelInitializer != null && executor != null) {
96                 channelInitializer.initialize(channel.channel(), new DefaultPromise<>(executor));
97             }
98         }
99
100         @Override
101         public void onTransportChannelFailed(final Throwable cause) {
102             LOG.error("Transport channel failed", cause);
103         }
104     }
105 }