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.client;
21  
22  import org.waarp.common.database.exception.WaarpDatabaseException;
23  import org.waarp.common.logging.SysErrLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  import org.waarp.common.logging.WaarpSlf4JLoggerFactory;
26  import org.waarp.common.utility.WaarpSystemUtil;
27  import org.waarp.openr66.client.utils.OutputFormat;
28  import org.waarp.openr66.client.utils.OutputFormat.FIELDS;
29  import org.waarp.openr66.context.ErrorCode;
30  import org.waarp.openr66.context.R66Result;
31  import org.waarp.openr66.database.data.DbRule;
32  import org.waarp.openr66.protocol.configuration.Configuration;
33  import org.waarp.openr66.protocol.configuration.Messages;
34  import org.waarp.openr66.protocol.networkhandler.NetworkTransaction;
35  import org.waarp.openr66.protocol.utils.R66Future;
36  
37  import java.util.ArrayList;
38  import java.util.List;
39  
40  import static org.waarp.common.database.DbConstant.*;
41  
42  /**
43   * Direct Transfer from a client with or without database connection to transfer
44   * for multiple files to
45   * multiple hosts at once.<br>
46   * Files will have to be separated by ','.<br>
47   * Hosts will have to be separated by ','.<br>
48   * <br>
49   * For instance: -to host1,host2,host3 -file file1,file2 <br>
50   * Will generate: <br>
51   * -to host1 -file file1<br>
52   * -to host1 -file file2<br>
53   * -to host2 -file file1<br>
54   * -to host2 -file file2<br>
55   * -to host3 -file file1<br>
56   * -to host3 -file file2<br>
57   */
58  public class MultipleDirectTransfer extends DirectTransfer {
59    private static final String TRANSFER_STATUS = "Transfer.Status";
60    private int errorMultiple;
61    private int doneMultiple;
62    private final List<OutputFormat> results = new ArrayList<OutputFormat>();
63  
64    public MultipleDirectTransfer(final R66Future future, final String remoteHost,
65                                  final String filename, final String rulename,
66                                  final String fileinfo, final boolean isMD5,
67                                  final int blocksize, final long id,
68                                  final NetworkTransaction networkTransaction) {
69      // no starttime since it is direct (blocking request, no delay)
70      super(future, remoteHost, filename, rulename, fileinfo, isMD5, blocksize,
71            id, networkTransaction);
72    }
73  
74    @Override
75    public void run() {
76      if (logger == null) {
77        logger = WaarpLoggerFactory.getLogger(MultipleDirectTransfer.class);
78      }
79      final String[] localfilenames = transferArgs.getFilename().split(",");
80      final String[] rhosts = transferArgs.getRemoteHost().split(",");
81      boolean inError = false;
82      R66Result resultError = null;
83      // first check if filenames contains wildcards
84      final DbRule dbrule;
85      try {
86        dbrule = new DbRule(transferArgs.getRulename());
87      } catch (final WaarpDatabaseException e1) {
88        logger.error(Messages.getString("Transfer.18") + ": {}",
89                     e1.getMessage()); //$NON-NLS-1$
90        future.setFailure(e1);
91        return;
92      }
93      List<String> files = null;
94      if (dbrule.isSendMode()) {
95        files = getLocalFiles(dbrule, localfilenames);
96      }
97      for (String host : rhosts) {
98        host = host.trim();
99        if (!host.isEmpty()) {
100         if (dbrule.isRecvMode()) {
101           files = getRemoteFiles(localfilenames, host, networkTransaction);
102         }
103         for (String filename : files) {
104           filename = filename.trim();
105           if (!filename.isEmpty()) {
106             logger.info(
107                 "Launch transfer to " + host + " with file " + filename);
108             final long time1 = System.currentTimeMillis();
109             final R66Future future = new R66Future(true);
110             final DirectTransfer transaction =
111                 runDirectTransfer(host, filename, future);
112             final long time2 = System.currentTimeMillis();
113             logger.debug("finish transfer: {}", future.isSuccess());
114             final long delay = time2 - time1;
115             final R66Result result = future.getResult();
116             final OutputFormat outputFormat = new OutputFormat(
117                 "Unique " + MultipleDirectTransfer.class.getSimpleName(), null);
118             if (future.isSuccess()) {
119               successTransfer(transaction, delay, result, outputFormat);
120             } else {
121               if (result == null || result.getRunner() == null) {
122                 prepareKoOutputFormat(future, outputFormat);
123                 outputFormat.sysout();
124                 if (WaarpSystemUtil.isJunit()) {
125                   return;
126                 }
127                 networkTransaction.closeAll();
128                 WaarpSystemUtil.systemExit(ErrorCode.Unknown.ordinal());
129                 return;
130               }
131               prepareKoOutputFormat(future, result, outputFormat);
132               getResults().add(outputFormat);
133               setErrorMultiple(getErrorMultiple() + 1);
134               inError = true;
135               resultError = result;
136             }
137           }
138         }
139       }
140     }
141     if (inError) {
142       if (resultError != null) {
143         future.setResult(resultError);
144       }
145       future.cancel();
146     } else {
147       future.setSuccess();
148     }
149   }
150 
151   private void successTransfer(final DirectTransfer transaction,
152                                final long delay, final R66Result result,
153                                final OutputFormat outputFormat) {
154     prepareOkOutputFormat(delay, result, outputFormat);
155     getResults().add(outputFormat);
156     setDoneMultiple(getDoneMultiple() + 1);
157     if (transaction.normalInfoAsWarn) {
158       logger.warn(outputFormat.loggerOut());
159     } else if (logger.isInfoEnabled()) {
160       logger.info(outputFormat.loggerOut());
161     }
162     if (nolog) {
163       // In case of success, delete the runner
164       try {
165         result.getRunner().delete();
166       } catch (final WaarpDatabaseException e) {
167         logger.warn(
168             "Cannot apply nolog to     " + result.getRunner().toShortString() +
169             " : {}", e.getMessage());
170       }
171     }
172   }
173 
174   private DirectTransfer runDirectTransfer(final String host,
175                                            final String filename,
176                                            final R66Future future) {
177     final DirectTransfer transaction =
178         new DirectTransfer(future, host, filename, transferArgs.getRulename(),
179                            transferArgs.getTransferInfo(), transferArgs.isMD5(),
180                            transferArgs.getBlockSize(), transferArgs.getId(),
181                            networkTransaction);
182     transaction.transferArgs.setFollowId(transferArgs.getFollowId());
183     transaction.normalInfoAsWarn = normalInfoAsWarn;
184     logger.debug("rhost: {}:{}", host,
185                  transaction.transferArgs.getRemoteHost());
186     transaction.run();
187     future.awaitOrInterruptible();
188     return transaction;
189   }
190 
191   public static void main(final String[] args) {
192     WaarpLoggerFactory.setDefaultFactoryIfNotSame(
193         new WaarpSlf4JLoggerFactory(null));
194     if (logger == null) {
195       logger = WaarpLoggerFactory.getLogger(MultipleDirectTransfer.class);
196     }
197     if (!getParams(args, false)) {
198       logger.error(Messages.getString("Configuration.WrongInit")); //$NON-NLS-1$
199       if (!OutputFormat.isQuiet()) {
200         SysErrLogger.FAKE_LOGGER.sysout(
201             Messages.getString("Configuration.WrongInit")); //$NON-NLS-1$
202       }
203       if (admin != null) {
204         admin.close();
205       }
206       WaarpSystemUtil.systemExit(2);
207       return;
208     }
209 
210     Configuration.configuration.pipelineInit();
211     final NetworkTransaction networkTransaction = new NetworkTransaction();
212     try {
213       final R66Future future = new R66Future(true);
214       final long time1 = System.currentTimeMillis();
215       final MultipleDirectTransfer multipleDirectTransfer =
216           new MultipleDirectTransfer(future, rhost, localFilename, rule,
217                                      transferInfo, ismd5, block, idt,
218                                      networkTransaction);
219       multipleDirectTransfer.normalInfoAsWarn = snormalInfoAsWarn;
220       multipleDirectTransfer.run();
221       future.awaitOrInterruptible();
222       final long time2 = System.currentTimeMillis();
223       logger.debug("finish all transfers: {}", future.isSuccess());
224       final long delay = time2 - time1;
225       final OutputFormat outputFormat =
226           new OutputFormat(MultipleDirectTransfer.class.getSimpleName(), args);
227       if (future.isSuccess()) {
228         outputFormat.setValue(FIELDS.status.name(), 0);
229         outputFormat.setValue(FIELDS.statusTxt.name(), "Multiple " +
230                                                        Messages.getString(
231                                                            TRANSFER_STATUS) +
232                                                        Messages.getString(
233                                                            "RequestInformation.Success")); //$NON-NLS-1$
234         outputFormat.setValue(FIELDS.remote.name(), rhost);
235         outputFormat.setValue("ok", multipleDirectTransfer.getDoneMultiple());
236         outputFormat.setValue("delay", delay);
237         if (multipleDirectTransfer.normalInfoAsWarn) {
238           logger.warn(outputFormat.loggerOut());
239         } else if (logger.isInfoEnabled()) {
240           logger.info(outputFormat.loggerOut());
241         }
242         if (!OutputFormat.isQuiet()) {
243           outputFormat.sysout();
244           for (final OutputFormat result : multipleDirectTransfer.getResults()) {
245             SysErrLogger.FAKE_LOGGER.sysout();
246             result.sysout();
247           }
248         }
249       } else {
250         outputFormat.setValue(FIELDS.status.name(), 2);
251         outputFormat.setValue(FIELDS.statusTxt.name(), "Multiple " +
252                                                        Messages.getString(
253                                                            TRANSFER_STATUS) +
254                                                        Messages.getString(
255                                                            "RequestInformation.Failure")); //$NON-NLS-1$
256         outputFormat.setValue(FIELDS.remote.name(), rhost);
257         outputFormat.setValue("ok", multipleDirectTransfer.getDoneMultiple());
258         outputFormat.setValue("ko", multipleDirectTransfer.getErrorMultiple());
259         outputFormat.setValue("delay", delay);
260         logger.error(outputFormat.loggerOut());
261         if (!OutputFormat.isQuiet()) {
262           outputFormat.sysout();
263           for (final OutputFormat result : multipleDirectTransfer.getResults()) {
264             SysErrLogger.FAKE_LOGGER.sysout();
265             result.sysout();
266           }
267         }
268         if (WaarpSystemUtil.isJunit()) {
269           return;
270         }
271         networkTransaction.closeAll();
272         WaarpSystemUtil.systemExit(multipleDirectTransfer.getErrorMultiple());
273       }
274     } catch (final Throwable e) {
275       logger.error("Exception", e);
276     } finally {
277       if (!WaarpSystemUtil.isJunit()) {
278         networkTransaction.closeAll();
279         WaarpSystemUtil.systemExit(0);
280       }
281     }
282   }
283 
284   /**
285    * @return the errorMultiple
286    */
287   public final int getErrorMultiple() {
288     return errorMultiple;
289   }
290 
291   /**
292    * @param errorMultiple the errorMultiple to set
293    */
294   private void setErrorMultiple(final int errorMultiple) {
295     this.errorMultiple = errorMultiple;
296   }
297 
298   /**
299    * @return the doneMultiple
300    */
301   public final int getDoneMultiple() {
302     return doneMultiple;
303   }
304 
305   /**
306    * @param doneMultiple the doneMultiple to set
307    */
308   private void setDoneMultiple(final int doneMultiple) {
309     this.doneMultiple = doneMultiple;
310   }
311 
312   /**
313    * @return the results
314    */
315   public final List<OutputFormat> getResults() {
316     return results;
317   }
318 }