1 package ch
.cyberduck
.core
.threading
;
4 * Copyright (c) 2002-2013 David Kocher. All rights reserved.
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
;
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
;
63 * Keeping track of the current transfer rate
65 private TransferSpeedometer meter
;
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);
159 switch(new TransferTypeFinder().type(session
, transfer
)) {
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
,
167 this.worker
= new SingleTransferWorker(session
, transfer
, options
,
168 meter
, prompt
, error
, this, progress
, stream
, callback
);
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()) {
181 switch(transfer
.getType()) {
186 final Upload feature
= session
.getFeature(Upload
.class);
187 if(feature
.pooled()) {
188 // Already pooled internally.
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
;
204 protected boolean connect(final Session session
) throws BackgroundException
{
205 switch(transfer
.getType()) {
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
)) {
215 // Skip opening connection when managed in pool
218 return super.connect(session
);
223 protected void close(final Session session
) throws BackgroundException
{
224 super.close(session
);
225 switch(transfer
.getType()) {
227 final Session target
= ((CopyTransfer
) transfer
).getDestination();
233 public void complete(final TransferItem item
) {
234 // Reset repeat counter. #8223
239 public void prepare() throws ConnectionCanceledException
{
242 listener
.start(transfer
);
243 timerPool
= new ScheduledThreadPool();
244 progressTimer
= timerPool
.repeat(new Runnable() {
247 if(transfer
.isReset()) {
248 listener
.progress(meter
.getStatus());
251 }, 100L, TimeUnit
.MILLISECONDS
);
255 public void message(final String message
) {
256 super.message(message
);
257 prompt
.message(message
);
260 public void finish() {
262 progressTimer
.cancel(false);
264 listener
.stop(transfer
);
265 timerPool
.shutdown();
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;
280 public String
getActivity() {
281 return StringUtils
.EMPTY
;
284 public TransferSpeedometer
getMeter() {
288 public Transfer
getTransfer() {