Fixed that small todo: Set KeepAlive based on the response code
[pub/Android/ownCloud.git] / src / eu / alefzero / owncloud / syncadapter / AbstractOwnCloudSyncAdapter.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
19 package eu.alefzero.owncloud.syncadapter;
20
21 import java.io.IOException;
22 import java.net.UnknownHostException;
23 import java.util.Date;
24 import java.util.LinkedList;
25
26 import org.apache.http.HttpHost;
27 import org.apache.http.HttpRequest;
28 import org.apache.http.HttpResponse;
29 import org.apache.http.client.ClientProtocolException;
30 import org.apache.http.conn.ConnectionKeepAliveStrategy;
31 import org.apache.http.impl.auth.BasicScheme;
32 import org.apache.http.impl.client.DefaultHttpClient;
33 import org.apache.http.protocol.BasicHttpContext;
34 import org.apache.http.protocol.HttpContext;
35
36 import android.accounts.Account;
37 import android.accounts.AccountManager;
38 import android.accounts.AuthenticatorException;
39 import android.accounts.OperationCanceledException;
40 import android.content.AbstractThreadedSyncAdapter;
41 import android.content.ContentProviderClient;
42 import android.content.Context;
43 import android.net.Uri;
44 import android.text.TextUtils;
45 import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
46 import eu.alefzero.owncloud.datamodel.OCFile;
47 import eu.alefzero.webdav.HttpPropFind;
48 import eu.alefzero.webdav.TreeNode;
49 import eu.alefzero.webdav.TreeNode.NodeProperty;
50 import eu.alefzero.webdav.WebdavClient;
51 import eu.alefzero.webdav.WebdavUtils;
52
53 /**
54 * Base SyncAdapter for OwnCloud
55 * Designed to be subclassed for the concrete SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc..
56 *
57 * @author sassman
58 *
59 */
60 public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter {
61
62 private AccountManager accountManager;
63 private Account account;
64 private ContentProviderClient contentProvider;
65 private Date lastUpdated;
66
67 private HttpHost mHost;
68 private WebdavClient mClient = null;
69
70 public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {
71 super(context, autoInitialize);
72 this.setAccountManager(AccountManager.get(context));
73 }
74
75 public AccountManager getAccountManager() {
76 return accountManager;
77 }
78
79 public void setAccountManager(AccountManager accountManager) {
80 this.accountManager = accountManager;
81 }
82
83 public Account getAccount() {
84 return account;
85 }
86
87 public void setAccount(Account account) {
88 this.account = account;
89 }
90
91 public ContentProviderClient getContentProvider() {
92 return contentProvider;
93 }
94
95 public void setContentProvider(ContentProviderClient contentProvider) {
96 this.contentProvider = contentProvider;
97 }
98
99 public Date getLastUpdated() {
100 return lastUpdated;
101 }
102
103 public void setLastUpdated(Date lastUpdated) {
104 this.lastUpdated = lastUpdated;
105 }
106
107 protected ConnectionKeepAliveStrategy getKeepAliveStrategy() {
108 return new ConnectionKeepAliveStrategy() {
109 public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
110 // Change keep alive straategy basing on response: ie forbidden/not found/etc
111 // should have keep alive 0
112 // default return: 5s
113 int statusCode = response.getStatusLine().getStatusCode();
114
115 // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed out
116 if((statusCode >= 400 && statusCode <= 418) ||
117 (statusCode >= 421 && statusCode <= 426) ||
118 (statusCode >= 500 && statusCode <= 510 ) ||
119 statusCode == 118) {
120 return 0;
121 }
122
123 return 5 * 1000;
124 }
125 };
126 }
127
128 protected HttpPropFind getPropFindQuery() throws OperationCanceledException, AuthenticatorException, IOException {
129 HttpPropFind query = new HttpPropFind(getUri().toString());
130 query.setHeader("Content-type", "text/xml");
131 query.setHeader("User-Agent", "Android-ownCloud");
132 return query;
133 }
134
135 protected HttpResponse fireRawRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
136 BasicHttpContext httpContext = new BasicHttpContext();
137 BasicScheme basicAuth = new BasicScheme();
138 httpContext.setAttribute("preemptive-auth", basicAuth);
139
140 HttpResponse response = getClient().execute(mHost, query, httpContext);
141 return response;
142 }
143
144 protected TreeNode fireRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
145 HttpResponse response = fireRawRequest(query);
146
147 TreeNode root = new TreeNode();
148 root.setProperty(TreeNode.NodeProperty.NAME, "");
149 this.parseResponse(response, getUri(), getClient(), mHost, root.getChildList(), false, 0);
150 return root;
151 }
152
153 protected Uri getUri() {
154 return Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL));
155 }
156
157 private DefaultHttpClient getClient() throws OperationCanceledException, AuthenticatorException, IOException {
158 if(mClient == null) {
159 String username = getAccount().name.split("@")[0];
160 String password = this.getAccountManager().blockingGetAuthToken(getAccount(), AccountAuthenticator.AUTH_TOKEN_TYPE, true);
161 if (this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL) == null) {
162 throw new UnknownHostException();
163 }
164 Uri uri = getUri();
165
166 mClient = new WebdavClient(uri);
167 mClient.setCredentials(username, password);
168 mClient.allowUnsignedCertificates();
169 mHost = mClient.getTargetHost();
170 }
171
172 return mClient.getHttpClient();
173 }
174
175 private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, LinkedList<TreeNode> insertList, boolean sf, long parent_id) throws IOException, OperationCanceledException, AuthenticatorException {
176 boolean skipFirst = sf, override_parent = !sf;
177 for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) {
178 if (skipFirst) {
179 skipFirst = false;
180 continue;
181 }
182 String path = n.stripPathFromFilename(uri.getPath());
183 OCFile new_file = OCFile.createNewFile(getContentProvider(),
184 getAccount(),
185 n.getProperty(NodeProperty.PATH),
186 0,//Long.parseLong(n.getProperty(NodeProperty.CONTENT_LENGTH)),
187 0,//Long.parseLong(n.getProperty(NodeProperty.CREATE_DATE)),
188 0,//Long.parseLong(n.getProperty(NodeProperty.LAST_MODIFIED_DATE)),
189 n.getProperty(NodeProperty.RESOURCE_TYPE),
190 parent_id);
191 new_file.save();
192 if (override_parent) {
193 parent_id = new_file.getFileId();
194 override_parent = false;
195 }
196
197 if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) &&
198 n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
199
200 HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/");
201 HttpResponse response = fireRawRequest(method);
202 parseResponse(response, uri, client, targetHost, n.getChildList(), true, new_file.getFileId());
203 }
204 }
205 }
206 }