Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java (revision 746932) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java (working copy) @@ -517,7 +517,11 @@ public void setValue(Calendar value) throws RepositoryException { if (value != null) { - setValue(session.getValueFactory().createValue(value)); + try { + setValue(session.getValueFactory().createValue(value)); + } catch (IllegalArgumentException e) { + throw new ValueFormatException(e.getMessage()); + } } else { remove(); } Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DateField.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DateField.java (revision 746932) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DateField.java (working copy) @@ -74,6 +74,8 @@ /** * Converts a millisecond time to a string suitable for indexing. * Supported date range is: 30 BC - 3189 + * @throws IllegalArgumentException if the given time is not + * within the supported date range. */ public static String timeToString(long time) { @@ -81,13 +83,13 @@ if (time < 0) { - throw new RuntimeException("time too early"); + throw new IllegalArgumentException("time too early"); } String s = Long.toString(time, Character.MAX_RADIX); if (s.length() > DATE_LEN) { - throw new RuntimeException("time too late"); + throw new IllegalArgumentException("time too late"); } // Pad with leading zeros Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (revision 746932) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (working copy) @@ -49,6 +49,7 @@ import java.util.Set; import java.util.List; import java.util.ArrayList; +import java.util.Date; /** * Creates a lucene Document object from a {@link javax.jcr.Node}. @@ -505,8 +506,13 @@ protected void addCalendarValue(Document doc, String fieldName, Object internalValue) { Calendar value = (Calendar) internalValue; long millis = value.getTimeInMillis(); - doc.add(createFieldWithoutNorms(fieldName, DateField.timeToString(millis), - PropertyType.DATE)); + try { + doc.add(createFieldWithoutNorms(fieldName, DateField.timeToString(millis), + PropertyType.DATE)); + } catch (IllegalArgumentException e) { + log.warn("'{}' is outside of supported date value range.", + new Date(value.getTimeInMillis())); + } } /** Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/InvalidDateTest.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/InvalidDateTest.java (revision 0) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/InvalidDateTest.java (revision 0) @@ -0,0 +1,59 @@ +/* + * 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.jackrabbit.core; + +import java.util.Calendar; + +import javax.jcr.RepositoryException; +import javax.jcr.Node; +import javax.jcr.ValueFormatException; +import javax.jcr.PropertyType; + +import org.apache.jackrabbit.test.AbstractJCRTest; + +/** + * InvalidDateTest contains tests for JCR-1996. + */ +public class InvalidDateTest extends AbstractJCRTest { + + public void testDateRange() throws RepositoryException { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.YEAR, 20000); + Node n = testRootNode.addNode(nodeName1); + try { + superuser.getValueFactory().createValue(cal); + fail("must throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + try { + n.setProperty(propertyName1, cal); + fail("must throw ValueFormatException"); + } catch (ValueFormatException e) { + // expected + } + String calString = superuser.getValueFactory().createValue( + Calendar.getInstance()).getString(); + calString = "1" + calString; + try { + n.setProperty(propertyName1, calString, PropertyType.DATE); + fail("must throw ValueFormatException"); + } catch (ValueFormatException e) { + // expected + } + } +} Property changes on: jackrabbit-core\src\test\java\org\apache\jackrabbit\core\InvalidDateTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java (revision 746932) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java (working copy) @@ -39,6 +39,7 @@ suite.addTestSuite(RestoreAndCheckoutTest.class); suite.addTestSuite(NodeImplTest.class); suite.addTestSuite(RetentionRegistryImplTest.class); + suite.addTestSuite(InvalidDateTest.class); return suite; } Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java =================================================================== --- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java (revision 746932) +++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java (working copy) @@ -211,23 +211,14 @@ * @param cal the time value to be formatted into a date/time string. * @return the formatted date/time string. * @throws IllegalArgumentException if a null argument is passed + * or the calendar cannot be represented as defined by ISO 8601 (i.e. year + * with more than four digits). */ - public static String format(Calendar cal) { + public static String format(Calendar cal) throws IllegalArgumentException { 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 @@ -237,7 +228,7 @@ */ StringBuffer buf = new StringBuffer(); // year ([-]YYYY) - buf.append(XXXX_FORMAT.format(year)); + buf.append(XXXX_FORMAT.format(getYear(cal))); buf.append('-'); // month (MM) buf.append(XX_FORMAT.format(cal.get(Calendar.MONTH) + 1)); @@ -272,4 +263,32 @@ } return buf.toString(); } + + /** + * Returns the astonomical year of the given calendar. + * + * @param cal a calendar instance. + * @return the astronomical year. + * @throws IllegalArgumentException if calendar cannot be represented as + * defined by ISO 8601 (i.e. year with more + * than four digits). + */ + public static int getYear(Calendar cal) throws IllegalArgumentException { + // 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; + } + + if (year > 9999 || year < -9999) { + throw new IllegalArgumentException("Calendar has more than four " + + "year digits, cannot be formatted as ISO8601: " + year); + } + return year; + } } Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java =================================================================== --- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java (revision 746932) +++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java (working copy) @@ -37,10 +37,13 @@ * Constructs a DateValue object representing a date. * * @param date the date this DateValue should represent + * @throws IllegalArgumentException if the given date cannot be represented + * as defined by ISO 8601. */ - public DateValue(Calendar date) { + public DateValue(Calendar date) throws IllegalArgumentException { super(TYPE); this.date = date; + ISO8601.getYear(date); } /**