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.data.AbstractDbData.UpdatedInfo;
23  import org.waarp.common.database.exception.WaarpDatabaseException;
24  import org.waarp.common.logging.SysErrLogger;
25  import org.waarp.common.logging.WaarpLoggerFactory;
26  import org.waarp.openr66.commander.ClientRunner;
27  import org.waarp.openr66.context.ErrorCode;
28  import org.waarp.openr66.context.R66Result;
29  import org.waarp.openr66.database.data.DbTaskRunner;
30  import org.waarp.openr66.protocol.configuration.Configuration;
31  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoConnectionException;
32  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotYetConnectionException;
33  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
34  import org.waarp.openr66.protocol.localhandler.LocalChannelReference;
35  import org.waarp.openr66.protocol.networkhandler.NetworkTransaction;
36  import org.waarp.openr66.protocol.utils.R66Future;
37  
38  /**
39   * Through API Transfer from a client with or without database connection, and
40   * enabling access to statistic of
41   * the transfer (unblocking transfer)
42   */
43  public abstract class ProgressBarTransfer extends AbstractTransfer {
44    protected final NetworkTransaction networkTransaction;
45    protected long intervalCallback = 100;
46    protected long filesize;
47  
48    protected ProgressBarTransfer(final R66Future future, final String remoteHost,
49                                  final String filename, final String rulename,
50                                  final String fileinfo, final boolean isMD5,
51                                  final int blocksize, final long id,
52                                  final NetworkTransaction networkTransaction,
53                                  final long callbackdelay) {
54      // no delay so starttime = null
55      super(ProgressBarTransfer.class, future, filename, rulename, fileinfo,
56            isMD5, remoteHost, blocksize, id, null);
57      this.networkTransaction = networkTransaction;
58      intervalCallback = callbackdelay;
59    }
60  
61    /**
62     * This function will be called every 100ms (or other fixed value in
63     * INTERVALCALLBACK). Note that final rank
64     * is unknown.
65     *
66     * @param currentBlock the current block rank (from 0 to n-1)
67     * @param blocksize blocksize of 1 block
68     */
69    public abstract void callBack(int currentBlock, int blocksize);
70  
71    /**
72     * This function will be called only once when the transfer is over
73     *
74     * @param success True if the transfer is successful
75     * @param currentBlock
76     * @param blocksize
77     */
78    public abstract void lastCallBack(boolean success, int currentBlock,
79                                      int blocksize);
80  
81    /**
82     * Prior to call this method, the pipeline and NetworkTransaction must have
83     * been initialized. It is the
84     * responsibility of the caller to finish all network resources.
85     */
86    @Override
87    public void run() {
88      if (logger == null) {
89        logger = WaarpLoggerFactory.getLogger(ProgressBarTransfer.class);
90      }
91      final DbTaskRunner taskRunner = initRequest();
92      if (taskRunner == null) {
93        // already an error from there
94        lastCallBack(false, 0, transferArgs.getBlockSize());
95        return;
96      }
97      final ClientRunner runner =
98          new ClientRunner(networkTransaction, taskRunner, future);
99      OpenR66ProtocolNotYetConnectionException exc = null;
100     for (int i = 0; i < Configuration.RETRYNB; i++) {
101       try {
102         logger.debug("starting connection done on progressBarTransfer");
103         final LocalChannelReference localChannelReference =
104             runner.initRequest();
105         localChannelReference.getFutureValidRequest().awaitOrInterruptible();
106         if (!localChannelReference.getFutureValidRequest().isSuccess() &&
107             localChannelReference.getFutureValidRequest() != null &&
108             localChannelReference.getFutureValidRequest().getResult()
109                                  .getCode() == ErrorCode.ServerOverloaded) {
110           switch (taskRunner.getUpdatedInfo()) {
111             case DONE:
112             case INERROR:
113             case INTERRUPTED:
114               break;
115             default:
116               runner.changeUpdatedInfo(UpdatedInfo.INERROR,
117                                        ErrorCode.ServerOverloaded, true);
118           }
119           // redo if possible
120           if (runner.incrementTaskRunnerTry(taskRunner,
121                                             Configuration.RETRYNB)) {
122             try {
123               Thread.sleep(
124                   Configuration.configuration.getConstraintLimitHandler()
125                                              .getSleepTime());
126             } catch (final InterruptedException e) {//NOSONAR
127               SysErrLogger.FAKE_LOGGER.ignoreLog(e);
128             }
129             i--;
130             continue;
131           } else {
132             throw new OpenR66ProtocolNotYetConnectionException(
133                 "End of retry on ServerOverloaded");
134           }
135         }
136         logger.debug("connection done on progressBarTransfer");
137         filesize = future.getFilesize();
138         while (!future.awaitOrInterruptible(intervalCallback)) {
139           if (future.isDone()) {
140             break;
141           }
142           callBack(future.getRunner().getRank(),
143                    future.getRunner().getBlocksize());
144         }
145         logger.debug("transfer done on progressBarTransfer");
146         runner.finishTransfer(localChannelReference);
147         lastCallBack(future.isSuccess(), future.getRunner().getRank(),
148                      future.getRunner().getBlocksize());
149         exc = null;
150         break;
151       } catch (final OpenR66ProtocolNoConnectionException e) {
152         logger.error("Cannot Connect", e);
153         future.setResult(
154             new R66Result(e, null, true, ErrorCode.ConnectionImpossible,
155                           taskRunner));
156         finalizeInErrorTransferRequest(runner, taskRunner,
157                                        ErrorCode.ConnectionImpossible);
158         // since no connection : just forget it
159         if (nolog || taskRunner.shallIgnoreSave()) {
160           try {
161             taskRunner.delete();
162           } catch (final WaarpDatabaseException ignored) {
163             // nothing
164           }
165         }
166         future.setFailure(e);
167         lastCallBack(false, taskRunner.getRank(), taskRunner.getBlocksize());
168         return;
169       } catch (final OpenR66ProtocolPacketException e) {
170         logger.error("Bad Protocol", e);
171         future.setResult(
172             new R66Result(e, null, true, ErrorCode.TransferError, taskRunner));
173         future.setFailure(e);
174         lastCallBack(false, taskRunner.getRank(), taskRunner.getBlocksize());
175         return;
176       } catch (final OpenR66ProtocolNotYetConnectionException e) {
177         logger.debug("Not Yet Connected", e);
178         exc = e;
179       }
180     }
181     if (exc != null) {
182       taskRunner.setLocalChannelReference(new LocalChannelReference());
183       logger.error("Cannot Connect", exc);
184       future.setResult(
185           new R66Result(exc, null, true, ErrorCode.ConnectionImpossible,
186                         taskRunner));
187       lastCallBack(false, taskRunner.getRank(), taskRunner.getBlocksize());
188       // since no connection : just forget it
189       if (nolog || taskRunner.shallIgnoreSave()) {
190         try {
191           taskRunner.delete();
192         } catch (final WaarpDatabaseException ignored) {
193           // nothing
194         }
195       }
196       future.setFailure(exc);
197     }
198   }
199 }