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  package org.waarp.openr66.context.task.localexec;
21  
22  import io.netty.bootstrap.Bootstrap;
23  import io.netty.channel.Channel;
24  import io.netty.channel.ChannelFuture;
25  import org.waarp.commandexec.client.LocalExecClientHandler;
26  import org.waarp.commandexec.client.LocalExecClientInitializer;
27  import org.waarp.commandexec.utils.LocalExecResult;
28  import org.waarp.common.crypto.ssl.WaarpSslUtility;
29  import org.waarp.common.future.WaarpFuture;
30  import org.waarp.common.logging.SysErrLogger;
31  import org.waarp.common.logging.WaarpLogger;
32  import org.waarp.common.logging.WaarpLoggerFactory;
33  import org.waarp.common.utility.WaarpNettyUtil;
34  import org.waarp.openr66.protocol.configuration.Configuration;
35  
36  import java.net.InetSocketAddress;
37  
38  /**
39   * Client to execute external command through Waarp Local Exec
40   */
41  public class LocalExecClient {
42    /**
43     * Internal Logger
44     */
45    private static final WaarpLogger logger =
46        WaarpLoggerFactory.getLogger(LocalExecClient.class);
47  
48    public static InetSocketAddress address;
49    // Configure the client.
50    private static Bootstrap bootstrapLocalExec;
51    // Configure the pipeline factory.
52    private static LocalExecClientInitializer localExecClientInitializer;
53  
54    /**
55     * Initialize the LocalExec Client context
56     */
57    public static void initialize() {
58      // Configure the client.
59      bootstrapLocalExec = new Bootstrap();
60      WaarpNettyUtil.setBootstrap(bootstrapLocalExec,
61                                  Configuration.configuration.getSubTaskGroup(),
62                                  (int) Configuration.configuration.getTimeoutCon());
63      // Configure the pipeline factory.
64      localExecClientInitializer = new LocalExecClientInitializer();
65      bootstrapLocalExec.handler(localExecClientInitializer);
66    }
67  
68    /**
69     * To be called when the server is shutting down to release the resources
70     */
71    public static void releaseResources() {
72      if (bootstrapLocalExec == null) {
73        return;
74      }
75      // Shut down all thread pools to exit.
76      bootstrapLocalExec.config().group().shutdownGracefully();
77      localExecClientInitializer.releaseResources();
78    }
79  
80    private Channel channel;
81    private LocalExecResult result;
82  
83    public LocalExecClient() {
84      // nothing
85    }
86  
87    public final LocalExecResult getLocalExecResult() {
88      return result;
89    }
90  
91    /**
92     * Run one command with a specific allowed delay for execution. The
93     * connection
94     * must be ready (done with
95     * connect()).
96     *
97     * @param command
98     * @param delay
99     * @param futureCompletion
100    */
101   public final void runOneCommand(final String command, final long delay,
102                                   final boolean waitFor,
103                                   final WaarpFuture futureCompletion) {
104     // Initialize the command context
105     final LocalExecClientHandler clientHandler =
106         (LocalExecClientHandler) channel.pipeline().last();
107     // Command to execute
108     clientHandler.initExecClient(delay, command);
109     if (!waitFor) {
110       futureCompletion.setSuccess();
111       logger.info("Exec OK with {}", command);
112     }
113     // Wait for the end of the exec command
114     result = clientHandler.waitFor(delay * 2);
115     if (futureCompletion == null) {
116       return;
117     }
118     if (result.getStatus() == 0) {
119       if (waitFor) {
120         futureCompletion.setSuccess();
121       }
122       logger.info("Exec OK with {}", command);
123     } else if (result.getStatus() == 1) {
124       logger.warn("Exec in warning with {}", command);
125       if (waitFor) {
126         futureCompletion.setSuccess();
127       }
128     } else {
129       logger.error(
130           "Status: " + result.getStatus() + " Exec in error with " + command +
131           ' ' + result.getResult());
132       if (waitFor) {
133         futureCompletion.cancel();
134       }
135     }
136   }
137 
138   /**
139    * Connect to the Server
140    */
141   public final boolean connect() {
142     // Start the connection attempt.
143     final ChannelFuture future = bootstrapLocalExec.connect(address);
144 
145     // Wait until the connection attempt succeeds or fails.
146     try {
147       channel = future.await().sync().channel();
148     } catch (final InterruptedException e) {//NOSONAR
149       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
150     }
151     if (!future.isSuccess()) {
152       logger.error("Client Not Connected", future.cause());
153       return false;
154     }
155     return true;
156   }
157 
158   /**
159    * Disconnect from the server
160    */
161   public final void disconnect() {
162     // Close the connection. Make sure the close operation ends because
163     // all I/O operations are asynchronous in Netty.
164     WaarpNettyUtil.awaitOrInterrupted(
165         WaarpSslUtility.closingSslChannel(channel));
166   }
167 }