mirror of
https://github.com/etesync/android
synced 2024-12-23 07:08:16 +00:00
Version bump to 0.5.3-alpha
* add null checks (should fix #117) * more detailed DAV exceptions for error handling * better logging (limited to 10 kB per log entry) to avoid memory problems * DavMultiget creates requests itself (instead of WebDavResource)
This commit is contained in:
parent
ec4fedf04e
commit
6cfaad35b1
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="at.bitfire.davdroid"
|
||||
android:versionCode="20"
|
||||
android:versionName="0.5.2-alpha" >
|
||||
android:versionCode="21"
|
||||
android:versionName="0.5.3-alpha" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
|
58
src/at/bitfire/davdroid/LoggingInputStream.java
Normal file
58
src/at/bitfire/davdroid/LoggingInputStream.java
Normal file
@ -0,0 +1,58 @@
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class LoggingInputStream extends FilterInputStream {
|
||||
private static final int MAX_LENGTH = 10*1024; // don't log more than 10 kB of data
|
||||
|
||||
String tag;
|
||||
|
||||
ByteArrayOutputStream log = new ByteArrayOutputStream(MAX_LENGTH);
|
||||
int logSize = 0;
|
||||
|
||||
public LoggingInputStream(String tag, InputStream proxy) {
|
||||
super(proxy);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int b = super.read();
|
||||
if (logSize < MAX_LENGTH) {
|
||||
log.write(b);
|
||||
logSize++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int byteOffset, int byteCount)
|
||||
throws IOException {
|
||||
int read = super.read(buffer, byteOffset, byteCount);
|
||||
int bytesToLog = read;
|
||||
if (bytesToLog + logSize > MAX_LENGTH)
|
||||
bytesToLog = MAX_LENGTH - logSize;
|
||||
if (bytesToLog > 0) {
|
||||
log.write(buffer, byteOffset, bytesToLog);
|
||||
logSize += bytesToLog;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Log.d(tag, "Content: " + log.toString());
|
||||
super.close();
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@ package at.bitfire.davdroid.resource;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
||||
|
||||
public class CalDavCalendar extends RemoteCollection<Event> {
|
||||
//private final static String TAG = "davdroid.CalDavCalendar";
|
||||
@ -20,8 +20,8 @@ public class CalDavCalendar extends RemoteCollection<Event> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MultigetType multiGetType() {
|
||||
return MultigetType.CALENDAR;
|
||||
protected DavMultiget.Type multiGetType() {
|
||||
return DavMultiget.Type.CALENDAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,7 +9,7 @@ package at.bitfire.davdroid.resource;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
||||
|
||||
public class CardDavAddressBook extends RemoteCollection<Contact> {
|
||||
//private final static String TAG = "davdroid.CardDavAddressBook";
|
||||
@ -20,8 +20,8 @@ public class CardDavAddressBook extends RemoteCollection<Contact> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MultigetType multiGetType() {
|
||||
return MultigetType.ADDRESS_BOOK;
|
||||
protected DavMultiget.Type multiGetType() {
|
||||
return DavMultiget.Type.ADDRESS_BOOK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,11 +192,11 @@ public class Event extends Resource {
|
||||
if (exdate != null)
|
||||
props.add(exdate);
|
||||
|
||||
if (summary != null)
|
||||
if (summary != null && !summary.isEmpty())
|
||||
props.add(new Summary(summary));
|
||||
if (location != null)
|
||||
if (location != null && !location.isEmpty())
|
||||
props.add(new Location(location));
|
||||
if (description != null)
|
||||
if (description != null && !description.isEmpty())
|
||||
props.add(new Description(description));
|
||||
|
||||
if (status != null)
|
||||
|
@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentProviderOperation;
|
||||
@ -72,8 +71,11 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
new String[] { entryColumnID(), entryColumnRemoteName(), entryColumnETag() },
|
||||
where, null, null);
|
||||
LinkedList<T> dirty = new LinkedList<T>();
|
||||
while (cursor != null && cursor.moveToNext())
|
||||
dirty.add(findById(cursor.getLong(0), true));
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
T resource = findById(cursor.getLong(0), true);
|
||||
if (resource != null)
|
||||
dirty.add(resource);
|
||||
}
|
||||
return dirty.toArray(new Resource[0]);
|
||||
}
|
||||
|
||||
@ -85,8 +87,11 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
new String[] { entryColumnID(), entryColumnRemoteName(), entryColumnETag() },
|
||||
where, null, null);
|
||||
LinkedList<T> deleted = new LinkedList<T>();
|
||||
while (cursor != null && cursor.moveToNext())
|
||||
deleted.add(findById(cursor.getLong(0), false));
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
T resource = findById(cursor.getLong(0), false);
|
||||
if (resource != null)
|
||||
deleted.add(resource);
|
||||
}
|
||||
return deleted.toArray(new Resource[0]);
|
||||
}
|
||||
|
||||
@ -100,16 +105,18 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
LinkedList<T> fresh = new LinkedList<T>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
T resource = findById(cursor.getLong(0), true);
|
||||
resource.initialize();
|
||||
|
||||
// new record: set generated UID + remote file name in database
|
||||
pendingOperations.add(ContentProviderOperation
|
||||
.newUpdate(ContentUris.withAppendedId(entriesURI(), resource.getLocalID()))
|
||||
.withValue(entryColumnUID(), resource.getUid())
|
||||
.withValue(entryColumnRemoteName(), resource.getName())
|
||||
.build());
|
||||
|
||||
fresh.add(resource);
|
||||
if (resource != null) {
|
||||
resource.initialize();
|
||||
|
||||
// new record: set generated UID + remote file name in database
|
||||
pendingOperations.add(ContentProviderOperation
|
||||
.newUpdate(ContentUris.withAppendedId(entriesURI(), resource.getLocalID()))
|
||||
.withValue(entryColumnUID(), resource.getUid())
|
||||
.withValue(entryColumnRemoteName(), resource.getName())
|
||||
.build());
|
||||
|
||||
fresh.add(resource);
|
||||
}
|
||||
}
|
||||
return fresh.toArray(new Resource[0]);
|
||||
}
|
||||
@ -162,17 +169,18 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
addDataRows(resource, -1, idx);
|
||||
}
|
||||
|
||||
public void updateByRemoteName(Resource remoteResource) throws RemoteException, ValidationException {
|
||||
public void updateByRemoteName(Resource remoteResource) throws RemoteException {
|
||||
T localResource = findByRemoteName(remoteResource.getName(), false);
|
||||
|
||||
pendingOperations.add(
|
||||
buildEntry(ContentProviderOperation.newUpdate(ContentUris.withAppendedId(entriesURI(), localResource.getLocalID())), remoteResource)
|
||||
.withValue(entryColumnETag(), remoteResource.getETag())
|
||||
.withYieldAllowed(true)
|
||||
.build());
|
||||
|
||||
removeDataRows(localResource);
|
||||
addDataRows(remoteResource, localResource.getLocalID(), -1);
|
||||
if (localResource != null) {
|
||||
pendingOperations.add(
|
||||
buildEntry(ContentProviderOperation.newUpdate(ContentUris.withAppendedId(entriesURI(), localResource.getLocalID())), remoteResource)
|
||||
.withValue(entryColumnETag(), remoteResource.getETag())
|
||||
.withYieldAllowed(true)
|
||||
.build());
|
||||
|
||||
removeDataRows(localResource);
|
||||
addDataRows(remoteResource, localResource.getLocalID(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(Resource resource) {
|
||||
|
@ -14,19 +14,21 @@ import java.net.URISyntaxException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Cleanup;
|
||||
import lombok.Getter;
|
||||
import net.fortuna.ical4j.data.ParserException;
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
import ezvcard.VCardException;
|
||||
import android.util.Log;
|
||||
import at.bitfire.davdroid.LoggingInputStream;
|
||||
import at.bitfire.davdroid.webdav.DAVException;
|
||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
||||
import at.bitfire.davdroid.webdav.HttpPropfind;
|
||||
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||
import ezvcard.VCardException;
|
||||
|
||||
public abstract class RemoteCollection<T extends Resource> {
|
||||
private static final String TAG = "davdroid.RemoteCollection";
|
||||
@ -34,7 +36,7 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
@Getter WebDavResource collection;
|
||||
|
||||
abstract protected String memberContentType();
|
||||
abstract protected MultigetType multiGetType();
|
||||
abstract protected DavMultiget.Type multiGetType();
|
||||
abstract protected T newResourceSkeleton(String name, String ETag);
|
||||
|
||||
public RemoteCollection(String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
|
||||
@ -48,13 +50,13 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
try {
|
||||
if (collection.getCTag() == null && collection.getMembers() == null) // not already fetched
|
||||
collection.propfind(HttpPropfind.Mode.COLLECTION_CTAG);
|
||||
} catch (InvalidDavResponseException e) {
|
||||
} catch (DAVException e) {
|
||||
return null;
|
||||
}
|
||||
return collection.getCTag();
|
||||
}
|
||||
|
||||
public Resource[] getMemberETags() throws IOException, InvalidDavResponseException, HttpException {
|
||||
public Resource[] getMemberETags() throws IOException, DAVException, HttpException {
|
||||
collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG);
|
||||
|
||||
List<T> resources = new LinkedList<T>();
|
||||
@ -67,7 +69,7 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Resource[] multiGet(Resource[] resources) throws IOException, InvalidDavResponseException, HttpException {
|
||||
public Resource[] multiGet(Resource[] resources) throws IOException, DAVException, HttpException {
|
||||
try {
|
||||
if (resources.length == 1) {
|
||||
Resource resource = get(resources[0]);
|
||||
@ -78,7 +80,7 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
for (Resource resource : resources)
|
||||
names.add(resource.getName());
|
||||
|
||||
collection.multiGet(names.toArray(new String[0]), multiGetType());
|
||||
collection.multiGet(multiGetType(), names.toArray(new String[0]));
|
||||
|
||||
LinkedList<T> foundResources = new LinkedList<T>();
|
||||
if (collection.getMembers() != null)
|
||||
@ -116,7 +118,9 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
public Resource get(Resource resources) throws IOException, HttpException, ParserException, VCardException {
|
||||
WebDavResource member = new WebDavResource(collection, resources.getName());
|
||||
member.get();
|
||||
resources.parseEntity(member.getContent());
|
||||
|
||||
@Cleanup InputStream loggedContent = new LoggingInputStream(TAG, member.getContent());
|
||||
resources.parseEntity(loggedContent);
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import at.bitfire.davdroid.resource.LocalCollection;
|
||||
import at.bitfire.davdroid.resource.RemoteCollection;
|
||||
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
||||
import at.bitfire.davdroid.webdav.DAVException;
|
||||
|
||||
public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
private final static String TAG = "davdroid.DavSyncAdapter";
|
||||
@ -72,7 +72,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
} catch (AuthenticationException ex) {
|
||||
syncResult.stats.numAuthExceptions++;
|
||||
Log.e(TAG, "HTTP authorization error", ex);
|
||||
} catch (InvalidDavResponseException ex) {
|
||||
} catch (DAVException ex) {
|
||||
syncResult.stats.numParseExceptions++;
|
||||
Log.e(TAG, "Invalid DAV response", ex);
|
||||
} catch (HttpException ex) {
|
||||
|
@ -148,15 +148,11 @@ public class SyncManager {
|
||||
local.commit();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Updating " + resourcesToUpdate.size() + " remote resource(s)");
|
||||
Log.i(TAG, "Updating from " + resourcesToUpdate.size() + " remote resource(s)");
|
||||
if (!resourcesToUpdate.isEmpty())
|
||||
for (Resource res : dav.multiGet(resourcesToUpdate.toArray(new Resource[0]))) {
|
||||
Log.i(TAG, "Updating " + res.getName());
|
||||
try {
|
||||
local.updateByRemoteName(res);
|
||||
} catch (ValidationException ex) {
|
||||
Log.e(TAG, "Ignoring invalid remote resource: " + res.getName(), ex);
|
||||
}
|
||||
local.updateByRemoteName(res);
|
||||
|
||||
if (++syncResult.stats.numUpdates % MAX_UPDATES_BEFORE_COMMIT == 0) // avoid TransactionTooLargeException
|
||||
local.commit();
|
||||
|
18
src/at/bitfire/davdroid/webdav/DAVException.java
Normal file
18
src/at/bitfire/davdroid/webdav/DAVException.java
Normal file
@ -0,0 +1,18 @@
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
public class DAVException extends HttpException {
|
||||
private static final long serialVersionUID = -2118919144443165706L;
|
||||
|
||||
final private static String prefix = "Invalid DAV response: ";
|
||||
|
||||
|
||||
public DAVException(String message) {
|
||||
super(prefix + message);
|
||||
}
|
||||
|
||||
public DAVException(String message, Throwable ex) {
|
||||
super(prefix + message, ex);
|
||||
}
|
||||
}
|
11
src/at/bitfire/davdroid/webdav/DAVNoContentException.java
Normal file
11
src/at/bitfire/davdroid/webdav/DAVNoContentException.java
Normal file
@ -0,0 +1,11 @@
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
public class DAVNoContentException extends DAVException {
|
||||
private static final long serialVersionUID = 6256645020350945477L;
|
||||
|
||||
private final static String message = "HTTP response entity (content) expected but not received";
|
||||
|
||||
public DAVNoContentException() {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
public class DAVNoMultiStatusException extends DAVException {
|
||||
private static final long serialVersionUID = -3600405724694229828L;
|
||||
|
||||
private final static String message = "207 Multi-Status expected but not received";
|
||||
|
||||
public DAVNoMultiStatusException() {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
******************************************************************************/
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.simpleframework.xml.Element;
|
||||
@ -15,9 +16,33 @@ import org.simpleframework.xml.Order;
|
||||
|
||||
@Order(elements={"prop","href"})
|
||||
public class DavMultiget {
|
||||
public enum Type {
|
||||
ADDRESS_BOOK,
|
||||
CALENDAR
|
||||
}
|
||||
|
||||
@Element
|
||||
DavProp prop;
|
||||
|
||||
@ElementList(inline=true)
|
||||
List<DavHref> hrefs;
|
||||
|
||||
|
||||
public static DavMultiget newRequest(Type type, String names[]) {
|
||||
DavMultiget multiget = (type == Type.ADDRESS_BOOK) ? new DavAddressbookMultiget() : new DavCalendarMultiget();
|
||||
|
||||
multiget.prop = new DavProp();
|
||||
multiget.prop.getetag = new DavProp.DavPropGetETag();
|
||||
|
||||
if (type == Type.ADDRESS_BOOK)
|
||||
multiget.prop.addressData = new DavProp.DavPropAddressData();
|
||||
else if (type == Type.CALENDAR)
|
||||
multiget.prop.calendarData = new DavProp.DavPropCalendarData();
|
||||
|
||||
multiget.hrefs = new ArrayList<DavHref>(names.length);
|
||||
for (String name : names)
|
||||
multiget.hrefs.add(new DavHref(name));
|
||||
|
||||
return multiget;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
public class InvalidDavResponseException extends HttpException {
|
||||
private static final long serialVersionUID = -2118919144443165706L;
|
||||
|
||||
public InvalidDavResponseException(String message) {
|
||||
super("Invalid DAV response: " + message);
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ public class TlsSniSocketFactory implements LayeredSocketFactory {
|
||||
|
||||
// set up SNI before the handshake
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
Log.i(TAG, "Setting SNI hostname");
|
||||
Log.d(TAG, "Setting SNI hostname");
|
||||
sslSocketFactory.setHostname(ssl, host);
|
||||
} else
|
||||
Log.i(TAG, "No SNI support below Android 4.2!");
|
||||
|
@ -8,13 +8,11 @@
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -22,12 +20,13 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Cleanup;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import org.apache.commons.io.input.TeeInputStream;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
@ -46,6 +45,7 @@ import org.simpleframework.xml.Serializer;
|
||||
import org.simpleframework.xml.core.Persister;
|
||||
|
||||
import android.util.Log;
|
||||
import at.bitfire.davdroid.LoggingInputStream;
|
||||
import at.bitfire.davdroid.URIUtils;
|
||||
import at.bitfire.davdroid.resource.Event;
|
||||
import at.bitfire.davdroid.webdav.DavProp.DavPropComp;
|
||||
@ -64,10 +64,6 @@ public class WebDavResource {
|
||||
CTAG, ETAG,
|
||||
CONTENT_TYPE
|
||||
}
|
||||
public enum MultigetType {
|
||||
ADDRESS_BOOK,
|
||||
CALENDAR
|
||||
}
|
||||
public enum PutMode {
|
||||
ADD_DONT_OVERWRITE,
|
||||
UPDATE_DONT_OVERWRITE
|
||||
@ -142,6 +138,8 @@ public class WebDavResource {
|
||||
protected void checkResponse(StatusLine statusLine) throws HttpException {
|
||||
int code = statusLine.getStatusCode();
|
||||
|
||||
Log.d(TAG, "Received " + statusLine.getProtocolVersion() + " " + code + " " + statusLine.getReasonPhrase());
|
||||
|
||||
if (code/100 == 1 || code/100 == 2) // everything OK
|
||||
return;
|
||||
|
||||
@ -252,52 +250,38 @@ public class WebDavResource {
|
||||
|
||||
/* collection operations */
|
||||
|
||||
public void propfind(HttpPropfind.Mode mode) throws IOException, InvalidDavResponseException, HttpException {
|
||||
public void propfind(HttpPropfind.Mode mode) throws IOException, DAVException, HttpException {
|
||||
HttpPropfind propfind = new HttpPropfind(location, mode);
|
||||
HttpResponse response = client.execute(propfind);
|
||||
checkResponse(response);
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) {
|
||||
InputStream content = response.getEntity().getContent();
|
||||
if (content == null)
|
||||
throw new InvalidDavResponseException("Multistatus response without content");
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MULTI_STATUS)
|
||||
throw new DAVNoMultiStatusException();
|
||||
|
||||
// duplicate content for logging
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
InputStream is = new TeeInputStream(content, logStream);
|
||||
|
||||
DavMultistatus multistatus;
|
||||
try {
|
||||
Serializer serializer = new Persister();
|
||||
multistatus = serializer.read(DavMultistatus.class, is, false);
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Invalid PROPFIND XML response", ex);
|
||||
throw new InvalidDavResponseException("Invalid PROPFIND response");
|
||||
} finally {
|
||||
Log.d(TAG, "Received multistatus response:\n" + logStream.toString("UTF-8"));
|
||||
is.close();
|
||||
content.close();
|
||||
}
|
||||
processMultiStatus(multistatus);
|
||||
|
||||
} else
|
||||
throw new InvalidDavResponseException("Multistatus response expected");
|
||||
@Cleanup("consumeContent") HttpEntity entity = response.getEntity();
|
||||
if (entity == null)
|
||||
throw new DAVNoContentException();
|
||||
InputStream content = entity.getContent();
|
||||
if (content == null)
|
||||
throw new DAVNoContentException();
|
||||
|
||||
@Cleanup LoggingInputStream loggedContent = new LoggingInputStream(TAG, content);
|
||||
|
||||
DavMultistatus multistatus;
|
||||
try {
|
||||
Serializer serializer = new Persister();
|
||||
multistatus = serializer.read(DavMultistatus.class, loggedContent, false);
|
||||
} catch (Exception ex) {
|
||||
throw new DAVException("Couldn't parse Multi-Status response on PROPFIND", ex);
|
||||
}
|
||||
processMultiStatus(multistatus);
|
||||
}
|
||||
|
||||
public void multiGet(String[] names, MultigetType type) throws IOException, InvalidDavResponseException, HttpException {
|
||||
DavMultiget multiget = (type == MultigetType.ADDRESS_BOOK) ? new DavAddressbookMultiget() : new DavCalendarMultiget();
|
||||
|
||||
multiget.prop = new DavProp();
|
||||
multiget.prop.getetag = new DavProp.DavPropGetETag();
|
||||
|
||||
if (type == MultigetType.ADDRESS_BOOK)
|
||||
multiget.prop.addressData = new DavProp.DavPropAddressData();
|
||||
else if (type == MultigetType.CALENDAR)
|
||||
multiget.prop.calendarData = new DavProp.DavPropCalendarData();
|
||||
|
||||
multiget.hrefs = new ArrayList<DavHref>(names.length);
|
||||
public void multiGet(DavMultiget.Type type, String[] names) throws IOException, DAVException, HttpException {
|
||||
List<String> hrefs = new LinkedList<String>();
|
||||
for (String name : names)
|
||||
multiget.hrefs.add(new DavHref(location.resolve(name).getRawPath()));
|
||||
hrefs.add(location.resolve(name).getRawPath());
|
||||
DavMultiget multiget = DavMultiget.newRequest(type, hrefs.toArray(new String[0]));
|
||||
|
||||
Serializer serializer = new Persister();
|
||||
StringWriter writer = new StringWriter();
|
||||
@ -305,38 +289,32 @@ public class WebDavResource {
|
||||
serializer.write(multiget, writer);
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Couldn't create XML multi-get request", ex);
|
||||
throw new InvalidDavResponseException("Couldn't create multi-get request");
|
||||
throw new DAVException("Couldn't create multi-get request");
|
||||
}
|
||||
|
||||
HttpReport report = new HttpReport(location, writer.toString());
|
||||
HttpResponse response = client.execute(report);
|
||||
checkResponse(response);
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) {
|
||||
InputStream content = response.getEntity().getContent();
|
||||
if (content == null)
|
||||
throw new InvalidDavResponseException("Multistatus response without content");
|
||||
|
||||
DavMultistatus multistatus;
|
||||
|
||||
// duplicate content for logging
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
InputStream is = new TeeInputStream(content, logStream, true);
|
||||
|
||||
try {
|
||||
multistatus = serializer.read(DavMultistatus.class, is, false);
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Couldn't parse multi-get response", ex);
|
||||
throw new InvalidDavResponseException("Invalid multi-get response");
|
||||
} finally {
|
||||
Log.d(TAG, "Received multistatus response:\n" + logStream.toString("UTF-8"));
|
||||
is.close();
|
||||
content.close();
|
||||
}
|
||||
processMultiStatus(multistatus);
|
||||
|
||||
} else
|
||||
throw new InvalidDavResponseException("Multistatus response expected");
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MULTI_STATUS)
|
||||
throw new DAVNoMultiStatusException();
|
||||
|
||||
@Cleanup("consumeContent") HttpEntity entity = response.getEntity();
|
||||
if (entity == null)
|
||||
throw new DAVNoContentException();
|
||||
InputStream content = entity.getContent();
|
||||
if (content == null)
|
||||
throw new DAVNoContentException();
|
||||
|
||||
@Cleanup LoggingInputStream loggedContent = new LoggingInputStream(TAG, content);
|
||||
|
||||
DavMultistatus multiStatus;
|
||||
try {
|
||||
multiStatus = serializer.read(DavMultistatus.class, loggedContent, false);
|
||||
} catch (Exception ex) {
|
||||
throw new DAVException("Couldn't parse Multi-Status response on REPORT multi-get", ex);
|
||||
}
|
||||
processMultiStatus(multiStatus);
|
||||
}
|
||||
|
||||
|
||||
@ -473,4 +451,5 @@ public class WebDavResource {
|
||||
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,11 @@ public class LombokTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testNonNull() {
|
||||
assertNull(appendSlash(null));
|
||||
//assertEquals("1/", appendSlash("1"));
|
||||
try {
|
||||
appendSlash(null);
|
||||
fail();
|
||||
} catch(NullPointerException e) {
|
||||
}
|
||||
assertEquals("1/", appendSlash("1"));
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,12 @@ import org.apache.http.HttpException;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import at.bitfire.davdroid.webdav.DAVException;
|
||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
||||
import at.bitfire.davdroid.webdav.HttpPropfind;
|
||||
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
||||
import at.bitfire.davdroid.webdav.NotFoundException;
|
||||
import at.bitfire.davdroid.webdav.PreconditionFailedException;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||
|
||||
// tests require running robohydra!
|
||||
@ -88,7 +88,7 @@ public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
try {
|
||||
simpleFile.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL);
|
||||
fail();
|
||||
} catch(InvalidDavResponseException ex) {
|
||||
} catch(DAVException ex) {
|
||||
}
|
||||
assertNull(simpleFile.getCurrentUserPrincipal());
|
||||
}
|
||||
@ -147,9 +147,9 @@ public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
));
|
||||
}
|
||||
|
||||
public void testMultiGet() throws InvalidDavResponseException, IOException, HttpException {
|
||||
public void testMultiGet() throws DAVException, IOException, HttpException {
|
||||
WebDavResource davAddressBook = new WebDavResource(davCollection, "addressbooks/default.vcf", true);
|
||||
davAddressBook.multiGet(new String[] { "1.vcf", "2.vcf" }, MultigetType.ADDRESS_BOOK);
|
||||
davAddressBook.multiGet(DavMultiget.Type.ADDRESS_BOOK, new String[] { "1.vcf", "2.vcf" });
|
||||
assertEquals(2, davAddressBook.getMembers().size());
|
||||
for (WebDavResource member : davAddressBook.getMembers()) {
|
||||
assertNotNull(member.getContent());
|
||||
|
Loading…
Reference in New Issue
Block a user