You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2010/03/17 01:34:38 UTC

svn commit: r924074 [5/6] - in /wicket/trunk: testing/wicket-threadtest/src/main/java/org/apache/wicket/threadtest/ wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/ wicket-guice/src/test/java/org/apac...

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Duration.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Duration.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Duration.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Duration.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,552 @@
+/*
+ * 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.wicket.util.time;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.wicket.util.string.StringValue;
+import org.apache.wicket.util.string.StringValueConversionException;
+import org.apache.wicket.util.thread.ICode;
+import org.slf4j.Logger;
+
+
+/**
+ * A <code>Duration</code> is an immutable length of time stored as a number of milliseconds.
+ * Various factory and conversion methods are available for convenience.
+ * <p>
+ * These static factory methods allow easy construction of value objects using either long values
+ * like <code>seconds(2034)</code> or <code>hours(3)</code>:
+ * <p>
+ * <ul>
+ * <li><code>Duration.milliseconds(long)</code>
+ * <li><code>Duration.seconds(int)</code>
+ * <li><code>Duration.minutes(int)</code>
+ * <li><code>Duration.hours(int)</code>
+ * <li><code>Duration.days(int)</code>
+ * </ul>
+ * <p>
+ * ...or double-precision floating point values like <code>days(3.2)</code>:
+ * <p>
+ * <ul>
+ * <li><code>Duration.milliseconds(double)</code>
+ * <li><code>Duration.seconds(double)</code>
+ * <li><code>Duration.minutes(double)</code>
+ * <li><code>Duration.hours(double)</code>
+ * <li><code>Duration.days(double)</code>
+ * </ul>
+ * <p>
+ * In the case of <code>milliseconds(double)</code>, the value will be rounded off to the nearest
+ * integral millisecond using <code>Math.round()</code>.
+ * <p>
+ * The precise number of milliseconds represented by a <code>Duration</code> object can be retrieved
+ * by calling the <code>getMilliseconds</code> method. The value of a <code>Duration</code> object
+ * in a given unit like days or hours can be retrieved by calling one of the following unit methods,
+ * each of which returns a double-precision floating point number:
+ * <p>
+ * <ul>
+ * <li><code>seconds()</code>
+ * <li><code>minutes()</code>
+ * <li><code>hours()</code>
+ * <li><code>days()</code>
+ * </ul>
+ * <p>
+ * Values can be added and subtracted using the <code>add(Duration)</code> and
+ * <code>subtract(Duration)</code> methods, each of which returns a new immutable
+ * <code>Duration</code> object.
+ * <p>
+ * <code>String</code> values can be converted to <code>Duration</code> objects using the static
+ * <code>valueOf</code> factory methods. The <code>String</code> format is the opposite of the one
+ * created by <code>toString()</code>, which converts a <code>Duration</code> object to a readable
+ * form, such as "3.2 hours" or "32.5 minutes". Valid units are: milliseconds, seconds, minutes
+ * hours and days. Correct English plural forms are used in creating <code>String</code> values and
+ * are parsed as well. The <code>Locale</code> is respected and "," will be used instead of "." in
+ * the Eurozone.
+ * <p>
+ * The benchmark method will "benchmark" a <code>Runnable</code> or an {@link ICode} implementing
+ * object, returning a <code>Duration</code> object that represents the amount of time elapsed in
+ * running the code.
+ * <p>
+ * Finally, the <code>sleep</code> method will sleep for the value of a <code>Duration</code>.
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public class Duration extends AbstractTimeValue
+{
+	private static final long serialVersionUID = 1L;
+
+	/** Constant for maximum duration. */
+	public static final Duration MAXIMUM = milliseconds(Long.MAX_VALUE);
+
+	/** Constant for no duration. */
+	public static final Duration NONE = milliseconds(0);
+
+	/** Constant for one day. */
+	public static final Duration ONE_DAY = days(1);
+
+	/** Constant for one hour. */
+	public static final Duration ONE_HOUR = hours(1);
+
+	/** Constant for on minute. */
+	public static final Duration ONE_MINUTE = minutes(1);
+
+	/** Constant for one second. */
+	public static final Duration ONE_SECOND = seconds(1);
+
+	/** Constant for one week. */
+	public static final Duration ONE_WEEK = days(7);
+
+	/** pattern to match strings */
+	private static final Pattern pattern = Pattern.compile(
+		"([0-9]+([.,][0-9]+)?)\\s+(millisecond|second|minute|hour|day)s?", Pattern.CASE_INSENSITIVE);
+
+	/**
+	 * Benchmark the given command.
+	 * 
+	 * @param code
+	 *            an <code>ICode</code>
+	 * @param log
+	 *            optional logger to use with errors and exceptions
+	 * @return the <code>Time</code> value it took to run the code
+	 */
+	public static Duration benchmark(final ICode code, final Logger log)
+	{
+		// Get time before running code
+		final Time start = Time.now();
+
+		// Run the code
+		code.run(log);
+
+		// Return the difference
+		return Time.now().subtract(start);
+	}
+
+	/**
+	 * Benchmark the given command.
+	 * 
+	 * @param code
+	 *            a <code>Runnable</code>
+	 * @return the <code>Time</code> value it took to run the code
+	 */
+	public static Duration benchmark(final Runnable code)
+	{
+		// Get time before running code
+		final Time start = Time.now();
+
+		// Run code
+		code.run();
+
+		// Return the difference
+		return Time.now().subtract(start);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on days.
+	 * 
+	 * @param days
+	 *            days <code>double</code> value
+	 * @return the <code>Duration</code> based on days
+	 */
+	public static Duration days(final double days)
+	{
+		return hours(24.0 * days);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on days.
+	 * 
+	 * @param days
+	 *            days <code>int</code> value
+	 * @return the <code>Duration</code> based on days
+	 */
+	public static Duration days(final int days)
+	{
+		return hours(24 * days);
+	}
+
+	/**
+	 * Calculates the amount of time elapsed since start time.
+	 * 
+	 * @param start
+	 *            the start <code>Time</code>
+	 * @return the elapsed period as a <code>Duration</code>
+	 * @throws IllegalStateException
+	 *             if start <code>Time</code> is in the future
+	 */
+	public static Duration elapsed(final Time start)
+	{
+		return start.elapsedSince();
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on hours.
+	 * 
+	 * @param hours
+	 *            hours <code>double</code> value
+	 * @return the <code>Duration</code> based on hours
+	 */
+	public static Duration hours(final double hours)
+	{
+		return minutes(60.0 * hours);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on hours.
+	 * 
+	 * @param hours
+	 *            hours <code>int</code> value
+	 * @return the <code>Duration</code> based on hours
+	 */
+	public static Duration hours(final int hours)
+	{
+		return minutes(60 * hours);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on milliseconds.
+	 * 
+	 * @param milliseconds
+	 *            milliseconds <code>double</code> value
+	 * @return the <code>Duration</code> based on milliseconds
+	 */
+	public static Duration milliseconds(final double milliseconds)
+	{
+		return milliseconds(Math.round(milliseconds));
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on milliseconds.
+	 * 
+	 * @param milliseconds
+	 *            milliseconds <code>long</code> value
+	 * @return the <code>Duration</code> based on milliseconds
+	 */
+	public static Duration milliseconds(final long milliseconds)
+	{
+		return new Duration(milliseconds);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on minutes.
+	 * 
+	 * @param minutes
+	 *            minutes <code>double</code> value
+	 * @return the <code>Duration</code> based on minutes
+	 */
+	public static Duration minutes(final double minutes)
+	{
+		return seconds(60.0 * minutes);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on minutes.
+	 * 
+	 * @param minutes
+	 *            minutes <code>int</code> value
+	 * @return the <code>Duration</code> based on minutes
+	 */
+	public static Duration minutes(final int minutes)
+	{
+		return seconds(60 * minutes);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on seconds.
+	 * 
+	 * @param seconds
+	 *            seconds <code>double</code> value
+	 * @return the <code>Duration</code> based on seconds
+	 */
+	public static Duration seconds(final double seconds)
+	{
+		return milliseconds(seconds * 1000.0);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> based on seconds.
+	 * 
+	 * @param seconds
+	 *            seconds <code>int</code> value
+	 * @return the <code>Duration</code> based on seconds
+	 */
+	public static Duration seconds(final int seconds)
+	{
+		return milliseconds(seconds * 1000L);
+	}
+
+	/**
+	 * Retrieves the given <code>long</code> as a <code>Duration</code>.
+	 * 
+	 * @param time
+	 *            the duration <code>long</code> value in milliseconds
+	 * @return the <code>Duration</code> value
+	 */
+	public static Duration valueOf(final long time)
+	{
+		return new Duration(time);
+	}
+
+	/**
+	 * Converts the given <code>String</code> to a new <code>Duration</code> object. The string can
+	 * take the form of a floating point number followed by a number of milliseconds, seconds,
+	 * minutes, hours or days. For example "6 hours" or "3.4 days". Parsing is case-insensitive.
+	 * 
+	 * @param string
+	 *            a <code>String</code> to parse
+	 * @return the <code>Duration</code> value of the given <code>String</code>
+	 * @throws StringValueConversionException
+	 */
+	public static Duration valueOf(final String string) throws StringValueConversionException
+	{
+		return valueOf(string, Locale.getDefault());
+	}
+
+	/**
+	 * Converts the given <code>String</code> to a new <code>Duration</code> object. The string can
+	 * take the form of a floating point number followed by a number of milliseconds, seconds,
+	 * minutes, hours or days. For example "6 hours" or "3.4 days". Parsing is case-insensitive.
+	 * 
+	 * @param string
+	 *            a <code>String</code> to parse
+	 * @param locale
+	 *            the <code>Locale</code> used for parsing
+	 * @return the <code>Duration</code> value of the given <code>String</code>
+	 * @throws StringValueConversionException
+	 */
+	public static Duration valueOf(final String string, final Locale locale)
+		throws StringValueConversionException
+	{
+		final Matcher matcher = pattern.matcher(string);
+
+		if (matcher.matches())
+		{
+			final double value = StringValue.valueOf(matcher.group(1), locale).toDouble();
+			final String units = matcher.group(3);
+
+			if (units.equalsIgnoreCase("millisecond"))
+			{
+				return milliseconds(value);
+			}
+			else if (units.equalsIgnoreCase("second"))
+			{
+				return seconds(value);
+			}
+			else if (units.equalsIgnoreCase("minute"))
+			{
+				return minutes(value);
+			}
+			else if (units.equalsIgnoreCase("hour"))
+			{
+				return hours(value);
+			}
+			else if (units.equalsIgnoreCase("day"))
+			{
+				return days(value);
+			}
+			else
+			{
+				throw new StringValueConversionException("Unrecognized units: " + string);
+			}
+		}
+		else
+		{
+			throw new StringValueConversionException("Unable to parse duration: " + string);
+		}
+	}
+
+	/**
+	 * Private constructor forces use of static factory methods.
+	 * 
+	 * @param milliseconds
+	 *            number of milliseconds in this <code>Duration</code>
+	 */
+	protected Duration(final long milliseconds)
+	{
+		super(milliseconds);
+	}
+
+	/**
+	 * Adds a given <code>Duration</code> to this <code>Duration</code>.
+	 * 
+	 * @param duration
+	 *            the <code>Duration</code> to add
+	 * @return the sum of the <code>Duration</code>s
+	 */
+	public Duration add(final Duration duration)
+	{
+		return valueOf(getMilliseconds() + duration.getMilliseconds());
+	}
+
+	/**
+	 * Retrieves the number of days of the current <code>Duration</code>.
+	 * 
+	 * @return number of days of the current <code>Duration</code>
+	 */
+	public final double days()
+	{
+		return hours() / 24.0;
+	}
+
+	/**
+	 * Retrieves the number of hours of the current <code>Duration</code>.
+	 * 
+	 * @return number of hours of the current <code>Duration</code>
+	 */
+	public final double hours()
+	{
+		return minutes() / 60.0;
+	}
+
+	/**
+	 * Retrieves the number of minutes of the current <code>Duration</code>.
+	 * 
+	 * @return number of minutes of the current <code>Duration</code>
+	 */
+	public final double minutes()
+	{
+		return seconds() / 60.0;
+	}
+
+	/**
+	 * Retrieves the number of seconds of the current <code>Duration</code>.
+	 * 
+	 * @return number of seconds of the current <code>Duration</code>
+	 */
+	public final double seconds()
+	{
+		return getMilliseconds() / 1000.0;
+	}
+
+	/**
+	 * Sleeps for the current <code>Duration</code>.
+	 */
+	public final void sleep()
+	{
+		if (getMilliseconds() > 0)
+		{
+			try
+			{
+				Thread.sleep(getMilliseconds());
+			}
+			catch (InterruptedException e)
+			{
+				// Ignored
+			}
+		}
+	}
+
+	/**
+	 * Subtracts a given <code>Duration</code> from this <code>Duration</code>.
+	 * 
+	 * @param that
+	 *            the <code>Duration</code> to subtract
+	 * @return this <code>Duration</code> minus that <code>Duration</code>
+	 */
+	public Duration subtract(final Duration that)
+	{
+		return valueOf(getMilliseconds() - that.getMilliseconds());
+	}
+
+	/**
+	 * Wait for this duration on the given monitor
+	 * 
+	 * @param object
+	 *            The monitor to wait on
+	 */
+	public void wait(Object object)
+	{
+		try
+		{
+			object.wait(getMilliseconds());
+		}
+		catch (InterruptedException e)
+		{
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * Retrieves the <code>String</code> representation of this <code>Duration</code> in days,
+	 * hours, minutes, seconds or milliseconds, as appropriate. Uses the default <code>Locale</code>
+	 * .
+	 * 
+	 * @return a <code>String</code> representation
+	 */
+	@Override
+	public String toString()
+	{
+		return toString(Locale.getDefault());
+	}
+
+	/**
+	 * Retrieves the <code>String</code> representation of this <code>Duration</code> in days,
+	 * hours, minutes, seconds or milliseconds, as appropriate.
+	 * 
+	 * @param locale
+	 *            a <code>Locale</code>
+	 * @return a <code>String</code> representation
+	 */
+	public String toString(final Locale locale)
+	{
+		if (getMilliseconds() >= 0)
+		{
+			if (days() >= 1.0)
+			{
+				return unitString(days(), "day", locale);
+			}
+
+			if (hours() >= 1.0)
+			{
+				return unitString(hours(), "hour", locale);
+			}
+
+			if (minutes() >= 1.0)
+			{
+				return unitString(minutes(), "minute", locale);
+			}
+
+			if (seconds() >= 1.0)
+			{
+				return unitString(seconds(), "second", locale);
+			}
+
+			return getMilliseconds() + " milliseconds";
+		}
+		else
+		{
+			return "N/A";
+		}
+	}
+
+	/**
+	 * Converts a value to a unit-suffixed value, taking care of English singular/plural suffix.
+	 * 
+	 * @param value
+	 *            a <code>double</code> value to format
+	 * @param units
+	 *            the units to apply singular or plural suffix to
+	 * @param locale
+	 *            the <code>Locale</code>
+	 * @return a <code>String</code> representation
+	 */
+	private String unitString(final double value, final String units, final Locale locale)
+	{
+		return StringValue.valueOf(value, locale) + " " + units + ((value > 1.0) ? "s" : "");
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Duration.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/ITimeFrameSource.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/ITimeFrameSource.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/ITimeFrameSource.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/ITimeFrameSource.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,38 @@
+/*
+ * 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.wicket.util.time;
+
+import java.io.Serializable;
+
+/**
+ * An <code>ITimeFrameSource</code> produces <code>TimeFrame</code> values. The value returned by an
+ * <code>ITimeFrameSource</code> source may vary over time.
+ * 
+ * @see TimeFrame
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public interface ITimeFrameSource extends Serializable
+{
+	/**
+	 * Retrieves the current <code>TimeFrame</code> value.
+	 * 
+	 * @return the current <code>TimeFrame</code> value
+	 */
+	TimeFrame getTimeFrame();
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/ITimeFrameSource.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Time.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Time.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Time.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Time.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,549 @@
+/*
+ * 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.wicket.util.time;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * An immutable <code>Time</code> class that represents a specific point in time. The underlying
+ * representation is a <code>long</code> value which holds a number of milliseconds since January 1,
+ * 1970, 0:00 GMT. To represent a duration of time, such as "6 seconds", use the
+ * <code>Duration</code> class. To represent a time period with a start and end time, use the
+ * <code>TimeFrame</code> class. To represent a time of day, use the <code>TimeOfDay</code> class.
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public final class Time extends AbstractTime
+{
+	private static final long serialVersionUID = 1L;
+
+	/** the beginning of UNIX time: January 1, 1970, 0:00 GMT. */
+	public static final Time START_OF_UNIX_TIME = milliseconds(0);
+
+	/** parser in 'yyyy.MM.dd' format. */
+	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
+
+	/** parser in 'yyyy.MM.dd-h.mma' format. */
+	private static final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy.MM.dd-h.mma");
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the given milliseconds.
+	 * 
+	 * @param time
+	 *            the time value in milliseconds since START_OF_UNIX_TIME
+	 * @return the given <code>Time</code>
+	 */
+	public static Time milliseconds(final long time)
+	{
+		return new Time(time);
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the current time.
+	 * 
+	 * @return the current <code>Time</code>
+	 */
+	public static Time now()
+	{
+		return new Time(System.currentTimeMillis());
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd' format.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use when parsing date <code>String</code>
+	 * @param string
+	 *            the <code>String</code> to parse
+	 * @return the time
+	 * @throws ParseException
+	 */
+	public static Time parseDate(final Calendar calendar, final String string)
+		throws ParseException
+	{
+		synchronized (dateFormat)
+		{
+			synchronized (calendar)
+			{
+				dateFormat.setCalendar(calendar);
+
+				return valueOf(dateFormat.parse(string));
+			}
+		}
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd' format using a local time
+	 * <code>Calendar</code>.
+	 * 
+	 * @param string
+	 *            the <code>String</code> to parse
+	 * @return the time
+	 * @throws ParseException
+	 */
+	public static Time parseDate(final String string) throws ParseException
+	{
+		return parseDate(localtime, string);
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd-h.mma' format.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use when parsing the <code>String</code>
+	 * @param string
+	 *            the <code>String</code> to parse
+	 * @return an immutable UNIX <code>Time</code> value
+	 * @throws ParseException
+	 */
+	public static Time valueOf(final Calendar calendar, final String string) throws ParseException
+	{
+		synchronized (dateTimeFormat)
+		{
+			synchronized (calendar)
+			{
+				dateTimeFormat.setCalendar(calendar);
+
+				return valueOf(dateTimeFormat.parse(string));
+			}
+		}
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the given <code>Calendar</code> and
+	 * {@link TimeOfDay} objects.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use
+	 * @param timeOfDay
+	 *            the time of day
+	 * @return a <code>Time</code> value for the time of day today
+	 */
+	public static Time valueOf(final Calendar calendar, final TimeOfDay timeOfDay)
+	{
+		synchronized (calendar)
+		{
+			// Set time to midnight today
+			calendar.setTimeInMillis(System.currentTimeMillis());
+			calendar.set(Calendar.HOUR_OF_DAY, 0); // WICKET-2349
+			calendar.set(Calendar.MINUTE, 0);
+			calendar.set(Calendar.SECOND, 0);
+			calendar.set(Calendar.MILLISECOND, 0); // WICKET-1670
+
+			// Add time of day milliseconds to midnight
+			return valueOf(calendar.getTimeInMillis() + timeOfDay.getMilliseconds());
+		}
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the given <code>Date</code> object.
+	 * 
+	 * @param date
+	 *            a <code>java.util.Date</code> object
+	 * @return a corresponding immutable <code>Time</code> object
+	 */
+	public static Time valueOf(final Date date)
+	{
+		return new Time(date.getTime());
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the given milliseconds.
+	 * 
+	 * @param time
+	 *            the <code>Time</code> value in milliseconds since START_OF_UNIX_TIME
+	 * @return a corresponding immutable <code>Time</code> object
+	 */
+	public static Time valueOf(final long time)
+	{
+		return new Time(time);
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd-h.mma' format.
+	 * 
+	 * @param string
+	 *            the <code>String</code> to parse
+	 * @return the <code>Time</code> instance
+	 * @throws ParseException
+	 */
+	public static Time valueOf(final String string) throws ParseException
+	{
+		return valueOf(localtime, string);
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance by parsing 'pattern' format.
+	 * 
+	 * @param string
+	 *            input
+	 * @param pattern
+	 *            the pattern to parse
+	 * @return a <code>Time</code> instance that resulted from parsing the given <code>String</code>
+	 * @throws ParseException
+	 */
+	public static Time valueOf(final String string, final String pattern) throws ParseException
+	{
+		final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(pattern);
+		dateTimeFormat.setCalendar(localtime);
+		return valueOf(dateTimeFormat.parse(string));
+	}
+
+	/**
+	 * Retrieves a <code>Time</code> instance based on the given {@link TimeOfDay} object.
+	 * 
+	 * @param timeOfDay
+	 *            the time of day in local time
+	 * @return a <code>Time</code> value for the time of day today
+	 */
+	public static Time valueOf(final TimeOfDay timeOfDay)
+	{
+		return valueOf(localtime, timeOfDay);
+	}
+
+	/**
+	 * Private constructor forces use of static factory methods.
+	 * 
+	 * @param time
+	 *            the <code>Time</code> value in milliseconds since START_OF_UNIX_TIME
+	 */
+	private Time(final long time)
+	{
+		super(time);
+	}
+
+	/**
+	 * Adds the given <code>Duration</code> to this <code>Time</code> object, moving the time into
+	 * the future.
+	 * 
+	 * @param duration
+	 *            the <code>Duration</code> to add
+	 * @return this <code>Time</code> + <code>Duration</code>
+	 */
+	public Time add(final Duration duration)
+	{
+		return milliseconds(getMilliseconds() + duration.getMilliseconds());
+	}
+
+	/**
+	 * Calculates the amount of time that has elapsed since this <code>Time</code> value.
+	 * 
+	 * @return the amount of time that has elapsed since this <code>Time</code> value
+	 * @throws IllegalStateException
+	 *             thrown if this <code>Time</code> value is in the future
+	 */
+	public Duration elapsedSince()
+	{
+		final Time now = now();
+		if (this.greaterThan(now))
+		{
+			throw new IllegalStateException("This time is in the future");
+		}
+		return now.subtract(this);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> from now to this <code>Time</code> value. If this
+	 * <code>Time</code> value is in the past, then the <code>Duration</code> returned will be
+	 * negative. Otherwise, it will be the number of milliseconds from now to this <code>Time</code>
+	 * .
+	 * 
+	 * @return the <code>Duration</code> from now to this <code>Time</code> value
+	 */
+	public Duration fromNow()
+	{
+		return subtract(now());
+	}
+
+	/**
+	 * Retrieves the value of a field from the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use
+	 * @param field
+	 *            the <code>Calendar</code> field to get
+	 * @return the field's value for this point in time on the given <code>Calendar</code>
+	 */
+	public int get(final Calendar calendar, final int field)
+	{
+		synchronized (calendar)
+		{
+			calendar.setTimeInMillis(getMilliseconds());
+
+			return calendar.get(field);
+		}
+	}
+
+	/**
+	 * Retrieves the value of a field.
+	 * 
+	 * @param field
+	 *            the <code>Calendar</code> field to get
+	 * @return the field's value (in local time)
+	 */
+	public int get(final int field)
+	{
+		return get(localtime, field);
+	}
+
+	/**
+	 * Retrieves the day of month field of the current <code>Calendar</code>.
+	 * 
+	 * @return the day of month field value
+	 */
+	public int getDayOfMonth()
+	{
+		return getDayOfMonth(localtime);
+	}
+
+	/**
+	 * Retrieves the day of month field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to get the field value from
+	 * @return the day of month field value
+	 */
+	public int getDayOfMonth(final Calendar calendar)
+	{
+		return get(calendar, Calendar.DAY_OF_MONTH);
+	}
+
+	/**
+	 * Retrieves the hour field of the current <code>Calendar</code>.
+	 * 
+	 * @return the hour field value
+	 */
+	public int getHour()
+	{
+		return getHour(localtime);
+	}
+
+	/**
+	 * Retrieves the hour field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to get the field value from
+	 * @return the hour field value
+	 */
+	public int getHour(final Calendar calendar)
+	{
+		return get(calendar, Calendar.HOUR);
+	}
+
+	/**
+	 * Retrieves the minute field of the current <code>Calendar</code>.
+	 * 
+	 * @return the minute field value
+	 */
+	public int getMinute()
+	{
+		return getMinute(localtime);
+	}
+
+	/**
+	 * Retrieves the minute field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> from which to get the field value
+	 * @return the minute field value
+	 */
+	public int getMinute(final Calendar calendar)
+	{
+		return get(calendar, Calendar.MINUTE);
+	}
+
+	/**
+	 * Retrieves the month field of the current <code>Calendar</code>.
+	 * 
+	 * @return the month field value
+	 */
+	public int getMonth()
+	{
+		return getMonth(localtime);
+	}
+
+	/**
+	 * Retrieves the month field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> from which to get the field value
+	 * @return the month field value
+	 */
+	public int getMonth(final Calendar calendar)
+	{
+		return get(calendar, Calendar.MONTH);
+	}
+
+	/**
+	 * Retrieves the seconds field of the current <code>Calendar</code>.
+	 * 
+	 * @return the seconds field value
+	 */
+	public int getSecond()
+	{
+		return getSecond(localtime);
+	}
+
+	/**
+	 * Retrieves the seconds field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> from which to get the field value
+	 * @return the seconds field value
+	 */
+	public int getSecond(final Calendar calendar)
+	{
+		return get(calendar, Calendar.SECOND);
+	}
+
+	/**
+	 * Retrieves the year field of the current <code>Calendar</code>.
+	 * 
+	 * @return the year field value
+	 */
+	public int getYear()
+	{
+		return getYear(localtime);
+	}
+
+	/**
+	 * Retrieves the year field of the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> from which to get the field value
+	 * @return the year field value
+	 */
+	public int getYear(final Calendar calendar)
+	{
+		return get(calendar, Calendar.YEAR);
+	}
+
+	/**
+	 * Subtracts the given <code>Duration</code> from this <code>Time</code> object, moving the time
+	 * into the past.
+	 * 
+	 * @param duration
+	 *            the <code>Duration</code> to subtract
+	 * @return this duration of time
+	 */
+	public Time subtract(final Duration duration)
+	{
+		return milliseconds(getMilliseconds() - duration.getMilliseconds());
+	}
+
+	/**
+	 * Subtract time from this and returns the difference as a <code>Duration</code> object.
+	 * 
+	 * @param that
+	 *            the time to subtract
+	 * @return the <code>Duration</code> between this and that time
+	 */
+	public Duration subtract(final Time that)
+	{
+		return Duration.milliseconds(getMilliseconds() - that.getMilliseconds());
+	}
+
+	/**
+	 * Retrieves a <code>Date</code> object for this <code>Time</code> object. A new
+	 * <code>Date</code> object is always returned rather than attempting to cache a date since
+	 * <code>Date</code> is mutable.
+	 * 
+	 * @return this immutable <code>Time</code> object as a mutable <code>java.util.Date</code>
+	 *         object
+	 */
+	public Date toDate()
+	{
+		return new Date(getMilliseconds());
+	}
+
+	/**
+	 * Converts this <code>Time</code> value to a date <code>String</code> using the date formatter
+	 * 'yyyy.MM.dd'.
+	 * 
+	 * @return the date string
+	 */
+	public String toDateString()
+	{
+		return toDateString(localtime);
+	}
+
+	/**
+	 * Converts this <code>Time</code> value to a date <code>String</code> using the formatter
+	 * 'yyyy.MM.dd'.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use in the conversion
+	 * @return the date <code>String</code>
+	 */
+	public String toDateString(final Calendar calendar)
+	{
+		synchronized (dateFormat)
+		{
+			synchronized (calendar)
+			{
+				dateFormat.setCalendar(calendar);
+
+				return dateFormat.format(new Date(getMilliseconds())).toLowerCase();
+			}
+		}
+	}
+
+	/**
+	 * Converts this <code>Time</code> value to a <code>String</code> suitable for use in a file
+	 * system name.
+	 * 
+	 * @return this <code>Time</code> value as a formatted <code>String</code>
+	 */
+	@Override
+	public String toString()
+	{
+		return toDateString() + "-" + toTimeString();
+	}
+
+	/**
+	 * Converts this <code>Time</code> object to a <code>String</code> using the given
+	 * <code>Calendar</code> and format.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use in the conversion
+	 * @param format
+	 *            the format to use
+	 * @return this <code>Time</code> value as a formatted <code>String</code>
+	 */
+	public String toString(final Calendar calendar, final String format)
+	{
+		final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(format);
+		dateTimeFormat.setCalendar(calendar == null ? localtime : calendar);
+		return dateTimeFormat.format(new Date(getMilliseconds()));
+	}
+
+	/**
+	 * Converts this <code>Time</code> value to a <code>String</code> using the given format.
+	 * 
+	 * @param format
+	 *            the format to use
+	 * @return this <code>Time</code> value as a formatted string
+	 */
+	public String toString(final String format)
+	{
+		return toString(null, format);
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/Time.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeFrame.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeFrame.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeFrame.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeFrame.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,256 @@
+/*
+ * 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.wicket.util.time;
+
+import org.apache.wicket.util.lang.Objects;
+
+/**
+ * Immutable class which represents an interval of time with a beginning and an end. The beginning
+ * value is inclusive and the end value is exclusive. In other words, the time frame of 1pm to 2pm
+ * includes 1pm, but not 2pm. 1:59:59 is the last value in the <code>TimeFrame</code>.
+ * <p>
+ * <code>TimeFrame</code>s can be constructed by calling the <code>valueOf</code> static factory
+ * methods <code>valueOf(Time, Time)</code> (yielding a <code>TimeFrame</code> between two absolute
+ * times) and <code>valueOf(Time, Duration)</code> yielding a <code>TimeFrame</code> starting at an
+ * absolute time and having a given length.
+ * <p>
+ * The start and end of a <code>TimeFrame</code> can be retrieved by calling <code>getStart</code>
+ * and <code>getEnd</code>. Its duration can be retrieved by calling <code>getDuration</code>.
+ * <p>
+ * The <code>contains(Time)</code> method can be called to determine if a <code>TimeFrame</code>
+ * contains a given point in time. The <code>overlaps(TimeFrame)</code> method can be called to
+ * determine if two <code>TimeFrames</code> overlap.
+ * <p>
+ * The <code>eachDay(TimeOfDay, TimeOfDay)</code> will return a <code>TimeFrameSource</code> which
+ * generates a <code>TimeFrame</code> using the two times of day. In other words, if the start is
+ * 3pm and the end is 4pm, the <code>TimeFrameSource</code> returned will yield 3-4pm on the day it
+ * is called (each day).
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public final class TimeFrame implements ITimeFrameSource
+{
+	private static final long serialVersionUID = 1L;
+
+	/** end of this <code>TimeFrame</code> */
+	private final Time end;
+
+	/** beginning of this <code>TimeFrame</code> */
+	private final Time start;
+
+	/**
+	 * Creates an <code>ITimeFrameSource</code> source for start and end <code>TimeOfDay</code>s.
+	 * For example, called with 3pm and 5pm as parameters, the <code>TimeFrame</code> source
+	 * returned would produce <code>TimeFrame</code> objects representing 3pm-5pm on whatever day it
+	 * is when the caller calls the <code>TimeFrameSource</code> interface.
+	 * 
+	 * @param startTimeOfDay
+	 *            the start <code>TimeOfDay</code> for this <code>TimeFrame</code> each day
+	 * @param endTimeOfDay
+	 *            the end <code>TimeOfDay</code> for this <code>TimeFrame</code> each day
+	 * @return a <code>TimeFrameSource</code> which will return the specified <code>TimeFrame</code>
+	 *         each day
+	 */
+	public static ITimeFrameSource eachDay(final TimeOfDay startTimeOfDay,
+		final TimeOfDay endTimeOfDay)
+	{
+		check(startTimeOfDay, endTimeOfDay);
+
+		return new ITimeFrameSource()
+		{
+			private static final long serialVersionUID = 1L;
+
+			public TimeFrame getTimeFrame()
+			{
+				return new TimeFrame(Time.valueOf(startTimeOfDay), Time.valueOf(endTimeOfDay));
+			}
+		};
+	}
+
+	/**
+	 * Creates a <code>TimeFrame</code> for a start <code>Time</code> and <code>Duration</code>.
+	 * 
+	 * @param start
+	 *            the start <code>Time</code>
+	 * @param duration
+	 *            the <code>Duration</code>
+	 * @return the <code>TimeFrame</code>
+	 * @throws IllegalArgumentException
+	 *             thrown if start <code>Time</code> value is before end <code>Time</code> value
+	 */
+	public static TimeFrame valueOf(final Time start, final Duration duration)
+	{
+		return new TimeFrame(start, start.add(duration));
+	}
+
+	/**
+	 * Creates a <code>TimeFrame</code> for given start and end <code>Time</code>s.
+	 * 
+	 * @param start
+	 *            the start <code>Time</code>
+	 * @param end
+	 *            the end <code>Time</code>
+	 * @return the <code>TimeFrame</code>
+	 * @throws IllegalArgumentException
+	 *             thrown if start <code>Time</code> value is before end <code>Time</code> value
+	 */
+	public static TimeFrame valueOf(final Time start, final Time end)
+	{
+		return new TimeFrame(start, end);
+	}
+
+	/**
+	 * Checks consistency of start and end <code>AbstractTimeValue</code> values, ensuring that the
+	 * end value is less than the start value.
+	 * 
+	 * @param start
+	 *            start <code>AbstractTimeValue</code> value
+	 * @param end
+	 *            end <code>AbstractTimeValue</code> value
+	 * @throws IllegalArgumentException
+	 *             thrown if end is less than start
+	 */
+	private static void check(final AbstractTimeValue start, final AbstractTimeValue end)
+	{
+		// Throw illegal argument exception if end is less than start
+		if (end.lessThan(start))
+		{
+			throw new IllegalArgumentException("Start time of time frame " + start +
+				" was after end time " + end);
+		}
+	}
+
+	/**
+	 * Private constructor to force use of static factory methods.
+	 * 
+	 * @param start
+	 *            the start <code>Time</code>
+	 * @param end
+	 *            the end <code>Time</code>
+	 * @throws IllegalArgumentException
+	 *             thrown if start <code>Time</code> value is before end <code>Time</code> value
+	 */
+	private TimeFrame(final Time start, final Time end)
+	{
+		check(start, end);
+		this.start = start;
+		this.end = end;
+	}
+
+	/**
+	 * Determines if this <code>TimeFrame</code> contains a given point in time.
+	 * 
+	 * @param time
+	 *            the <code>Time</code> to check
+	 * @return <code>true</code> if this <code>TimeFrame</code> contains the given time
+	 */
+	public boolean contains(final Time time)
+	{
+		return (start.equals(time) || start.before(time)) && end.after(time);
+	}
+
+	/**
+	 * Retrieves the <code>Duration</code> of this <code>TimeFrame</code>.
+	 * 
+	 * @return the <code>Duration</code> of this <code>TimeFrame</code>
+	 */
+	public Duration getDuration()
+	{
+		return end.subtract(start);
+	}
+
+	/**
+	 * Retrieves the end <code>Time</code> of this <code>TimeFrame</code>.
+	 * 
+	 * @return the end of this <code>TimeFrame</code>
+	 */
+	public Time getEnd()
+	{
+		return end;
+	}
+
+	/**
+	 * Retrieves the start <code>Time</code> of this <code>TimeFrame</code>.
+	 * 
+	 * @return the start of this <code>TimeFrame</code>
+	 */
+	public Time getStart()
+	{
+		return start;
+	}
+
+	/**
+	 * Implementation of <code>ITimeFrameSource</code> that simply returns this
+	 * <code>TimeFrame</code>.
+	 * 
+	 * @return this <code>TimeFrame</code>
+	 */
+	public TimeFrame getTimeFrame()
+	{
+		return this;
+	}
+
+	/**
+	 * Determines if two <code>TimeFrame</code>s overlap.
+	 * 
+	 * @param timeframe
+	 *            the <code>TimeFrame</code> to test
+	 * @return <code>true</code> if the given <code>TimeFrame</code> overlaps this one
+	 */
+	public boolean overlaps(final TimeFrame timeframe)
+	{
+		return contains(timeframe.start) || contains(timeframe.end) || timeframe.contains(start) ||
+			timeframe.contains(end);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hashCode(start, end);
+	}
+
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (this == obj)
+		{
+			return true;
+		}
+		if (obj == null)
+		{
+			return false;
+		}
+		if (getClass() != obj.getClass())
+		{
+			return false;
+		}
+		TimeFrame other = (TimeFrame)obj;
+		return Objects.equal(start, other.start) && Objects.equal(end, other.end);
+	}
+
+	/**
+	 * Converts this <code>TimeFrame</code> to a <code>String</code> representation.
+	 * 
+	 * @return a <code>String</code> representation of this object
+	 */
+	@Override
+	public String toString()
+	{
+		return "[start=" + start + ", end=" + end + "]";
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeFrame.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeMap.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeMap.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeMap.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeMap.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,109 @@
+/*
+ * 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.wicket.util.time;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class maps <code>ITimeFrame</code>s to <code>Object</code>s. Since values are stored using
+ * <code>ITimeFrameSource</code> implementing objects, the value returned by the source may vary
+ * over time. For example, one implementation of <code>ITimeFrameSource</code> might return the
+ * start and end time of lunch on any given day.
+ * <p>
+ * To associate an object with a dynamic <code>TimeFrame</code> (via <code>ITimeFrameSource</code>),
+ * call <code>put(ITimeFrameSource, Object)</code>. You can later retrieve the first object for a
+ * point in time with <code>get(Time)</code>. The <code>get</code> method is provided for
+ * convenience and is equivalent to <code>get(Time.now())</code>.
+ * <p>
+ * This class is not thread-safe.
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public final class TimeMap implements Serializable
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <code>Map</code> from <code>ITimeFrameSource</code> implementing objects to
+	 * <code>Object</code> values.
+	 */
+	private final Map<ITimeFrameSource, Object> sources = new ConcurrentHashMap<ITimeFrameSource, Object>();
+
+	/**
+	 * Retrieves an <code>Object</code> for the current <code>Time</code> value.
+	 * 
+	 * @return <code>Object</code> for the current <code>Time</code> value
+	 */
+	public Object get()
+	{
+		return get(Time.now());
+	}
+
+	/**
+	 * Retrieves an <code>Object</code> for the given <code>Time</code> value.
+	 * 
+	 * @param time
+	 *            the <code>Time</code> value
+	 * @return gets an <code>Object</code> for the given <code>Time</code> value or
+	 *         <code>null</code> if none exists
+	 */
+	public Object get(final Time time)
+	{
+		for (final Iterator<ITimeFrameSource> iterator = sources.keySet().iterator(); iterator.hasNext();)
+		{
+			final TimeFrame current = iterator.next().getTimeFrame();
+			if (current.contains(time))
+			{
+				return sources.get(current);
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Associates an <code>Object</code> with a dynamic <code>TimeFrame</code>.
+	 * 
+	 * @param source
+	 *            a source that can produce a <code>TimeFrame</code> with which to compare a
+	 *            <code>Time</code> value
+	 * @param o
+	 *            the <code>Object</code> to be returned for the given dynamic
+	 *            <code>TimeFrame</code>
+	 */
+	public void put(final ITimeFrameSource source, final Object o)
+	{
+		final TimeFrame timeframe = source.getTimeFrame();
+
+		for (final Iterator<ITimeFrameSource> iterator = sources.keySet().iterator(); iterator.hasNext();)
+		{
+			final TimeFrame current = iterator.next().getTimeFrame();
+
+			if (timeframe.overlaps(current))
+			{
+				throw new IllegalArgumentException("Timeframe " + timeframe +
+					" overlaps timeframe " + current);
+			}
+		}
+
+		sources.put(source, o);
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeOfDay.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeOfDay.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeOfDay.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeOfDay.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,417 @@
+/*
+ * 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.wicket.util.time;
+
+import java.text.ParseException;
+import java.util.Calendar;
+
+import org.apache.wicket.util.lang.EnumeratedType;
+
+
+/**
+ * An immutable time of day value represented as milliseconds since the most recent midnight.
+ * <p>
+ * Values can be constructed using various factory methods:
+ * <ul>
+ * <li><code>valueOf(long)</code> where <code>long</code> is milliseconds since midnight
+ * <li><code>valueOf(String)</code> where the <code>String</code> is in 'h.mma' format
+ * <li><code>valueOf(Calendar, String)</code> where the <code>String</code> is in 'h.mma' format
+ * <li><code>valueOf(Duration)</code> where <code>Duration</code> is time since midnight
+ * <li><code>valueOf(Time)</code> where <code>Time</code> is some point in time today
+ * <li><code>valueOf(Calendar, Time)</code> where <code>Time</code> is some point in time today
+ * <li><code>militaryTime(int hour, int minute, int second)</code> for 24-hour time
+ * <li><code>time(int hour, int minute, Meridian)</code> where <code>Meridian</code> is AM or PM
+ * <li><code>time(int hour, int minute, int second, Meridian)</code> where <code>Meridian</code> is
+ * AM or PM
+ * <li><code>now()</code> to construct the current time of day
+ * <li><code>now(Calendar)</code> to construct the current time of day using a given
+ * <code>Calendar</code>
+ * </ul>
+ * <p>
+ * If an attempt is made to construct an illegal time of day value (one that is greater than 24
+ * hours worth of milliseconds), an <code>IllegalArgumentException</code> will be thrown.
+ * <p>
+ * Military hours, minutes and seconds of the time of day can be retrieved by calling the
+ * <code>hour</code>, <code>minute</code>, and <code>second</code> methods.
+ * <p>
+ * The next occurrence of a given <code>TimeOfDay</code> can be retrieved by calling
+ * <code>next()</code> or <code>next(Calendar)</code>.
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public final class TimeOfDay extends AbstractTime
+{
+	private static final long serialVersionUID = 1L;
+
+	/** Constant for AM time. */
+	public static final Meridian AM = new Meridian("AM");
+
+	/** Constant for midnight. */
+	public static final TimeOfDay MIDNIGHT = time(12, 0, AM);
+
+	/** Constant for PM time. */
+	public static final Meridian PM = new Meridian("PM");
+
+	/** Constant for noon. */
+	public static final TimeOfDay NOON = time(12, 0, PM);
+
+	/** Typesafe AM/PM enumeration. */
+	public static final class Meridian extends EnumeratedType
+	{
+		private static final long serialVersionUID = 1L;
+
+		/**
+		 * Constructor.
+		 * 
+		 * @param name
+		 *            the meridian name (value)
+		 */
+		Meridian(final String name)
+		{
+			super(name);
+		}
+	}
+
+	/**
+	 * Retrieves a <code>TimeOfDay</code> value on a 24-hour clock.
+	 * 
+	 * @param hour
+	 *            the hour (0-23)
+	 * @param minute
+	 *            the minute (0-59)
+	 * @param second
+	 *            the second (0-59)
+	 * @return the time of day
+	 */
+	public static TimeOfDay militaryTime(final int hour, final int minute, final int second)
+	{
+		if ((hour > 23) || (hour < 0))
+		{
+			throw new IllegalArgumentException("Hour " + hour + " is not valid");
+		}
+
+		if ((minute > 59) || (minute < 0))
+		{
+			throw new IllegalArgumentException("Minute " + minute + " is not valid");
+		}
+
+		if ((second > 59) || (second < 0))
+		{
+			throw new IllegalArgumentException("Second " + second + " is not valid");
+		}
+
+		return valueOf(Duration.hours(hour).add(Duration.minutes(minute)).add(
+			Duration.seconds(second)));
+	}
+
+	/**
+	 * Retrieves the <code>TimeOfDay</code> representing 'now'.
+	 * 
+	 * @return the time of day it is now
+	 */
+	public static TimeOfDay now()
+	{
+		return valueOf(Time.now());
+	}
+
+	/**
+	 * Retrieves the <code>TimeOfDay</code> representing 'now' on the given <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use
+	 * @return the time of day it is now on the given <code>Calendar</code>
+	 */
+	public static TimeOfDay now(final Calendar calendar)
+	{
+		return valueOf(calendar, Time.now());
+	}
+
+	/**
+	 * Retrieves a <code>TimeOfDay</code> on a 12-hour clock.
+	 * 
+	 * @param hour
+	 *            the hour (1-12)
+	 * @param minute
+	 *            the minute (0-59)
+	 * @param second
+	 *            the second (0-59)
+	 * @param meridian
+	 *            AM or PM
+	 * @return the <code>TimeOfDay</code> value
+	 */
+	public static TimeOfDay time(final int hour, final int minute, final int second,
+		final Meridian meridian)
+	{
+		if (meridian == PM)
+		{
+			if (hour == 12)
+			{
+				return militaryTime(12, minute, second);
+			}
+			else
+			{
+				return militaryTime(hour + 12, minute, second);
+			}
+		}
+		else
+		{
+			if (hour == 12)
+			{
+				return militaryTime(0, minute, second);
+			}
+			else
+			{
+				return militaryTime(hour, minute, second);
+			}
+		}
+	}
+
+	/**
+	 * Retrieves a <code>TimeOfDay</code> on a 12-hour clock.
+	 * 
+	 * @param hour
+	 *            the hour (1-12)
+	 * @param minute
+	 *            the minute (0-59)
+	 * @param meridian
+	 *            AM of PM
+	 * @return the <code>TimeOfDay</code> value
+	 */
+	public static TimeOfDay time(final int hour, final int minute, final Meridian meridian)
+	{
+		return time(hour, minute, 0, meridian);
+	}
+
+	/**
+	 * Converts a time <code>String</code> and <code>Calendar</code> to a <code>TimeOfDay</code>
+	 * instance.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use when parsing time <code>String</code>
+	 * @param time
+	 *            a <code>String</code> in 'h.mma' format
+	 * @return the <code>TimeOfDay</code> on the given <code>Calendar</code>
+	 * @throws ParseException
+	 */
+	public static TimeOfDay valueOf(final Calendar calendar, final String time)
+		throws ParseException
+	{
+		synchronized (timeFormat)
+		{
+			synchronized (calendar)
+			{
+				timeFormat.setCalendar(calendar);
+				return new TimeOfDay(timeFormat.parse(time).getTime());
+			}
+		}
+	}
+
+	/**
+	 * Converts a <code>Time</code> instance and <code>Calendar</code> to a <code>TimeOfDay</code>
+	 * instance.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use
+	 * @param time
+	 *            a <code>Time</code> instance
+	 * @return the <code>TimeOfDay</code> on the given <code>Calendar</code>
+	 */
+	public static TimeOfDay valueOf(final Calendar calendar, final Time time)
+	{
+		return militaryTime(time.getHour(calendar), time.getMinute(calendar),
+			time.getSecond(calendar));
+	}
+
+	/**
+	 * Converts a <code>Duration</code> instance to a <code>TimeOfDay</code> instance.
+	 * 
+	 * @param duration
+	 *            the <code>Duration</code> to use
+	 * @return the <code>TimeOfDay</code> of the given <code>Duration</code>
+	 */
+	public static TimeOfDay valueOf(final Duration duration)
+	{
+		return new TimeOfDay(duration.getMilliseconds());
+	}
+
+	/**
+	 * Converts a <code>long</code> value to a <code>TimeOfDay</code> instance.
+	 * 
+	 * @param time
+	 *            the time in milliseconds today
+	 * @return the <code>TimeOfDay</code>
+	 */
+	public static TimeOfDay valueOf(final long time)
+	{
+		return new TimeOfDay(time);
+	}
+
+	/**
+	 * Converts a <code>String</code> value to a <code>TimeOfDay</code> instance.
+	 * 
+	 * @param time
+	 *            a <code>String</code> in 'h.mma' format
+	 * @return the <code>TimeOfDay</code>
+	 * @throws ParseException
+	 */
+	public static TimeOfDay valueOf(final String time) throws ParseException
+	{
+		return valueOf(localtime, time);
+	}
+
+	/**
+	 * Converts a <code>String</code> value to a <code>TimeOfDay</code> instance.
+	 * 
+	 * @param time
+	 *            a <code>Time</code> to convert to <code>TimeOfDay</code>
+	 * @return the <code>TimeOfDay</code> in the current time zone
+	 */
+	public static TimeOfDay valueOf(final Time time)
+	{
+		return valueOf(AbstractTime.localtime, time);
+	}
+
+	/**
+	 * Private utility constructor forces use of static factory methods.
+	 * 
+	 * @param time
+	 *            the time today in milliseconds
+	 */
+	private TimeOfDay(final long time)
+	{
+		super(time);
+
+		// A time of day value must be less than 1 day of milliseconds
+		if (Duration.valueOf(time).greaterThan(Duration.ONE_DAY))
+		{
+			throw new IllegalArgumentException("Time " + this + " is not a time of day value");
+		}
+	}
+
+	/**
+	 * Retrieves the hour of the day.
+	 * 
+	 * @return the hour (0-23) of this <code>TimeOfDay</code>
+	 */
+	public int hour()
+	{
+		return toHours(getMilliseconds());
+	}
+
+	/**
+	 * Retrieves the minute.
+	 * 
+	 * @return the minute (0-59) of this <code>TimeOfDay</code>
+	 */
+	public int minute()
+	{
+		return toMinutes(getMilliseconds()) % 60;
+	}
+
+	/**
+	 * Retrieves the next occurrence of this <code>TimeOfDay</code> in local time.
+	 * 
+	 * @return the next occurrence of this <code>TimeOfDay</code> in local time
+	 */
+	public Time next()
+	{
+		return next(AbstractTime.localtime);
+	}
+
+	/**
+	 * Retrieves the next occurrence of this <code>TimeOfDay</code> on the given
+	 * <code>Calendar</code>.
+	 * 
+	 * @param calendar
+	 *            the <code>Calendar</code> to use
+	 * @return the next occurrence of this <code>TimeOfDay</code> on the given <code>Calendar</code>
+	 */
+	public Time next(final Calendar calendar)
+	{
+		// Get this time of day today
+		final Time timeToday = Time.valueOf(calendar, this);
+
+		// If it has already passed
+		if (timeToday.before(Time.now()))
+		{
+			// Return the time tomorrow
+			return Time.valueOf(calendar, this).add(Duration.ONE_DAY);
+		}
+		else
+		{
+			// Time hasn't happened yet today
+			return timeToday;
+		}
+	}
+
+	/**
+	 * Retrieves the second.
+	 * 
+	 * @return the second (0-59)
+	 */
+	public int second()
+	{
+		return toSeconds(getMilliseconds()) % 60;
+	}
+
+	/**
+	 * @see Object#toString()
+	 */
+	@Override
+	public String toString()
+	{
+		final int second = second();
+		return "" + hour() + ":" + minute() + (second != 0 ? ":" + second : "");
+	}
+
+	/**
+	 * Retrieves milliseconds as hours.
+	 * 
+	 * @param milliseconds
+	 *            milliseconds to convert
+	 * @return converted input
+	 */
+	private int toHours(final long milliseconds)
+	{
+		return toMinutes(milliseconds) / 60;
+	}
+
+	/**
+	 * Retrieves milliseconds as minutes.
+	 * 
+	 * @param milliseconds
+	 *            milliseconds to convert
+	 * @return converted input
+	 */
+	private int toMinutes(final long milliseconds)
+	{
+		return toSeconds(milliseconds) / 60;
+	}
+
+	/**
+	 * Retrieves milliseconds as seconds.
+	 * 
+	 * @param milliseconds
+	 *            milliseconds to convert
+	 * @return converted input
+	 */
+	private int toSeconds(final long milliseconds)
+	{
+		return (int)(milliseconds / 1000);
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/TimeOfDay.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/package.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/package.html?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/package.html (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/package.html Wed Mar 17 00:34:34 2010
@@ -0,0 +1,29 @@
+<!--
+   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.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML 3.2 Final//NL">
+<html>
+	<head>
+		<title>
+			org.apache.wicket.util.time package
+		</title>
+	</head>
+	<body>
+		<p>
+			Utilities for working with <code>Time</code>(s).
+		</p>
+	</body>
+</html>
\ No newline at end of file

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/time/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/AttributeMap.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/AttributeMap.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/AttributeMap.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/AttributeMap.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,49 @@
+/*
+ * 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.wicket.util.value;
+
+import java.util.Map;
+
+/**
+ * <code>ValueMap</code> for attributes.
+ * 
+ * @author Eelco Hillenius
+ * @since 1.2.6
+ */
+public final class AttributeMap extends ValueMap
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructs an empty <code>AttributeMap</code>.
+	 */
+	public AttributeMap()
+	{
+		super();
+	}
+
+	/**
+	 * Copy constructor.
+	 * 
+	 * @param map
+	 *            a <code>Map</code> to be copied
+	 */
+	public AttributeMap(Map<String, Object> map)
+	{
+		super(map);
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/AttributeMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/CopyOnWriteValueMap.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/CopyOnWriteValueMap.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/CopyOnWriteValueMap.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/CopyOnWriteValueMap.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,451 @@
+/*
+ * 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.wicket.util.value;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.util.string.StringValue;
+import org.apache.wicket.util.string.StringValueConversionException;
+import org.apache.wicket.util.time.Duration;
+import org.apache.wicket.util.time.Time;
+
+
+/**
+ * An implementation of <code>IValueMap</code> that makes a copy when a caller tries to change an
+ * immutable <code>Map</code>. That is, the <code>Map</code> may or may not be immutable, but if it
+ * is, a copy is made.
+ * 
+ * @author Johan Compagner
+ * @author Doug Donohoe
+ * @since 1.2.6
+ */
+public class CopyOnWriteValueMap implements IValueMap, Serializable
+{
+	private static final long serialVersionUID = 1L;
+
+	/** the wrapped <code>IValueMap</code> */
+	private IValueMap wrapped;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param wrapped
+	 *            the wrapped <code>IValueMap</code>
+	 */
+	public CopyOnWriteValueMap(IValueMap wrapped)
+	{
+		this.wrapped = wrapped;
+	}
+
+	/**
+	 * @see java.util.Map#clear()
+	 */
+	public void clear()
+	{
+		checkAndCopy();
+		wrapped.clear();
+	}
+
+	/**
+	 * Checks if this <code>IValueMap</code> is immutable. If it is, this method makes a new
+	 * <code>IValueMap</code> using the <code>ValueMap</code> copy constructor, and sets it to be
+	 * this <code>CopyOnWriteValueMap</code>.
+	 */
+	private void checkAndCopy()
+	{
+		if (wrapped.isImmutable())
+		{
+			wrapped = new ValueMap(wrapped);
+		}
+	}
+
+	/**
+	 * @see java.util.Map#containsKey(Object)
+	 */
+	public boolean containsKey(Object key)
+	{
+		return wrapped.containsKey(key);
+	}
+
+	/**
+	 * @see java.util.Map#containsValue(Object)
+	 */
+	public boolean containsValue(Object value)
+	{
+		return wrapped.containsValue(value);
+	}
+
+	/**
+	 * @see java.util.Map#entrySet()
+	 */
+	public Set entrySet()
+	{
+		checkAndCopy();
+		return wrapped.entrySet();
+	}
+
+	/**
+	 * @see java.util.Map#equals(Object)
+	 */
+	@Override
+	public boolean equals(Object o)
+	{
+		return wrapped.equals(o);
+	}
+
+	/**
+	 * @see java.util.Map#get(Object)
+	 */
+	public Object get(Object key)
+	{
+		return wrapped.get(key);
+	}
+
+	/**
+	 * @see IValueMap#getBoolean(String)
+	 */
+	public boolean getBoolean(String key) throws StringValueConversionException
+	{
+		return wrapped.getBoolean(key);
+	}
+
+	/**
+	 * @see IValueMap#getCharSequence(String)
+	 */
+	public CharSequence getCharSequence(String key)
+	{
+		return wrapped.getCharSequence(key);
+	}
+
+	/**
+	 * @see IValueMap#getDouble(String)
+	 */
+	public double getDouble(String key) throws StringValueConversionException
+	{
+		return wrapped.getDouble(key);
+	}
+
+	/**
+	 * @see IValueMap#getDouble(String, double)
+	 */
+	public double getDouble(String key, double defaultValue) throws StringValueConversionException
+	{
+		return wrapped.getDouble(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getDuration(String)
+	 */
+	public Duration getDuration(String key) throws StringValueConversionException
+	{
+		return wrapped.getDuration(key);
+	}
+
+	/**
+	 * @see IValueMap#getInt(String, int)
+	 */
+	public int getInt(String key, int defaultValue) throws StringValueConversionException
+	{
+		return wrapped.getInt(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getInt(String)
+	 */
+	public int getInt(String key) throws StringValueConversionException
+	{
+		return wrapped.getInt(key);
+	}
+
+	/**
+	 * @see IValueMap#getKey(String)
+	 */
+	public String getKey(String key)
+	{
+		return wrapped.getKey(key);
+	}
+
+	/**
+	 * @see IValueMap#getLong(String, long)
+	 */
+	public long getLong(String key, long defaultValue) throws StringValueConversionException
+	{
+		return wrapped.getLong(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getLong(String)
+	 */
+	public long getLong(String key) throws StringValueConversionException
+	{
+		return wrapped.getLong(key);
+	}
+
+	/**
+	 * @see IValueMap#getString(String, String)
+	 */
+	public String getString(String key, String defaultValue)
+	{
+		return wrapped.getString(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getString(String)
+	 */
+	public String getString(String key)
+	{
+		return wrapped.getString(key);
+	}
+
+	/**
+	 * @see IValueMap#getStringArray(String)
+	 */
+	public String[] getStringArray(String key)
+	{
+		return wrapped.getStringArray(key);
+	}
+
+	/**
+	 * @see IValueMap#getStringValue(String)
+	 */
+	public StringValue getStringValue(String key)
+	{
+		return wrapped.getStringValue(key);
+	}
+
+	/**
+	 * @see IValueMap#getTime(String)
+	 */
+	public Time getTime(String key) throws StringValueConversionException
+	{
+		return wrapped.getTime(key);
+	}
+
+	/**
+	 * @see java.util.Map#isEmpty()
+	 */
+	public boolean isEmpty()
+	{
+		return wrapped.isEmpty();
+	}
+
+	/**
+	 * @see IValueMap#isImmutable()
+	 */
+	public boolean isImmutable()
+	{
+		return false;
+	}
+
+	/**
+	 * @see java.util.Map#keySet()
+	 */
+	public Set keySet()
+	{
+		checkAndCopy();
+		return wrapped.keySet();
+	}
+
+	/**
+	 * @see IValueMap#makeImmutable()
+	 */
+	public IValueMap makeImmutable()
+	{
+		return wrapped.makeImmutable();
+	}
+
+	/**
+	 * @see java.util.Map#put(Object, Object)
+	 */
+	public Object put(String key, Object value)
+	{
+		checkAndCopy();
+		return wrapped.put(key, value);
+	}
+
+	/**
+	 * @see java.util.Map#putAll(Map)
+	 */
+	public void putAll(Map map)
+	{
+		checkAndCopy();
+		wrapped.putAll(map);
+	}
+
+	/**
+	 * @see java.util.Map#remove(Object)
+	 */
+	public Object remove(Object key)
+	{
+		checkAndCopy();
+		return wrapped.remove(key);
+	}
+
+	/**
+	 * @see java.util.Map#size()
+	 */
+	public int size()
+	{
+		return wrapped.size();
+	}
+
+	/**
+	 * @see java.util.Map#values()
+	 */
+	public Collection values()
+	{
+		return wrapped.values();
+	}
+
+	/**
+	 * @see IValueMap#toString()
+	 */
+	@Override
+	public String toString()
+	{
+		return super.toString();
+	}
+
+	// //
+	// // getAs convenience methods
+	// //
+
+	/**
+	 * @see IValueMap#getAsBoolean(String)
+	 * 
+	 */
+	public Boolean getAsBoolean(String key)
+	{
+		return wrapped.getAsBoolean(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsBoolean(String, boolean)
+	 * 
+	 */
+	public boolean getAsBoolean(String key, boolean defaultValue)
+	{
+		return wrapped.getAsBoolean(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsInteger(String)
+	 */
+	public Integer getAsInteger(String key)
+	{
+		return wrapped.getAsInteger(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsInteger(String, int)
+	 */
+	public int getAsInteger(String key, int defaultValue)
+	{
+		return wrapped.getAsInteger(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsLong(String)
+	 */
+	public Long getAsLong(String key)
+	{
+		return wrapped.getAsLong(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsLong(String, long)
+	 */
+	public long getAsLong(String key, long defaultValue)
+	{
+		return wrapped.getAsLong(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsDouble(String)
+	 */
+	public Double getAsDouble(String key)
+	{
+		return wrapped.getAsDouble(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsDouble(String, double)
+	 */
+	public double getAsDouble(String key, double defaultValue)
+	{
+		return wrapped.getAsDouble(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsDuration(String)
+	 */
+	public Duration getAsDuration(String key)
+	{
+		return wrapped.getAsDuration(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsDuration(String, Duration)
+	 */
+	public Duration getAsDuration(String key, Duration defaultValue)
+	{
+		return wrapped.getAsDuration(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsTime(String)
+	 */
+	public Time getAsTime(String key)
+	{
+		return wrapped.getAsTime(key);
+	}
+
+	/**
+	 * @see IValueMap#getAsTime(String, Time)
+	 */
+	public Time getAsTime(String key, Time defaultValue)
+	{
+		return wrapped.getAsTime(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsEnum(String, Class)
+	 */
+	public <T extends Enum<T>> T getAsEnum(String key, Class<T> eClass)
+	{
+		return wrapped.getAsEnum(key, eClass);
+	}
+
+	/**
+	 * @see IValueMap#getAsEnum
+	 */
+	public <T extends Enum<T>> T getAsEnum(String key, T defaultValue)
+	{
+		return wrapped.getAsEnum(key, defaultValue);
+	}
+
+	/**
+	 * @see IValueMap#getAsEnum(String, Class, Enum)
+	 */
+	public <T extends Enum<T>> T getAsEnum(String key, Class<T> eClass, T defaultValue)
+	{
+		return wrapped.getAsEnum(key, eClass, defaultValue);
+	}
+}
\ No newline at end of file

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/CopyOnWriteValueMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/Count.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/Count.java?rev=924074&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/Count.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/Count.java Wed Mar 17 00:34:34 2010
@@ -0,0 +1,51 @@
+/*
+ * 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.wicket.util.value;
+
+import org.apache.wicket.IClusterable;
+
+/**
+ * A class for counting things.
+ * 
+ * @author Jonathan Locke
+ * @since 1.2.6
+ */
+public final class Count implements IClusterable
+{
+	private static final long serialVersionUID = 1L;
+
+	/** the count */
+	private int count = 0;
+
+	/**
+	 * Retrieves the current count value.
+	 * 
+	 * @return the count value
+	 */
+	public int getCount()
+	{
+		return count;
+	}
+
+	/**
+	 * Increases the count value by one.
+	 */
+	public void increment()
+	{
+		count++;
+	}
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/value/Count.java
------------------------------------------------------------------------------
    svn:executable = *