Index: web/modeshape-web-jcr-rest-client/pom.xml =================================================================== --- web/modeshape-web-jcr-rest-client/pom.xml (revision 2271) +++ web/modeshape-web-jcr-rest-client/pom.xml (working copy) @@ -26,6 +26,10 @@ javax.jcr jcr + + joda-time + joda-time + org.modeshape modeshape-common Index: web/modeshape-web-jcr-rest-client/src/main/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinition.java =================================================================== --- web/modeshape-web-jcr-rest-client/src/main/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinition.java (revision 2271) +++ web/modeshape-web-jcr-rest-client/src/main/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinition.java (working copy) @@ -27,14 +27,10 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Map; -import java.util.TimeZone; import javax.jcr.Binary; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -42,6 +38,8 @@ import javax.jcr.Value; import javax.jcr.ValueFormatException; import javax.jcr.version.OnParentVersionAction; import net.jcip.annotations.Immutable; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; import org.modeshape.web.jcr.rest.client.RestClientI18n; /** @@ -50,37 +48,9 @@ import org.modeshape.web.jcr.rest.client.RestClientI18n; @Immutable public class PropertyDefinition extends ItemDefinition implements javax.jcr.nodetype.PropertyDefinition { - private static final String DATE_PATTERN1 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - private static final String DATE_PATTERN2 = "yyyy-MM-dd'T'HH:mm:ss.SSSz"; - private static final String DATE_PATTERN3 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; - - public static Calendar parseDate( String dateString ) throws ParseException { - try { - Date date = new SimpleDateFormat(DATE_PATTERN1).parse(dateString); - Calendar result = Calendar.getInstance(); - result.setTime(date); - return result; - } catch (ParseException t) { - try { - // JCR allows the time zone to use ':' between hours and minutes, but this is not handled by SimpleDateFormat, - // so remove the ':' in the time zone ... - dateString = dateString.replaceAll("([.]\\d{1,3}[+-]?\\d{1,2})[:](\\d{1,2})$", "$1$2"); - Date date = new SimpleDateFormat(DATE_PATTERN2).parse(dateString); - Calendar result = Calendar.getInstance(); - result.setTime(date); - return result; - } catch (ParseException t2) { - try { - Date date = new SimpleDateFormat(DATE_PATTERN3).parse(dateString); - Calendar result = Calendar.getInstance(); - result.setTime(date); - result.setTimeZone(TimeZone.getTimeZone("UTC")); - return result; - } catch (ParseException t3) { - throw t; - } - } - } + public static Calendar parseDate( String dateString ) throws IllegalArgumentException { + DateTime result = new DateTime(dateString); + return result.toCalendar(null); } private final Id id; @@ -320,7 +290,22 @@ public class PropertyDefinition extends ItemDefinition implements javax.jcr.node public Calendar getDate() throws ValueFormatException, RepositoryException { try { return parseDate(value); - } catch (ParseException e) { + } catch (IllegalArgumentException e) { + String from = PropertyType.nameFromValue(getType()); + String to = PropertyType.nameFromValue(PropertyType.LONG); + throw new ValueFormatException(RestClientI18n.unableToConvertValue.text(value, from, to), e); + } + } + + public Calendar getDateInUtc() throws ValueFormatException, RepositoryException { + try { + DateTime result = new DateTime(value); + DateTimeZone utc = DateTimeZone.forID("UTC"); + if (!result.getZone().equals(utc)) { + result = result.withZone(utc); + } + return result.toCalendar(null); + } catch (IllegalArgumentException e) { String from = PropertyType.nameFromValue(getType()); String to = PropertyType.nameFromValue(PropertyType.LONG); throw new ValueFormatException(RestClientI18n.unableToConvertValue.text(value, from, to), e); @@ -336,7 +321,7 @@ public class PropertyDefinition extends ItemDefinition implements javax.jcr.node public BigDecimal getDecimal() throws ValueFormatException, RepositoryException { try { if (getRequiredType() == PropertyType.DATE) { - return new BigDecimal(getDate().getTime().getTime()); + return new BigDecimal(getDateInUtc().getTime().getTime()); } return new BigDecimal(value); } catch (NumberFormatException t) { @@ -355,7 +340,7 @@ public class PropertyDefinition extends ItemDefinition implements javax.jcr.node public double getDouble() throws ValueFormatException, RepositoryException { try { if (getRequiredType() == PropertyType.DATE) { - return getDate().getTime().getTime(); + return getDateInUtc().getTime().getTime(); } return Double.parseDouble(value); } catch (NumberFormatException t) { @@ -374,7 +359,7 @@ public class PropertyDefinition extends ItemDefinition implements javax.jcr.node public long getLong() throws ValueFormatException, RepositoryException { try { if (getRequiredType() == PropertyType.DATE) { - return getDate().getTime().getTime(); + return getDateInUtc().getTime().getTime(); } return Long.parseLong(value); } catch (NumberFormatException t) { Index: web/modeshape-web-jcr-rest-client/src/test/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinitionTest.java =================================================================== --- web/modeshape-web-jcr-rest-client/src/test/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinitionTest.java (revision 2271) +++ web/modeshape-web-jcr-rest-client/src/test/java/org/modeshape/web/jcr/rest/client/domain/PropertyDefinitionTest.java (working copy) @@ -30,13 +30,13 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; -import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import javax.jcr.Binary; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -176,7 +176,31 @@ public class PropertyDefinitionTest { defn = createPropertyDefinition(); assertThat(defn.getDefaultValues()[0].getString(), is("2010-03-22T01:02:03.456Z")); assertThat(defn.getDefaultValues()[0].getDate(), is(dateFrom("2010-03-22T01:02:03.456Z"))); - assertThat(defn.getDefaultValues()[0].getLong(), is(1269237723456L)); + assertThat(defn.getDefaultValues()[0].getLong(), is(1269219723456L)); + } + + @Test + public void shouldAllowConversionOfDefaultValueFromDateBeforeUtcToCompatibleTypes() throws Exception { + defaultValues.add("2010-03-22T01:02:03.456+08:00"); // 8 hours ahead of UTC + requiredType = PropertyType.DATE; + defn = createPropertyDefinition(); + assertThat(defn.getDefaultValues()[0].getString(), is("2010-03-22T01:02:03.456+08:00")); + assertThat(defn.getDefaultValues()[0].getDate(), is(dateFrom("2010-03-22T01:02:03.456+08:00"))); + assertThat(defn.getDefaultValues()[0].getLong(), is(1269190923456L)); + // Verify that the supplied time in millis is 8 hours ahead of the same time in UTC millis ... + assertThat(TimeUnit.HOURS.convert(1269219723456L - 1269190923456L, TimeUnit.MILLISECONDS), is(8L)); + } + + @Test + public void shouldAllowConversionOfDefaultValueFromDateAfterUtcToCompatibleTypes() throws Exception { + defaultValues.add("2010-03-22T01:02:03.456-08:00"); // 8 hours after of UTC + requiredType = PropertyType.DATE; + defn = createPropertyDefinition(); + assertThat(defn.getDefaultValues()[0].getString(), is("2010-03-22T01:02:03.456-08:00")); + assertThat(defn.getDefaultValues()[0].getDate(), is(dateFrom("2010-03-22T01:02:03.456-08:00"))); + assertThat(defn.getDefaultValues()[0].getLong(), is(1269248523456L)); + // Verify that the supplied time in millis is 8 hours behind the same time in UTC millis ... + assertThat(TimeUnit.HOURS.convert(1269219723456L - 1269248523456L, TimeUnit.MILLISECONDS), is(-8L)); } @SuppressWarnings( "deprecation" ) @@ -201,25 +225,32 @@ public class PropertyDefinitionTest { defn.getDefaultValues()[0].getBoolean(); } - @Test( expected = ValueFormatException.class ) - public void shouldFailToConvertDefaultValueFromDoubleToDate() throws Exception { + @Test + public void shouldConvertDefaultValueFromDoubleToDate() throws Exception { defaultValues.add("8"); requiredType = PropertyType.DOUBLE; defn = createPropertyDefinition(); defn.getDefaultValues()[0].getDate(); } + @Test( expected = ValueFormatException.class ) + public void shouldConvertDefaultValueFromNameToDate() throws Exception { + defaultValues.add("jcr:name"); + requiredType = PropertyType.NAME; + defn = createPropertyDefinition(); + defn.getDefaultValues()[0].getDate(); + } + @Test - public void shouldParseDate() throws ParseException { + public void shouldParseDate() { PropertyDefinition.parseDate("2010-03-22T01:02:03.456-0800"); PropertyDefinition.parseDate("2010-03-22T01:02:03.456-08:00"); PropertyDefinition.parseDate("2010-03-22T01:02:03.456+0800"); PropertyDefinition.parseDate("2010-03-22T01:02:03.456+08:00"); PropertyDefinition.parseDate("2010-03-22T01:02:03.456Z"); - PropertyDefinition.parseDate("2010-03-22T01:02:03.456UTC"); } - protected Calendar dateFrom( String dateStr ) throws ParseException { + protected Calendar dateFrom( String dateStr ) { return PropertyDefinition.parseDate(dateStr); }