From: David A. Velasco Date: Thu, 16 Aug 2012 14:06:12 +0000 (+0200) Subject: Refactoring of WebdavClient creation and setup X-Git-Tag: oc-android-1.4.3~206 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/99d52af203f63a5dd3d43626f569ac88c5ac9b14?ds=inline Refactoring of WebdavClient creation and setup --- diff --git a/src/com/owncloud/android/Uploader.java b/src/com/owncloud/android/Uploader.java index d6e7a4ad..c3414b35 100644 --- a/src/com/owncloud/android/Uploader.java +++ b/src/com/owncloud/android/Uploader.java @@ -30,6 +30,7 @@ import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.utils.OwnCloudClientUtils; import android.accounts.Account; import android.accounts.AccountManager; @@ -373,8 +374,7 @@ public class Uploader extends ListActivity implements OnItemClickListener, andro public void uploadFiles() { try { - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - wdc.allowSelfsignedCertificates(); + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); // create last directory in path if necessary if (mCreateDir) { diff --git a/src/com/owncloud/android/authenticator/AuthenticationRunnable.java b/src/com/owncloud/android/authenticator/AuthenticationRunnable.java index dba32819..f40701f4 100644 --- a/src/com/owncloud/android/authenticator/AuthenticationRunnable.java +++ b/src/com/owncloud/android/authenticator/AuthenticationRunnable.java @@ -22,6 +22,8 @@ import java.net.URL; import org.apache.commons.httpclient.HttpStatus; +import com.owncloud.android.utils.OwnCloudClientUtils; + import eu.alefzero.webdav.WebdavClient; import android.net.Uri; @@ -52,7 +54,8 @@ public class AuthenticationRunnable implements Runnable { public void run() { Uri uri; uri = Uri.parse(mUrl.toString()); - int login_result = WebdavClient.tryToLogin(uri, mUsername, mPassword); + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(uri, mUsername, mPassword); + int login_result = wdc.tryToLogin(); switch (login_result) { case HttpStatus.SC_OK: postResult(true, uri.toString()); diff --git a/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java b/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java index 52e4eb09..2d32f188 100644 --- a/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java +++ b/src/com/owncloud/android/authenticator/ConnectionCheckerRunnable.java @@ -19,18 +19,15 @@ package com.owncloud.android.authenticator; import java.io.IOException; -import java.net.ConnectException; import java.net.MalformedURLException; import java.net.SocketException; import java.net.SocketTimeoutException; -import java.net.URI; -import java.net.URL; import java.net.UnknownHostException; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; +import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; @@ -39,6 +36,7 @@ import org.json.JSONObject; import com.owncloud.android.AccountUtils; import com.owncloud.android.authenticator.OnConnectCheckListener.ResultType; +import com.owncloud.android.utils.OwnCloudClientUtils; import com.owncloud.android.utils.OwnCloudVersion; import eu.alefzero.webdav.WebdavClient; @@ -107,15 +105,14 @@ public class ConnectionCheckerRunnable implements Runnable { private boolean tryConnection(String urlSt) { boolean retval = false; + GetMethod get = null; try { - WebdavClient wc = new WebdavClient(); - wc.allowSelfsignedCertificates(); - URL url = new URL(urlSt); // better than android.net.Uri in this case; provides URL validation - GetMethod get = new GetMethod(url.toString()); - int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(urlSt)); + get = new GetMethod(urlSt); + int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); + String response = get.getResponseBodyAsString(); switch (status) { case HttpStatus.SC_OK: { - String response = get.getResponseBodyAsString(); JSONObject json = new JSONObject(response); if (!json.getBoolean("installed")) { mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED; @@ -168,17 +165,25 @@ public class ConnectionCheckerRunnable implements Runnable { mLatestResult = ResultType.SSL_INIT_ERROR; Log.e(TAG, "SSL exception while trying connection", e); - } catch (HttpException e) { // specific exceptions from org.apache.commons.httpclient + } catch (ConnectTimeoutException e) { // timeout specific exception from org.apache.commons.httpclient + mLatestResult = ResultType.TIMEOUT; + Log.e(TAG, "Socket timeout exception while trying connection", e); + + } catch (HttpException e) { // other specific exceptions from org.apache.commons.httpclient mLatestResult = ResultType.UNKNOWN_ERROR; Log.e(TAG, "HTTP exception while trying connection", e); - } catch (IOException e) { // UnkownsServiceException, and any other weird I/O Exception that could occur + } catch (IOException e) { // UnkownsServiceException, and any other transport exceptions that could occur mLatestResult = ResultType.UNKNOWN_ERROR; Log.e(TAG, "I/O exception while trying connection", e); } catch (Exception e) { mLatestResult = ResultType.UNKNOWN_ERROR; Log.e(TAG, "Unexpected exception while trying connection", e); + + } finally { + if (get != null) + get.releaseConnection(); } return retval; diff --git a/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java b/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java index 75035464..55464199 100644 --- a/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java +++ b/src/com/owncloud/android/authenticator/EasySSLSocketFactory.java @@ -186,7 +186,7 @@ public class EasySSLSocketFactory implements ProtocolSocketFactory { socket.setSoTimeout(params.getSoTimeout()); return socket; } else { - Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout" + params.getSoTimeout()); + Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout()); Socket socket = socketfactory.createSocket(); SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); diff --git a/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java b/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java deleted file mode 100644 index f3ae82bb..00000000 --- a/src/com/owncloud/android/files/interfaces/OnDatatransferProgressListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.owncloud.android.files.interfaces; - -public interface OnDatatransferProgressListener { - void transferProgress(long progressRate); - -} diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 4aafcceb..d88dbb0c 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -7,7 +7,8 @@ import java.util.Map; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; -import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; +import eu.alefzero.webdav.OnDatatransferProgressListener; +import com.owncloud.android.utils.OwnCloudClientUtils; import android.accounts.Account; import android.accounts.AccountManager; @@ -141,22 +142,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis boolean downloadResult = false; /// prepare client object to send the request to the ownCloud server - AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE); - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - String username = mAccount.name.split("@")[0]; - String password = null; - try { - password = am.blockingGetAuthToken(mAccount, - AccountAuthenticator.AUTH_TOKEN_TYPE, true); - } catch (Exception e) { - Log.e(TAG, "Access to account credentials failed", e); - sendFinalBroadcast(downloadResult, null); - return; - } - wdc.setCredentials(username, password); - wdc.allowSelfsignedCertificates(); + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); wdc.setDataTransferProgressListener(this); - /// download will be in a temporal file File tmpFile = new File(getTemporalPath(mAccount.name) + mFilePath); diff --git a/src/com/owncloud/android/files/services/FileOperation.java b/src/com/owncloud/android/files/services/FileOperation.java index bdb76cd3..ce61dc77 100644 --- a/src/com/owncloud/android/files/services/FileOperation.java +++ b/src/com/owncloud/android/files/services/FileOperation.java @@ -21,6 +21,7 @@ import java.io.File; import com.owncloud.android.AccountUtils; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.utils.OwnCloudClientUtils; import android.accounts.Account; import android.content.Context; @@ -42,7 +43,7 @@ public class FileOperation { public boolean delete(OCFile file){ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext); - WebdavClient client = new WebdavClient(account, mContext); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(account, mContext); if(client.deleteFile(file.getRemotePath())){ File localFile = new File(file.getStoragePath()); return localFile.delete(); diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 34d795b1..488447a8 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -7,7 +7,8 @@ import java.util.Map; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; +import eu.alefzero.webdav.OnDatatransferProgressListener; +import com.owncloud.android.utils.OwnCloudClientUtils; import android.accounts.Account; import android.app.Notification; @@ -150,8 +151,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mTotalDataToSend = mSendData = mPreviousPercent = 0; /// prepare client object to send the request to the ownCloud server - WebdavClient wc = new WebdavClient(mAccount, getApplicationContext()); - wc.allowSelfsignedCertificates(); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); wc.setDataTransferProgressListener(this); /// create status notification to show the upload progress diff --git a/src/com/owncloud/android/files/services/InstantUploadService.java b/src/com/owncloud/android/files/services/InstantUploadService.java index 0324f592..a0b5b779 100644 --- a/src/com/owncloud/android/files/services/InstantUploadService.java +++ b/src/com/owncloud/android/files/services/InstantUploadService.java @@ -28,6 +28,7 @@ import org.apache.jackrabbit.webdav.client.methods.MkColMethod; import com.owncloud.android.AccountUtils; import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.utils.OwnCloudClientUtils; import com.owncloud.android.utils.OwnCloudVersion; import eu.alefzero.webdav.WebdavClient; @@ -126,35 +127,19 @@ public class InstantUploadService extends Service { public void run() { HashMap working_map; - AccountManager am = AccountManager.get(getApplicationContext()); while ((working_map = getFirstObject()) != null) { Account account = (Account) working_map.get(KEY_ACCOUNT); - String username = account.name.substring(0, account.name.lastIndexOf('@')); - String password = am.getPassword(account); String filename = (String) working_map.get(KEY_DISPLAY_NAME); String filepath = (String) working_map.get(KEY_FILE_PATH); String mimetype = (String) working_map.get(KEY_MIME_TYPE); - String oc_base_url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); - String oc_version = am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION); - OwnCloudVersion ocv = new OwnCloudVersion(oc_version); - String webdav_path = AccountUtils.getWebdavPath(ocv); - WebdavClient wdc = new WebdavClient(account, getApplicationContext()); - wdc.allowSelfsignedCertificates(); - wdc.setCredentials(username, password); + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(account, getApplicationContext()); - MkColMethod mkcol = new MkColMethod(oc_base_url+webdav_path+INSTANT_UPLOAD_DIR); int status = 0; - try { - status = wdc.executeMethod(mkcol); - Log.e(TAG, "mkcol returned " + status); - wdc.putFile(filepath, INSTANT_UPLOAD_DIR + "/" + filename, mimetype); - } catch (HttpException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } + wdc.createDirectory(INSTANT_UPLOAD_DIR); + Log.e(TAG, "mkcol returned " + status); + wdc.putFile(filepath, INSTANT_UPLOAD_DIR + "/" + filename, mimetype); } } } diff --git a/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java b/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java index e8b1fcb2..ecb320eb 100644 --- a/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java @@ -30,6 +30,7 @@ import org.apache.http.protocol.HttpContext; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.utils.OwnCloudClientUtils; import android.accounts.Account; import android.accounts.AccountManager; @@ -154,9 +155,7 @@ public abstract class AbstractOwnCloudSyncAdapter extends AccountAuthenticator.KEY_OC_URL) == null) { throw new UnknownHostException(); } - mClient = new WebdavClient(account, getContext()); - mClient.allowSelfsignedCertificates(); - // mHost = mClient.getTargetHost(); + mClient = OwnCloudClientUtils.createOwnCloudClient(account, getContext()); } return mClient; diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java index f7bfa432..1a3afe61 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -91,7 +91,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { sendStickyBroadcast(true, null); // message to signal the start to the UI - PropFindMethod query; + PropFindMethod query = null; try { mCurrentSyncTime = System.currentTimeMillis(); query = new PropFindMethod(getUri().toString() + "/"); @@ -123,6 +123,10 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { // TODO update syncResult Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t); t.printStackTrace(); + + } finally { + if (query != null) + query.releaseConnection(); // let the connection available for other methods } /* Commented code for ugly performance tests @@ -150,11 +154,12 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { } private void fetchData(String uri, SyncResult syncResult, long parentId) { + PropFindMethod query = null; try { Log.d(TAG, "fetching " + uri); // remote request - PropFindMethod query = new PropFindMethod(uri); + query = new PropFindMethod(uri); /* Commented code for ugly performance tests long responseDelay = System.currentTimeMillis(); */ @@ -236,8 +241,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { if (mDelaysIndex >= MAX_DELAYS) mDelaysIndex = 0; */ - - } catch (OperationCanceledException e) { e.printStackTrace(); @@ -254,6 +257,10 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { // TODO update syncResult Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t); t.printStackTrace(); + + } finally { + if (query != null) + query.releaseConnection(); // let the connection available for other methods } } diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java index 6344dadb..a71f65b8 100644 --- a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -266,7 +266,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity String url_str = prefix + url + webdav_path; uri = new URL(url_str); } catch (MalformedURLException e) { - // should not happend + // should not happen e.printStackTrace(); } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index da1668a2..59560048 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -70,6 +70,7 @@ import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.syncadapter.FileSyncService; import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; +import com.owncloud.android.utils.OwnCloudClientUtils; import com.owncloud.android.R; import eu.alefzero.webdav.WebdavClient; @@ -643,14 +644,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements @Override public void run() { - WebdavClient wdc = new WebdavClient(mAccount, getApplicationContext()); - - String username = mAccount.name.substring(0, - mAccount.name.lastIndexOf('@')); - String password = mAm.getPassword(mAccount); - - wdc.setCredentials(username, password); - wdc.allowSelfsignedCertificates(); + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); boolean created = wdc.createDirectory(mTargetPath); if (created) { mHandler.post(new Runnable() { diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index ae38a0a0..a77d9ad6 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -82,6 +82,7 @@ import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.ui.activity.FileDetailActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.utils.OwnCloudClientUtils; import com.owncloud.android.utils.OwnCloudVersion; import com.owncloud.android.R; @@ -661,7 +662,7 @@ public class FileDetailFragment extends SherlockFragment implements final String WEBDAV_SCRIPT = "webdav.php"; final String WEBDAV_FILES_LOCATION = "/files/"; - WebdavClient wc = new WebdavClient(); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext()); HttpConnectionManagerParams params = new HttpConnectionManagerParams(); params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5); @@ -684,7 +685,6 @@ public class FileDetailFragment extends SherlockFragment implements PropFindMethod find = new PropFindMethod(url+"/"); find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL)); Log.d("sharer", ""+ url+"/"); - wc.setCredentials(account.name.substring(0, account.name.lastIndexOf('@')), am.getPassword(account)); for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) { Log.d("sharer-h", a.getName() + ":"+a.getValue()); @@ -809,8 +809,7 @@ public class FileDetailFragment extends SherlockFragment implements } public void run() { - WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); - wc.allowSelfsignedCertificates(); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); AccountManager am = AccountManager.get(getSherlockActivity()); String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); @@ -825,6 +824,7 @@ public class FileDetailFragment extends SherlockFragment implements try { int status = wc.executeMethod(move); success = move.succeeded(); + move.getResponseBodyAsString(); // exhaust response, although not interesting Log.d(TAG, "Move returned status: " + status); } catch (HttpException e) { @@ -835,7 +835,10 @@ public class FileDetailFragment extends SherlockFragment implements } catch (Exception e) { Log.e(TAG, "Unexpected exception renaming file " + mOld.getRemotePath() + " to " + mNew.getRemotePath(), e); - } + + } finally { + move.releaseConnection(); + } if (success) { FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver()); @@ -973,8 +976,7 @@ public class FileDetailFragment extends SherlockFragment implements } public void run() { - WebdavClient wc = new WebdavClient(mAccount, getSherlockActivity().getApplicationContext()); - wc.allowSelfsignedCertificates(); + WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); AccountManager am = AccountManager.get(getSherlockActivity()); String baseUrl = am.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL); OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); @@ -988,6 +990,7 @@ public class FileDetailFragment extends SherlockFragment implements try { status = wc.executeMethod(delete); success = (delete.succeeded()); + delete.getResponseBodyAsString(); // exhaust the response, although not interesting Log.d(TAG, "Delete: returned status " + status); } catch (HttpException e) { @@ -998,6 +1001,9 @@ public class FileDetailFragment extends SherlockFragment implements } catch (Exception e) { Log.e(TAG, "Unexpected exception removing file " + mFileToRemove.getRemotePath(), e); + + } finally { + delete.releaseConnection(); } if (success) { diff --git a/src/com/owncloud/android/utils/OwnCloudClientUtils.java b/src/com/owncloud/android/utils/OwnCloudClientUtils.java new file mode 100644 index 00000000..f8b5a683 --- /dev/null +++ b/src/com/owncloud/android/utils/OwnCloudClientUtils.java @@ -0,0 +1,147 @@ +/* ownCloud Android client application + * Copyright (C) 2011 Bartek Przybylski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.utils; + +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.protocol.Protocol; + +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.authenticator.EasySSLSocketFactory; +import com.owncloud.android.utils.OwnCloudVersion; + +import eu.alefzero.webdav.WebdavClient; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +public class OwnCloudClientUtils { + + final private static String TAG = "OwnCloudClientFactory"; + + /** Default timeout for waiting data from the server */ + public static final int DEFAULT_DATA_TIMEOUT = 10000; + + /** Default timeout for establishing a connection */ + public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; + + /** Connection manager for all the WebdavClients */ + static private MultiThreadedHttpConnectionManager mConnManager = null; + + + /** + * Creates a WebdavClient setup for an ownCloud account + * + * @param account The ownCloud account + * @param context The application context + * @return A WebdavClient object ready to be used + */ + public static WebdavClient createOwnCloudClient (Account account, Context context) { + Log.d(TAG, "Creating WebdavClient associated to " + account.name); + + String baseUrl = AccountManager.get(context).getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); + OwnCloudVersion ownCloudVersion = new OwnCloudVersion(AccountManager.get(context).getUserData(account, AccountAuthenticator.KEY_OC_VERSION)); + String webDavPath = AccountUtils.getWebdavPath(ownCloudVersion); + + WebdavClient client = createOwnCloudClient(Uri.parse(baseUrl + webDavPath)); + + String username = account.name.substring(0, account.name.lastIndexOf('@')); + String password = AccountManager.get(context).getPassword(account); + //String password = am.blockingGetAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, true); + + client.setCredentials(username, password); + + return client; + } + + + /** + * Creates a WebdavClient to try a new account before saving it + * + * @param uri URL to the ownCloud server + * @param username User name + * @param password User password + * @return A WebdavClient object ready to be used + */ + public static WebdavClient createOwnCloudClient(Uri uri, String username, String password) { + Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri); + + WebdavClient client = createOwnCloudClient(uri); + + client.setCredentials(username, password); + + return client; + } + + + /** + * Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections. + * + * @param uri URL to the ownCloud server + * @return A WebdavClient object ready to be used + */ + public static WebdavClient createOwnCloudClient(Uri uri) { + Log.d(TAG, "Creating WebdavClient for " + uri); + + allowSelfsignedCertificates(true); + + WebdavClient client = new WebdavClient(getMultiThreadedConnManager()); + + allowSelfsignedCertificates(true); + client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); + client.setBaseUri(uri); + + return client; + } + + + /** + * Allows or disallows self-signed certificates in ownCloud servers to reach + * + * @param allow 'True' to allow, 'false' to disallow + */ + public static void allowSelfsignedCertificates(boolean allow) { + Protocol pr = null; + try { + pr = Protocol.getProtocol("https"); + } catch (IllegalStateException e) { + // nothing to do here; really + } + boolean isAllowed = (pr != null && pr.getSocketFactory() instanceof EasySSLSocketFactory); + if (allow && !isAllowed) { + Protocol.registerProtocol("https", new Protocol("https", new EasySSLSocketFactory(), 443)); + } else if (!allow && isAllowed) { + // TODO - a more strict SocketFactory object should be provided here + } + } + + + + static private MultiThreadedHttpConnectionManager getMultiThreadedConnManager() { + if (mConnManager == null) { + mConnManager = new MultiThreadedHttpConnectionManager(); + mConnManager.getParams().setDefaultMaxConnectionsPerHost(5); + mConnManager.getParams().setMaxTotalConnections(5); + } + return mConnManager; + } + +} diff --git a/src/eu/alefzero/webdav/FileRequestEntity.java b/src/eu/alefzero/webdav/FileRequestEntity.java index 61ba4565..2a3ba025 100644 --- a/src/eu/alefzero/webdav/FileRequestEntity.java +++ b/src/eu/alefzero/webdav/FileRequestEntity.java @@ -8,7 +8,7 @@ import java.io.OutputStream; import org.apache.commons.httpclient.methods.RequestEntity; -import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; +import eu.alefzero.webdav.OnDatatransferProgressListener; import android.util.Log; diff --git a/src/eu/alefzero/webdav/OnDatatransferProgressListener.java b/src/eu/alefzero/webdav/OnDatatransferProgressListener.java new file mode 100644 index 00000000..7d6dda1f --- /dev/null +++ b/src/eu/alefzero/webdav/OnDatatransferProgressListener.java @@ -0,0 +1,5 @@ +package eu.alefzero.webdav; + +public interface OnDatatransferProgressListener { + public void transferProgress(long progressRate); +} diff --git a/src/eu/alefzero/webdav/OnUploadProgressListener.java b/src/eu/alefzero/webdav/OnUploadProgressListener.java deleted file mode 100644 index 9a92c514..00000000 --- a/src/eu/alefzero/webdav/OnUploadProgressListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package eu.alefzero.webdav; - -public interface OnUploadProgressListener { - public void OnUploadProgress(long currentProgress); -} diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java index 493c4b8a..abd70489 100644 --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -21,35 +21,26 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpVersion; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.params.HttpMethodParams; -import org.apache.commons.httpclient.protocol.Protocol; import org.apache.http.HttpStatus; import org.apache.http.params.CoreProtocolPNames; import org.apache.jackrabbit.webdav.client.methods.DavMethod; import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; import org.apache.jackrabbit.webdav.client.methods.MkColMethod; -import com.owncloud.android.AccountUtils; -import com.owncloud.android.authenticator.AccountAuthenticator; -import com.owncloud.android.authenticator.EasySSLSocketFactory; -import com.owncloud.android.files.interfaces.OnDatatransferProgressListener; -import com.owncloud.android.utils.OwnCloudVersion; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; import android.net.Uri; import android.util.Log; @@ -59,56 +50,17 @@ public class WebdavClient extends HttpClient { final private static String TAG = "WebdavClient"; private static final String USER_AGENT = "Android-ownCloud"; - /** Default timeout for waiting data from the server: 10 seconds */ - public static final int DEFAULT_DATA_TIMEOUT = 10000; - - /** Default timeout for establishing a connection: infinite */ - public static final int DEFAULT_CONNECTION_TIMEOUT = 0; - private OnDatatransferProgressListener mDataTransferListener; - static private MultiThreadedHttpConnectionManager mConnManager = null; - - static public MultiThreadedHttpConnectionManager getMultiThreadedConnManager() { - if (mConnManager == null) { - mConnManager = new MultiThreadedHttpConnectionManager(); - mConnManager.setMaxConnectionsPerHost(5); - mConnManager.setMaxTotalConnections(5); - } - return mConnManager; - } + static private byte[] sExhaustBuffer = new byte[1024]; /** - * Creates a WebdavClient setup for the current account - * @param account The client accout - * @param context The application context - * @return + * Constructor */ - public WebdavClient (Account account, Context context) { - Log.d(TAG, "Creating WebdavClient associated to " + account.name); - - setDefaultTimeouts(); - - OwnCloudVersion ownCloudVersion = new OwnCloudVersion(AccountManager.get(context).getUserData(account, - AccountAuthenticator.KEY_OC_VERSION)); - String baseUrl = AccountManager.get(context).getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); - String webDavPath = AccountUtils.getWebdavPath(ownCloudVersion); - String username = account.name.substring(0, account.name.lastIndexOf('@')); - String password = AccountManager.get(context).getPassword(account); - - mUri = Uri.parse(baseUrl + webDavPath); - Log.e("ASD", ""+username); - setCredentials(username, password); - } - - public WebdavClient() { - super(getMultiThreadedConnManager()); + public WebdavClient(HttpConnectionManager connectionMgr) { + super(connectionMgr); Log.d(TAG, "Creating WebdavClient"); - - setDefaultTimeouts(); - getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); - allowSelfsignedCertificates(); } public void setCredentials(String username, String password) { @@ -124,33 +76,18 @@ public class WebdavClient extends HttpClient { } /** - * Sets the connection and wait-for-data timeouts to be applied by default. - */ - private void setDefaultTimeouts() { - getParams().setSoTimeout(DEFAULT_DATA_TIMEOUT); - getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT); - } - - public void allowSelfsignedCertificates() { - // https - Protocol.registerProtocol("https", new Protocol("https", - new EasySSLSocketFactory(), 443)); - } - - /** * Downloads a file in remoteFilepath to the local targetPath. * * @param remoteFilepath Path to the file in the remote server, URL DECODED. * @param targetFile Local path to save the downloaded file. * @return 'True' when the file is successfully downloaded. */ - public boolean downloadFile(String remoteFilepath, File targetFile) { + public boolean downloadFile(String remoteFilePath, File targetFile) { boolean ret = false; - GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilepath)); + GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); - int status = -1; try { - status = executeMethod(get); + int status = executeMethod(get); if (status == HttpStatus.SC_OK) { targetFile.createNewFile(); BufferedInputStream bis = new BufferedInputStream( @@ -165,26 +102,19 @@ public class WebdavClient extends HttpClient { fos.write(bytes, 0, readResult); } ret = true; + } else { + exhaustResponse(get.getResponseBodyAsStream()); } + Log.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); - } catch (HttpException e) { - Log.e(TAG, "HTTP exception downloading " + remoteFilepath, e); - - } catch (IOException e) { - Log.e(TAG, "I/O exception downloading " + remoteFilepath, e); - } catch (Exception e) { - Log.e(TAG, "Unexpected exception downloading " + remoteFilepath, e); + logException(e, "dowloading " + remoteFilePath); } finally { - if (!ret) { - if (status >= 0) { - Log.e(TAG, "Download of " + remoteFilepath + " to " + targetFile + " failed with HTTP status " + status); - } - if (targetFile.exists()) { - targetFile.delete(); - } + if (!ret && targetFile.exists()) { + targetFile.delete(); } + get.releaseConnection(); // let the connection available for other methods } return ret; } @@ -194,17 +124,26 @@ public class WebdavClient extends HttpClient { * @param remoteFilePath Remote file path of the file to delete, in URL DECODED format. * @return */ - public boolean deleteFile(String remoteFilePath){ + public boolean deleteFile(String remoteFilePath) { + boolean ret = false; DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath)); try { - executeMethod(delete); - } catch (Throwable e) { - Log.e(TAG, "Deleting failed with error: " + e.getMessage(), e); - return false; + int status = executeMethod(delete); + ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT); + exhaustResponse(delete.getResponseBodyAsStream()); + + Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status + (!ret?"(FAIL)":"")); + + } catch (Exception e) { + logException(e, "deleting " + remoteFilePath); + + } finally { + delete.releaseConnection(); // let the connection available for other methods } - return true; + return ret; } + public void setDataTransferProgressListener(OnDatatransferProgressListener listener) { mDataTransferListener = listener; } @@ -221,56 +160,51 @@ public class WebdavClient extends HttpClient { public boolean putFile(String localFile, String remoteTarget, String contentType) { boolean result = false; int status = -1; - + PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget)); + try { File f = new File(localFile); FileRequestEntity entity = new FileRequestEntity(f, contentType); entity.setOnDatatransferProgressListener(mDataTransferListener); - PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget)); put.setRequestEntity(entity); status = executeMethod(put); result = (status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT); - Log.d(TAG, "PUT response for " + remoteTarget + " finished with HTTP status " + status); - - } catch (HttpException e) { - Log.e(TAG, "HTTP exception uploading " + localFile + " to " + remoteTarget, e); - - } catch (IOException e) { - Log.e(TAG, "I/O exception uploading " + localFile + " to " + remoteTarget, e); + Log.d(TAG, "PUT to " + remoteTarget + " finished with HTTP status " + status + (!result?"(FAIL)":"")); + exhaustResponse(put.getResponseBodyAsStream()); + } catch (Exception e) { - Log.e(TAG, "Unexpected exception uploading " + localFile + " to " + remoteTarget, e); + logException(e, "uploading " + localFile + " to " + remoteTarget); + + } finally { + put.releaseConnection(); // let the connection available for other methods } - - if (!result && status >= 0) Log.e(TAG, "Upload of " + localFile + " to " + remoteTarget + " FAILED with HTTP status " + status); - return result; } /** - * Tries to log in to the given WedDavURI, with the given credentials - * @param uri To test - * @param username Username to check - * @param password Password to verify + * Tries to log in to the current URI, with the current credentials + * * @return A {@link HttpStatus}-Code of the result. SC_OK is good. */ - public static int tryToLogin(Uri uri, String username, String password) { - int returnCode = 0; + public int tryToLogin() { + int status = 0; + HeadMethod head = new HeadMethod(mUri.toString()); try { - WebdavClient client = new WebdavClient(); - client.setCredentials(username, password); - HeadMethod head = new HeadMethod(uri.toString()); - returnCode = client.executeMethod(head); - } catch (HttpException e) { - Log.e(TAG, "HTTP exception trying to login at " + uri.getEncodedPath(), e); - } catch (IOException e) { - Log.e(TAG, "I/O exception trying to login at " + uri.getEncodedPath(), e); + status = executeMethod(head); + boolean result = status == HttpStatus.SC_OK; + Log.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":"")); + exhaustResponse(head.getResponseBodyAsStream()); + } catch (Exception e) { - Log.e(TAG, "Unexpected exception trying to login at " + uri.getEncodedPath(), e); + logException(e, "trying to login at " + mUri.toString()); + + } finally { + head.releaseConnection(); } - return returnCode; + return status; } /** @@ -282,25 +216,21 @@ public class WebdavClient extends HttpClient { public boolean createDirectory(String path) { boolean result = false; int status = -1; + MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path)); try { - MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path)); Log.d(TAG, "Creating directory " + path); status = executeMethod(mkcol); Log.d(TAG, "Status returned: " + status); result = mkcol.succeeded(); - } catch (HttpException e) { - Log.e(TAG, "HTTP exception creating directory " + path, e); - - } catch (IOException e) { - Log.e(TAG, "I/O exception creating directory " + path, e); - + Log.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":"")); + exhaustResponse(mkcol.getResponseBodyAsStream()); + } catch (Exception e) { - Log.e(TAG, "Unexpected exception creating directory " + path, e); + logException(e, "creating directory " + path); - } - if (!result && status >= 0) { - Log.e(TAG, "Creation of directory " + path + " failed with HTTP status " + status); + } finally { + mkcol.releaseConnection(); // let the connection available for other methods } return result; } @@ -312,13 +242,19 @@ public class WebdavClient extends HttpClient { * @return 'Boolean.TRUE' if the file exists; 'Boolean.FALSE' it doesn't exist; NULL if couldn't be checked */ public Boolean existsFile(String path) { + HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path)); try { - HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path)); int status = executeMethod(head); + Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":"")); + exhaustResponse(head.getResponseBodyAsStream()); return (status == HttpStatus.SC_OK); + } catch (Exception e) { - e.printStackTrace(); + logException(e, "checking existence of " + path); return null; + + } finally { + head.releaseConnection(); // let the connection available for other methods } } @@ -328,24 +264,83 @@ public class WebdavClient extends HttpClient { * * Executes the method through the inherited HttpClient.executedMethod(method). * - * Sets the socket timeout for the HttpMethodBase method received. + * Sets the socket and connection timeouts only for the method received. + * + * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default' * - * @param method HTTP method request. - * @param timeout Timeout to set, in milliseconds; <= 0 means infinite. + * @param method HTTP method request. + * @param readTimeout Timeout to set for data reception + * @param conntionTimout Timeout to set for connection establishment */ - public int executeMethod(HttpMethodBase method, int readTimeout) throws HttpException, IOException { + public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException { int oldSoTimeout = getParams().getSoTimeout(); + int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout(); try { - if (readTimeout < 0) { - readTimeout = 0; + if (readTimeout >= 0) { + method.getParams().setSoTimeout(readTimeout); // this should be enough... + getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS + } + if (connectionTimeout >= 0) { + getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); } - HttpMethodParams params = method.getParams(); - params.setSoTimeout(readTimeout); - method.setParams(params); // this should be enough... - getParams().setSoTimeout(readTimeout); // ... but this is necessary for HTTPS return executeMethod(method); } finally { getParams().setSoTimeout(oldSoTimeout); + getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout); } } + + /** + * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. + * + * @param responseBodyAsStream InputStream with the HTTP response to exhaust. + */ + private static void exhaustResponse(InputStream responseBodyAsStream) { + if (responseBodyAsStream != null) { + try { + while (responseBodyAsStream.read(sExhaustBuffer) >= 0); + responseBodyAsStream.close(); + + } catch (IOException io) { + Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io); + } + } + } + + + /** + * Logs an exception triggered in a HTTP request. + * + * @param e Caught exception. + * @param doing Suffix to add at the end of the logged message. + */ + private static void logException(Exception e, String doing) { + if (e instanceof HttpException) { + Log.e(TAG, "HTTP violation while " + doing, e); + + } else if (e instanceof IOException) { + Log.e(TAG, "Unrecovered transport exception while " + doing, e); + + } else { + Log.e(TAG, "Unexpected exception while " + doing, e); + } + } + + + /** + * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client. + */ + public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { + getParams().setSoTimeout(defaultDataTimeout); + getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); + } + + /** + * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs + * @param uri + */ + public void setBaseUri(Uri uri) { + mUri = uri; + } + }