diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml
index d8b605eedf..2f09ea5b40 100644
--- a/config/alfresco/application-context.xml
+++ b/config/alfresco/application-context.xml
@@ -52,6 +52,7 @@
+
diff --git a/config/alfresco/model/dictionaryModel.xml b/config/alfresco/model/dictionaryModel.xml
index 9bee7d365a..e870393d6c 100644
--- a/config/alfresco/model/dictionaryModel.xml
+++ b/config/alfresco/model/dictionaryModel.xml
@@ -112,6 +112,11 @@
org.alfresco.repo.search.impl.lucene.analysis.VerbatimAnalyserorg.alfresco.util.VersionNumber
+
+
+ org.alfresco.repo.search.impl.lucene.analysis.VerbatimAnalyser
+ org.alfresco.service.cmr.repository.Period
+
diff --git a/source/java/org/alfresco/cmis/mapping/CMISMapping.java b/source/java/org/alfresco/cmis/mapping/CMISMapping.java
index 79ea7b9ea4..cd099fe1de 100644
--- a/source/java/org/alfresco/cmis/mapping/CMISMapping.java
+++ b/source/java/org/alfresco/cmis/mapping/CMISMapping.java
@@ -156,6 +156,7 @@ public class CMISMapping implements InitializingBean
mapAlfrescoToCmisDataType.put(DataTypeDefinition.FLOAT, CMISDataTypeEnum.DECIMAL);
mapAlfrescoToCmisDataType.put(DataTypeDefinition.INT, CMISDataTypeEnum.INTEGER);
mapAlfrescoToCmisDataType.put(DataTypeDefinition.LOCALE, null);
+ mapAlfrescoToCmisDataType.put(DataTypeDefinition.PERIOD, null);
mapAlfrescoToCmisDataType.put(DataTypeDefinition.LONG, CMISDataTypeEnum.INTEGER);
mapAlfrescoToCmisDataType.put(DataTypeDefinition.MLTEXT, CMISDataTypeEnum.STRING);
mapAlfrescoToCmisDataType.put(DataTypeDefinition.NODE_REF, CMISDataTypeEnum.ID);
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/AbstractCalendarPeriodProvider.java b/source/java/org/alfresco/repo/dictionary/types/period/AbstractCalendarPeriodProvider.java
new file mode 100644
index 0000000000..93a89c78bb
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/AbstractCalendarPeriodProvider.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Support for calendar based periods
+ * @author andyh
+ *
+ */
+public abstract class AbstractCalendarPeriodProvider extends AbstractPeriodProvider
+{
+
+ public String getDefaultExpression()
+ {
+ return "1";
+ }
+
+ public ExpressionMutiplicity getExpressionMutiplicity()
+ {
+ return ExpressionMutiplicity.OPTIONAL;
+ }
+
+ public Date getNextDate(Date date, String expression)
+ {
+ int value = Integer.parseInt(expression);
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ add(calendar, value);
+ Date next = calendar.getTime();
+ return next;
+ }
+
+ /**
+ * Implementation add
+ * @param calendar
+ * @param value
+ */
+ public abstract void add(Calendar calendar, int value);
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/AbstractEndOfCalendarPeriodProvider.java b/source/java/org/alfresco/repo/dictionary/types/period/AbstractEndOfCalendarPeriodProvider.java
new file mode 100644
index 0000000000..e08790d463
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/AbstractEndOfCalendarPeriodProvider.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * Support for calendar based "end of" periods with month and day offsets for fiscal year support
+ * @author andyh
+ *
+ */
+public abstract class AbstractEndOfCalendarPeriodProvider extends AbstractCalendarPeriodProvider
+{
+ private int startDayOfMonth = 1;
+
+ private int startMonth = Calendar.JANUARY;
+
+ /**
+ * Get the start day of the month (as defined by Calendar)
+ * @return - the start day of the month
+ */
+ public int getStartDayOfMonth()
+ {
+ return startDayOfMonth;
+ }
+
+ /**
+ * Set the start day of the month (as defined by Calendar)
+ * @param startDayOfMonth
+ */
+ public void setStartDayOfMonth(int startDayOfMonth)
+ {
+ this.startDayOfMonth = startDayOfMonth;
+ }
+
+ /**
+ * Get the start month (as defined by Calendar)
+ * @return - the start month
+ */
+ public int getStartMonth()
+ {
+ return startMonth;
+ }
+
+ /**
+ * Set the start month (as defined by Calendar)
+ * @param startMonth
+ */
+ public void setStartMonth(int startMonth)
+ {
+ this.startMonth = startMonth;
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/AbstractPeriodProvider.java b/source/java/org/alfresco/repo/dictionary/types/period/AbstractPeriodProvider.java
new file mode 100644
index 0000000000..1444cb5683
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/AbstractPeriodProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import org.alfresco.service.cmr.repository.Period;
+import org.alfresco.service.cmr.repository.PeriodProvider;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Common support for period implementations.
+ *
+ * They are Spring beans that register in the bootstrap context.
+ *
+ * @author andyh
+ *
+ */
+public abstract class AbstractPeriodProvider implements PeriodProvider, InitializingBean
+{
+ /**
+ * Default constructor
+ */
+ public AbstractPeriodProvider()
+ {
+ super();
+ }
+
+ public void afterPropertiesSet() throws Exception
+ {
+ Period.registerProvider(this);
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Cron.java b/source/java/org/alfresco/repo/dictionary/types/period/Cron.java
new file mode 100644
index 0000000000..24544c3ea2
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Cron.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.text.ParseException;
+import java.util.Date;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.quartz.CronExpression;
+
+/**
+ * Cron based periods
+ * @author andyh
+ *
+ */
+public class Cron extends AbstractPeriodProvider
+{
+ /**
+ * Period type
+ */
+ public static final String PERIOD_TYPE = "cron";
+
+ public String getDefaultExpression()
+ {
+ return "59 59 23 * * ?";
+ }
+
+ public ExpressionMutiplicity getExpressionMutiplicity()
+ {
+ return ExpressionMutiplicity.MANDATORY;
+ }
+
+ public Date getNextDate(Date date, String expression)
+ {
+ CronExpression ce;
+ try
+ {
+ ce = new CronExpression(expression);
+ }
+ catch (ParseException e)
+ {
+ throw new AlfrescoRuntimeException("Invalid cron expression: "+expression);
+ }
+ return ce.getNextValidTimeAfter(date);
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Days.java b/source/java/org/alfresco/repo/dictionary/types/period/Days.java
new file mode 100644
index 0000000000..531059d07f
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Days.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+
+/**
+ * Day based periods
+ * @author andyh
+ *
+ */
+public class Days extends AbstractCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "day";
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ calendar.add(Calendar.DAY_OF_YEAR, value);
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialMonth.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialMonth.java
new file mode 100644
index 0000000000..0941de42f3
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialMonth.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+/**
+ * End of financial month
+ * @author andyh
+ *
+ */
+public class EndOfFinancialMonth extends EndOfMonth
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "fmend";
+
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialQuarter.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialQuarter.java
new file mode 100644
index 0000000000..c93c58010f
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialQuarter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+/**
+ * End of financial quarter
+ * @author andyh
+ *
+ */
+public class EndOfFinancialQuarter extends EndOfQuarter
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "fqend";
+
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialYear.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialYear.java
new file mode 100644
index 0000000000..624af2a73e
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfFinancialYear.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+/**
+ * End of financial year
+ * @author andyh
+ *
+ */
+public class EndOfFinancialYear extends EndOfYear
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "fyend";
+
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfMonth.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfMonth.java
new file mode 100644
index 0000000000..62781b4060
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfMonth.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * End of month
+ * @author andyh
+ *
+ */
+public class EndOfMonth extends AbstractEndOfCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "monthend";
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ // Add a milli to nudge roll over given a month end date
+ if (value > 0)
+ {
+ calendar.add(Calendar.MILLISECOND, 1);
+ }
+
+ int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ if(dayOfMonth < getStartDayOfMonth())
+ {
+ calendar.add(Calendar.MONTH, value-1);
+ }
+ else
+ {
+ calendar.add(Calendar.MONTH, value);
+ }
+
+ calendar.set(Calendar.DAY_OF_MONTH, getStartDayOfMonth());
+ calendar.add(Calendar.DAY_OF_YEAR, -1);
+
+ // Set the time one minute to midnight
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfQuarter.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfQuarter.java
new file mode 100644
index 0000000000..934f0f8fd6
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfQuarter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * End of quarter
+ * @author andyh
+ *
+ */
+public class EndOfQuarter extends AbstractEndOfCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "quarterend";
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ // Add a milli to nudge roll over given a quarter end date
+ if (value > 0)
+ {
+ calendar.add(Calendar.MILLISECOND, 1);
+ }
+
+ int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ int month = calendar.get(Calendar.MONTH);
+ int monthInYear = month - getStartMonth();
+ if(monthInYear < 0)
+ {
+ monthInYear += 12;
+ }
+ int residualMonths = monthInYear % 3;
+ if(dayOfMonth < getStartDayOfMonth() && (residualMonths == 0))
+ {
+ calendar.add(Calendar.MONTH, (value-1)*3);
+
+ }
+ else
+ {
+ calendar.add(Calendar.MONTH, value*3);
+ }
+
+ calendar.add(Calendar.MONTH, -residualMonths);
+ calendar.set(Calendar.DAY_OF_MONTH, getStartDayOfMonth());
+ calendar.add(Calendar.DAY_OF_YEAR, -1);
+
+ // Set the time one minute to midnight
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/EndOfYear.java b/source/java/org/alfresco/repo/dictionary/types/period/EndOfYear.java
new file mode 100644
index 0000000000..2fcbc63972
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/EndOfYear.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * End of year
+ * @author andyh
+ *
+ */
+public class EndOfYear extends AbstractEndOfCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "yearend";
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ // Add a milli to nudge roll over given a year end date
+ if (value > 0)
+ {
+ calendar.add(Calendar.MILLISECOND, 1);
+ }
+
+ int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ int month = calendar.get(Calendar.MONTH);
+ if ((month < getStartMonth()) || ((dayOfMonth < getStartDayOfMonth()) && (month == getStartMonth())))
+ {
+ calendar.add(Calendar.YEAR, value - 1);
+ }
+ else
+ {
+ calendar.add(Calendar.YEAR, value);
+ }
+
+ calendar.set(Calendar.MONTH, getStartMonth());
+ calendar.set(Calendar.DAY_OF_MONTH, getStartDayOfMonth());
+
+ calendar.add(Calendar.DAY_OF_YEAR, -1);
+
+ // Set the time one minute to midnight
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Months.java b/source/java/org/alfresco/repo/dictionary/types/period/Months.java
new file mode 100644
index 0000000000..ee5376cae3
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Months.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * Months
+ * @author andyh
+ *
+ */
+public class Months extends AbstractCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "month";
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ calendar.add(Calendar.MONTH, value);
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/NoPeriod.java b/source/java/org/alfresco/repo/dictionary/types/period/NoPeriod.java
new file mode 100644
index 0000000000..d04c9f172f
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/NoPeriod.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Date;
+/**
+ * No period
+ * Period type "none"
+ * @author andyh
+ *
+ */
+public class NoPeriod extends AbstractPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "none";
+
+ /**
+ * Default constructor
+ */
+ public NoPeriod()
+ {
+
+ }
+
+ public String getDefaultExpression()
+ {
+ return null;
+ }
+
+ public ExpressionMutiplicity getExpressionMutiplicity()
+ {
+ return ExpressionMutiplicity.NONE;
+ }
+
+ public Date getNextDate(Date date, String expression)
+ {
+ return null;
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/PeriodTest.java b/source/java/org/alfresco/repo/dictionary/types/period/PeriodTest.java
new file mode 100644
index 0000000000..3e46022aa3
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/PeriodTest.java
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.alfresco.service.cmr.repository.Period;
+import org.alfresco.service.cmr.repository.PeriodProvider;
+import org.alfresco.util.ApplicationContextHelper;
+import org.alfresco.util.CachingDateFormat;
+
+/**
+ * Tests for period implementations - persistence and search is tested elsewhere
+ *
+ * @author andyh
+ */
+public class PeriodTest extends TestCase
+{
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ ApplicationContextHelper.getApplicationContext();
+ }
+
+ /**
+ * "none"
+ */
+ public void testNoPeriod()
+ {
+ assertTrue(Period.getProviderNames().contains(NoPeriod.PERIOD_TYPE));
+ Period period = new Period(NoPeriod.PERIOD_TYPE);
+ assertNull(period.getNextDate(new Date()));
+
+ PeriodProvider provider = Period.getProvider(NoPeriod.PERIOD_TYPE);
+ assertNull(provider.getDefaultExpression());
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.NONE);
+ assertNull(provider.getNextDate(new Date(), null));
+ assertNull(provider.getNextDate(new Date(), ""));
+ assertNull(provider.getNextDate(new Date(), "meep"));
+ assertEquals(provider.getPeriodType(), NoPeriod.PERIOD_TYPE);
+ }
+
+ /**
+ * Days
+ */
+ public void testDays()
+ {
+ assertTrue(Period.getProviderNames().contains(Days.PERIOD_TYPE));
+ Period period = new Period(Days.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Days.PERIOD_TYPE + "|0");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_YEAR, 0);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Days.PERIOD_TYPE + "|1");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Days.PERIOD_TYPE + "|2");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_YEAR, 2);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ PeriodProvider provider = Period.getProvider(Days.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), Days.PERIOD_TYPE);
+ }
+
+ /**
+ * Weeks
+ */
+ public void testWeeks()
+ {
+ assertTrue(Period.getProviderNames().contains(Weeks.PERIOD_TYPE));
+ Period period = new Period(Weeks.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.WEEK_OF_YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Weeks.PERIOD_TYPE + "|0");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.WEEK_OF_YEAR, 0);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Weeks.PERIOD_TYPE + "|1");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.WEEK_OF_YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Weeks.PERIOD_TYPE + "|2");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.WEEK_OF_YEAR, 2);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ PeriodProvider provider = Period.getProvider(Weeks.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), Weeks.PERIOD_TYPE);
+ }
+
+ /**
+ * Months
+ */
+ public void testMonths()
+ {
+ assertTrue(Period.getProviderNames().contains(Months.PERIOD_TYPE));
+ Period period = new Period(Months.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Months.PERIOD_TYPE + "|0");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 0);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Months.PERIOD_TYPE + "|1");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Months.PERIOD_TYPE + "|2");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 2);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ PeriodProvider provider = Period.getProvider(Months.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), Months.PERIOD_TYPE);
+ }
+
+ /**
+ * Quarters
+ */
+ public void testQuarters()
+ {
+ assertTrue(Period.getProviderNames().contains(Quarters.PERIOD_TYPE));
+ Period period = new Period(Quarters.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 3);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Quarters.PERIOD_TYPE + "|0");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 0);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Quarters.PERIOD_TYPE + "|1");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 3);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Quarters.PERIOD_TYPE + "|2");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 6);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ PeriodProvider provider = Period.getProvider(Quarters.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), Quarters.PERIOD_TYPE);
+ }
+
+ /**
+ * Years
+ */
+ public void testYears()
+ {
+ assertTrue(Period.getProviderNames().contains(Years.PERIOD_TYPE));
+ Period period = new Period(Years.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Years.PERIOD_TYPE + "|0");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, 0);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Years.PERIOD_TYPE + "|1");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, 1);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ period = new Period(Years.PERIOD_TYPE + "|2");
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, 2);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ PeriodProvider provider = Period.getProvider(Years.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), Years.PERIOD_TYPE);
+ }
+
+ /**
+ * EndOfMonth
+ */
+ public void testEndOfMonth()
+ {
+ assertTrue(Period.getProviderNames().contains(EndOfMonth.PERIOD_TYPE));
+ Period period = new Period(EndOfMonth.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 1);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.add(Calendar.DAY_OF_MONTH, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ for (int i = -100; i < 100; i++)
+ {
+ period = new Period(EndOfMonth.PERIOD_TYPE + "|" + i);
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, i);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.add(Calendar.DAY_OF_MONTH, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+ }
+
+ PeriodProvider provider = Period.getProvider(EndOfMonth.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), EndOfMonth.PERIOD_TYPE);
+ }
+
+ /**
+ * EndOfYear
+ */
+ public void testEndOfYear()
+ {
+ assertTrue(Period.getProviderNames().contains(EndOfYear.PERIOD_TYPE));
+ Period period = new Period(EndOfYear.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, 1);
+ calendar.set(Calendar.DAY_OF_YEAR, 1);
+ calendar.add(Calendar.DAY_OF_YEAR, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ for (int i = -100; i < 100; i++)
+ {
+ period = new Period(EndOfYear.PERIOD_TYPE + "|" + i);
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.YEAR, i);
+ calendar.set(Calendar.DAY_OF_YEAR, 1);
+ calendar.add(Calendar.DAY_OF_YEAR, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+ }
+
+ PeriodProvider provider = Period.getProvider(EndOfYear.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), EndOfYear.PERIOD_TYPE);
+ }
+
+ /**
+ * End of Quarter
+ *
+ * @throws ParseException
+ */
+ public void testEndOfQuarter() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfQuarter.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfQuarter.PERIOD_TYPE);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfQuarter.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2009-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T00:00:00.000");
+ assertEquals("2009-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-01T00:00:00.000");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-01T23:59:59.999");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.998");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-10-01T23:59:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfQuarter.PERIOD_TYPE + "|2");
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T00:00:00.000");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-01T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-01T23:59:59.999");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-10-01T23:59:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfQuarter.PERIOD_TYPE + "|3");
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-01T00:00:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-01T23:59:59.999");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-10-01T23:59:00.000");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:00.000");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfQuarter.PERIOD_TYPE + "|4");
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T00:00:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-01T00:00:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-01T23:59:59.999");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-10-01T23:59:00.000");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:00.000");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfQuarter.PERIOD_TYPE + "|5");
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T00:00:00.000");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-01T00:00:00.000");
+ assertEquals("2010-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-01T23:59:59.999");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2010-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-10-01T23:59:00.000");
+ assertEquals("2010-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:00.000");
+ assertEquals("2010-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ }
+
+ /**
+ * End of F Month For 1 Oct this is the same as month
+ */
+ public void testEndOfDefaultFinancialMonth()
+ {
+ assertTrue(Period.getProviderNames().contains(EndOfFinancialMonth.PERIOD_TYPE));
+ Period period = new Period(EndOfFinancialMonth.PERIOD_TYPE);
+ Date now = new Date();
+ assertNotNull(period.getNextDate(now));
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, 1);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.add(Calendar.DAY_OF_MONTH, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+
+ for (int i = -100; i < 100; i++)
+ {
+ period = new Period(EndOfFinancialMonth.PERIOD_TYPE + "|" + i);
+ assertNotNull(period.getNextDate(now));
+ calendar.setTime(now);
+ calendar.add(Calendar.MONTH, i);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.add(Calendar.DAY_OF_MONTH, -1);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ assertEquals(period.getNextDate(now), calendar.getTime());
+ }
+
+ PeriodProvider provider = Period.getProvider(EndOfFinancialMonth.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertNotNull(provider.getNextDate(now, "0"));
+ assertNotNull(provider.getNextDate(now, "1"));
+ assertNotNull(provider.getNextDate(now, "2"));
+ assertEquals(provider.getPeriodType(), EndOfFinancialMonth.PERIOD_TYPE);
+ }
+
+ /**
+ * EndOfFinacialYear
+ *
+ * @throws ParseException
+ */
+ public void testEndOfDefaultFinancialYear() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfFinancialYear.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfFinancialYear.PERIOD_TYPE);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfFinancialYear.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2008-10-01T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.998");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2010-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfFinancialYear.PERIOD_TYPE + "|10");
+ date = df.parse("2008-10-01T00:00:00.000");
+ assertEquals("2018-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.998");
+ assertEquals("2018-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2019-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ }
+
+ /**
+ * End of FQ
+ *
+ * @throws ParseException
+ */
+ public void testEndOfDefaultFinancialQuarter() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfFinancialQuarter.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfFinancialQuarter.PERIOD_TYPE);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfFinancialQuarter.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2008-10-01T00:00:00.000");
+ assertEquals("2008-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-12-31T23:59:59.998");
+ assertEquals("2008-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-12-31T23:59:59.999");
+ assertEquals("2009-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-01-01T00:00:00.000");
+ assertEquals("2009-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T23:59:59.998");
+ assertEquals("2009-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-31T23:59:59.999");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-04-01T00:00:00.000");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.998");
+ assertEquals("2009-06-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-06-30T23:59:59.999");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-07-01T00:00:00.000");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.998");
+ assertEquals("2009-09-30T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-09-30T23:59:59.999");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-10-01T00:00:00.000");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:59.998");
+ assertEquals("2009-12-31T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-12-31T23:59:59.999");
+ assertEquals("2010-03-31T23:59:59.999", df.format(period.getNextDate(date)));
+ }
+
+ /**
+ * EndOfFinacialYear
+ *
+ * @throws ParseException
+ */
+ public void testEndOfUKTaxYear() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfFinancialYear.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfFinancialYear.PERIOD_TYPE);
+
+ AbstractEndOfCalendarPeriodProvider instance = (AbstractEndOfCalendarPeriodProvider) provider;
+ instance.setStartDayOfMonth(6);
+ instance.setStartMonth(Calendar.APRIL);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfFinancialYear.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2008-4-06T00:00:00.000");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.998");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.999");
+ assertEquals("2010-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ period = new Period(EndOfFinancialYear.PERIOD_TYPE + "|10");
+ date = df.parse("2008-4-06T00:00:00.000");
+ assertEquals("2018-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.998");
+ assertEquals("2018-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.999");
+ assertEquals("2019-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ }
+
+ /**
+ * End of FQ
+ *
+ * @throws ParseException
+ */
+ public void testEndOfUKTaxQuarter() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfFinancialQuarter.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfFinancialQuarter.PERIOD_TYPE);
+
+ AbstractEndOfCalendarPeriodProvider instance = (AbstractEndOfCalendarPeriodProvider) provider;
+ instance.setStartDayOfMonth(6);
+ instance.setStartMonth(Calendar.APRIL);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfFinancialQuarter.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2008-04-06T00:00:00.000");
+ assertEquals("2008-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-07-05T23:59:59.998");
+ assertEquals("2008-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-07-05T23:59:59.999");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-07-06T00:00:00.000");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-10-05T23:59:59.998");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-10-05T23:59:59.999");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-10-06T00:00:00.000");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-01-05T23:59:59.998");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-01-05T23:59:59.999");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-01-06T00:00:00.000");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.998");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.999");
+ assertEquals("2009-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-04-06T00:00:00.000");
+ assertEquals("2009-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-05T23:59:59.998");
+ assertEquals("2009-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-07-05T23:59:59.999");
+ assertEquals("2009-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+ }
+
+ /**
+ * End of FQ
+ *
+ * @throws ParseException
+ */
+ public void testEndOfUKTaxMonth() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(EndOfFinancialMonth.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "1");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.OPTIONAL);
+ assertEquals(provider.getPeriodType(), EndOfFinancialMonth.PERIOD_TYPE);
+
+ AbstractEndOfCalendarPeriodProvider instance = (AbstractEndOfCalendarPeriodProvider) provider;
+ instance.setStartDayOfMonth(6);
+ instance.setStartMonth(Calendar.APRIL);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(EndOfFinancialMonth.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2008-04-06T00:00:00.000");
+ assertEquals("2008-05-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-05-05T23:59:59.998");
+ assertEquals("2008-05-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-05-05T23:59:59.999");
+ assertEquals("2008-06-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-05-06T00:00:00.000");
+ assertEquals("2008-06-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-06-05T23:59:59.998");
+ assertEquals("2008-06-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-06-05T23:59:59.999");
+ assertEquals("2008-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-06-06T00:00:00.000");
+ assertEquals("2008-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-07-05T23:59:59.998");
+ assertEquals("2008-07-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-07-05T23:59:59.999");
+ assertEquals("2008-08-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-07-06T00:00:00.000");
+ assertEquals("2008-08-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-08-05T23:59:59.998");
+ assertEquals("2008-08-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-08-05T23:59:59.999");
+ assertEquals("2008-09-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-08-06T00:00:00.000");
+ assertEquals("2008-09-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-09-05T23:59:59.998");
+ assertEquals("2008-09-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-09-05T23:59:59.999");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-09-06T00:00:00.000");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-10-05T23:59:59.998");
+ assertEquals("2008-10-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-10-05T23:59:59.999");
+ assertEquals("2008-11-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-10-06T00:00:00.000");
+ assertEquals("2008-11-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-11-05T23:59:59.998");
+ assertEquals("2008-11-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-11-05T23:59:59.999");
+ assertEquals("2008-12-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-11-06T00:00:00.000");
+ assertEquals("2008-12-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-12-05T23:59:59.998");
+ assertEquals("2008-12-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2008-12-05T23:59:59.999");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2008-12-06T00:00:00.000");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-01-05T23:59:59.998");
+ assertEquals("2009-01-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-01-05T23:59:59.999");
+ assertEquals("2009-02-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-01-06T00:00:00.000");
+ assertEquals("2009-02-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-02-05T23:59:59.998");
+ assertEquals("2009-02-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-02-05T23:59:59.999");
+ assertEquals("2009-03-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-02-06T00:00:00.000");
+ assertEquals("2009-03-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-05T23:59:59.998");
+ assertEquals("2009-03-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-03-05T23:59:59.999");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-03-06T00:00:00.000");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.998");
+ assertEquals("2009-04-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-04-05T23:59:59.999");
+ assertEquals("2009-05-05T23:59:59.999", df.format(period.getNextDate(date)));
+
+ date = df.parse("2009-04-06T00:00:00.000");
+ assertEquals("2009-05-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-05-05T23:59:59.998");
+ assertEquals("2009-05-05T23:59:59.999", df.format(period.getNextDate(date)));
+ date = df.parse("2009-05-05T23:59:59.999");
+ assertEquals("2009-06-05T23:59:59.999", df.format(period.getNextDate(date)));
+ }
+
+ /**
+ * Cron
+ * @throws ParseException
+ */
+ public void testCron() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(Cron.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "59 59 23 * * ?");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.MANDATORY);
+ assertEquals(provider.getPeriodType(), Cron.PERIOD_TYPE);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(Cron.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2009-06-02T00:00:00.000");
+ assertEquals("2009-06-02T23:59:59.000", df.format(period.getNextDate(date)));
+
+ period = new Period(Cron.PERIOD_TYPE+"|0 0 2 ? * 6#1"); // First Friday of month
+ assertEquals("2009-06-05T02:00:00.000", df.format(period.getNextDate(date)));
+ }
+
+ /**
+ * XMLDuration
+ * @throws ParseException
+ */
+ public void testXMLDuration() throws ParseException
+ {
+ PeriodProvider provider = Period.getProvider(XMLDuration.PERIOD_TYPE);
+ assertEquals(provider.getDefaultExpression(), "P1D");
+ assertEquals(provider.getExpressionMutiplicity(), PeriodProvider.ExpressionMutiplicity.MANDATORY);
+ assertEquals(provider.getPeriodType(), XMLDuration.PERIOD_TYPE);
+
+ SimpleDateFormat df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true);
+ Period period = new Period(XMLDuration.PERIOD_TYPE);
+ Date date;
+ date = df.parse("2009-06-02T01:02:03.004");
+ assertEquals("2009-06-03T01:02:03.004", df.format(period.getNextDate(date)));
+
+ period = new Period(XMLDuration.PERIOD_TYPE+"|P2Y6M5DT12H35M30.100S"); // First Friday of month
+ assertEquals("2011-12-07T13:37:33.104", df.format(period.getNextDate(date)));
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Quarters.java b/source/java/org/alfresco/repo/dictionary/types/period/Quarters.java
new file mode 100644
index 0000000000..f1d9514e05
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Quarters.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * Quarters
+ * @author andyh
+ *
+ */
+public class Quarters extends AbstractCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "quarter";
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ calendar.add(Calendar.MONTH, value*3);
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Weeks.java b/source/java/org/alfresco/repo/dictionary/types/period/Weeks.java
new file mode 100644
index 0000000000..07c3f0bebb
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Weeks.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+/**
+ * Weeks
+ * @author andyh
+ *
+ */
+public class Weeks extends AbstractCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "week";
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ calendar.add(Calendar.WEEK_OF_YEAR, value);
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/XMLDuration.java b/source/java/org/alfresco/repo/dictionary/types/period/XMLDuration.java
new file mode 100644
index 0000000000..fa23495fd4
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/XMLDuration.java
@@ -0,0 +1,40 @@
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Date;
+
+import org.alfresco.service.cmr.repository.datatype.Duration;
+
+/**
+ * XMLDuration
+ * @author andyh
+ *
+ */
+public class XMLDuration extends AbstractPeriodProvider
+{
+ /**
+ * Period type
+ */
+ public static final String PERIOD_TYPE = "duration";
+
+ public String getDefaultExpression()
+ {
+ return "P1D";
+ }
+
+ public ExpressionMutiplicity getExpressionMutiplicity()
+ {
+ return ExpressionMutiplicity.MANDATORY;
+ }
+
+ public Date getNextDate(Date date, String expression)
+ {
+ Duration d = new Duration(expression);
+ return Duration.add(date, d);
+ }
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/dictionary/types/period/Years.java b/source/java/org/alfresco/repo/dictionary/types/period/Years.java
new file mode 100644
index 0000000000..7dabd3ed61
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/types/period/Years.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary.types.period;
+
+import java.util.Calendar;
+
+/**
+ * Years
+ * @author andyh
+ *
+ */
+public class Years extends AbstractCalendarPeriodProvider
+{
+ /**
+ *
+ */
+ public static final String PERIOD_TYPE = "year";
+
+ public String getPeriodType()
+ {
+ return PERIOD_TYPE;
+ }
+
+ @Override
+ public void add(Calendar calendar, int value)
+ {
+ calendar.add(Calendar.YEAR, value);
+ }
+}
diff --git a/source/java/org/alfresco/repo/domain/NodePropertyValue.java b/source/java/org/alfresco/repo/domain/NodePropertyValue.java
index d084ce92d6..d75e3b707c 100644
--- a/source/java/org/alfresco/repo/domain/NodePropertyValue.java
+++ b/source/java/org/alfresco/repo/domain/NodePropertyValue.java
@@ -45,6 +45,7 @@ import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
+import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
@@ -453,7 +454,28 @@ public class NodePropertyValue implements Cloneable, Serializable
return value;
}
}
- };
+ },
+ PERIOD
+ {
+ @Override
+ public Integer getOrdinalNumber()
+ {
+ return Integer.valueOf(20);
+ }
+
+ @Override
+ protected ValueType getPersistedType(Serializable value)
+ {
+ return ValueType.STRING;
+ }
+
+ @Override
+ Serializable convert(Serializable value)
+ {
+ return DefaultTypeConverter.INSTANCE.convert(Period.class, value);
+ }
+ }
+ ;
/**
* @return Returns the manually-maintained ordinal number for the value
@@ -555,6 +577,10 @@ public class NodePropertyValue implements Cloneable, Serializable
{
return ValueType.MLTEXT;
}
+ else if (value instanceof Period)
+ {
+ return ValueType.PERIOD;
+ }
else
{
// type is not recognised as belonging to any particular slot
@@ -590,6 +616,7 @@ public class NodePropertyValue implements Cloneable, Serializable
valueTypesByPropertyType.put(DataTypeDefinition.PATH, ValueType.PATH);
valueTypesByPropertyType.put(DataTypeDefinition.QNAME, ValueType.QNAME);
valueTypesByPropertyType.put(DataTypeDefinition.LOCALE, ValueType.LOCALE);
+ valueTypesByPropertyType.put(DataTypeDefinition.PERIOD, ValueType.PERIOD);
valueTypesByOrdinalNumber = new HashMap(37);
for (ValueType valueType : ValueType.values())
diff --git a/source/java/org/alfresco/repo/domain/PropertyValue.java b/source/java/org/alfresco/repo/domain/PropertyValue.java
index fa8c9a0cac..51b03c534a 100644
--- a/source/java/org/alfresco/repo/domain/PropertyValue.java
+++ b/source/java/org/alfresco/repo/domain/PropertyValue.java
@@ -48,6 +48,7 @@ import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
+import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
@@ -441,6 +442,26 @@ public class PropertyValue implements Cloneable, Serializable
{
return DefaultTypeConverter.INSTANCE.convert(VersionNumber.class, value);
}
+ },
+ PERIOD
+ {
+ @Override
+ public Integer getOrdinalNumber()
+ {
+ return Integer.valueOf(20);
+ }
+
+ @Override
+ protected ValueType getPersistedType(Serializable value)
+ {
+ return ValueType.STRING;
+ }
+
+ @Override
+ Serializable convert(Serializable value)
+ {
+ return DefaultTypeConverter.INSTANCE.convert(Period.class, value);
+ }
};
/**
@@ -567,6 +588,10 @@ public class PropertyValue implements Cloneable, Serializable
{
return ValueType.MLTEXT;
}
+ else if (value instanceof Period)
+ {
+ return ValueType.PERIOD;
+ }
else
{
// type is not recognised as belonging to any particular slot
@@ -602,6 +627,7 @@ public class PropertyValue implements Cloneable, Serializable
valueTypesByPropertyType.put(DataTypeDefinition.PATH, ValueType.PATH);
valueTypesByPropertyType.put(DataTypeDefinition.QNAME, ValueType.QNAME);
valueTypesByPropertyType.put(DataTypeDefinition.LOCALE, ValueType.LOCALE);
+ valueTypesByPropertyType.put(DataTypeDefinition.PERIOD, ValueType.PERIOD);
valueTypesByOrdinalNumber = new HashMap(37);
for (ValueType valueType : ValueType.values())
diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
index 6e918687d5..d395aa201e 100644
--- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
@@ -129,7 +129,8 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
public static final QName PROP_QNAME_CATEGORY_VALUE = QName.createQName(NAMESPACE, "categoryValue");
public static final QName PROP_QNAME_LOCALE_VALUE = QName.createQName(NAMESPACE, "localeValue");
public static final QName PROP_QNAME_NULL_VALUE = QName.createQName(NAMESPACE, "nullValue");
- public static final QName PROP_QNAME_MULTI_VALUE = QName.createQName(NAMESPACE, "multiValue");
+ public static final QName PROP_QNAME_MULTI_VALUE = QName.createQName(NAMESPACE, "multiValue");
+ public static final QName PROP_QNAME_PERIOD_VALUE = QName.createQName(NAMESPACE, "periodValue");
public static final QName PROP_QNAME_MULTI_ML_VALUE = QName.createQName(NAMESPACE, "multiMLValue");
public static final QName PROP_QNAME_MARKER_PROP = QName.createQName(NAMESPACE, "markerProp");
public static final QName PROP_QNAME_PROP1 = QName.createQName(NAMESPACE, "prop1");
@@ -1533,6 +1534,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
properties.put(PROP_QNAME_LOCALE_VALUE, Locale.CHINESE);
properties.put(PROP_QNAME_NULL_VALUE, null);
properties.put(PROP_QNAME_MULTI_VALUE, listProperty);
+ properties.put(PROP_QNAME_PERIOD_VALUE, "period|1");
// Get the check values
Map expectedProperties = new HashMap(properties);
getExpectedPropertyValues(expectedProperties);
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
index d45568dcd7..fb0504512c 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
@@ -81,6 +81,7 @@ import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
+import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.Duration;
@@ -314,6 +315,7 @@ public class ADMLuceneTest extends TestCase
testProperties.put(QName.createQName(TEST_NAMESPACE, "noderef-ista"), n1);
testProperties.put(QName.createQName(TEST_NAMESPACE, "path-ista"), nodeService.getPath(n3));
testProperties.put(QName.createQName(TEST_NAMESPACE, "locale-ista"), Locale.UK);
+ testProperties.put(QName.createQName(TEST_NAMESPACE, "period-ista"), new Period("period|12"));
testProperties.put(QName.createQName(TEST_NAMESPACE, "null"), null);
testProperties.put(QName.createQName(TEST_NAMESPACE, "list"), new ArrayList