You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2013/02/12 13:38:14 UTC

svn commit: r1445139 - in /chemistry/opencmis/trunk: chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/jav...

Author: fmui
Date: Tue Feb 12 12:38:14 2013
New Revision: 1445139

URL: http://svn.apache.org/r1445139
Log:
unified datetime parsing and formatting

Added:
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java   (with props)
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java   (with props)
Modified:
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
    chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java
    chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/tube/server/WssTube.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/AtomDocumentBase.java
    chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/ObjectService.java

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/StandardAuthenticationProvider.java Tue Feb 12 12:38:14 2013
@@ -19,13 +19,11 @@
 package org.apache.chemistry.opencmis.client.bindings.spi;
 
 import java.io.UnsupportedEncodingException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.TimeZone;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -33,6 +31,7 @@ import javax.xml.parsers.ParserConfigura
 import org.apache.chemistry.opencmis.client.bindings.spi.cookies.CmisCookieManager;
 import org.apache.chemistry.opencmis.commons.SessionParameter;
 import org.apache.chemistry.opencmis.commons.impl.Base64;
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -153,8 +152,6 @@ public class StandardAuthenticationProvi
         }
 
         // set time
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
         long created = System.currentTimeMillis();
         long expires = created + 24 * 60 * 60 * 1000; // 24 hours
 
@@ -168,11 +165,11 @@ public class StandardAuthenticationProvi
             wsseSecurityElement.appendChild(wsuTimestampElement);
 
             Element tsCreatedElement = document.createElementNS(WSU_NAMESPACE, "Created");
-            tsCreatedElement.appendChild(document.createTextNode(sdf.format(created)));
+            tsCreatedElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(created)));
             wsuTimestampElement.appendChild(tsCreatedElement);
 
             Element tsExpiresElement = document.createElementNS(WSU_NAMESPACE, "Expires");
-            tsExpiresElement.appendChild(document.createTextNode(sdf.format(expires)));
+            tsExpiresElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(expires)));
             wsuTimestampElement.appendChild(tsExpiresElement);
 
             Element usernameTokenElement = document.createElementNS(WSSE_NAMESPACE, "UsernameToken");
@@ -189,7 +186,7 @@ public class StandardAuthenticationProvi
             usernameTokenElement.appendChild(passwordElement);
 
             Element createdElement = document.createElementNS(WSU_NAMESPACE, "Created");
-            createdElement.appendChild(document.createTextNode(sdf.format(created)));
+            createdElement.appendChild(document.createTextNode(DateTimeHelper.formatXmlDateTime(created)));
             usernameTokenElement.appendChild(createdElement);
 
             return wsseSecurityElement;

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/atompub/AtomEntryWriter.java Tue Feb 12 12:38:14 2013
@@ -31,8 +31,7 @@ import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.GregorianCalendar;
 import java.util.List;
 import java.util.TimeZone;
 
@@ -44,6 +43,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
 import org.apache.chemistry.opencmis.commons.impl.Base64;
 import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
 import org.apache.chemistry.opencmis.commons.impl.JaxBHelper;
 import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
 import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisProperty;
