You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/12/13 15:03:48 UTC
[4/4] git commit: ISIS-630: also reimplemented VSP for Joda
LocalDateTime
ISIS-630: also reimplemented VSP for Joda LocalDateTime
... so it too no longer has any dependencies on the concept of UTC.
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/192b6b22
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/192b6b22
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/192b6b22
Branch: refs/heads/master
Commit: 192b6b229ab21ca9a0a6f3a893fc90272898942a
Parents: b87c2a9
Author: Dan Haywood <da...@apache.org>
Authored: Fri Dec 13 14:03:18 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Dec 13 14:03:18 2013 +0000
----------------------------------------------------------------------
.../progmodel/facets/value/JodaFunctions.java | 55 +++++
.../value/datejodalocal/JodaLocalDateUtil.java | 127 ++++++++++
.../JodaLocalDateValueSemanticsProvider.java | 221 ++++--------------
.../JodaLocalDateTimeUtil.java | 124 ++++++++++
...JodaLocalDateTimeValueSemanticsProvider.java | 232 +++++++++++++++++--
...lDateTimeValueSemanticsProviderAbstract.java | 118 ----------
6 files changed, 574 insertions(+), 303 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/JodaFunctions.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/JodaFunctions.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/JodaFunctions.java
new file mode 100644
index 0000000..2ff05e3
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/JodaFunctions.java
@@ -0,0 +1,55 @@
+/*
+ * 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.isis.core.progmodel.facets.value;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+
+public final class JodaFunctions {
+
+ private JodaFunctions(){}
+
+ public static Function<DateTimeFormatter, DateTimeFormatter> withLocale(final Localization localization) {
+ return new Function<DateTimeFormatter, DateTimeFormatter>() {
+ @Override
+ public DateTimeFormatter apply(DateTimeFormatter input) {
+ if (localization == null) {
+ return input;
+ }
+ final Locale locale = localization.getLocale();
+ if (locale == null) {
+ return input;
+ }
+ return input.withLocale(locale);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateUtil.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateUtil.java
new file mode 100644
index 0000000..ebcd901
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateUtil.java
@@ -0,0 +1,127 @@
+/*
+ * 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.isis.core.progmodel.facets.value.datejodalocal;
+
+import java.util.List;
+import java.util.StringTokenizer;
+
+import com.google.common.collect.Iterables;
+
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+import org.apache.isis.core.progmodel.facets.value.JodaFunctions;
+
+public final class JodaLocalDateUtil {
+
+ private JodaLocalDateUtil(){}
+
+ static LocalDate parseDate(final String dateStr, final Localization localization, List<DateTimeFormatter> parseFormatters) {
+ Iterable<DateTimeFormatter> elements = Iterables.transform(parseFormatters, JodaFunctions.withLocale(localization));
+ LocalDate parsedDate = parseDate(dateStr, elements);
+ return parsedDate;
+ }
+
+
+ private static LocalDate parseDate(String dateStr, Iterable<DateTimeFormatter> formatters) {
+ for(DateTimeFormatter formatter: formatters) {
+ try {
+ return formatter.parseLocalDate(dateStr);
+ } catch (final IllegalArgumentException e) {
+ // continue to next
+ }
+ }
+ throw new TextEntryParseException("Not recognised as a date: " + dateStr);
+ }
+
+ // //////////////////////////////////////
+
+ static LocalDate relativeDate(final LocalDate contextDate, final String str, final boolean add) {
+ LocalDate relativeDate = contextDate;
+ if (str.equals("")) {
+ return contextDate;
+ }
+
+ try {
+ final StringTokenizer st = new StringTokenizer(str.substring(1), " ");
+ while (st.hasMoreTokens()) {
+ final String token = st.nextToken();
+ relativeDate = adjustDate(relativeDate, token, add);
+ }
+ return relativeDate;
+ } catch (final Exception e) {
+ return contextDate;
+ }
+ }
+
+ private static LocalDate adjustDate(final LocalDate contextDate, String str, final boolean add) {
+ int hours = 0;
+ int minutes = 0;
+ int days = 0;
+ int months = 0;
+ int years = 0;
+
+ if (str.endsWith("H")) {
+ str = str.substring(0, str.length() - 1);
+ hours = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("M")) {
+ str = str.substring(0, str.length() - 1);
+ minutes = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("w")) {
+ str = str.substring(0, str.length() - 1);
+ days = 7 * Integer.valueOf(str).intValue();
+ } else if (str.endsWith("y")) {
+ str = str.substring(0, str.length() - 1);
+ years = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("m")) {
+ str = str.substring(0, str.length() - 1);
+ months = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("d")) {
+ str = str.substring(0, str.length() - 1);
+ days = Integer.valueOf(str).intValue();
+ } else {
+ days = Integer.valueOf(str).intValue();
+ }
+
+ if (add) {
+ return add(contextDate, years, months, days, hours, minutes);
+ } else {
+ return add(contextDate, -years, -months, -days, -hours, -minutes);
+ }
+ }
+
+ private static LocalDate add(final LocalDate original, final int years, final int months, final int days, final int hours, final int minutes) {
+ if(hours != 0 || minutes != 0) {
+ throw new IllegalArgumentException("cannot add non-zero hours or minutes to a LocalDate");
+ }
+ return original.plusYears(years).plusMonths(months).plusDays(days);
+ }
+
+
+ // //////////////////////////////////////
+
+ public static String titleString(final DateTimeFormatter formatter, final LocalDate date) {
+ return date == null ? "" : formatter.print(date);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateValueSemanticsProvider.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateValueSemanticsProvider.java
index 16ed066..27ab588 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datejodalocal/JodaLocalDateValueSemanticsProvider.java
@@ -19,13 +19,13 @@
package org.apache.isis.core.progmodel.facets.value.datejodalocal;
-import java.text.SimpleDateFormat;
-import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -55,18 +55,18 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
* <p>
* REVIEW: This seems only to have any effect if 'propertyType' is set to 'date'.
*
- * @see #setPatternOverride(String)
+ * @see #setTitlePatternOverride(String)
* @deprecated - because 'propertyType' parameter is never used
*/
@Deprecated
public static void setFormat(final String propertyType, final String pattern) {
- setPatternOverride(pattern);
+ setTitlePatternOverride(pattern);
}
/**
* A replacement for {@link #setFormat(String, String)}.
*/
- public static void setPatternOverride(final String pattern) {
- OVERRIDE_PATTERN.set(pattern);
+ public static void setTitlePatternOverride(final String pattern) {
+ OVERRIDE_TITLE_PATTERN.set(pattern);
}
/**
@@ -80,9 +80,9 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
*
* <p>
* A pre-determined list of values is available, specifically 'iso_encoding', 'iso' and 'medium' (see
- * {@link #NAMED_FORMATTERS}). Alternatively, can also specify a mask, eg <tt>dd-MMM-yyyy</tt>.
+ * {@link #NAMED_TITLE_FORMATTERS}). Alternatively, can also specify a mask, eg <tt>dd-MMM-yyyy</tt>.
*
- * @see #NAMED_FORMATTERS
+ * @see #NAMED_TITLE_FORMATTERS
*/
public final static String CFG_FORMAT_KEY = ConfigurationConstants.ROOT + "value.format.date";
@@ -91,20 +91,33 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
* Keys represent the values which can be configured, and which are used for the rendering of dates.
*
*/
- private static Map<String, DateTimeFormatter> NAMED_FORMATTERS = Maps.newHashMap();
+ private static Map<String, DateTimeFormatter> NAMED_TITLE_FORMATTERS = Maps.newHashMap();
static {
- NAMED_FORMATTERS.put("iso_encoding", DateTimeFormat.forPattern("yyyyMMdd"));
- NAMED_FORMATTERS.put("iso", DateTimeFormat.forPattern("yyyy-MM-dd"));
- NAMED_FORMATTERS.put("medium", DateTimeFormat.forStyle("M-"));
+ NAMED_TITLE_FORMATTERS.put("iso_encoding", DateTimeFormat.forPattern("yyyyMMdd"));
+ NAMED_TITLE_FORMATTERS.put("iso", DateTimeFormat.forPattern("yyyy-MM-dd"));
+ NAMED_TITLE_FORMATTERS.put("long", DateTimeFormat.forStyle("L-"));
+ NAMED_TITLE_FORMATTERS.put("medium", DateTimeFormat.forStyle("M-"));
+ NAMED_TITLE_FORMATTERS.put("short", DateTimeFormat.forStyle("S-"));
}
- private final static ThreadLocal<String> OVERRIDE_PATTERN = new ThreadLocal<String>() {
+ private final static ThreadLocal<String> OVERRIDE_TITLE_PATTERN = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return null;
}
};
+
+ private final static List<DateTimeFormatter> PARSE_FORMATTERS = Lists.newArrayList();
+ static {
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("L-"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("M-"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("S-"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forPattern("yyyy-MM-dd"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forPattern("yyyyMMdd"));
+ }
+
+
public static Class<? extends Facet> type() {
return JodaLocalDateValueFacet.class;
@@ -115,8 +128,9 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
private static final LocalDate DEFAULT_VALUE = null;
- private final DateTimeFormatter encodingFormatter;
- protected DateTimeFormatter titleStringFormatter;
+ private final DateTimeFormatter encodingFormatter = DateTimeFormat.forPattern("yyyyMMdd");
+
+ private DateTimeFormatter titleStringFormatter;
private String titleStringFormatNameOrPattern;
@@ -139,15 +153,13 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
final FacetHolder holder, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
super(type(), holder, LocalDate.class, 12, Immutability.IMMUTABLE, EqualByContent.HONOURED, DEFAULT_VALUE, configuration, context);
- encodingFormatter = DateTimeFormat.forPattern("yyyyMMdd");
-
String configuredNameOrPattern = getConfiguration().getString(CFG_FORMAT_KEY, "medium").toLowerCase().trim();
updateTitleStringFormatter(configuredNameOrPattern);
}
private void updateTitleStringFormatter(String titleStringFormatNameOrPattern) {
- titleStringFormatter = NAMED_FORMATTERS.get(titleStringFormatNameOrPattern);
+ titleStringFormatter = NAMED_TITLE_FORMATTERS.get(titleStringFormatNameOrPattern);
if (titleStringFormatter == null) {
titleStringFormatter = DateTimeFormat.forPattern(titleStringFormatNameOrPattern);
}
@@ -161,24 +173,23 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
@Override
protected LocalDate doParse(final Object context, final String entry, final Localization localization) {
-
+
updateTitleStringFormatterIfOverridden();
+
+ LocalDate contextDate = (LocalDate) context;
- final String dateString = entry.trim();
- final String str = dateString.toLowerCase();
- if (str.equals("today") || str.equals("now")) {
- return now();
- } else if (dateString.startsWith("+")) {
- return relativeDate(context == null ? now() : context, dateString, true);
- } else if (dateString.startsWith("-")) {
- return relativeDate(context == null ? now() : context, dateString, false);
+ final String dateString = entry.trim().toUpperCase();
+ if (dateString.startsWith("+") && contextDate != null) {
+ return JodaLocalDateUtil.relativeDate(contextDate, dateString, true);
+ } else if (dateString.startsWith("-") && contextDate != null) {
+ return JodaLocalDateUtil.relativeDate(contextDate, dateString, false);
} else {
- return parseDate(dateString, context == null ? now() : context, localization);
+ return parseDate(dateString, contextDate, localization);
}
}
private void updateTitleStringFormatterIfOverridden() {
- final String overridePattern = OVERRIDE_PATTERN.get();
+ final String overridePattern = OVERRIDE_TITLE_PATTERN.get();
if (overridePattern == null ||
titleStringFormatNameOrPattern.equals(overridePattern)) {
return;
@@ -188,78 +199,10 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
updateTitleStringFormatter(overridePattern);
}
- private LocalDate parseDate(final String dateString, final Object original, final Localization localization) {
- List<DateTimeFormatter> elements = formatsToTry(localization);
- LocalDate parsedDate = parseDate(dateString, elements.iterator());
- return setDate(parsedDate);
- }
-
- private LocalDate parseDate(final String dateString, final Iterator<DateTimeFormatter> iterator) {
- final DateTimeFormatter format = iterator.next();
- try {
- return format.parseLocalDate(dateString);
- } catch (final IllegalArgumentException e) {
- if (iterator.hasNext()) {
- return parseDate(dateString, iterator);
- } else {
- throw new TextEntryParseException("Not recognised as a date: " + dateString);
- }
- }
- }
-
- private LocalDate relativeDate(final Object object, final String str, final boolean add) {
- if (str.equals("")) {
- return now();
- }
-
- try {
- LocalDate date = (LocalDate) object;
- final StringTokenizer st = new StringTokenizer(str.substring(1), " ");
- while (st.hasMoreTokens()) {
- final String token = st.nextToken();
- date = relativeDate2(date, token, add);
- }
- return date;
- } catch (final Exception e) {
- return now();
- }
- }
-
- private LocalDate relativeDate2(final LocalDate original, String str, final boolean add) {
- int hours = 0;
- int minutes = 0;
- int days = 0;
- int months = 0;
- int years = 0;
-
- if (str.endsWith("H")) {
- str = str.substring(0, str.length() - 1);
- hours = Integer.valueOf(str).intValue();
- } else if (str.endsWith("M")) {
- str = str.substring(0, str.length() - 1);
- minutes = Integer.valueOf(str).intValue();
- } else if (str.endsWith("w")) {
- str = str.substring(0, str.length() - 1);
- days = 7 * Integer.valueOf(str).intValue();
- } else if (str.endsWith("y")) {
- str = str.substring(0, str.length() - 1);
- years = Integer.valueOf(str).intValue();
- } else if (str.endsWith("m")) {
- str = str.substring(0, str.length() - 1);
- months = Integer.valueOf(str).intValue();
- } else if (str.endsWith("d")) {
- str = str.substring(0, str.length() - 1);
- days = Integer.valueOf(str).intValue();
- } else {
- days = Integer.valueOf(str).intValue();
- }
-
- if (add) {
- return add(original, years, months, days, hours, minutes);
- } else {
- return add(original, -years, -months, -days, -hours, -minutes);
- }
+ private LocalDate parseDate(final String dateStr, final Object original, final Localization localization) {
+ return JodaLocalDateUtil.parseDate(dateStr, localization, PARSE_FORMATTERS);
}
+
// ///////////////////////////////////////////////////////////////////////////
// TitleProvider
@@ -270,23 +213,20 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
if (value == null) {
return null;
}
- final LocalDate date = dateValue(value);
+ final LocalDate date = (LocalDate) value;
DateTimeFormatter f = titleStringFormatter;
if (localization != null) {
- f = format(localization);
+ f = titleStringFormatter.withLocale(localization.getLocale());
}
- return titleString(f, date);
+ return JodaLocalDateUtil.titleString(f, date);
}
@Override
public String titleStringWithMask(final Object value, final String usingMask) {
- final LocalDate date = dateValue(value);
- return titleString(new SimpleDateFormat(usingMask), date);
+ final LocalDate date = (LocalDate) value;
+ return JodaLocalDateUtil.titleString(DateTimeFormat.forPattern(usingMask), date);
}
- private String titleString(final DateTimeFormatter formatter, final LocalDate date) {
- return date == null ? "" : formatter.print(date);
- }
// //////////////////////////////////////////////////////////////////
// EncoderDecoder
@@ -294,7 +234,7 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
@Override
protected String doEncode(final Object object) {
- final LocalDate date = dateValue(object);
+ final LocalDate date = (LocalDate) object;
return encode(date);
}
@@ -330,72 +270,11 @@ public class JodaLocalDateValueSemanticsProvider extends ValueSemanticsProviderA
}
- // //////////////////////////////////////////////////////////////////
- // temporal-specific stuff
- // //////////////////////////////////////////////////////////////////
-
- protected boolean isEmpty() {
- return false;
- }
-
-
-
-
- // //////////////////////////////////////////////////////////////////
- // temporal-specific stuff
- // //////////////////////////////////////////////////////////////////
-
- protected DateTimeFormatter format(final Localization localization) {
- return DateTimeFormat.forStyle("M-").withLocale(localization.getLocale());
- }
-
- protected List<DateTimeFormatter> formatsToTry(Localization localization) {
- List<DateTimeFormatter> formats = Lists.newArrayList();
-
- formats.add(withLocale(DateTimeFormat.forStyle("L-"), localization));
- formats.add(withLocale(DateTimeFormat.forStyle("M-"), localization));
- formats.add(withLocale(DateTimeFormat.forStyle("S-"), localization));
- formats.add(withLocale(DateTimeFormat.forPattern("yyyy-MM-dd"), localization));
- formats.add(withLocale(DateTimeFormat.forPattern("yyyyMMdd"), localization));
-
- return formats;
- }
-
-
- private static DateTimeFormatter withLocale(DateTimeFormatter formatter, Localization localization) {
- if(localization != null) {
- Locale locale2 = localization.getLocale();
- formatter.withLocale(locale2);
- }
- return formatter;
- }
-
- // //////////////////////////////////////
-
- protected LocalDate add(final LocalDate original, final int years, final int months, final int days, final int hours, final int minutes) {
- if(hours != 0 || minutes != 0) {
- throw new IllegalArgumentException("cannot add non-zero hours or minutes to a LocalDate");
- }
- return original.plusYears(years).plusMonths(months).plusDays(days);
- }
-
- protected LocalDate now() {
- return new LocalDate();
- }
-
- protected LocalDate dateValue(final Object value) {
- return (LocalDate) value;
- }
-
- protected LocalDate setDate(final LocalDate date) {
- return date;
- }
-
// //////////////////////////////////////
@Override
public String toString() {
- return "DateValueSemanticsProvider: " + titleStringFormatter;
+ return "JodaLocalDateValueSemanticsProvider: " + titleStringFormatter;
}
}
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeUtil.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeUtil.java
new file mode 100644
index 0000000..7038f47
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeUtil.java
@@ -0,0 +1,124 @@
+/*
+ * 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.isis.core.progmodel.facets.value.datetimejodalocal;
+
+import java.util.List;
+import java.util.StringTokenizer;
+
+import com.google.common.collect.Iterables;
+
+import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormatter;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+import org.apache.isis.core.progmodel.facets.value.JodaFunctions;
+
+public final class JodaLocalDateTimeUtil {
+
+ private JodaLocalDateTimeUtil(){}
+
+ static LocalDateTime parseDate(final String dateStr, final Localization localization, List<DateTimeFormatter> parseFormatters) {
+ Iterable<DateTimeFormatter> elements = Iterables.transform(parseFormatters, JodaFunctions.withLocale(localization));
+ return parseDateTime(dateStr, elements);
+ }
+
+
+ private static LocalDateTime parseDateTime(String dateStr, Iterable<DateTimeFormatter> formatters) {
+ for(DateTimeFormatter formatter: formatters) {
+ try {
+ return formatter.parseLocalDateTime(dateStr);
+ } catch (final IllegalArgumentException e) {
+ // continue to next
+ }
+ }
+ throw new TextEntryParseException("Not recognised as a date: " + dateStr);
+ }
+
+ // //////////////////////////////////////
+
+
+ static LocalDateTime relativeDateTime(final LocalDateTime contextDate, final String str, final boolean add) {
+ LocalDateTime relativeDate = contextDate;
+ if (str.equals("")) {
+ return contextDate;
+ }
+
+ try {
+ final StringTokenizer st = new StringTokenizer(str.substring(1), " ");
+ while (st.hasMoreTokens()) {
+ final String token = st.nextToken();
+ relativeDate = adjustDateTime(relativeDate, token, add);
+ }
+ return relativeDate;
+ } catch (final Exception e) {
+ return contextDate;
+ }
+ }
+
+ private static LocalDateTime adjustDateTime(final LocalDateTime contextDateTime, String str, final boolean add) {
+ int hours = 0;
+ int minutes = 0;
+ int days = 0;
+ int months = 0;
+ int years = 0;
+
+ if (str.endsWith("H")) {
+ str = str.substring(0, str.length() - 1);
+ hours = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("M")) {
+ str = str.substring(0, str.length() - 1);
+ minutes = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("w")) {
+ str = str.substring(0, str.length() - 1);
+ days = 7 * Integer.valueOf(str).intValue();
+ } else if (str.endsWith("y")) {
+ str = str.substring(0, str.length() - 1);
+ years = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("m")) {
+ str = str.substring(0, str.length() - 1);
+ months = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("d")) {
+ str = str.substring(0, str.length() - 1);
+ days = Integer.valueOf(str).intValue();
+ } else {
+ days = Integer.valueOf(str).intValue();
+ }
+
+ if (add) {
+ return add(contextDateTime, years, months, days, hours, minutes);
+ } else {
+ return add(contextDateTime, -years, -months, -days, -hours, -minutes);
+ }
+ }
+
+ private static LocalDateTime add(final LocalDateTime original, final int years, final int months, final int days, final int hours, final int minutes) {
+ return original.plusYears(years).plusMonths(months).plusDays(days).plusHours(hours).plusMinutes(minutes);
+ }
+
+
+ // //////////////////////////////////////
+
+ public static String titleString(final DateTimeFormatter formatter, final LocalDateTime date) {
+ return date == null ? "" : formatter.print(date);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProvider.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProvider.java
index a7b9165..d3f1cee 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProvider.java
@@ -19,22 +19,121 @@
package org.apache.isis.core.progmodel.facets.value.datetimejodalocal;
-import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
import org.apache.isis.applib.adapters.EncoderDecoder;
+import org.apache.isis.applib.adapters.EncodingException;
import org.apache.isis.applib.adapters.Parser;
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.config.ConfigurationConstants;
import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.progmodel.facets.object.value.ValueSemanticsProviderAndFacetAbstract;
import org.apache.isis.core.progmodel.facets.object.value.ValueSemanticsProviderContext;
-public class JodaLocalDateTimeValueSemanticsProvider extends JodaLocalDateTimeValueSemanticsProviderAbstract<LocalDateTime> {
+public class JodaLocalDateTimeValueSemanticsProvider extends ValueSemanticsProviderAndFacetAbstract<LocalDateTime> implements JodaLocalDateTimeValueFacet {
+
+
+ /**
+ * Introduced to allow BDD tests to provide a different format string "mid-flight".
+ *
+ * <p>
+ * REVIEW: This seems only to have any effect if 'propertyType' is set to 'date'.
+ *
+ * @see #setTitlePatternOverride(String)
+ * @deprecated - because 'propertyType' parameter is never used
+ */
+ @Deprecated
+ public static void setFormat(final String propertyType, final String pattern) {
+ setTitlePatternOverride(pattern);
+ }
+ /**
+ * A replacement for {@link #setFormat(String, String)}.
+ */
+ public static void setTitlePatternOverride(final String pattern) {
+ OVERRIDE_TITLE_PATTERN.set(pattern);
+ }
+
+ /**
+ * Key to indicate how LocalDateTime should be parsed/rendered.
+ *
+ * <p>
+ * eg:
+ * <pre>
+ * isis.value.format.datetime=iso
+ * </pre>
+ *
+ * <p>
+ * A pre-determined list of values is available, specifically 'iso_encoding', 'iso' and 'medium' (see
+ * {@link #NAMED_TITLE_FORMATTERS}). Alternatively, can also specify a mask, eg <tt>dd-MMM-yyyy</tt>.
+ *
+ * @see #NAMED_TITLE_FORMATTERS
+ */
+ public final static String CFG_FORMAT_KEY = ConfigurationConstants.ROOT + "value.format.datetime";
+
+
+ /**
+ * Keys represent the values which can be configured, and which are used for the rendering of dates.
+ *
+ */
+ private static Map<String, DateTimeFormatter> NAMED_TITLE_FORMATTERS = Maps.newHashMap();
+ static {
+ NAMED_TITLE_FORMATTERS.put("iso_encoding", ISODateTimeFormat.basicDateTime());
+ NAMED_TITLE_FORMATTERS.put("iso", ISODateTimeFormat.basicDateTimeNoMillis());
+ NAMED_TITLE_FORMATTERS.put("long", DateTimeFormat.forStyle("LL"));
+ NAMED_TITLE_FORMATTERS.put("medium", DateTimeFormat.forStyle("MM"));
+ NAMED_TITLE_FORMATTERS.put("short", DateTimeFormat.forStyle("SS"));
+ }
+
+ private final static ThreadLocal<String> OVERRIDE_TITLE_PATTERN = new ThreadLocal<String>() {
+ @Override
+ protected String initialValue() {
+ return null;
+ }
+ };
+
+
+ private final static List<DateTimeFormatter> PARSE_FORMATTERS = Lists.newArrayList();
+ static {
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("LL"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("MM"));
+ PARSE_FORMATTERS.add(DateTimeFormat.forStyle("SS"));
+ PARSE_FORMATTERS.add(ISODateTimeFormat.basicDateTimeNoMillis());
+ PARSE_FORMATTERS.add(ISODateTimeFormat.basicDateTime());
+ }
+
+
+
+ public static Class<? extends Facet> type() {
+ return JodaLocalDateTimeValueFacet.class;
+ }
+
// no default
private static final LocalDateTime DEFAULT_VALUE = null;
+ private final DateTimeFormatter encodingFormatter = ISODateTimeFormat.basicDateTime();
+
+ private DateTimeFormatter titleStringFormatter;
+ private String titleStringFormatNameOrPattern;
+
+
+ // //////////////////////////////////////
+ // constructor
+ // //////////////////////////////////////
+
/**
* Required because implementation of {@link Parser} and
* {@link EncoderDecoder}.
@@ -43,30 +142,135 @@ public class JodaLocalDateTimeValueSemanticsProvider extends JodaLocalDateTimeVa
this(null, null, null);
}
- public JodaLocalDateTimeValueSemanticsProvider(final FacetHolder holder, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
- super(holder, LocalDateTime.class, DEFAULT_VALUE, configuration, context);
+ /**
+ * Uses {@link #type()} as the facet type.
+ */
+ public JodaLocalDateTimeValueSemanticsProvider(
+ final FacetHolder holder, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
+ super(type(), holder, LocalDateTime.class, 12, Immutability.IMMUTABLE, EqualByContent.HONOURED, DEFAULT_VALUE, configuration, context);
+
+ String configuredNameOrPattern = getConfiguration().getString(CFG_FORMAT_KEY, "medium").toLowerCase().trim();
+ updateTitleStringFormatter(configuredNameOrPattern);
}
+
+ private void updateTitleStringFormatter(String titleStringFormatNameOrPattern) {
+ titleStringFormatter = NAMED_TITLE_FORMATTERS.get(titleStringFormatNameOrPattern);
+ if (titleStringFormatter == null) {
+ titleStringFormatter = DateTimeFormat.forPattern(titleStringFormatNameOrPattern);
+ }
+ this.titleStringFormatNameOrPattern = titleStringFormatNameOrPattern;
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // Parsing
+ // //////////////////////////////////////////////////////////////////
+
@Override
- protected LocalDateTime add(final LocalDateTime original, final int years, final int months, final int days, final int hours, final int minutes) {
- if(hours != 0 || minutes != 0) {
- throw new IllegalArgumentException("cannot add non-zero hours or minutes to a LocalDateTime");
+ protected LocalDateTime doParse(final Object context, final String entry, final Localization localization) {
+
+ updateTitleStringFormatterIfOverridden();
+
+ LocalDateTime contextDateTime = (LocalDateTime) context;
+
+ final String dateString = entry.trim().toUpperCase();
+ if (dateString.startsWith("+") && contextDateTime != null) {
+ return JodaLocalDateTimeUtil.relativeDateTime(contextDateTime, dateString, true);
+ } else if (dateString.startsWith("-") && contextDateTime != null) {
+ return JodaLocalDateTimeUtil.relativeDateTime(contextDateTime, dateString, false);
+ } else {
+ return parseDateTime(dateString, contextDateTime, localization);
+ }
+ }
+
+ private void updateTitleStringFormatterIfOverridden() {
+ final String overridePattern = OVERRIDE_TITLE_PATTERN.get();
+ if (overridePattern == null ||
+ titleStringFormatNameOrPattern.equals(overridePattern)) {
+ return;
+ }
+
+ // (re)create format
+ updateTitleStringFormatter(overridePattern);
+ }
+
+ private LocalDateTime parseDateTime(final String dateStr, final Object original, final Localization localization) {
+ return JodaLocalDateTimeUtil.parseDate(dateStr, localization, PARSE_FORMATTERS);
+ }
+
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // TitleProvider
+ // ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String titleString(final Object value, final Localization localization) {
+ if (value == null) {
+ return null;
+ }
+ final LocalDateTime dateTime = (LocalDateTime) value;
+ DateTimeFormatter f = titleStringFormatter;
+ if (localization != null) {
+ f = titleStringFormatter.withLocale(localization.getLocale());
+ }
+ return JodaLocalDateTimeUtil.titleString(f, dateTime);
+ }
+
+ @Override
+ public String titleStringWithMask(final Object value, final String usingMask) {
+ final LocalDateTime dateTime = (LocalDateTime) value;
+ return JodaLocalDateTimeUtil.titleString(DateTimeFormat.forPattern(usingMask), dateTime);
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // EncoderDecoder
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected String doEncode(final Object object) {
+ final LocalDateTime date = (LocalDateTime) object;
+ return encode(date);
+ }
+
+ private synchronized String encode(final LocalDateTime date) {
+ return encodingFormatter.print(date);
+ }
+
+ @Override
+ protected LocalDateTime doRestore(final String data) {
+ try {
+ return parse(data);
+ } catch (final IllegalArgumentException e) {
+ throw new EncodingException(e);
}
- return original.plusYears(years).plusMonths(months).plusDays(days);
}
+ private synchronized LocalDateTime parse(final String data) {
+ return encodingFormatter.parseLocalDateTime(data);
+ }
+
+ // //////////////////////////////////////////////////////////////////
+ // JodaLocalDateValueFacet
+ // //////////////////////////////////////////////////////////////////
+
@Override
- protected LocalDateTime now() {
- return new LocalDateTime();
+ public final LocalDateTime dateValue(final ObjectAdapter object) {
+ return (LocalDateTime) (object == null ? null : object.getObject());
}
@Override
- protected Date dateValue(final Object value) {
- return ((LocalDateTime) value).toDateTime().toDate();
+ public final ObjectAdapter createValue(final LocalDateTime date) {
+ return getAdapterManager().adapterFor(date);
}
+
+ // //////////////////////////////////////
+
@Override
- protected LocalDateTime setDate(final Date date) {
- return new LocalDateTime(date.getTime());
+ public String toString() {
+ return "JodaLocalDateValueSemanticsProvider: " + titleStringFormatter;
}
+
}
http://git-wip-us.apache.org/repos/asf/isis/blob/192b6b22/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProviderAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProviderAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProviderAbstract.java
deleted file mode 100644
index dc94786..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/value/datetimejodalocal/JodaLocalDateTimeValueSemanticsProviderAbstract.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.isis.core.progmodel.facets.value.datetimejodalocal;
-
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import com.google.common.collect.Maps;
-
-import org.apache.isis.applib.profiles.Localization;
-import org.apache.isis.core.commons.config.ConfigurationConstants;
-import org.apache.isis.core.commons.config.IsisConfiguration;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.progmodel.facets.object.value.ValueSemanticsProviderContext;
-import org.apache.isis.core.progmodel.facets.value.ValueSemanticsProviderAbstractTemporal;
-
-public abstract class JodaLocalDateTimeValueSemanticsProviderAbstract<T> extends ValueSemanticsProviderAbstractTemporal<T> {
-
- private static Map<String, DateFormat> formats = Maps.newHashMap();
-
- static {
- formats.put(ISO_ENCODING_FORMAT, createDateEncodingFormat("yyyyMMdd"));
- formats.put("iso", createDateFormat("yyyy-MM-dd"));
- formats.put("medium", DateFormat.getDateInstance(DateFormat.MEDIUM));
- }
-
- public JodaLocalDateTimeValueSemanticsProviderAbstract(final FacetHolder holder, final Class<T> adaptedClass, final T defaultValue, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
- super("date", holder, adaptedClass, 12, Immutability.IMMUTABLE, EqualByContent.HONOURED, defaultValue, configuration, context);
-
- final String formatRequired = configuration.getString(ConfigurationConstants.ROOT + "value.format.date");
- if (formatRequired == null) {
- format = formats().get(defaultFormat());
- } else {
- setMask(formatRequired);
- }
- }
-
-
- // //////////////////////////////////////////////////////////////////
- // temporal-specific stuff
- // //////////////////////////////////////////////////////////////////
-
- @Override
- protected void clearFields(final Calendar cal) {
- cal.set(Calendar.HOUR, 0);
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- cal.set(Calendar.AM_PM, 0);
- cal.set(Calendar.MILLISECOND, 0);
- }
-
- @Override
- protected String defaultFormat() {
- return "medium";
- }
-
- @Override
- protected boolean ignoreTimeZone() {
- return true;
- }
-
- @Override
- protected Map<String, DateFormat> formats() {
- return formats;
- }
-
- @Override
- public String toString() {
- return "DateValueSemanticsProvider: " + format;
- }
-
- @Override
- protected DateFormat format(final Localization localization) {
- final DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, localization.getLocale());
- dateFormat.setTimeZone(UTC_TIME_ZONE);
- return dateFormat;
- }
-
- protected List<DateFormat> formatsToTry(Localization localization) {
- List<DateFormat> formats = new ArrayList<DateFormat>();
-
- Locale locale = localization == null ? Locale.getDefault() : localization.getLocale();
- formats.add(DateFormat.getDateInstance(DateFormat.LONG, locale));
- formats.add(DateFormat.getDateInstance(DateFormat.MEDIUM, locale));
- formats.add(DateFormat.getDateInstance(DateFormat.SHORT, locale));
- formats.add(createDateFormat("yyyy-MM-dd"));
- formats.add(createDateFormat("yyyyMMdd"));
-
- for (DateFormat format : formats) {
- format.setTimeZone(UTC_TIME_ZONE);
- }
-
- return formats;
- }
-
-}