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:
18 * feedback@cyberduck.ch
21 import ch
.cyberduck
.core
.BookmarkNameProvider
;
22 import ch
.cyberduck
.core
.Cache
;
23 import ch
.cyberduck
.core
.ConnectionService
;
24 import ch
.cyberduck
.core
.HostKeyCallback
;
25 import ch
.cyberduck
.core
.LoginCallback
;
26 import ch
.cyberduck
.core
.LoginConnectionService
;
27 import ch
.cyberduck
.core
.LoginService
;
28 import ch
.cyberduck
.core
.PasswordStoreFactory
;
29 import ch
.cyberduck
.core
.Path
;
30 import ch
.cyberduck
.core
.ProgressListener
;
31 import ch
.cyberduck
.core
.Session
;
32 import ch
.cyberduck
.core
.TranscriptListener
;
33 import ch
.cyberduck
.core
.exception
.BackgroundException
;
34 import ch
.cyberduck
.core
.exception
.ConnectionCanceledException
;
35 import ch
.cyberduck
.core
.preferences
.PreferencesFactory
;
37 import org
.apache
.log4j
.Logger
;
42 public abstract class SessionBackgroundAction
<T
> extends AbstractBackgroundAction
<T
>
43 implements ProgressListener
, TranscriptListener
{
44 private static final Logger log
= Logger
.getLogger(SessionBackgroundAction
.class);
47 * Contains all exceptions thrown while this action was running
49 private BackgroundException exception
;
52 * This action encountered one or more exceptions
54 private boolean failed
;
57 * Contains the transcript of the session while this action was running
59 private StringBuilder transcript
60 = new StringBuilder();
63 * The number of times this action has been run
65 protected int repeat
= 0;
67 private static final String LINE_SEPARATOR
68 = System
.getProperty("line.separator");
70 private AlertCallback alert
;
72 private ProgressListener progressListener
;
74 private TranscriptListener transcriptListener
;
76 protected ConnectionService connection
;
78 private final FailureDiagnostics
<Exception
> diagnostics
79 = new DefaultFailureDiagnostics();
81 protected Session
<?
> session
;
83 private Cache
<Path
> cache
;
85 public SessionBackgroundAction(final Session
<?
> session
,
86 final Cache
<Path
> cache
,
87 final AlertCallback alert
,
88 final ProgressListener progress
,
89 final TranscriptListener transcript
,
90 final LoginCallback prompt
,
91 final HostKeyCallback key
) {
92 this(new LoginConnectionService(prompt
, key
, PasswordStoreFactory
.get(),
93 progress
, transcript
), session
, cache
, alert
, progress
, transcript
);
96 public SessionBackgroundAction(final LoginService login
,
97 final Session
<?
> session
,
98 final Cache
<Path
> cache
,
99 final AlertCallback alert
,
100 final ProgressListener progress
,
101 final TranscriptListener transcript
,
102 final HostKeyCallback key
) {
103 this(new LoginConnectionService(login
, key
, progress
, transcript
), session
, cache
, alert
, progress
, transcript
);
106 public SessionBackgroundAction(final ConnectionService connection
,
107 final Session
<?
> session
,
108 final Cache
<Path
> cache
,
109 final AlertCallback alert
,
110 final ProgressListener progress
,
111 final TranscriptListener transcript
) {
112 this.connection
= connection
;
113 this.session
= session
;
116 this.progressListener
= progress
;
117 this.transcriptListener
= transcript
;
120 public BackgroundException
getException() {
125 public void message(final String message
) {
126 progressListener
.message(message
);
130 * Append to the transcript and notify listeners.
133 public void log(final boolean request
, final String message
) {
134 transcript
.append(message
).append(LINE_SEPARATOR
);
135 transcriptListener
.log(request
, message
);
139 public void prepare() throws ConnectionCanceledException
{
141 this.message(this.getActivity());
145 public void cancel() {
151 * The number of times a new connection attempt should be made. Takes into
152 * account the number of times already tried.
154 * @return Greater than zero if a failed action should be repeated again
156 protected int retry() {
157 // The initial connection attempt does not count
158 return PreferencesFactory
.get().getInteger("connection.retry") - repeat
;
161 protected void reset() throws BackgroundException
{
162 // Clear the transcript and exceptions
163 transcript
= new StringBuilder();
164 // Reset the failure status but remember the previous exception for automatic retry.
169 * @return True if the the action had a permanent failures. Returns false if
170 * there were only temporary exceptions and the action succeeded upon retry
172 public boolean hasFailed() {
182 this.connect(session
);
186 catch(ConnectionCanceledException failure
) {
187 // Do not report as failed if instanceof ConnectionCanceledException
188 log
.warn(String
.format("Connection canceled %s", failure
.getMessage()));
190 catch(BackgroundException failure
) {
191 log
.warn(String
.format("Failure executing background action: %s", failure
));
194 if(diagnostics
.determine(failure
) == FailureDiagnostics
.Type
.network
) {
195 if(this.retry() > 0) {
196 if(log
.isInfoEnabled()) {
197 log
.info(String
.format("Retry failed background action %s", this));
199 // This is an automated retry. Wait some time first.
201 if(!this.isCanceled()) {
203 // Re-run the action with the previous lock used
212 protected boolean connect(final Session session
) throws BackgroundException
{
213 if(connection
.check(session
, cache
, exception
)) {
216 // Use existing connection
220 protected void close(final Session session
) throws BackgroundException
{
226 public boolean alert() {
227 if(this.hasFailed() && !this.isCanceled()) {
228 // Display alert if the action was not canceled intentionally
229 return alert
.alert(session
.getHost(), exception
, transcript
);
235 public void cleanup() {
240 * Idle this action for some time. Blocks the caller.
242 public void pause() {
243 final BackgroundActionPauser pauser
= new BackgroundActionPauser(this);
248 public String
getName() {
249 return BookmarkNameProvider
.toString(session
.getHost());
253 * @return The session instance
256 public Object
lock() {
261 public String
toString() {
262 final StringBuilder sb
= new StringBuilder("SessionBackgroundAction{");
263 sb
.append("session=").append(session
);
264 sb
.append(", failed=").append(failed
);
265 sb
.append(", exception=").append(exception
);
267 return sb
.toString();