@@ -190,10 +190,8 @@ public class AtomEntryWriter {
     }
 
     private static String getUpdated() {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
-
-        return sdf.format(new Date());
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        return DateTimeHelper.formatXmlDateTime(cal);
     }
 
     private void writeContent(XMLStreamWriter writer) throws Exception {

Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/cookies/CmisHttpCookie.java Tue Feb 12 12:38:14 2013
@@ -31,6 +31,8 @@ import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
+
 /**
  * This class represents a http cookie, which indicates the status information
  * between the client agent side and the server side. According to RFC, there
@@ -362,7 +364,6 @@ public final class CmisHttpCookie implem
         });
 
         attributeSet.put("expires", new Setter() {
-            @SuppressWarnings("deprecation")
             @Override
             void setValue(String value, CmisHttpCookie cookie) {
                 cookie.setVersion(0);
@@ -373,9 +374,11 @@ public final class CmisHttpCookie implem
                         cookie.setMaxAge(0);
                         return;
                     }
-                    try {
-                        cookie.setMaxAge((Date.parse(value) - System.currentTimeMillis()) / 1000);
-                    } catch (IllegalArgumentException e) {
+
+                    Date date = DateTimeHelper.parseHttpDateTime(value);
+                    if (date != null) {
+                        cookie.setMaxAge((date.getTime() - System.currentTimeMillis()) / 1000);
+                    } else {
                         cookie.setMaxAge(0);
                     }
                 }

Added: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java?rev=1445139&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java Tue Feb 12 12:38:14 2013
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.commons.impl;
+
+import java.lang.ref.SoftReference;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DateTimeHelper {
+
+    private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+    private static final Pattern XML_DATETIME = Pattern
+            .compile("(\\d{4,9})-([01]\\d)-([0-3]\\d)T([0-2]\\d):([0-5]\\d):([0-5]\\d)(\\.(\\d+))?(([+-][0-2]\\d:[0-5]\\d)|Z)?");
+    private static final BigDecimal BD1000 = new BigDecimal(1000);
+
+    private static final String[] HTTP_DATETIME = new String[] { "EEE, dd MMM yyyy HH:mm:ss zzz",
+            "EEE, dd-MMM-yy HH:mm:ss zzz", "EEE MMM d HH:mm:ss yyyy" };
+
+    private static final ThreadLocal<SoftReference<SimpleDateFormat[]>> THREADLOCAL_HTTP_FORMATS = new ThreadLocal<SoftReference<SimpleDateFormat[]>>() {
+        @Override
+        protected SoftReference<SimpleDateFormat[]> initialValue() {
+            return new SoftReference<SimpleDateFormat[]>(new SimpleDateFormat[HTTP_DATETIME.length]);
+        }
+    };
+
+    /**
+     * Parses a xsd:dateTime string.
+     */
+    public static GregorianCalendar parseXmlDateTime(String s) throws IllegalArgumentException {
+        if (s == null) {
+            return null;
+        }
+
+        Matcher m = XML_DATETIME.matcher(s);
+
+        if (!m.matches()) {
+            return null;
+        }
+
+        try {
+            int year = Integer.parseInt(m.group(1));
+            int month = Integer.parseInt(m.group(2));
+            int day = Integer.parseInt(m.group(3));
+            int hour = Integer.parseInt(m.group(4));
+            int minute = Integer.parseInt(m.group(5));
+            int second = Integer.parseInt(m.group(6));
+            int millisecond = 0;
+
+            if (m.group(8) != null) {
+                millisecond = (new BigDecimal("0." + m.group(8))).multiply(BD1000).intValue();
+            }
+
+            TimeZone tz = GMT;
+
+            if (m.group(10) != null) {
+                tz = TimeZone.getTimeZone("GMT" + m.group(10));
+            }
+
+            GregorianCalendar result = new GregorianCalendar();
+            result.clear();
+
+            result.setTimeZone(tz);
+            result.set(year, month - 1, day, hour, minute, second);
+            result.set(Calendar.MILLISECOND, millisecond);
+
+            return result;
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a xsd:dateTime string.
+     */
+    public static String formatXmlDateTime(long millis) {
+        GregorianCalendar cal = new GregorianCalendar(GMT);
+        cal.setTimeInMillis(millis);
+
+        return formatXmlDateTime(cal);
+    }
+
+    /**
+     * Returns a xsd:dateTime string.
+     */
+    public static String formatXmlDateTime(GregorianCalendar cal) {
+        if (cal == null) {
+            throw new IllegalArgumentException();
+        }
+
+        StringBuilder sb = new StringBuilder(String.format("%04d-%02d-%02dT%02d:%02d:%02d", cal.get(Calendar.YEAR),
+                cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY),
+                cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)));
+
+        int ms = cal.get(Calendar.MILLISECOND);
+        if (ms > 0) {
+            StringBuilder mssb = new StringBuilder(String.format("%03d", ms));
+            while (mssb.charAt(mssb.length() - 1) == '0') {
+                mssb.deleteCharAt(mssb.length() - 1);
+            }
+            sb.append(".");
+            sb.append(mssb);
+        }
+
+        int tz = cal.getTimeZone().getRawOffset();
+        if (tz == 0) {
+            sb.append("Z");
+        } else {
+            if (tz > 0) {
+                sb.append("+");
+            } else {
+                sb.append("-");
+                tz *= -1;
+            }
+            sb.append(String.format("%02d", tz / 3600000));
+            sb.append(":");
+            int tzm = tz % 3600000;
+            sb.append(String.format("%02d", tzm == 0 ? 0 : tzm / 60000));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Parses a HTTP date.
+     */
+    public static Date parseHttpDateTime(String s) {
+        if (s == null) {
+            return null;
+        }
+
+        s = s.trim();
+        if (s.length() > 1 && s.startsWith("'") && s.endsWith("'")) {
+            s = s.substring(1, s.length() - 1);
+        }
+
+        for (int i = 0; i < HTTP_DATETIME.length; i++) {
+            SimpleDateFormat sdf = getFormatter(i);
+
+            try {
+                return sdf.parse(s);
+            } catch (ParseException e) {
+                // try next
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a HTTP date.
+     */
+    public static String formateHttpDateTime(long millis) {
+        return getFormatter(0).format(millis);
+    }
+
+    /**
+     * Returns a HTTP date.
+     */
+    public static String formateHttpDateTime(Date date) {
+        return getFormatter(0).format(date);
+    }
+
+    /**
+     * Returns a HTTP date.
+     */
+    public static String formateHttpDateTime(GregorianCalendar cal) {
+        return getFormatter(0).format(cal.getTimeInMillis());
+    }
+
+    private static SimpleDateFormat getFormatter(int x) {
+        SoftReference<SimpleDateFormat[]> ref = THREADLOCAL_HTTP_FORMATS.get();
+        SimpleDateFormat[] sdfs = ref.get();
+        if (sdfs == null) {
+            ref = new SoftReference<SimpleDateFormat[]>(new SimpleDateFormat[HTTP_DATETIME.length]);
+            THREADLOCAL_HTTP_FORMATS.set(ref);
+            sdfs = ref.get();
+        }
+
+        SimpleDateFormat sdf = sdfs[x];
+        if (sdf == null) {
+            sdf = new SimpleDateFormat(HTTP_DATETIME[x], Locale.US);
+            sdf.setTimeZone(GMT);
+            sdfs[x] = sdf;
+        }
+
+        return sdf;
+    }
+}

Propchange: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/DateTimeHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/tube/server/WssTube.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/tube/server/WssTube.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/tube/server/WssTube.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/tube/server/WssTube.java Tue Feb 12 12:38:14 2013
@@ -18,11 +18,9 @@
  */
 package org.apache.chemistry.opencmis.commons.impl.tube.server;
 
-import java.text.SimpleDateFormat;
-import java.util.TimeZone;
-
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
 import org.apache.chemistry.opencmis.commons.impl.tube.AbstractWssTube;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -58,8 +56,6 @@ public class WssTube extends AbstractWss
         }
 
         try {
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
             long created = System.currentTimeMillis();
             long expires = created + 24 * 60 * 60 * 1000; // 24 hours
 
@@ -71,11 +67,11 @@ public class WssTube extends AbstractWss
             wsseSecurityElement.appendChild(wsuTimestampElement);
 
             Element tsCreatedElement = document.createElementNS(WSU_NAMESPACE, "Created");
-            tsCreatedElement.setTextContent(sdf.format(created));
+            tsCreatedElement.setTextContent(DateTimeHelper.formatXmlDateTime(created));
             wsuTimestampElement.appendChild(tsCreatedElement);
 
             Element tsExpiresElement = document.createElementNS(WSU_NAMESPACE, "Expires");
-            tsExpiresElement.setTextContent(sdf.format(expires));
+            tsExpiresElement.setTextContent(DateTimeHelper.formatXmlDateTime(expires));
             wsuTimestampElement.appendChild(tsExpiresElement);
 
             HeaderList headers = message.getHeaders();

Added: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java?rev=1445139&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java Tue Feb 12 12:38:14 2013
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.commons.impl.misc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
+import org.junit.Test;
+
+public class DateTimeTest {
+
+    @Test
+    public void testXmlDateTimeParser() {
+        GregorianCalendar cal1 = DateTimeHelper.parseXmlDateTime("2012-12-24T09:15:06.123Z");
+        assertEquals(2012, cal1.get(Calendar.YEAR));
+        assertEquals(11, cal1.get(Calendar.MONTH));
+        assertEquals(24, cal1.get(Calendar.DAY_OF_MONTH));
+        assertEquals(9, cal1.get(Calendar.HOUR_OF_DAY));
+        assertEquals(15, cal1.get(Calendar.MINUTE));
+        assertEquals(6, cal1.get(Calendar.SECOND));
+        assertEquals(123, cal1.get(Calendar.MILLISECOND));
+        assertEquals(0, cal1.getTimeZone().getRawOffset());
+
+        GregorianCalendar cal2 = DateTimeHelper.parseXmlDateTime("2013-02-04T23:45:55.9876543");
+        assertEquals(2013, cal2.get(Calendar.YEAR));
+        assertEquals(1, cal2.get(Calendar.MONTH));
+        assertEquals(4, cal2.get(Calendar.DAY_OF_MONTH));
+        assertEquals(23, cal2.get(Calendar.HOUR_OF_DAY));
+        assertEquals(45, cal2.get(Calendar.MINUTE));
+        assertEquals(55, cal2.get(Calendar.SECOND));
+        assertEquals(987, cal2.get(Calendar.MILLISECOND));
+        assertEquals(0, cal2.getTimeZone().getRawOffset());
+
+        GregorianCalendar cal3 = DateTimeHelper.parseXmlDateTime("2013-01-02T03:04:05.678+05:00");
+        assertEquals(2013, cal3.get(Calendar.YEAR));
+        assertEquals(0, cal3.get(Calendar.MONTH));
+        assertEquals(02, cal3.get(Calendar.DAY_OF_MONTH));
+        assertEquals(03, cal3.get(Calendar.HOUR_OF_DAY));
+        assertEquals(04, cal3.get(Calendar.MINUTE));
+        assertEquals(5, cal3.get(Calendar.SECOND));
+        assertEquals(678, cal3.get(Calendar.MILLISECOND));
+        assertEquals(5 * 60 * 60 * 1000, cal3.getTimeZone().getRawOffset());
+    }
+
+    @Test
+    public void testXmlDateTimeWriter() {
+        GregorianCalendar cal1 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal1.set(2012, 11, 24, 9, 10, 11);
+        cal1.set(Calendar.MILLISECOND, 0);
+
+        assertEquals("2012-12-24T09:10:11Z", DateTimeHelper.formatXmlDateTime(cal1));
+
+        GregorianCalendar cal2 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal2.set(2013, 0, 1, 2, 3, 4);
+        cal2.set(Calendar.MILLISECOND, 50);
+
+        assertEquals("2013-01-01T02:03:04.05Z", DateTimeHelper.formatXmlDateTime(cal2));
+
+        GregorianCalendar cal3 = new GregorianCalendar(TimeZone.getTimeZone("GMT+05:00"));
+        cal3.set(2012, 11, 24, 9, 10, 11);
+        cal3.set(Calendar.MILLISECOND, 0);
+
+        assertEquals("2012-12-24T09:10:11+05:00", DateTimeHelper.formatXmlDateTime(cal3));
+
+        GregorianCalendar cal4 = new GregorianCalendar(TimeZone.getTimeZone("GMT-03:02"));
+        cal4.set(100, 8, 17, 18, 30, 7);
+        cal4.set(Calendar.MILLISECOND, 654);
+
+        assertEquals("0100-09-17T18:30:07.654-03:02", DateTimeHelper.formatXmlDateTime(cal4));
+
+        GregorianCalendar cal5 = new GregorianCalendar(TimeZone.getTimeZone("GMT+01:00"));
+        cal5.set(2012, 11, 24, 9, 10, 11);
+        cal5.set(Calendar.MILLISECOND, 0);
+
+        assertEquals("2012-12-24T08:10:11Z", DateTimeHelper.formatXmlDateTime(cal5.getTimeInMillis()));
+    }
+
+    @Test
+    public void testXmlDateTimeWriterAndParser() {
+        GregorianCalendar cal1 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal1.set(2012, 11, 24, 9, 10, 11);
+        cal1.set(Calendar.MILLISECOND, 0);
+
+        GregorianCalendar cal2 = DateTimeHelper.parseXmlDateTime(DateTimeHelper.formatXmlDateTime(cal1));
+
+        assertEquals(cal1, cal2);
+
+        GregorianCalendar cal3 = new GregorianCalendar(TimeZone.getTimeZone("GMT+05:00"));
+        cal3.set(2012, 11, 24, 9, 10, 11);
+        cal3.set(Calendar.MILLISECOND, 12);
+
+        GregorianCalendar cal4 = DateTimeHelper.parseXmlDateTime(DateTimeHelper.formatXmlDateTime(cal3));
+
+        assertEquals(cal3, cal4);
+    }
+
+    @Test
+    public void testInvalidXmlDateTime() {
+        // null is not a date
+        assertNull(DateTimeHelper.parseXmlDateTime(null));
+
+        // "" is not a date
+        assertNull(DateTimeHelper.parseXmlDateTime(""));
+
+        // wrong format
+        assertNull(DateTimeHelper.parseXmlDateTime("1111111111111111"));
+
+        // invalid year
+        assertNull(DateTimeHelper.parseXmlDateTime("111-11-11T11:11:11.111Z"));
+
+        // invalid month
+        assertNull(DateTimeHelper.parseXmlDateTime("1111-21-11T11:11:11.111Z"));
+
+        // invalid day
+        assertNull(DateTimeHelper.parseXmlDateTime("1111-11-51T11:11:11.111Z"));
+    }
+
+    @Test
+    public void testHttpDateTimeParser() {
+        GregorianCalendar cal1 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal1.set(2012, 11, 24, 9, 10, 11);
+        cal1.set(Calendar.MILLISECOND, 0);
+
+        String dateStr1 = DateTimeHelper.formateHttpDateTime(cal1.getTime());
+        assertEquals("Mon, 24 Dec 2012 09:10:11 GMT", dateStr1);
+
+        Date date1 = DateTimeHelper.parseHttpDateTime(dateStr1);
+
+        assertEquals(cal1.getTime(), date1);
+
+        GregorianCalendar cal2 = new GregorianCalendar(TimeZone.getTimeZone("GMT+05:00"));
+        cal2.set(2013, 0, 1, 2, 3, 4);
+        cal2.set(Calendar.MILLISECOND, 0);
+
+        String dateStr2 = "  '" + DateTimeHelper.formateHttpDateTime(cal2.getTimeInMillis()) + "' ";
+        Date date2 = DateTimeHelper.parseHttpDateTime(dateStr2);
+
+        assertEquals(cal2.getTime(), date2);
+
+        GregorianCalendar cal3 = new GregorianCalendar(TimeZone.getTimeZone("GMT+05:00"));
+        cal3.set(2012, 11, 24, 9, 10, 11);
+        cal3.set(Calendar.MILLISECOND, 0);
+
+        String dateStr3 = DateTimeHelper.formateHttpDateTime(cal3);
+        Date date3 = DateTimeHelper.parseHttpDateTime(dateStr3);
+
+        assertEquals(cal3.getTime(), date3);
+
+        GregorianCalendar cal4 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal4.set(1994, 10, 6, 8, 49, 37);
+        cal4.set(Calendar.MILLISECOND, 0);
+
+        String dateStr4 = "Sunday, 06-Nov-94 08:49:37 GMT";
+
+        assertEquals(cal4.getTime(), DateTimeHelper.parseHttpDateTime(dateStr4));
+
+        GregorianCalendar cal5 = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+        cal5.set(1994, 10, 6, 8, 49, 37);
+        cal5.set(Calendar.MILLISECOND, 0);
+
+        String dateStr5 = "Sun Nov  6 08:49:37 1994";
+
+        assertEquals(cal5.getTime(), DateTimeHelper.parseHttpDateTime(dateStr5));
+    }
+
+    @Test
+    public void testInvalidHttpDateTime() {
+        // null is not a date
+        assertNull(DateTimeHelper.parseHttpDateTime(null));
+
+        // "" is not a date
+        assertNull(DateTimeHelper.parseHttpDateTime(""));
+
+        // wrong format
+        assertNull(DateTimeHelper.parseHttpDateTime("1111111111111111"));
+
+        // invalid year
+        assertNull(DateTimeHelper.parseHttpDateTime("Mon, 24 Dec abcd 09:10:11 GMT"));
+
+        // invalid month
+        assertNull(DateTimeHelper.parseHttpDateTime("Mon, 24 abc 2012 09:10:11 GMT"));
+
+        // invalid day
+        assertNull(DateTimeHelper.parseHttpDateTime("Mon, xy Dec 2012 09:10:11 GMT"));
+
+        // invalid week day
+        assertNull(DateTimeHelper.parseHttpDateTime("abc, 24 Dec 2012 09:10:11 GMT"));
+    }
+}

Propchange: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/misc/DateTimeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/AtomDocumentBase.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/AtomDocumentBase.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/AtomDocumentBase.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/atompub/AtomDocumentBase.java Tue Feb 12 12:38:14 2013
@@ -21,359 +21,315 @@ package org.apache.chemistry.opencmis.se
 import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
 import java.net.URLEncoder;
-import java.text.SimpleDateFormat;
 import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
 
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.chemistry.opencmis.commons.impl.Base64;
 import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
 
 /**
  * Atom base class.
  */
 public abstract class AtomDocumentBase extends XMLDocumentBase {
 
-	private static final String ID_PREFIX = "http://chemistry.apache.org/";
-	private static final String ID_DUMMY = "http://chemistry.apache.org/no-id";
+    private static final String ID_PREFIX = "http://chemistry.apache.org/";
+    private static final String ID_DUMMY = "http://chemistry.apache.org/no-id";
 
-	private SimpleDateFormat dateFormater;
-
-	/**
-	 * Formats a DateTime.
-	 */
-	public String formatDate(long millis) {
-		if (dateFormater == null) {
-			dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
-					Locale.US);
-			dateFormater.setTimeZone(TimeZone.getTimeZone("UTC"));
-		}
-
-		return dateFormater.format(millis);
-	}
-
-	/**
-	 * Generates a valid Atom id.
-	 */
-	public String generateAtomId(String input) {
-		if (input == null) {
-			return ID_DUMMY;
-		}
-
-		try {
-			return ID_PREFIX + Base64.encodeBytes(input.getBytes("UTF-8"));
-		} catch (UnsupportedEncodingException e) {
-			return ID_DUMMY;
-		}
-	}
-
-	/**
-	 * Writes a simple tag.
-	 */
-	public void writeSimpleTag(String namespace, String name, String value)
-			throws XMLStreamException {
-		if (value == null) {
-			return;
-		}
-
-		XMLStreamWriter xsw = getWriter();
-
-		xsw.writeStartElement(namespace, name);
-		xsw.writeCharacters(value);
-		xsw.writeEndElement();
-	}
-
-	/**
-	 * Writes a simple date tag.
-	 */
-	public void writeSimpleDate(String namespace, String name,
-			GregorianCalendar value) throws XMLStreamException {
-		if (value == null) {
-			return;
-		}
-
-		writeSimpleTag(namespace, name, formatDate(value.getTimeInMillis()));
-	}
-
-	/**
-	 * Writes a simple date tag.
-	 */
-	public void writeSimpleDate(String namespace, String name, long millis)
-			throws XMLStreamException {
-		writeSimpleTag(namespace, name, formatDate(millis));
-	}
-
-	/**
-	 * Writes an Atom id tag.
-	 */
-	public void writeId(String id) throws XMLStreamException {
-		writeSimpleTag(Constants.NAMESPACE_ATOM, "id", id);
-	}
-
-	/**
-	 * Writes an Atom title tag.
-	 */
-	public void writeTitle(String title) throws XMLStreamException {
-		writeSimpleTag(Constants.NAMESPACE_ATOM, "title", title);
-	}
-
-	/**
-	 * Writes an Atom author tag.
-	 */
-	public void writeAuthor(String author) throws XMLStreamException {
-		XMLStreamWriter xsw = getWriter();
-
-		xsw.writeStartElement(Constants.NAMESPACE_ATOM, "author");
-		writeSimpleTag(Constants.NAMESPACE_ATOM, "name", author);
-		xsw.writeEndElement();
-	}
-
-	/**
-	 * Writes an Atom updated tag.
-	 */
-	public void writeUpdated(GregorianCalendar updated)
-			throws XMLStreamException {
-		writeSimpleDate(Constants.NAMESPACE_APP, "edited", updated);
-		writeSimpleDate(Constants.NAMESPACE_ATOM, "updated", updated);
-	}
-
-	/**
-	 * Writes an Atom updated tag.
-	 */
-	public void writeUpdated(long updated) throws XMLStreamException {
-		writeSimpleDate(Constants.NAMESPACE_APP, "edited", updated);
-		writeSimpleDate(Constants.NAMESPACE_ATOM, "updated", updated);
-	}
-
-	/**
-	 * Writes an Atom published tag.
-	 */
-	public void writePublished(GregorianCalendar published)
-			throws XMLStreamException {
-		writeSimpleDate(Constants.NAMESPACE_ATOM, "published", published);
-	}
-
-	/**
-	 * Writes an Atom published tag.
-	 */
-	public void writePublished(long published) throws XMLStreamException {
-		writeSimpleDate(Constants.NAMESPACE_ATOM, "published", published);
-	}
-
-	/**
-	 * Writes a CMIS pathSegment tag.
-	 */
-	public void writePathSegment(String pathSegment) throws XMLStreamException {
-		writeSimpleTag(Constants.NAMESPACE_RESTATOM, "pathSegment", pathSegment);
-	}
-
-	/**
-	 * Writes a CMIS relativePathSegment tag.
-	 */
-	public void writeRelativePathSegment(String relativePathSegment)
-			throws XMLStreamException {
-		writeSimpleTag(Constants.NAMESPACE_RESTATOM, "relativePathSegment",
-				relativePathSegment);
-	}
-
-	/**
-	 * Writes an Atom collection.
-	 */
-	public void writeCollection(String href, String collectionType,
-			String text, String... accept) throws XMLStreamException {
-		XMLStreamWriter xsw = getWriter();
-
-		xsw.writeStartElement(Constants.NAMESPACE_APP, "collection");
-		xsw.writeAttribute("href", href);
-
-		if (collectionType != null) {
-			xsw.writeStartElement(Constants.NAMESPACE_RESTATOM,
-					"collectionType");
-			xsw.writeCharacters(collectionType);
-			xsw.writeEndElement();
-		}
-
-		xsw.writeStartElement(Constants.NAMESPACE_ATOM, "title");
-		xsw.writeAttribute("type", "text");
-		xsw.writeCharacters(text);
-		xsw.writeEndElement();
-
-		for (String ct : accept) {
-			xsw.writeStartElement(Constants.NAMESPACE_APP, "accept");
-			xsw.writeCharacters(ct);
-			xsw.writeEndElement();
-		}
-
-		xsw.writeEndElement();
-	}
-
-	/**
-	 * Writes a link.
-	 */
-	public void writeLink(String rel, String href, String type, String id)
-			throws XMLStreamException {
-		XMLStreamWriter xsw = getWriter();
-
-		xsw.writeStartElement(Constants.NAMESPACE_ATOM, "link");
-
-		xsw.writeAttribute("rel", rel);
-		xsw.writeAttribute("href", href);
-		if (type != null) {
-			xsw.writeAttribute("type", type);
-		}
-		if (id != null) {
-			xsw.writeAttribute(Constants.NAMESPACE_RESTATOM, "id", id);
-		}
-
-		xsw.writeEndElement();
-	}
-
-	public void writeServiceLink(String href, String repositoryId)
-			throws XMLStreamException {
-		try {
-			writeLink(Constants.REL_SERVICE, href + "?repositoryId="
-					+ URLEncoder.encode(repositoryId, "UTF-8"),
-					Constants.MEDIATYPE_SERVICE, null);
-		} catch (UnsupportedEncodingException e) {
-		}
-	}
-
-	public void writeSelfLink(String href, String id) throws XMLStreamException {
-		writeLink(Constants.REL_SELF, href, Constants.MEDIATYPE_ENTRY, id);
-	}
-
-	public void writeEnclosureLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_ENCLOSURE, href, Constants.MEDIATYPE_ENTRY,
-				null);
-	}
-
-	public void writeEditLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_EDIT, href, Constants.MEDIATYPE_ENTRY, null);
-	}
-
-	public void writeAlternateLink(String href, String type, String kind,
-			String title, BigInteger length) throws XMLStreamException {
-		XMLStreamWriter xsw = getWriter();
-
-		xsw.writeStartElement(Constants.NAMESPACE_ATOM, "link");
-
-		xsw.writeAttribute("rel", Constants.REL_ALTERNATE);
-		xsw.writeAttribute("href", href);
-		if (type != null) {
-			xsw.writeAttribute("type", type);
-		}
-		if (kind != null) {
-			xsw.writeAttribute(Constants.NAMESPACE_RESTATOM, "renditionKind",
-					kind);
-		}
-		if (title != null) {
-			xsw.writeAttribute("title", title);
-		}
-		if (length != null) {
-			xsw.writeAttribute("length", length.toString());
-		}
-
-		xsw.writeEndElement();
-	}
-
-	public void writeWorkingCopyLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_WORKINGCOPY, href, Constants.MEDIATYPE_ENTRY,
-				null);
-	}
-
-	public void writeUpLink(String href, String type) throws XMLStreamException {
-		writeLink(Constants.REL_UP, href, type, null);
-	}
-
-	public void writeDownLink(String href, String type)
-			throws XMLStreamException {
-		writeLink(Constants.REL_DOWN, href, type, null);
-	}
-
-	public void writeVersionHistoryLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_VERSIONHISTORY, href, Constants.MEDIATYPE_FEED,
-				null);
-	}
-
-	public void writeCurrentVerionsLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_CURRENTVERSION, href,
-				Constants.MEDIATYPE_ENTRY, null);
-	}
-
-	public void writeEditMediaLink(String href, String type)
-			throws XMLStreamException {
-		writeLink(Constants.REL_EDITMEDIA, href, type, null);
-	}
-
-	public void writeDescribedByLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_DESCRIBEDBY, href, Constants.MEDIATYPE_ENTRY,
-				null);
-	}
-
-	public void writeAllowableActionsLink(String href)
-			throws XMLStreamException {
-		writeLink(Constants.REL_ALLOWABLEACTIONS, href,
-				Constants.MEDIATYPE_ALLOWABLEACTION, null);
-	}
-
-	public void writeAclLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_ACL, href, Constants.MEDIATYPE_ACL, null);
-	}
-
-	public void writePoliciesLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_POLICIES, href, Constants.MEDIATYPE_FEED, null);
-	}
-
-	public void writeRelationshipsLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_RELATIONSHIPS, href, Constants.MEDIATYPE_FEED,
-				null);
-	}
-
-	public void writeRelationshipSourceLink(String href)
-			throws XMLStreamException {
-		writeLink(Constants.REL_SOURCE, href, Constants.MEDIATYPE_ENTRY, null);
-	}
-
-	public void writeRelationshipTargetLink(String href)
-			throws XMLStreamException {
-		writeLink(Constants.REL_TARGET, href, Constants.MEDIATYPE_ENTRY, null);
-	}
-
-	public void writeFolderTreeLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_FOLDERTREE, href,
-				Constants.MEDIATYPE_FEED, null);
-	}
-
-	public void writeTypeUpLink(String href, String type)
-			throws XMLStreamException {
-		writeLink(Constants.REL_UP, href, type, null);
-	}
-
-	public void writeTypeDownLink(String href, String type)
-			throws XMLStreamException {
-		writeLink(Constants.REL_DOWN, href, type, null);
-	}
-
-	public void writeViaLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_VIA, href, Constants.MEDIATYPE_ENTRY, null);
-	}
-
-	public void writeFirstLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_FIRST, href, Constants.MEDIATYPE_FEED, null);
-	}
-
-	public void writeLastLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_LAST, href, Constants.MEDIATYPE_FEED, null);
-	}
-
-	public void writePreviousLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_PREV, href, Constants.MEDIATYPE_FEED, null);
-	}
-
-	public void writeNextLink(String href) throws XMLStreamException {
-		writeLink(Constants.REL_NEXT, href, Constants.MEDIATYPE_FEED, null);
-	}
+    /**
+     * Generates a valid Atom id.
+     */
+    public String generateAtomId(String input) {
+        if (input == null) {
+            return ID_DUMMY;
+        }
+
+        try {
+            return ID_PREFIX + Base64.encodeBytes(input.getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            return ID_DUMMY;
+        }
+    }
+
+    /**
+     * Writes a simple tag.
+     */
+    public void writeSimpleTag(String namespace, String name, String value) throws XMLStreamException {
+        if (value == null) {
+            return;
+        }
+
+        XMLStreamWriter xsw = getWriter();
+
+        xsw.writeStartElement(namespace, name);
+        xsw.writeCharacters(value);
+        xsw.writeEndElement();
+    }
+
+    /**
+     * Writes a simple date tag.
+     */
+    public void writeSimpleDate(String namespace, String name, GregorianCalendar value) throws XMLStreamException {
+        if (value == null) {
+            return;
+        }
+
+        writeSimpleTag(namespace, name, DateTimeHelper.formateHttpDateTime(value.getTimeInMillis()));
+    }
+
+    /**
+     * Writes a simple date tag.
+     */
+    public void writeSimpleDate(String namespace, String name, long millis) throws XMLStreamException {
+        writeSimpleTag(namespace, name, DateTimeHelper.formateHttpDateTime(millis));
+    }
+
+    /**
+     * Writes an Atom id tag.
+     */
+    public void writeId(String id) throws XMLStreamException {
+        writeSimpleTag(Constants.NAMESPACE_ATOM, "id", id);
+    }
+
+    /**
+     * Writes an Atom title tag.
+     */
+    public void writeTitle(String title) throws XMLStreamException {
+        writeSimpleTag(Constants.NAMESPACE_ATOM, "title", title);
+    }
+
+    /**
+     * Writes an Atom author tag.
+     */
+    public void writeAuthor(String author) throws XMLStreamException {
+        XMLStreamWriter xsw = getWriter();
+
+        xsw.writeStartElement(Constants.NAMESPACE_ATOM, "author");
+        writeSimpleTag(Constants.NAMESPACE_ATOM, "name", author);
+        xsw.writeEndElement();
+    }
+
+    /**
+     * Writes an Atom updated tag.
+     */
+    public void writeUpdated(GregorianCalendar updated) throws XMLStreamException {
+        writeSimpleDate(Constants.NAMESPACE_APP, "edited", updated);
+        writeSimpleDate(Constants.NAMESPACE_ATOM, "updated", updated);
+    }
+
+    /**
+     * Writes an Atom updated tag.
+     */
+    public void writeUpdated(long updated) throws XMLStreamException {
+        writeSimpleDate(Constants.NAMESPACE_APP, "edited", updated);
+        writeSimpleDate(Constants.NAMESPACE_ATOM, "updated", updated);
+    }
+
+    /**
+     * Writes an Atom published tag.
+     */
+    public void writePublished(GregorianCalendar published) throws XMLStreamException {
+        writeSimpleDate(Constants.NAMESPACE_ATOM, "published", published);
+    }
+
+    /**
+     * Writes an Atom published tag.
+     */
+    public void writePublished(long published) throws XMLStreamException {
+        writeSimpleDate(Constants.NAMESPACE_ATOM, "published", published);
+    }
+
+    /**
+     * Writes a CMIS pathSegment tag.
+     */
+    public void writePathSegment(String pathSegment) throws XMLStreamException {
+        writeSimpleTag(Constants.NAMESPACE_RESTATOM, "pathSegment", pathSegment);
+    }
+
+    /**
+     * Writes a CMIS relativePathSegment tag.
+     */
+    public void writeRelativePathSegment(String relativePathSegment) throws XMLStreamException {
+        writeSimpleTag(Constants.NAMESPACE_RESTATOM, "relativePathSegment", relativePathSegment);
+    }
+
+    /**
+     * Writes an Atom collection.
+     */
+    public void writeCollection(String href, String collectionType, String text, String... accept)
+            throws XMLStreamException {
+        XMLStreamWriter xsw = getWriter();
+
+        xsw.writeStartElement(Constants.NAMESPACE_APP, "collection");
+        xsw.writeAttribute("href", href);
+
+        if (collectionType != null) {
+            xsw.writeStartElement(Constants.NAMESPACE_RESTATOM, "collectionType");
+            xsw.writeCharacters(collectionType);
+            xsw.writeEndElement();
+        }
+
+        xsw.writeStartElement(Constants.NAMESPACE_ATOM, "title");
+        xsw.writeAttribute("type", "text");
+        xsw.writeCharacters(text);
+        xsw.writeEndElement();
+
+        for (String ct : accept) {
+            xsw.writeStartElement(Constants.NAMESPACE_APP, "accept");
+            xsw.writeCharacters(ct);
+            xsw.writeEndElement();
+        }
+
+        xsw.writeEndElement();
+    }
+
+    /**
+     * Writes a link.
+     */
+    public void writeLink(String rel, String href, String type, String id) throws XMLStreamException {
+        XMLStreamWriter xsw = getWriter();
+
+        xsw.writeStartElement(Constants.NAMESPACE_ATOM, "link");
+
+        xsw.writeAttribute("rel", rel);
+        xsw.writeAttribute("href", href);
+        if (type != null) {
+            xsw.writeAttribute("type", type);
+        }
+        if (id != null) {
+            xsw.writeAttribute(Constants.NAMESPACE_RESTATOM, "id", id);
+        }
+
+        xsw.writeEndElement();
+    }
+
+    public void writeServiceLink(String href, String repositoryId) throws XMLStreamException {
+        try {
+            writeLink(Constants.REL_SERVICE, href + "?repositoryId=" + URLEncoder.encode(repositoryId, "UTF-8"),
+                    Constants.MEDIATYPE_SERVICE, null);
+        } catch (UnsupportedEncodingException e) {
+        }
+    }
+
+    public void writeSelfLink(String href, String id) throws XMLStreamException {
+        writeLink(Constants.REL_SELF, href, Constants.MEDIATYPE_ENTRY, id);
+    }
+
+    public void writeEnclosureLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_ENCLOSURE, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeEditLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_EDIT, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeAlternateLink(String href, String type, String kind, String title, BigInteger length)
+            throws XMLStreamException {
+        XMLStreamWriter xsw = getWriter();
+
+        xsw.writeStartElement(Constants.NAMESPACE_ATOM, "link");
+
+        xsw.writeAttribute("rel", Constants.REL_ALTERNATE);
+        xsw.writeAttribute("href", href);
+        if (type != null) {
+            xsw.writeAttribute("type", type);
+        }
+        if (kind != null) {
+            xsw.writeAttribute(Constants.NAMESPACE_RESTATOM, "renditionKind", kind);
+        }
+        if (title != null) {
+            xsw.writeAttribute("title", title);
+        }
+        if (length != null) {
+            xsw.writeAttribute("length", length.toString());
+        }
+
+        xsw.writeEndElement();
+    }
+
+    public void writeWorkingCopyLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_WORKINGCOPY, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeUpLink(String href, String type) throws XMLStreamException {
+        writeLink(Constants.REL_UP, href, type, null);
+    }
+
+    public void writeDownLink(String href, String type) throws XMLStreamException {
+        writeLink(Constants.REL_DOWN, href, type, null);
+    }
+
+    public void writeVersionHistoryLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_VERSIONHISTORY, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeCurrentVerionsLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_CURRENTVERSION, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeEditMediaLink(String href, String type) throws XMLStreamException {
+        writeLink(Constants.REL_EDITMEDIA, href, type, null);
+    }
+
+    public void writeDescribedByLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_DESCRIBEDBY, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeAllowableActionsLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_ALLOWABLEACTIONS, href, Constants.MEDIATYPE_ALLOWABLEACTION, null);
+    }
+
+    public void writeAclLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_ACL, href, Constants.MEDIATYPE_ACL, null);
+    }
+
+    public void writePoliciesLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_POLICIES, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeRelationshipsLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_RELATIONSHIPS, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeRelationshipSourceLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_SOURCE, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeRelationshipTargetLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_TARGET, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeFolderTreeLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_FOLDERTREE, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeTypeUpLink(String href, String type) throws XMLStreamException {
+        writeLink(Constants.REL_UP, href, type, null);
+    }
+
+    public void writeTypeDownLink(String href, String type) throws XMLStreamException {
+        writeLink(Constants.REL_DOWN, href, type, null);
+    }
+
+    public void writeViaLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_VIA, href, Constants.MEDIATYPE_ENTRY, null);
+    }
+
+    public void writeFirstLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_FIRST, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeLastLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_LAST, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writePreviousLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_PREV, href, Constants.MEDIATYPE_FEED, null);
+    }
+
+    public void writeNextLink(String href) throws XMLStreamException {
+        writeLink(Constants.REL_NEXT, href, Constants.MEDIATYPE_FEED, null);
+    }
 }

