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>&quot;9d7bb64e8e18ee34eec06dd2cf37b766&quot;</ETag><Size>136</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListContainerHandler>";
 
    public void testCanParseListContainerResult() throws HttpException {