Merge branch 'master' into oauth_login
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / RemoteOperation.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18 package com.owncloud.android.operations;
19
20 import java.io.IOException;
21
22 import com.owncloud.android.network.OwnCloudClientUtils;
23
24 import android.accounts.Account;
25 import android.accounts.AccountsException;
26 import android.app.Activity;
27 import android.content.Context;
28 import android.os.Handler;
29 import android.util.Log;
30
31 import eu.alefzero.webdav.WebdavClient;
32
33 /**
34 * Operation which execution involves one or several interactions with an ownCloud server.
35 *
36 * Provides methods to execute the operation both synchronously or asynchronously.
37 *
38 * @author David A. Velasco
39 */
40 public abstract class RemoteOperation implements Runnable {
41
42 private static final String TAG = RemoteOperation.class.getSimpleName();
43
44 /** ownCloud account in the remote ownCloud server to operate */
45 private Account mAccount = null;
46
47 /** Android Application context */
48 private Context mContext = null;
49
50 /** Object to interact with the remote server */
51 private WebdavClient mClient = null;
52
53 /** Callback object to notify about the execution of the remote operation */
54 private OnRemoteOperationListener mListener = null;
55
56 /** Handler to the thread where mListener methods will be called */
57 private Handler mListenerHandler = null;
58
59 /** Activity */
60 private Activity mCallerActivity;
61
62
63 /**
64 * Abstract method to implement the operation in derived classes.
65 */
66 protected abstract RemoteOperationResult run(WebdavClient client);
67
68
69 /**
70 * Synchronously executes the remote operation on the received ownCloud account.
71 *
72 * Do not call this method from the main thread.
73 *
74 * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}.
75 *
76 * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
77 * @param context Android context for the component calling the method.
78 * @return Result of the operation.
79 */
80 public final RemoteOperationResult execute(Account account, Context context) {
81 if (account == null)
82 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
83 if (context == null)
84 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
85 mAccount = account;
86 mContext = context.getApplicationContext();
87 try {
88 mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
89 } catch (Exception e) {
90 Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
91 return new RemoteOperationResult(e);
92 }
93 return run(mClient);
94 }
95
96
97 /**
98 * Synchronously executes the remote operation
99 *
100 * Do not call this method from the main thread.
101 *
102 * @param client Client object to reach an ownCloud server during the execution of the operation.
103 * @return Result of the operation.
104 */
105 public final RemoteOperationResult execute(WebdavClient client) {
106 if (client == null)
107 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
108 mClient = client;
109 return run(client);
110 }
111
112
113 /**
114 * Asynchronously executes the remote operation
115 *
116 * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}.
117 *
118 * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
119 * @param context Android context for the component calling the method.
120 * @param listener Listener to be notified about the execution of the operation.
121 * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
122 * @return Thread were the remote operation is executed.
123 */
124 public final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
125 if (account == null)
126 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
127 if (context == null)
128 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
129 mAccount = account;
130 mContext = context.getApplicationContext();
131 mCallerActivity = callerActivity;
132 mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below
133
134 if (listener == null) {
135 throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
136 }
137 mListener = listener;
138
139 if (listenerHandler == null) {
140 throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
141 }
142 mListenerHandler = listenerHandler;
143
144 Thread runnerThread = new Thread(this);
145 runnerThread.start();
146 return runnerThread;
147 }
148
149
150 /**
151 * Asynchronously executes the remote operation
152 *
153 * @param client Client object to reach an ownCloud server during the execution of the operation.
154 * @param listener Listener to be notified about the execution of the operation.
155 * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
156 * @return Thread were the remote operation is executed.
157 */
158 public final Thread execute(WebdavClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
159 if (client == null) {
160 throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
161 }
162 mClient = client;
163
164 if (listener == null) {
165 throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
166 }
167 mListener = listener;
168
169 if (listenerHandler == null) {
170 throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
171 }
172 mListenerHandler = listenerHandler;
173
174 Thread runnerThread = new Thread(this);
175 runnerThread.start();
176 return runnerThread;
177 }
178
179 /**
180 * Synchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient)}
181 *
182 * @param listener Listener to be notified about the execution of the operation.
183 * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
184 * @return Thread were the remote operation is executed.
185 */
186 public final RemoteOperationResult retry() {
187 return execute(mClient);
188 }
189
190 /**
191 * Asynchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}
192 *
193 * @param listener Listener to be notified about the execution of the operation.
194 * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
195 * @return Thread were the remote operation is executed.
196 */
197 public final Thread retry(OnRemoteOperationListener listener, Handler listenerHandler) {
198 return execute(mClient, listener, listenerHandler);
199 }
200
201
202 /**
203 * Asynchronous execution of the operation
204 * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)},
205 * and result posting.
206 */
207 @Override
208 public final void run() {
209 RemoteOperationResult result = null;
210 try{
211 if (mClient == null) {
212 if (mAccount != null && mContext != null) {
213 if (mCallerActivity != null) {
214 mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity);
215 } else {
216 mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
217 }
218 } else {
219 throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
220 }
221 }
222
223 } catch (IOException e) {
224 Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
225 result = new RemoteOperationResult(e);
226
227 } catch (AccountsException e) {
228 Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
229 result = new RemoteOperationResult(e);
230 }
231
232 if (result == null)
233 result = run(mClient);
234
235 final RemoteOperationResult resultToSend = result;
236 if (mListenerHandler != null && mListener != null) {
237 mListenerHandler.post(new Runnable() {
238 @Override
239 public void run() {
240 mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
241 }
242 });
243 }
244 }
245
246
247 /**
248 * Returns the current client instance to access the remote server.
249 *
250 * @return Current client instance to access the remote server.
251 */
252 public final WebdavClient getClient() {
253 return mClient;
254 }
255
256 }