Modified: chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/ObjectService.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/ObjectService.java?rev=1445139&r1=1445138&r2=1445139&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/ObjectService.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/ObjectService.java Tue Feb 12 12:38:14 2013
@@ -60,8 +60,6 @@ import java.io.BufferedOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.math.BigInteger;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -87,6 +85,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
 import org.apache.chemistry.opencmis.commons.impl.Constants;
+import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
 import org.apache.chemistry.opencmis.commons.impl.JSONConverter;
 import org.apache.chemistry.opencmis.commons.impl.MimeHelper;
 import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
@@ -548,29 +547,22 @@ public final class ObjectService {
             if (lastModified != null) {
                 long lastModifiedSecs = (long) Math.floor((double) lastModified.getTimeInMillis() / 1000);
 
-                SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
-
-                String modifiedSinceStr = request.getHeader("If-Modified-Since");
-                if (modifiedSinceStr != null) {
-                    try {
-                        Date modifiedSince = sdf.parse(modifiedSinceStr);
-                        long modifiedSinceSecs = (long) Math.floor((double) modifiedSince.getTime() / 1000);
-
-                        if (modifiedSinceSecs >= lastModifiedSecs) {
-                            // close stream
-                            content.getStream().close();
-
-                            // send not modified status code
-                            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-                            response.setContentLength(0);
-                            return;
-                        }
-                    } catch (ParseException e) {
-                        // ignore
+                Date modifiedSince = DateTimeHelper.parseHttpDateTime(request.getHeader("If-Modified-Since"));
+                if (modifiedSince != null) {
+                    long modifiedSinceSecs = (long) Math.floor((double) modifiedSince.getTime() / 1000);
+
+                    if (modifiedSinceSecs >= lastModifiedSecs) {
+                        // close stream
+                        content.getStream().close();
+
+                        // send not modified status code
+                        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                        response.setContentLength(0);
+                        return;
                     }
                 }
 
-                response.setHeader("Last-Modified", sdf.format(lastModifiedSecs * 1000));
+                response.setHeader("Last-Modified", DateTimeHelper.formateHttpDateTime(lastModifiedSecs * 1000));
             }
         }