You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2006/11/24 20:59:45 UTC
svn commit: r478969 - in
/jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value:
DateValue.java StringValue.java
Author: jukka
Date: Fri Nov 24 11:59:44 2006
New Revision: 478969
URL: http://svn.apache.org/viewvc?view=rev&rev=478969
Log:
1.1: Merged revision 467992 (JCR-606)
Modified:
jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/DateValue.java
jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/StringValue.java
Modified: jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/DateValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/DateValue.java?view=diff&rev=478969&r1=478968&r2=478969
==============================================================================
--- jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/DateValue.java (original)
+++ jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/DateValue.java Fri Nov 24 11:59:44 2006
@@ -17,10 +17,10 @@
package org.apache.jackrabbit.rmi.value;
import java.io.Serializable;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
+import java.text.DecimalFormat;
import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
import javax.jcr.PropertyType;
import javax.jcr.ValueFormatException;
@@ -29,12 +29,6 @@
* The <code>DateValue</code> class implements the committed value state for
* Date values as a part of the State design pattern (Gof) used by this
* package.
- * <p>
- * To convert <code>Calendar</code> instances to and from strings, this class
- * uses a <code>SimpleDateFormat</code> instance with the pattern
- * <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code>. The issue with this pattern is that
- * the era specification as defined in the JCR specification (+/- prefix) as
- * well as full time zone naming are not supported.
*
* @since 0.16.4.1
* @see org.apache.jackrabbit.rmi.value.SerialValue
@@ -49,52 +43,28 @@
private final Calendar value;
/**
- * This should probably actually be a reference to the ISO8601 utility
- * class.
- */
- private static final DateFormat DATE_FORMAT =
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-
- /**
* Creates an instance for the given <code>Calendar</code> <code>value</code>.
+ *
+ * @param value the calendar for this value.
*/
protected DateValue(Calendar value) {
this.value = value;
}
/**
- * Creates an instance for the given string representation of a
- * <code>Calendar</code>.
- * <p>
- * This implementation uses a <code>SimpleDateFormat</code> instance with
- * the pattern <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code> to parse the string into
- * a <code>Calendar</code> object. See the class comment for issues regarding
- * this pattern.
+ * Creates a new <code>DateValue</code> initialized to the value
+ * represented by the specified <code>String</code>.
+ * <p/>
+ * The specified <code>String</code> must be a ISO8601-compliant date/time
+ * string.
+ *
+ * @param value the string to be parsed.
+ * @throws javax.jcr.ValueFormatException If the <code>String</code> is not a valid
+ * ISO8601-compliant date/time string.
+ * @see ISO8601
*/
protected DateValue(String value) throws ValueFormatException {
- this(toCalendar(value));
- }
-
- /**
- * Returns the string <code>value</code> parsed into a
- * <code>Calendar</code> instance.
- *
- * @param value The string value.
- * @return The <code>Calendar</code> instance parsed from the string
- * value.
- * @throws ValueFormatException if the string value cannot be parsed into a
- * <code>Calendar</code> instance.
- */
- protected static Calendar toCalendar(String value) throws ValueFormatException {
- synchronized (DATE_FORMAT) {
- try {
- Calendar time = Calendar.getInstance();
- time.setTime(DATE_FORMAT.parse(value));
- return time;
- } catch (ParseException pe) {
- throw new ValueFormatException(pe.getMessage());
- }
- }
+ this(ISO8601.parse(value));
}
/**
@@ -113,15 +83,11 @@
}
/**
- * Returns the string represented of this <code>Calendar</code> value
- * formatted using a <code>SimpleDateFormatter</code> with the pattern
- * <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code>. See the class comment for issues
- * regarding this pattern.
+ * Returns the string represented of this <code>DateValue</code> value
+ * formatted using a ISO8601-compliant date/time.
*/
public String getString() {
- synchronized (DATE_FORMAT) {
- return DATE_FORMAT.format(value.getTime());
- }
+ return ISO8601.format(value);
}
/**
@@ -141,3 +107,260 @@
return (Calendar) value.clone();
}
}
+
+/**
+ * Note: this class was copied from <code>org.apache.jackrabbit.util.ISO8601</code>
+ * for now we try to avoid dependencies on other libs can jcr.
+ *
+ * The <code>ISO8601</code> utility class provides helper methods
+ * to deal with date/time formatting using a specific ISO8601-compliant
+ * format (see <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a>).
+ * <p/>
+ * The currently supported format is:
+ * <pre>
+ * ±YYYY-MM-DDThh:mm:ss.SSSTZD
+ * </pre>
+ * where:
+ * <pre>
+ * ±YYYY = four-digit year with optional sign where values <= 0 are
+ * denoting years BCE and values > 0 are denoting years CE,
+ * e.g. -0001 denotes the year 2 BCE, 0000 denotes the year 1 BCE,
+ * 0001 denotes the year 1 CE, and so on...
+ * MM = two-digit month (01=January, etc.)
+ * DD = two-digit day of month (01 through 31)
+ * hh = two digits of hour (00 through 23) (am/pm NOT allowed)
+ * mm = two digits of minute (00 through 59)
+ * ss = two digits of second (00 through 59)
+ * SSS = three digits of milliseconds (000 through 999)
+ * TZD = time zone designator, Z for Zulu (i.e. UTC) or an offset from UTC
+ * in the form of +hh:mm or -hh:mm
+ * </pre>
+ */
+final class ISO8601 {
+ /**
+ * misc. numeric formats used in formatting
+ */
+ private static final DecimalFormat XX_FORMAT = new DecimalFormat("00");
+ private static final DecimalFormat XXX_FORMAT = new DecimalFormat("000");
+ private static final DecimalFormat XXXX_FORMAT = new DecimalFormat("0000");
+
+ /**
+ * Parses an ISO8601-compliant date/time string.
+ *
+ * @param text the date/time string to be parsed
+ * @return a <code>Calendar</code>, or <code>null</code> if the input could
+ * not be parsed
+ * @throws IllegalArgumentException if a <code>null</code> argument is passed
+ */
+ public static Calendar parse(String text) {
+ if (text == null) {
+ throw new IllegalArgumentException("argument can not be null");
+ }
+
+ // check optional leading sign
+ char sign;
+ int start;
+ if (text.startsWith("-")) {
+ sign = '-';
+ start = 1;
+ } else if (text.startsWith("+")) {
+ sign = '+';
+ start = 1;
+ } else {
+ sign = '+'; // no sign specified, implied '+'
+ start = 0;
+ }
+
+ /**
+ * the expected format of the remainder of the string is:
+ * YYYY-MM-DDThh:mm:ss.SSSTZD
+ *
+ * note that we cannot use java.text.SimpleDateFormat for
+ * parsing because it can't handle years <= 0 and TZD's
+ */
+
+ int year, month, day, hour, min, sec, ms;
+ String tzID;
+ try {
+ // year (YYYY)
+ year = Integer.parseInt(text.substring(start, start + 4));
+ start += 4;
+ // delimiter '-'
+ if (text.charAt(start) != '-') {
+ return null;
+ }
+ start++;
+ // month (MM)
+ month = Integer.parseInt(text.substring(start, start + 2));
+ start += 2;
+ // delimiter '-'
+ if (text.charAt(start) != '-') {
+ return null;
+ }
+ start++;
+ // day (DD)
+ day = Integer.parseInt(text.substring(start, start + 2));
+ start += 2;
+ // delimiter 'T'
+ if (text.charAt(start) != 'T') {
+ return null;
+ }
+ start++;
+ // hour (hh)
+ hour = Integer.parseInt(text.substring(start, start + 2));
+ start += 2;
+ // delimiter ':'
+ if (text.charAt(start) != ':') {
+ return null;
+ }
+ start++;
+ // minute (mm)
+ min = Integer.parseInt(text.substring(start, start + 2));
+ start += 2;
+ // delimiter ':'
+ if (text.charAt(start) != ':') {
+ return null;
+ }
+ start++;
+ // second (ss)
+ sec = Integer.parseInt(text.substring(start, start + 2));
+ start += 2;
+ // delimiter '.'
+ if (text.charAt(start) != '.') {
+ return null;
+ }
+ start++;
+ // millisecond (SSS)
+ ms = Integer.parseInt(text.substring(start, start + 3));
+ start += 3;
+ // time zone designator (Z or +00:00 or -00:00)
+ if (text.charAt(start) == '+' || text.charAt(start) == '-') {
+ // offset to UTC specified in the format +00:00/-00:00
+ tzID = "GMT" + text.substring(start);
+ } else if (text.substring(start).equals("Z")) {
+ tzID = "GMT";
+ } else {
+ // invalid time zone designator
+ return null;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ } catch (NumberFormatException e) {
+ return null;
+ }
+
+ TimeZone tz = TimeZone.getTimeZone(tzID);
+ // verify id of returned time zone (getTimeZone defaults to "GMT")
+ if (!tz.getID().equals(tzID)) {
+ // invalid time zone
+ return null;
+ }
+
+ // initialize Calendar object
+ Calendar cal = Calendar.getInstance(tz);
+ cal.setLenient(false);
+ // year and era
+ if (sign == '-' || year == 0) {
+ // not CE, need to set era (BCE) and adjust year
+ cal.set(Calendar.YEAR, year + 1);
+ cal.set(Calendar.ERA, GregorianCalendar.BC);
+ } else {
+ cal.set(Calendar.YEAR, year);
+ cal.set(Calendar.ERA, GregorianCalendar.AD);
+ }
+ // month (0-based!)
+ cal.set(Calendar.MONTH, month - 1);
+ // day of month
+ cal.set(Calendar.DAY_OF_MONTH, day);
+ // hour
+ cal.set(Calendar.HOUR_OF_DAY, hour);
+ // minute
+ cal.set(Calendar.MINUTE, min);
+ // second
+ cal.set(Calendar.SECOND, sec);
+ // millisecond
+ cal.set(Calendar.MILLISECOND, ms);
+
+ try {
+ /**
+ * the following call will trigger an IllegalArgumentException
+ * if any of the set values are illegal or out of range
+ */
+ cal.getTime();
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ return cal;
+ }
+
+ /**
+ * Formats a <code>Calendar</code> value into an ISO8601-compliant
+ * date/time string.
+ *
+ * @param cal the time value to be formatted into a date/time string.
+ * @return the formatted date/time string.
+ * @throws IllegalArgumentException if a <code>null</code> argument is passed
+ */
+ public static String format(Calendar cal) {
+ if (cal == null) {
+ throw new IllegalArgumentException("argument can not be null");
+ }
+
+ // determine era and adjust year if necessary
+ int year = cal.get(Calendar.YEAR);
+ if (cal.isSet(Calendar.ERA)
+ && cal.get(Calendar.ERA) == GregorianCalendar.BC) {
+ /**
+ * calculate year using astronomical system:
+ * year n BCE => astronomical year -n + 1
+ */
+ year = 0 - year + 1;
+ }
+
+ /**
+ * the format of the date/time string is:
+ * YYYY-MM-DDThh:mm:ss.SSSTZD
+ *
+ * note that we cannot use java.text.SimpleDateFormat for
+ * formatting because it can't handle years <= 0 and TZD's
+ */
+ StringBuffer buf = new StringBuffer();
+ // year ([-]YYYY)
+ buf.append(XXXX_FORMAT.format(year));
+ buf.append('-');
+ // month (MM)
+ buf.append(XX_FORMAT.format(cal.get(Calendar.MONTH) + 1));
+ buf.append('-');
+ // day (DD)
+ buf.append(XX_FORMAT.format(cal.get(Calendar.DAY_OF_MONTH)));
+ buf.append('T');
+ // hour (hh)
+ buf.append(XX_FORMAT.format(cal.get(Calendar.HOUR_OF_DAY)));
+ buf.append(':');
+ // minute (mm)
+ buf.append(XX_FORMAT.format(cal.get(Calendar.MINUTE)));
+ buf.append(':');
+ // second (ss)
+ buf.append(XX_FORMAT.format(cal.get(Calendar.SECOND)));
+ buf.append('.');
+ // millisecond (SSS)
+ buf.append(XXX_FORMAT.format(cal.get(Calendar.MILLISECOND)));
+ // time zone designator (Z or +00:00 or -00:00)
+ TimeZone tz = cal.getTimeZone();
+ // determine offset of timezone from UTC (incl. daylight saving)
+ int offset = tz.getOffset(cal.getTimeInMillis());
+ if (offset != 0) {
+ int hours = Math.abs((offset / (60 * 1000)) / 60);
+ int minutes = Math.abs((offset / (60 * 1000)) % 60);
+ buf.append(offset < 0 ? '-' : '+');
+ buf.append(XX_FORMAT.format(hours));
+ buf.append(':');
+ buf.append(XX_FORMAT.format(minutes));
+ } else {
+ buf.append('Z');
+ }
+ return buf.toString();
+ }
+}
+
Modified: jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/StringValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/StringValue.java?view=diff&rev=478969&r1=478968&r2=478969
==============================================================================
--- jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/StringValue.java (original)
+++ jackrabbit/branches/1.1/jcr-rmi/src/java/org/apache/jackrabbit/rmi/value/StringValue.java Fri Nov 24 11:59:44 2006
@@ -89,7 +89,7 @@
* <code>Calendar</code> instance.
*/
public Calendar getDate() throws ValueFormatException {
- return DateValue.toCalendar(value);
+ return ISO8601.parse(value);
}
/**