View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.gateway.ftp.exec;
22  
23  import io.netty.bootstrap.Bootstrap;
24  import io.netty.channel.Channel;
25  import io.netty.channel.ChannelFuture;
26  import io.netty.channel.EventLoopGroup;
27  import io.netty.channel.nio.NioEventLoopGroup;
28  import org.waarp.commandexec.client.LocalExecClientHandler;
29  import org.waarp.commandexec.client.LocalExecClientInitializer;
30  import org.waarp.commandexec.utils.LocalExecResult;
31  import org.waarp.common.crypto.ssl.WaarpSslUtility;
32  import org.waarp.common.future.WaarpFuture;
33  import org.waarp.common.logging.SysErrLogger;
34  import org.waarp.common.logging.WaarpLogger;
35  import org.waarp.common.logging.WaarpLoggerFactory;
36  import org.waarp.common.utility.WaarpNettyUtil;
37  import org.waarp.common.utility.WaarpThreadFactory;
38  import org.waarp.openr66.protocol.configuration.Configuration;
39  
40  import java.net.InetSocketAddress;
41  
42  /**
43   * Client to execute external command through Waarp Local Exec
44   */
45  public class LocalExecClient {
46    /**
47     * Internal Logger
48     */
49    private static final WaarpLogger logger =
50        WaarpLoggerFactory.getLogger(LocalExecClient.class);
51  
52    private static InetSocketAddress address;
53    // Configure the client.
54    private static Bootstrap bootstrapLocalExec;
55    // Configure the pipeline factory.
56    private static LocalExecClientInitializer localExecClientInitializer;
57  
58    /**
59     * Initialize the LocalExec Client context
60     */
61    public static void initialize(final int clientThread,
62                                  final long maxGlobalMemory) {
63      final EventLoopGroup localPipelineExecutor =
64          new NioEventLoopGroup(clientThread * 2,
65                                new WaarpThreadFactory("LocalExecutor"));
66      // Configure the client.
67      bootstrapLocalExec = new Bootstrap();
68      WaarpNettyUtil.setBootstrap(bootstrapLocalExec, localPipelineExecutor,
69                                  (int) Configuration.configuration.getTimeoutCon());
70      // Configure the pipeline factory.
71      localExecClientInitializer = new LocalExecClientInitializer();
72      bootstrapLocalExec.handler(localExecClientInitializer);
73    }
74  
75    /**
76     * To be called when the server is shutting down to release the resources
77     */
78    public static void releaseResources() {
79      if (bootstrapLocalExec == null) {
80        return;
81      }
82      // Shut down all thread pools to exit.
83      bootstrapLocalExec.config().group().shutdownGracefully();
84      localExecClientInitializer.releaseResources();
85    }
86  
87    private Channel channel;
88    private LocalExecResult result;
89  
90    public LocalExecClient() {
91      // nothing
92    }
93  
94    public final LocalExecResult getLocalExecResult() {
95      return result;
96    }
97  
98    /**
99     * Run one command with a specific allowed delay for execution. The
100    * connection
101    * must be ready (done with
102    * connect()).
103    *
104    * @param command
105    * @param delay
106    * @param futureCompletion
107    */
108   public final void runOneCommand(final String command, final long delay,
109                                   final WaarpFuture futureCompletion) {
110     // Initialize the command context
111     final LocalExecClientHandler clientHandler =
112         (LocalExecClientHandler) channel.pipeline().last();
113     // Command to execute
114     clientHandler.initExecClient(delay, command);
115     // Wait for the end of the exec command
116     result = clientHandler.waitFor(delay * 2);
117     if (futureCompletion == null) {
118       return;
119     }
120     if (result.getStatus() == 0) {
121       futureCompletion.setSuccess();
122       logger.info("Exec OK with {}", command);
123     } else if (result.getStatus() == 1) {
124       logger.warn("Exec in warning with {}", command);
125       futureCompletion.setSuccess();
126     } else {
127       logger.error(
128           "Status: " + result.getStatus() + " Exec in error with " + command +
129           '\n' + result.getResult());
130       futureCompletion.cancel();
131     }
132   }
133 
134   /**
135    * Connect to the Server
136    */
137   public final boolean connect() {
138     // Start the connection attempt.
139     final ChannelFuture future = bootstrapLocalExec.connect(getAddress());
140 
141     // Wait until the connection attempt succeeds or fails.
142     try {
143       channel = future.await().sync().channel();
144     } catch (final InterruptedException e) {//NOSONAR
145       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
146     }
147     if (!future.isSuccess()) {
148       logger.error("Client Not Connected", future.cause());
149       return false;
150     }
151     return true;
152   }
153 
154   /**
155    * Disconnect from the server
156    */
157   public final void disconnect() {
158     // Close the connection. Make sure the close operation ends because
159     // all I/O operations are asynchronous in Netty.
160     WaarpNettyUtil.awaitOrInterrupted(
161         WaarpSslUtility.closingSslChannel(channel));
162   }
163 
164   /**
165    * @return the address
166    */
167   public static InetSocketAddress getAddress() {
168     return address;
169   }
170 
171   /**
172    * @param address the address to set
173    */
174   public static void setAddress(final InetSocketAddress address) {
175     LocalExecClient.address = address;
176   }
177 }