Author: awiner
Date: Mon Mar 16 18:55:29 2009
New Revision: 754978

URL: http://svn.apache.org/viewvc?rev=754978&view=rev
Log:
SHINDIG-933: JsonSerializer doesn't serialize dates as valid xs:date or 
xs:dateTime
- Patch from Aaron Evans, slightly cleaned up (use Joda ISODateTimeFormat class)
- Added Javascript ISO parsing routine to create Date objects off of ISO strings

Modified:
    incubator/shindig/trunk/features/pom.xml
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
    
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/JsonSerializer.java
    
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/DateUtil.java
    
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/DateUtilTest.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponseBuilder.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java

Modified: incubator/shindig/trunk/features/pom.xml
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/pom.xml?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- incubator/shindig/trunk/features/pom.xml (original)
+++ incubator/shindig/trunk/features/pom.xml Mon Mar 16 18:55:29 2009
@@ -102,6 +102,7 @@
                 <source>opensocial-reference/phone.js</source>
                 <source>opensocial-reference/responseitem.js</source>
                 <source>opensocial-reference/url.js</source>
+                <source>opensocial-base/fieldtranslations.js</source>
                 <source>opensocial-base/jsonactivity.js</source>
                 <source>opensocial-base/jsonperson.js</source>
                 <source>opensocial-rest/restfulcontainer.js</source>

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/fieldtranslations.js
 Mon Mar 16 18:55:29 2009
@@ -114,7 +114,33 @@
   }
 
   // displayName and id always need to be requested
-  fields.push("id");
-  fields.push("displayName");
+  fields.push('id');
+  fields.push('displayName');
 };
 
+FieldTranslations.translateIsoStringToDate = function(isoString) {
+  // Date parsing code from http://delete.me.uk/2005/03/iso8601.html
+  var regexp = '([0-9]{4})(-([0-9]{2})(-([0-9]{2})' +
+      '(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?' +
+      '(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?';
+  var d = isoString.match(new RegExp(regexp));
+
+  var offset = 0;
+  var date = new Date(d[1], 0, 1);
+
+  if (d[3]) { date.setMonth(d[3] - 1); }
+  if (d[5]) { date.setDate(d[5]); }
+  if (d[7]) { date.setHours(d[7]); }
+  if (d[8]) { date.setMinutes(d[8]); }
+  if (d[10]) { date.setSeconds(d[10]); }
+  if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
+  if (d[14]) {
+    offset = (Number(d[16]) * 60) + Number(d[17]);
+    offset *= ((d[15] == '-') ? 1 : -1);
+  }
+
+  offset -= date.getTimezoneOffset();
+  time = (Number(date) + (offset * 60 * 1000));
+  
+  return new Date(Number(time));
+}
\ No newline at end of file

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-base/jsonperson.js
 Mon Mar 16 18:55:29 2009
@@ -28,11 +28,12 @@
 
   JsonPerson.constructObject(opt_params, "bodyType", opensocial.BodyType);
   JsonPerson.constructObject(opt_params, "currentLocation", 
opensocial.Address);
-  JsonPerson.constructObject(opt_params, "dateOfBirth", Date);
   JsonPerson.constructObject(opt_params, "name", opensocial.Name);
   JsonPerson.constructObject(opt_params, "profileSong", opensocial.Url);
   JsonPerson.constructObject(opt_params, "profileVideo", opensocial.Url);
 
+  JsonPerson.constructDate(opt_params, "dateOfBirth");
+
   JsonPerson.constructArrayObject(opt_params, "addresses", opensocial.Address);
   JsonPerson.constructArrayObject(opt_params, "emails", opensocial.Email);
   JsonPerson.constructArrayObject(opt_params, "jobs", opensocial.Organization);
@@ -78,6 +79,14 @@
   }
 };
 
