Repository: jclouds
Updated Branches:
  refs/heads/master 9677ed18e -> d57bbebe7


Try iso8601SecondsDateParse if iso8601DateParse fails.

S3 compatible blobStores sometimes return date in the format:
"2014-07-23T20:53:17+0000" instead of the more common
"2014-07-23T18:09:39.944Z". This caused jclouds to barf with an
IllegalArgumentException.

This commit tries to parse both the formats for S3. The exception
is thrown if both fail.

Added unit tests for the same.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/d57bbebe
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/d57bbebe
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/d57bbebe

Branch: refs/heads/master
Commit: d57bbebe7e0217b9a3818c6e1ed460c90469da78
Parents: 9677ed1
Author: Shri Javadekar <[email protected]>
Authored: Fri Jul 25 16:59:18 2014 -0700
Committer: Andrew Gaul <[email protected]>
Committed: Sat Jul 26 22:19:54 2014 -0700

----------------------------------------------------------------------
 .../org/jclouds/s3/xml/CopyObjectHandler.java   |  3 ++-
 .../jclouds/s3/xml/ListAllMyBucketsHandler.java |  3 ++-
 .../org/jclouds/s3/xml/ListBucketHandler.java   |  3 ++-
 .../jclouds/s3/xml/CopyObjectHandlerTest.java   | 19 +++++++++++++++++++
 .../jclouds/s3/xml/ListBucketHandlerTest.java   | 20 +++++++++++++++++++-
 .../main/java/org/jclouds/date/DateService.java | 15 +++++++++++++++
 .../internal/SimpleDateFormatDateService.java   | 18 +++++++++++++++++-
 .../java/org/jclouds/date/DateServiceTest.java  |  9 +++++++++
 .../org/jclouds/date/joda/JodaDateService.java  | 14 ++++++++++++++
 9 files changed, 99 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/apis/s3/src/main/java/org/jclouds/s3/xml/CopyObjectHandler.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/xml/CopyObjectHandler.java 
b/apis/s3/src/main/java/org/jclouds/s3/xml/CopyObjectHandler.java
index f540496..12fdb07 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/xml/CopyObjectHandler.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/xml/CopyObjectHandler.java
@@ -51,7 +51,8 @@ public class CopyObjectHandler extends 
ParseSax.HandlerWithResult<ObjectMetadata
       if (qName.equals("ETag")) {
          this.currentETag = currentOrNull(currentText);
       } else if (qName.equals("LastModified")) {
-         this.currentLastModified = 
dateParser.iso8601DateParse(currentOrNull(currentText));
+         this.currentLastModified = dateParser
+             .iso8601DateParseWithOptionalTZ(currentOrNull(currentText));
       } else if (qName.equals("CopyObjectResult")) {
          metadata = new CopyObjectResult(currentLastModified, currentETag);
       }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/apis/s3/src/main/java/org/jclouds/s3/xml/ListAllMyBucketsHandler.java
----------------------------------------------------------------------
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 ad601ff..1f3ffb5 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
@@ -68,7 +68,8 @@ public class ListAllMyBucketsHandler extends 
ParseSax.HandlerWithResult<Set<Buck
       } else if (qName.equals("Name")) {
          currentName = currentOrNull(currentText);
       } else if (qName.equals("CreationDate")) {
-         currentCreationDate = 
dateParser.iso8601DateParse(currentOrNull(currentText));
+         currentCreationDate = dateParser
+               .iso8601DateParseWithOptionalTZ(currentOrNull(currentText));
       }
       currentText = new StringBuilder();
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/apis/s3/src/main/java/org/jclouds/s3/xml/ListBucketHandler.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/xml/ListBucketHandler.java 
b/apis/s3/src/main/java/org/jclouds/s3/xml/ListBucketHandler.java
index de81ff9..a53de4b 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/xml/ListBucketHandler.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/xml/ListBucketHandler.java
@@ -96,7 +96,8 @@ public class ListBucketHandler extends 
ParseSax.HandlerWithResult<ListBucketResp
          builder.key(currentKey);
          
