Return initial value if call is not successful.
[cyberduck.git] / source / ch / cyberduck / core / threading / TransferBackgroundAction.java
blob34436278f82bb46493b8c568a2c3ab1149837207
1 package ch.cyberduck.core.threading;
3 /*
4 * Copyright (c) 2002-2013 David Kocher. All rights reserved.
5 * http://cyberduck.ch/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to feedback@cyberduck.ch
20 import ch.cyberduck.core.*;
21 import ch.cyberduck.core.exception.BackgroundException;
22 import ch.cyberduck.core.exception.ConnectionCanceledException;
23 import ch.cyberduck.core.features.Upload;
24 import ch.cyberduck.core.io.DisabledStreamListener;
25 import ch.cyberduck.core.io.StreamListener;
26 import ch.cyberduck.core.notification.NotificationService;
27 import ch.cyberduck.core.notification.NotificationServiceFactory;
28 import ch.cyberduck.core.preferences.PreferencesFactory;
29 import ch.cyberduck.core.ssl.DefaultTrustManagerHostnameCallback;
30 import ch.cyberduck.core.ssl.KeychainX509KeyManager;
31 import ch.cyberduck.core.ssl.KeychainX509TrustManager;
32 import ch.cyberduck.core.ssl.X509KeyManager;
33 import ch.cyberduck.core.ssl.X509TrustManager;
34 import ch.cyberduck.core.transfer.CopyTransfer;
35 import ch.cyberduck.core.transfer.Transfer;
36 import ch.cyberduck.core.transfer.TransferErrorCallback;
37 import ch.cyberduck.core.transfer.TransferItem;
38 import ch.cyberduck.core.transfer.TransferItemCallback;
39 import ch.cyberduck.core.transfer.TransferListener;
40 import ch.cyberduck.core.transfer.TransferOptions;
41 import ch.cyberduck.core.transfer.TransferPrompt;
42 import ch.cyberduck.core.transfer.TransferSpeedometer;
43 import ch.cyberduck.core.worker.ConcurrentTransferWorker;
44 import ch.cyberduck.core.worker.SingleTransferWorker;
46 import org.apache.commons.lang3.StringUtils;
47 import org.apache.log4j.Logger;
49 import java.util.concurrent.ScheduledFuture;
50 import java.util.concurrent.TimeUnit;
52 /**
53 * @version $Id$
55 public class TransferBackgroundAction extends WorkerBackgroundAction<Boolean> implements TransferItemCallback {
56 private static final Logger log = Logger.getLogger(TransferBackgroundAction.class);
58 private Transfer transfer;
60 private TransferOptions options;
62 /**
63 * Keeping track of the current transfer rate
65 private TransferSpeedometer meter;
67 /**
68 * Timer to update the progress indicator
70 private ScheduledFuture progressTimer;
72 private ScheduledThreadPool timerPool
73 = new ScheduledThreadPool();
75 private TransferListener listener;
77 private TransferPrompt prompt;
79 private NotificationService growl = NotificationServiceFactory.get();
81 public TransferBackgroundAction(final Controller controller,
82 final Session<?> session,
83 final PathCache cache,
84 final TransferListener listener,
85 final Transfer transfer,
86 final TransferOptions options) {
87 this(controller, session, cache, listener, controller, controller, transfer, options,
88 TransferPromptControllerFactory.get(controller, transfer, session),
89 TransferErrorCallbackControllerFactory.get(controller),
90 new TransferSpeedometer(transfer), new DisabledStreamListener());
93 public TransferBackgroundAction(final Controller controller,
94 final Session<?> session,
95 final PathCache cache,
96 final TransferListener listener,
97 final ProgressListener progress,
98 final TranscriptListener transcript,
99 final Transfer transfer,
100 final TransferOptions options) {
101 this(controller, session, cache, listener, progress, transcript, transfer, options,
102 TransferPromptControllerFactory.get(controller, transfer, session),
103 TransferErrorCallbackControllerFactory.get(controller),
104 new TransferSpeedometer(transfer), new DisabledStreamListener());
107 public TransferBackgroundAction(final Controller controller,
108 final Session<?> session,
109 final PathCache cache,
110 final TransferListener listener,
111 final ProgressListener progress,
112 final TranscriptListener transcript,
113 final Transfer transfer,
114 final TransferOptions options,
115 final TransferPrompt prompt,
116 final TransferErrorCallback error) {
117 this(controller, session, cache, listener, progress, transcript, transfer, options, prompt, error,
118 new TransferSpeedometer(transfer), new DisabledStreamListener());
121 public TransferBackgroundAction(final Controller controller,
122 final Session<?> session,
123 final PathCache cache,
124 final TransferListener listener,
125 final ProgressListener progress,
126 final TranscriptListener transcript,
127 final Transfer transfer,
128 final TransferOptions options,
129 final TransferPrompt prompt,
130 final TransferErrorCallback error,
131 final TransferSpeedometer meter,
132 final StreamListener stream) {
133 this(new KeychainLoginService(LoginCallbackFactory.get(controller), PasswordStoreFactory.get()),
134 LoginCallbackFactory.get(controller),
135 HostKeyCallbackFactory.get(controller, session.getHost().getProtocol()),
136 controller, session, cache, listener, progress, transcript, transfer, options, prompt, error, meter, stream,
137 new KeychainX509TrustManager(new DefaultTrustManagerHostnameCallback(session.getHost()), controller), new KeychainX509KeyManager(controller));
140 public TransferBackgroundAction(final LoginService login,
141 final ConnectionCallback callback,
142 final HostKeyCallback key,
143 final Controller controller,
144 final Session<?> session,
145 final PathCache cache,
146 final TransferListener listener,
147 final ProgressListener progress,
148 final TranscriptListener transcript,
149 final Transfer transfer,
150 final TransferOptions options,
151 final TransferPrompt prompt,
152 final TransferErrorCallback error,
153 final TransferSpeedometer meter,
154 final StreamListener stream,
155 final X509TrustManager x509Trust,
156 final X509KeyManager x509Key) {
157 super(new LoginConnectionService(login, key, progress, transcript), controller, session, cache, null);
158 // Initialize worker
159 switch(new TransferTypeFinder().type(session, transfer)) {
160 case concurrent:
161 final int connections = PreferencesFactory.get().getInteger("queue.maxtransfers");
162 this.worker = new ConcurrentTransferWorker(new LoginConnectionService(login, key, progress, transcript), transfer, options,
163 meter, prompt, error, this, callback, progress, stream, x509Trust, x509Key, cache,
164 connections);
165 break;
166 default:
167 this.worker = new SingleTransferWorker(session, transfer, options,
168 meter, prompt, error, this, progress, stream, callback);
170 this.meter = meter;
171 this.transfer = transfer.withCache(cache);
172 this.options = options;
173 this.listener = listener;
174 this.prompt = prompt;
177 private static final class TransferTypeFinder {
178 private Host.TransferType type(final Session<?> session, final Transfer transfer) {
179 switch(session.getTransferType()) {
180 case concurrent:
181 switch(transfer.getType()) {
182 case copy:
183 case move:
184 break;
185 case upload:
186 final Upload feature = session.getFeature(Upload.class);
187 if(feature.pooled()) {
188 // Already pooled internally.
189 break;
191 default:
192 // Setup concurrent worker if not already pooled internally
193 final int connections = PreferencesFactory.get().getInteger("queue.maxtransfers");
194 if(connections > 1) {
195 return Host.TransferType.concurrent;
199 return Host.TransferType.newconnection;
203 @Override
204 protected boolean connect(final Session session) throws BackgroundException {
205 switch(transfer.getType()) {
206 case copy:
207 final Session target = ((CopyTransfer) transfer).getDestination();
208 if(connection.check(target, PathCache.empty())) {
209 // New connection opened
210 growl.notify("Connection opened", session.getHost().getHostname());
213 switch(new TransferTypeFinder().type(session, transfer)) {
214 case concurrent:
215 // Skip opening connection when managed in pool
216 return false;
217 default:
218 return super.connect(session);
222 @Override
223 protected void close(final Session session) throws BackgroundException {
224 super.close(session);
225 switch(transfer.getType()) {
226 case copy:
227 final Session target = ((CopyTransfer) transfer).getDestination();
228 super.close(target);
232 @Override
233 public void complete(final TransferItem item) {
234 // Reset repeat counter. #8223
235 repeat = 0;
238 @Override
239 public void prepare() throws ConnectionCanceledException {
240 super.prepare();
241 transfer.start();
242 listener.start(transfer);
243 timerPool = new ScheduledThreadPool();
244 progressTimer = timerPool.repeat(new Runnable() {
245 @Override
246 public void run() {
247 if(transfer.isReset()) {
248 listener.progress(meter.getStatus());
251 }, 100L, TimeUnit.MILLISECONDS);
254 @Override
255 public void message(final String message) {
256 super.message(message);
257 prompt.message(message);
260 public void finish() {
261 super.finish();
262 progressTimer.cancel(false);
263 transfer.stop();
264 listener.stop(transfer);
265 timerPool.shutdown();
268 @Override
269 public void pause() {
270 if(log.isDebugEnabled()) {
271 log.debug(String.format("Pause background action for transfer %s", transfer));
273 // Upon retry do not suggest to overwrite already completed items from the transfer
274 options.reloadRequested = false;
275 options.resumeRequested = true;
276 super.pause();
279 @Override
280 public String getActivity() {
281 return StringUtils.EMPTY;
284 public TransferSpeedometer getMeter() {
285 return meter;
288 public Transfer getTransfer() {
289 return transfer;