+// Converts the fieldName into an instance of a Date
+JsonPerson.constructDate = function(map, fieldName) {
+  var fieldValue = map[fieldName];
+  if (fieldValue) {
+    map[fieldName] = FieldTranslations.translateIsoStringToDate(fieldValue);
+  }
+};
+
 JsonPerson.constructArrayObject = function(map, fieldName, className) {
   var fieldValue = map[fieldName];
   if (fieldValue) {

Modified: 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/JsonSerializer.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/JsonSerializer.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/JsonSerializer.java
 (original)
+++ 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/JsonSerializer.java
 Mon Mar 16 18:55:29 2009
@@ -22,6 +22,7 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.MapMaker;
 
+import org.apache.shindig.common.util.DateUtil;
 import org.joda.time.DateTime;
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -157,10 +158,11 @@
       buf.append(value.toString());
     } else if (value instanceof CharSequence ||
                value instanceof DateTime ||
-               value instanceof Date ||
                value.getClass().isEnum()) {
       // String-like Primitives
       appendString(buf, value.toString());
+    } else if(value instanceof Date) {
+      appendString(buf, DateUtil.formatIso8601Date((Date)value));  
     } else if (value instanceof JSONObject) {
       appendJsonObject(buf, (JSONObject) value);
     } else if (value instanceof JSONArray) {

Modified: 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/DateUtil.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/DateUtil.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/DateUtil.java
 (original)
+++ 
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/DateUtil.java
 Mon Mar 16 18:55:29 2009
@@ -18,9 +18,11 @@
  */
 package org.apache.shindig.common.util;
 
+import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
 
 import java.util.Date;
 import java.util.Locale;
@@ -29,12 +31,15 @@
  * Date parsing and writing utilities.
  */
 public class DateUtil {
-
+    
   private static final DateTimeFormatter rfc1123DateFormat = DateTimeFormat
       .forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'")
       .withLocale(Locale.US)
       .withZone(DateTimeZone.UTC);
 
+  private static final DateTimeFormatter iso8601DateFormat = 
ISODateTimeFormat.dateTime()
+      .withZone(DateTimeZone.UTC); 
+ 
   private DateUtil() {}
 
   /**
@@ -44,7 +49,7 @@
    * @param dateStr
    * @return the date
    */
-  public static Date parseDate(String dateStr) {
+  public static Date parseRfc1123Date(String dateStr) {
     try {
       return rfc1123DateFormat.parseDateTime(dateStr).toDate();
     } catch (Exception e) {
@@ -52,18 +57,49 @@
       return null;
     }
   }
+  
+  /**
+   * Parses an ISO8601 formatted datetime into a Date or null
+   * is parsing fails.
+   *  
+   * @param dateStr A datetime string in ISO8601 format
+   * @return the date
+   */
+   public static Date parseIso8601DateTime(String dateStr) {
+      try {
+          // joda does our ISO 8601 parsing
+          return new DateTime(dateStr).toDate();
+      } catch(Exception e) {
+          return null;
+      }
+  }
+  
+  /**
+   * Formats an ISO 8601 format date.
+   */
+  public static String formatIso8601Date(Date date) {
+      return formatIso8601Date(date.getTime());
+  }
+ 
+  /**
+   * Formats an ISO 8601 format date.
+   */
+  public static String formatIso8601Date(long time) {      
+      return iso8601DateFormat.print(time);
+  }
 
   /**
    * Formats an RFC 1123 format date.
    */
-  public static String formatDate(Date date) {
-    return formatDate(date.getTime());
+  public static String formatRfc1123Date(Date date) {
+    return formatRfc1123Date(date.getTime());
   }
 
   /**
    * Formats an RFC 1123 format date.
    */
-  public static String formatDate(long timeStamp) {
+  public static String formatRfc1123Date(long timeStamp) {
     return rfc1123DateFormat.print(timeStamp);
   }
+
 }

Modified: 
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/DateUtilTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/DateUtilTest.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/DateUtilTest.java
 (original)
+++ 
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/util/DateUtilTest.java
 Mon Mar 16 18:55:29 2009
@@ -28,14 +28,21 @@
 
 public class DateUtilTest {
 
-  String[] text = {
+  String[] rfc1123text = new String[] {
     "Tue, 27 May 2008 05:12:50 GMT",
     "Wed, 28 May 2008 04:40:48 GMT",
     "Mon, 30 Jun 3090 03:29:55 GMT",
     "Fri, 06 Jun 1670 01:57:27 GMT",
   };
 
-  Date[] timeStamps = {
+  String[] iso8601text = new String[] {
+          "2008-05-27T05:12:50.000Z",
+          "2008-05-28T04:40:48.000Z",
+          "3090-06-30T03:29:55.000Z",
+          "1670-06-06T01:57:27.000Z"
+   };
+  
+  Date[] timeStamps = new Date[] {
     new Date(1211865170000L),
     new Date(1211949648000L),
     new Date(35359385395000L),
@@ -44,48 +51,67 @@
 
   @Test
   public void parse() {
-    for (int i = 0, j = text.length; i < j; ++i) {
-      assertEquals(timeStamps[i].getTime(), 
DateUtil.parseDate(text[i]).getTime());
-    }
+    for (int i = 0, j = rfc1123text.length; i < j; ++i) {
+      assertEquals(timeStamps[i].getTime(), 
DateUtil.parseRfc1123Date(rfc1123text[i]).getTime());
+    }    
   }
 
   @Test
   public void format() {
     for (int i = 0, j = timeStamps.length; i < j; ++i) {
-      assertEquals(text[i], DateUtil.formatDate(timeStamps[i].getTime()));
+      assertEquals(rfc1123text[i], 
DateUtil.formatRfc1123Date(timeStamps[i].getTime()));
     }
   }
-
+  
   @Test
-  public void formatDate() {
+  public void formatIso8601() {
+      for (int i = 0, j = timeStamps.length; i < j; ++i) {
+          assertEquals(iso8601text[i], 
DateUtil.formatIso8601Date(timeStamps[i].getTime()));
+      }
+  }
+  
+  @Test
+  public void formatRfc1123Date() {
     for (int i = 0, j = timeStamps.length; i < j; ++i) {
-      assertEquals(text[i], DateUtil.formatDate(timeStamps[i]));
+      assertEquals(rfc1123text[i], DateUtil.formatRfc1123Date(timeStamps[i]));
     }
   }
-
+  
   @Test
-  public void parseMalformed() {
-    assertNull(DateUtil.parseDate("Invalid date format"));
+  public void formatIso8601Date() {
+      for (int i = 0, j = timeStamps.length; i < j; ++i) {
+          assertEquals(iso8601text[i], 
DateUtil.formatIso8601Date(timeStamps[i]));
+      }
   }
-
+  
+  @Test
+  public void parseMalformedRfc1123() {
+    assertNull(DateUtil.parseRfc1123Date("Invalid date format"));
+  }
+  
+  @Test
+  public void parseMalformedIso8691() {
+      assertNull(DateUtil.parseIso8601DateTime("invalid date format"));
+  }
+  
   @Test
   public void parseWrongTimeZone() {
     String expires = "Mon, 12 May 2008 09:23:29 PDT";
-    assertNull(DateUtil.parseDate(expires));
+    assertNull(DateUtil.parseRfc1123Date(expires));
   }
 
   @Test
   public void parseRfc1036() {
     // We don't support this, though RFC 2616 suggests we should
     String expires = "Sunday, 06-Nov-94 08:49:37 GMT";
-    assertNull(DateUtil.parseDate(expires));
+    assertNull(DateUtil.parseRfc1123Date(expires));
   }
 
   @Test
   public void parseAsctime() {
     // We don't support this, though RFC 2616 suggests we should
     String expires = "Sun Nov  6 08:49:37 1994";
-    assertNull(DateUtil.parseDate(expires));
+    assertNull(DateUtil.parseRfc1123Date(expires));
   }
 
   @Test
@@ -93,7 +119,7 @@
     Locale orig = Locale.getDefault();
     try {
       Locale.setDefault(Locale.ITALY);
-      formatDate();
+      formatRfc1123Date();
     } finally {
       Locale.setDefault(orig);
     }

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
 Mon Mar 16 18:55:29 2009
@@ -363,7 +363,7 @@
   private long getExpiresTime() {
     String expires = getHeader("Expires");
     if (expires != null) {
-      Date expiresDate = DateUtil.parseDate(expires);
+      Date expiresDate = DateUtil.parseRfc1123Date(expires);
       if (expiresDate != null) {
         return expiresDate.getTime();
       }
@@ -406,14 +406,14 @@
     Collection<String> dates = headers.get("Date");
 
     if (!dates.isEmpty()) {
-      Date d = DateUtil.parseDate(dates.iterator().next());
+      Date d = DateUtil.parseRfc1123Date(dates.iterator().next());
       if (d != null) {
         timestamp = d.getTime();
       }
     }
     if (timestamp == -1) {
       timestamp = System.currentTimeMillis();
-      headers.put("Date", DateUtil.formatDate(timestamp));
+      headers.put("Date", DateUtil.formatRfc1123Date(timestamp));
     }
     return timestamp;
   }

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponseBuilder.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponseBuilder.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponseBuilder.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponseBuilder.java
 Mon Mar 16 18:55:29 2009
@@ -160,7 +160,7 @@
   public HttpResponseBuilder setExpirationTime(long expirationTime) {
     headers.removeAll("Cache-Control");
     headers.removeAll("Pragma");
-    headers.put("Expires", DateUtil.formatDate(expirationTime));
+    headers.put("Expires", DateUtil.formatRfc1123Date(expirationTime));
     return this;
   }
 

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
 Mon Mar 16 18:55:29 2009
@@ -246,7 +246,7 @@
     int maxAge = 10;
     int time = roundToSeconds(System.currentTimeMillis()) + maxAge;
     HttpResponse response = new HttpResponseBuilder()
-        .addHeader("Expires", DateUtil.formatDate(1000L * time))
+        .addHeader("Expires", DateUtil.formatRfc1123Date(1000L * time))
         .create();
     assertEquals(time, roundToSeconds(response.getCacheExpiration()));
     // Second rounding makes this n-1.
@@ -288,7 +288,7 @@
     int maxAge = 10;
     int now = roundToSeconds(System.currentTimeMillis());
     HttpResponse response = new HttpResponseBuilder()
-        .addHeader("Date", DateUtil.formatDate(1000L * now))
+        .addHeader("Date", DateUtil.formatRfc1123Date(1000L * now))
         .addHeader("Cache-Control", "public, max-age=" + maxAge)
         .create();
 
@@ -300,7 +300,7 @@
   public void testFixedDate() throws Exception {
     int time = roundToSeconds(System.currentTimeMillis());
     HttpResponse response = new HttpResponseBuilder()
-        .addHeader("Date", DateUtil.formatDate(1000L * time))
+        .addHeader("Date", DateUtil.formatRfc1123Date(1000L * time))
         .create();
     assertEquals(time + roundToSeconds(HttpResponse.DEFAULT_TTL),
         roundToSeconds(response.getCacheExpiration()));
@@ -352,7 +352,7 @@
   public void testSetNoCache() {
     int time = roundToSeconds(System.currentTimeMillis());
     HttpResponse response = new HttpResponseBuilder()
-        .addHeader("Expires", DateUtil.formatDate(1000L * time))
+        .addHeader("Expires", DateUtil.formatRfc1123Date(1000L * time))
         .setStrictNoCache()
         .create();
     assertNull(response.getHeader("Expires"));
@@ -423,7 +423,7 @@
         .addHeader("Foo", "bar")
         .addHeader("Foo", "baz")
         .addHeader("Blah", "blah")
-        .addHeader("Date", DateUtil.formatDate(now))
+        .addHeader("Date", DateUtil.formatRfc1123Date(now))
         .setHttpStatusCode(204)
         .setResponseString("This is the response string")
         .setMetadata("foo", "bar")
@@ -440,7 +440,7 @@
         .addHeader("Foo", "bar")
         .addHeader("Foo", "baz")
         .addHeader("Blah", "blah")
-        .addHeader("Date", DateUtil.formatDate(now))
+        .addHeader("Date", DateUtil.formatRfc1123Date(now))
         .setHttpStatusCode(204)
         .setResponseString("This is the response string")
         .create();

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HttpServletResponseRecorder.java
 Mon Mar 16 18:55:29 2009
@@ -100,7 +100,7 @@
 
   @Override
   public void addDateHeader(String name, long date) {
-    headers.put(name, DateUtil.formatDate(date));
+    headers.put(name, DateUtil.formatRfc1123Date(date));
   }
 
   @Override

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java?rev=754978&r1=754977&r2=754978&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
 Mon Mar 16 18:55:29 2009
@@ -64,7 +64,7 @@
 
   public void checkCacheControlHeaders(int ttl, boolean noProxy) {
 
-    long expires = DateUtil.parseDate(recorder.getHeader("Expires")).getTime();
+    long expires = 
DateUtil.parseRfc1123Date(recorder.getHeader("Expires")).getTime();
 
     long lowerBound = testStartTime + (1000L * (ttl - 1));
     long upperBound = lowerBound + 2000L;


Reply via email to