builder.uri(uriBuilder(getRequest().getEndpoint()).clearQuery().appendPath(currentKey).build());
       } else if (qName.equals("LastModified")) {
-         
builder.lastModified(dateParser.iso8601DateParse(currentOrNull(currentText)));
+         builder.lastModified(dateParser
+               .iso8601DateParseWithOptionalTZ(currentOrNull(currentText)));
       } else if (qName.equals("ETag")) {
          String currentETag = currentOrNull(currentText);
          builder.eTag(currentETag);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/apis/s3/src/test/java/org/jclouds/s3/xml/CopyObjectHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/apis/s3/src/test/java/org/jclouds/s3/xml/CopyObjectHandlerTest.java 
b/apis/s3/src/test/java/org/jclouds/s3/xml/CopyObjectHandlerTest.java
index 961d2cc..559e597 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/xml/CopyObjectHandlerTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/xml/CopyObjectHandlerTest.java
@@ -25,6 +25,7 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
 import org.jclouds.http.functions.BaseHandlerTest;
 import org.jclouds.s3.domain.ObjectMetadata;
 import org.jclouds.s3.domain.internal.CopyObjectResult;
+import org.jclouds.util.Strings2;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
@@ -37,6 +38,8 @@ public class CopyObjectHandlerTest extends BaseHandlerTest {
 
    private DateService dateService;
 
+   private final String copyObjectXML = "<CopyObjectResult 
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\";><LastModified>2014-07-23T20:53:17+0000</LastModified><ETag>\"92836a3ea45a6984d1b4d23a747d46bb\"</ETag></CopyObjectResult>";
+
    @BeforeTest
    @Override
    protected void setUpInjector() {
@@ -57,4 +60,20 @@ public class CopyObjectHandlerTest extends BaseHandlerTest {
       assertEquals(result, expected);
    }
 
+   /**
+    * Verifies that the parser doesn't barf if the timestamp in the copy object
+    * xml has time zone designators.
+    */
+   public void testTimeStampWithTZ() {
+      InputStream is = Strings2.toInputStream(copyObjectXML);
+      ObjectMetadata expected = new CopyObjectResult(
+            new SimpleDateFormatDateService()
+                  .iso8601SecondsDateParse("2014-07-23T20:53:17+0000"),
+            "\"92836a3ea45a6984d1b4d23a747d46bb\"");
+
+      ObjectMetadata result = factory.create(
+            injector.getInstance(CopyObjectHandler.class)).parse(is);
+
+      assertEquals(result, expected);
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/apis/s3/src/test/java/org/jclouds/s3/xml/ListBucketHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/apis/s3/src/test/java/org/jclouds/s3/xml/ListBucketHandlerTest.java 
b/apis/s3/src/test/java/org/jclouds/s3/xml/ListBucketHandlerTest.java
index 3ff7ff3..1e887b0 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/xml/ListBucketHandlerTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/xml/ListBucketHandlerTest.java
@@ -33,6 +33,7 @@ import org.jclouds.s3.domain.CanonicalUser;
 import org.jclouds.s3.domain.ListBucketResponse;
 import org.jclouds.s3.domain.ObjectMetadata;
 import org.jclouds.s3.domain.ObjectMetadataBuilder;
+import org.jclouds.s3.domain.internal.CopyObjectResult;
 import org.jclouds.s3.domain.internal.ListBucketResponseImpl;
 import org.jclouds.util.Strings2;
 import org.testng.annotations.Test;
@@ -46,6 +47,7 @@ import com.google.common.collect.ImmutableList;
 @Test(groups = "unit", testName = "ListBucketHandlerTest")
 public class ListBucketHandlerTest extends BaseHandlerTest {
    public static final String listBucketWithPrefixAppsSlash = 
"<ListBucketResult 
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\";><Name>adriancole.org.jclouds.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/0</Key><LastModified>2009-05-07T18:27:08.000Z</LastModified><ETag>&quot;c82e6a0025c31c5de5947fda62ac51ab&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/1</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;944fab2c5a9a6bacf07db5e688310d7a&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/2</Key><LastModified>2009-05-07T18:27:09.000Z</Las
 
tModified><ETag>&quot;a227b8888045c8fd159fb495214000f0&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/3</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;c9caa76c3dec53e2a192608ce73eef03&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/4</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;1ce5d0dcc6154a647ea90c7bdf82a224&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/5</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;79433524d874
 
62ee05708a8ef894ed55&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/6</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;dd00a060b28ddca8bc5a21a49e306f67&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/7</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;8cd06eca6e819a927b07a285d750b100&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/8</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;174495094d0633b92cbe46603eee6bad&quot;</ETag><
 
Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/9</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>";
+   public static final String listBucketWithTSTimeZone = "<ListBucketResult 
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\";><Name>adriancole.org.jclouds.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/9</Key><LastModified>2014-07-23T20:53:17+0000</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>";
    public static final String listBucketWithSlashDelimiterAndCommonPrefixApps 
= "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\";> 
<Delimiter>/</Delimiter> 
<CommonPrefixes><Prefix>apps/</Prefix></CommonPrefixes></ListBucketResult>";
    private DateService dateService = new SimpleDateFormatDateService();
 
@@ -130,7 +132,23 @@ public class ListBucketHandlerTest extends BaseHandlerTest 
{
       assertEquals(bucket.getPrefix(), "apps/");
       assertEquals(bucket.getMaxKeys(), 1000);
       assert bucket.getMarker() == null;
-
    }
 
+   /**
+    * Verifies that the parser doesn't barf if the timestamp returned in the
+    * list bucket response has time zone designators in it.
+    */
+   @Test
+   public void testListMyBucketsWithTZ() {
+      ListBucketResponse bucket = createParser().parse(
+            Strings2.toInputStream(listBucketWithTSTimeZone));
+      ObjectMetadata expected = new CopyObjectResult(
+            new SimpleDateFormatDateService()
+                  .iso8601SecondsDateParse("2014-07-23T20:53:17+0000"),
+            "\"92836a3ea45a6984d1b4d23a747d46bb\"");
+
+      // Verify that the date was parsed successfully.
+      ObjectMetadata metadata = bucket.iterator().next();
+      assertEquals(metadata.getLastModified(), expected.getLastModified());
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/core/src/main/java/org/jclouds/date/DateService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/date/DateService.java 
b/core/src/main/java/org/jclouds/date/DateService.java
index 3897d85..408f125 100644
--- a/core/src/main/java/org/jclouds/date/DateService.java
+++ b/core/src/main/java/org/jclouds/date/DateService.java
@@ -73,6 +73,21 @@ public interface DateService {
     */
    Date iso8601SecondsDateParse(String toParse) throws 
IllegalArgumentException;
 
+   /**
+    * Parse a given date in either of two iso8601 formats:
+    * "yyyy-MM-dd'T'HH:mm:ssZ" or "yyyy-MM-dd'T'HH:mm:ss.SSSZ". The latter one
+    * has the timezone designator, e.g. 2014-07-23T20:53:17+0000. At least one
+    * S3 compatible blobstore uses both these formats when returning
+    * container/object metadata.
+    *
+    * @param toParse
+    *           The string to parse.
+    * @return the Date object of the parsed string.
+    * @throws IllegalArgumentException
+    */
+   Date iso8601DateParseWithOptionalTZ(String toParse)
+         throws IllegalArgumentException;
+
    String rfc1123DateFormat(Date date);
 
    String rfc1123DateFormat();

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java 
b/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java
index 38e1aa6..d928c32 100644
--- 
a/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java
+++ 
b/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java
@@ -18,6 +18,7 @@ package org.jclouds.date.internal;
 import static org.jclouds.date.internal.DateUtils.findTZ;
 import static org.jclouds.date.internal.DateUtils.trimTZ;
 import static org.jclouds.date.internal.DateUtils.trimToMillis;
+import static org.jclouds.util.SaxUtils.currentOrNull;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -149,7 +150,8 @@ public class SimpleDateFormatDateService implements 
DateService {
    }
 
    @Override
-   public final Date iso8601SecondsDateParse(String toParse) {
+   public final Date iso8601SecondsDateParse(String toParse)
+         throws IllegalArgumentException {
       if (toParse.length() < 10)
          throw new IllegalArgumentException("incorrect date format " + 
toParse);
       String tz = findTZ(toParse);
@@ -201,4 +203,18 @@ public class SimpleDateFormatDateService implements 
DateService {
          }
       }
    }
+
+   @Override
+   public Date iso8601DateParseWithOptionalTZ(String toParse)
+         throws IllegalArgumentException {
+      try {
+         return iso8601DateParse(toParse);
+      } catch (IllegalArgumentException orig) {
+         try {
+            return iso8601SecondsDateParse(toParse);
+         } catch (IllegalArgumentException ie) {
+            throw orig;
+         }
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/core/src/test/java/org/jclouds/date/DateServiceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/date/DateServiceTest.java 
b/core/src/test/java/org/jclouds/date/DateServiceTest.java
index 5a91608..4fa3712 100644
--- a/core/src/test/java/org/jclouds/date/DateServiceTest.java
+++ b/core/src/test/java/org/jclouds/date/DateServiceTest.java
@@ -107,6 +107,15 @@ public class DateServiceTest extends PerformanceTest {
    }
 
    @Test
+   public void testIso8601OptionalTZDateParse() {
+      Date dsDate = dateService
+            
.iso8601DateParseWithOptionalTZ(testData[0].iso8601SecondsDateString);
+      Date secondsDate = dateService
+            .iso8601SecondsDateParse(testData[0].iso8601SecondsDateString);
+      assertEquals(dsDate, secondsDate);
+   }
+
+   @Test
    public void testIso8601SecondsDateParse() {
       Date dsDate = 
dateService.iso8601SecondsDateParse(testData[0].iso8601SecondsDateString);
       assertEquals(dsDate, testData[0].date);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/d57bbebe/drivers/joda/src/main/java/org/jclouds/date/joda/JodaDateService.java
----------------------------------------------------------------------
diff --git 
a/drivers/joda/src/main/java/org/jclouds/date/joda/JodaDateService.java 
b/drivers/joda/src/main/java/org/jclouds/date/joda/JodaDateService.java
index 0438de7..074758a 100644
--- a/drivers/joda/src/main/java/org/jclouds/date/joda/JodaDateService.java
+++ b/drivers/joda/src/main/java/org/jclouds/date/joda/JodaDateService.java
@@ -141,4 +141,18 @@ public class JodaDateService implements DateService {
    public final Date rfc1123DateParse(String toParse) {
       return rfc1123DateFormat.parseDateTime(toParse).toDate();
    }
+
+   @Override
+   public Date iso8601DateParseWithOptionalTZ(String toParse)
+         throws IllegalArgumentException {
+      try {
+         return iso8601DateParse(toParse);
+      } catch (IllegalArgumentException orig) {
+         try {
+            return iso8601SecondsDateParse(toParse);
+         } catch (IllegalArgumentException ie) {
+            throw orig;
+         }
+      }
+   }
 }

Reply via email to