Connect to copy target first.
[cyberduck.git] / source / ch / cyberduck / core / threading / TransferBackgroundAction.java
blobeeeff1c5b37d14ba20a309a56fa25ee0e33f3e3f
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())), new KeychainX509KeyManager());
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 void reset() throws BackgroundException {
205 super.reset();
206 transfer.start();
209 @Override
210 protected boolean connect(final Session session) throws BackgroundException {
211 switch(transfer.getType()) {
212 case copy:
213 final Session target = ((CopyTransfer) transfer).getDestination();
214 if(connection.check(target, PathCache.empty())) {
215 // New connection opened
216 growl.notify("Connection opened", session.getHost().getHostname());
219 switch(new TransferTypeFinder().type(session, transfer)) {
220 case concurrent:
221 // Skip opening connection when managed in pool
222 return false;
223 default:
224 return super.connect(session);
228 @Override
229 protected void close(final Session session) throws BackgroundException {
230 super.close(session);
231 switch(transfer.getType()) {
232 case copy:
233 final Session target = ((CopyTransfer) transfer).getDestination();
234 super.close(target);
238 @Override
239 public void complete(final TransferItem item) {
240 // Reset repeat counter. #8223
241 repeat = 0;
244 @Override
245 public void prepare() throws ConnectionCanceledException {
246 super.prepare();
247 listener.start(transfer);
248 timerPool = new ScheduledThreadPool();
249 progressTimer = timerPool.repeat(new Runnable() {
250 @Override
251 public void run() {
252 if(transfer.isReset()) {
253 listener.progress(meter.getStatus());
256 }, 100L, TimeUnit.MILLISECONDS);
259 @Override
260 public void message(final String message) {
261 super.message(message);
262 prompt.message(message);
265 public void finish() {
266 super.finish();
267 progressTimer.cancel(false);
268 transfer.stop();
269 listener.stop(transfer);
270 timerPool.shutdown();
273 @Override
274 public void pause() {
275 if(log.isDebugEnabled()) {
276 log.debug(String.format("Pause background action for transfer %s", transfer));
278 // Upon retry do not suggest to overwrite already completed items from the transfer
279 options.reloadRequested = false;
280 options.resumeRequested = true;
281 super.pause();
284 @Override
285 public String getActivity() {
286 return StringUtils.EMPTY;
289 public TransferSpeedometer getMeter() {
290 return meter;
293 public Transfer getTransfer() {
294 return transfer;