Parse out of order ListBuckets response elements
Currently, jclouds assumes that the ListBuckets response follows a
specific order: the <Owner> tag, followed by the <Buckets> tag. Within
the <Owner> tag, jclouds further assumes that the <ID> must occur before
the <DisplayName> tag. If the XML body does not adhere to this order,
the parser throws a NullPointerException.
DigitalOcean spaces does not adhere to this order and returns the
<DisplayName> tag before the <ID> tag. The patch changes the parser to
not depend on the order of the tags.
diff --git a/apis/s3/src/main/java/org/jclouds/s3/domain/CanonicalUser.java b/apis/s3/src/main/java/org/jclouds/s3/domain/CanonicalUser.java
index f4fbc55..8880b53 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/domain/CanonicalUser.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/domain/CanonicalUser.java
@@ -23,9 +23,11 @@
* <p/>
*/
public class CanonicalUser {
- private final String id;
+ private String id;
private String displayName;
+ public CanonicalUser() {}
+
public CanonicalUser(String id) {
this.id = id;
}
@@ -44,6 +46,8 @@
return id;
}
+ public void setId(String id) { this.id = id; }
+
/**
* read-only as is maintained by Amazon.
*/
diff --git a/apis/s3/src/main/java/org/jclouds/s3/xml/ListAllMyBucketsHandler.java b/apis/s3/src/main/java/org/jclouds/s3/xml/ListAllMyBucketsHandler.java
index 39ada83..058a358 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/xml/ListAllMyBucketsHandler.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/xml/ListAllMyBucketsHandler.java
@@ -39,6 +39,7 @@
private Set<BucketMetadata> buckets = Sets.newLinkedHashSet();
private CanonicalUser currentOwner;
+ private String currentDisplayName;
private StringBuilder currentText = new StringBuilder();
private final DateService dateParser;
@@ -48,6 +49,7 @@
@Inject
public ListAllMyBucketsHandler(DateService dateParser) {
this.dateParser = dateParser;
+ this.currentOwner = new CanonicalUser();
}
public Set<BucketMetadata> getResult() {
@@ -56,7 +58,7 @@
public void endElement(String uri, String name, String qName) {
if (qName.equals("ID")) { // owner stuff
- currentOwner = new CanonicalUser(currentOrNull(currentText));
+ currentOwner.setId(currentOrNull(currentText));
} else if (qName.equals("DisplayName")) {
currentOwner.setDisplayName(currentOrNull(currentText));
} else if (qName.equals("Bucket")) {
diff --git a/apis/s3/src/test/java/org/jclouds/s3/xml/S3ParserTest.java b/apis/s3/src/test/java/org/jclouds/s3/xml/S3ParserTest.java
index b5d2bd9..6cd1485 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/xml/S3ParserTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/xml/S3ParserTest.java
@@ -70,6 +70,8 @@
}
public static final String listAllMyBucketsResultOn200 = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket><Bucket><Name>adrianjbosstest2</Name><CreationDate>2009-03-12T02:00:09.000Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>";
+ public static final String listAllMyBucketsResultOn200DisplayNameFirst = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Owner><DisplayName>TestName</DisplayName><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>";
+ public static final String listAllMyBucketsResultOn200OwnerLast = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket></Buckets><Owner><DisplayName>TestName</DisplayName><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner></ListAllMyBucketsResult>";
@Test
void testParseListAllMyBucketsSerialResponseTime() throws HttpException {
@@ -114,6 +116,36 @@
assert container2.getOwner().equals(owner);
}
+ @Test
+ public void testCanParseListAllMyBucketsDisplayNameFirst() throws HttpException {
+ Set<BucketMetadata> s3Buckets = factory.create(injector.getInstance(ListAllMyBucketsHandler.class)).parse(
+ Strings2.toInputStream(listAllMyBucketsResultOn200DisplayNameFirst));
+ BucketMetadata container = Iterables.get(s3Buckets, 0);
+ assert container.getName().equals("adrianjbosstest");
+ Date expectedDate1 = new SimpleDateFormatDateService().iso8601DateParse("2009-03-12T02:00:07.000Z");
+ Date date = container.getCreationDate();
+ assert date.equals(expectedDate1);
+ assert s3Buckets.size() == 1;
+ CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
+ "TestName");
+ assert container.getOwner().equals(owner);
+ }
+
+ @Test
+ public void testCanParseListAllMyBucketsOwnerLast() throws HttpException {
+ Set<BucketMetadata> s3Buckets = factory.create(injector.getInstance(ListAllMyBucketsHandler.class)).parse(
+ Strings2.toInputStream(listAllMyBucketsResultOn200OwnerLast));
+ BucketMetadata container = Iterables.get(s3Buckets, 0);
+ assert container.getName().equals("adrianjbosstest");
+ Date expectedDate = new SimpleDateFormatDateService().iso8601DateParse("2009-03-12T02:00:07.000Z");
+ Date date1 = container.getCreationDate();
+ assert date1.equals(expectedDate);
+ assert s3Buckets.size() == 1;
+ CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
+ "TestName");
+ assert container.getOwner().equals(owner);
+ }
+
public static final String listContainerResult = "<ListContainerHandler xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adrianjbosstest</Name><Prefix></Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>3366</Key><LastModified>2009-03-12T02:00:13.000Z</LastModified><ETag>"9d7bb64e8e18ee34eec06dd2cf37b766"</ETag><Size>136</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListContainerHandler>";
public void testCanParseListContainerResult() throws HttpException {