d6a24cb3d1119816534dd2e7cec03bc9239820d0
[netconf.git] / transport / transport-ssh / src / main / java / org / opendaylight / netconf / transport / ssh / SSHTransportStackFactory.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.transport.ssh;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.util.concurrent.ListenableFuture;
14 import io.netty.bootstrap.Bootstrap;
15 import io.netty.bootstrap.ServerBootstrap;
16 import io.netty.channel.EventLoopGroup;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.netconf.shaded.sshd.server.subsystem.SubsystemFactory;
19 import org.opendaylight.netconf.transport.api.TransportChannelListener;
20 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
21 import org.opendaylight.netconf.transport.tcp.NettyTransportSupport;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.SshClientGrouping;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.server.rev230417.SshServerGrouping;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev230417.TcpServerGrouping;
26
27 /**
28  * A factory capable of instantiating {@link SSHClient}s and {@link SSHServer}s.
29  */
30 public final class SSHTransportStackFactory implements AutoCloseable {
31     private final EventLoopGroup group;
32     private final EventLoopGroup parentGroup;
33
34     private SSHTransportStackFactory(final EventLoopGroup group, final EventLoopGroup parentGroup) {
35         this.group = requireNonNull(group);
36         this.parentGroup = parentGroup;
37         // FIXME: factoryFactory = new NettyIoServiceFactoryFactory(group);
38     }
39
40     public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads) {
41         this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads), null);
42     }
43
44     public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads,
45             final @NonNull String parentGroupName, final int parentGroupThreads) {
46         this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads),
47             NettyTransportSupport.newEventLoopGroup(parentGroupName, parentGroupThreads));
48     }
49
50     public @NonNull ListenableFuture<SSHClient> connectClient(final TransportChannelListener listener,
51             final TcpClientGrouping connectParams, final SshClientGrouping clientParams)
52                 throws UnsupportedConfigurationException {
53         return SSHClient.of(group, listener, clientParams).connect(newBootstrap(), connectParams);
54     }
55
56     public @NonNull ListenableFuture<SSHClient> listenClient(final TransportChannelListener listener,
57             final TcpServerGrouping listenParams, final SshClientGrouping clientParams)
58                 throws UnsupportedConfigurationException {
59         return SSHClient.of(group, listener, clientParams).listen(newServerBootstrap(), listenParams);
60     }
61
62     public @NonNull ListenableFuture<SSHServer> connectServer(final TransportChannelListener listener,
63             final SubsystemFactory subsystemFactory, final TcpClientGrouping connectParams,
64             final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
65         return SSHServer.of(group, listener, subsystemFactory, requireNonNull(serverParams), null)
66             .connect(newBootstrap(), connectParams);
67     }
68
69     public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
70             final SubsystemFactory subsystemFactory, final TcpServerGrouping connectParams,
71             final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
72         return listenServer(listener, subsystemFactory, connectParams, requireNonNull(serverParams), null);
73     }
74
75     /**
76      * Builds and starts SSH Server.
77      *
78      * @param listener server channel listener, required
79      * @param subsystemFactory A {@link SubsystemFactory} for the hosted subsystem
80      * @param listenParams TCP transport configuration, required
81      * @param serverParams SSH overlay configuration, optional if configurator is defined, required otherwise
82      * @param configurator server factory manager configurator, optional if serverParams is defined, required otherwise
83      * @return server instance as listenable future
84      * @throws UnsupportedConfigurationException if any of configurations is invalid or incomplete
85      * @throws NullPointerException if any of required parameters is null
86      * @throws IllegalArgumentException if both configurator and serverParams are null
87      */
88     public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
89             final SubsystemFactory subsystemFactory, final TcpServerGrouping listenParams,
90             final SshServerGrouping serverParams, final ServerFactoryManagerConfigurator configurator)
91                     throws UnsupportedConfigurationException {
92         checkArgument(serverParams != null || configurator != null,
93             "Neither server parameters nor factory configurator is defined");
94         return SSHServer.of(group, listener, subsystemFactory, serverParams, configurator)
95             .listen(newServerBootstrap(), listenParams);
96     }
97
98     /**
99      * Create a new {@link Bootstrap} based on this factory's {@link EventLoopGroup}s.
100      *
101      * @return A new {@link Bootstrap}
102      */
103     public @NonNull Bootstrap newBootstrap() {
104         return NettyTransportSupport.newBootstrap().group(group);
105     }
106
107     /**
108      * Create a new {@link ServerBootstrap} based on this factory's {@link EventLoopGroup}s.
109      *
110      * @return A new {@link ServerBootstrap}
111      */
112     public @NonNull ServerBootstrap newServerBootstrap() {
113         return NettyTransportSupport.newServerBootstrap().group(parentGroup != null ? parentGroup : group, group);
114     }
115
116     @Override
117     public void close() {
118         if (parentGroup != null) {
119             parentGroup.shutdownGracefully();
120         }
121         group.shutdownGracefully();
122     }
123 }