From c4068d27bf9ce04fe86bbd6a24af8fc445fec3d1 Mon Sep 17 00:00:00 2001 From: Dustin Johnson Date: Fri, 11 Jan 2013 12:23:15 -0600 Subject: [PATCH] Issue #1453 Fix handling of active period across year boundary Change-Id: I6bd5f075d74d394eab2a47a2b5fee3e2d91fd272 Former-commit-id: eb1c45cff6c9b0a6b5d194e8f5b9b582646ebde2 --- .../CreateSubscriptionDlgPresenter.java | 11 +- .../datadelivery/registry/Subscription.java | 6 + .../uf/common/time/CalendarBuilder.java | 174 ++++++++++++++++++ .../registry/SubscriptionTest.java | 23 ++- .../CreateSubscriptionPresenterTest.java | 59 +++++- 5 files changed, 265 insertions(+), 8 deletions(-) create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/CalendarBuilder.java diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java index 92f54e66c8..4206bb890e 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java @@ -99,6 +99,7 @@ import com.raytheon.viz.ui.presenter.components.WidgetConf; * Jan 02, 2012 1345 djohnson Use gui thread task executor. * Jan 02, 2013 1441 djohnson Access GroupDefinitionManager in a static fashion. * Jan 04, 2012 1420 mpduff Add Latency to PriorityComp. + * Jan 11, 2013 1453 djohnson Sets cycle times on construction. * * * @author mpduff @@ -165,8 +166,7 @@ public class CreateSubscriptionDlgPresenter { private final IGuiThreadTaskExecutor guiThreadTaskExecutor; - @VisibleForTesting - Set cycleTimes; + private final Set cycleTimes; private final ISubscriptionNotificationService subscriptionNotificationService = DataDeliveryServices .getSubscriptionNotificationService(); @@ -188,6 +188,10 @@ public class CreateSubscriptionDlgPresenter { this.create = create; this.guiThreadTaskExecutor = guiThreadTaskExecutor; + // Get cycles + cycleTimes = Sets.newTreeSet(((OpenDapGriddedDataSet) dataSet) + .getCycles()); + groupComboAction = new Runnable() { @Override public void run() { @@ -227,9 +231,6 @@ public class CreateSubscriptionDlgPresenter { init(); } }; - // Get cycles - cycleTimes = Sets.newTreeSet(((OpenDapGriddedDataSet) dataSet) - .getCycles()); this.view.setCycleTimes(cycleTimes); this.view.setSubscription(this.subscription); this.view.setPreOpenCallback(callback); diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java index 9dd5c08587..a7eb9581e0 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java @@ -872,6 +872,12 @@ public class Subscription implements ISerializableObject, Serializable { endCal.setTime(activePeriodEnd); endCal = TimeUtil.maxCalendarFields(endCal, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND); + + // If the period crosses a year boundary, add a year to the end + if (endCal.before(startCal)) { + endCal.add(Calendar.YEAR, 1); + } + activePeriodEnd = endCal.getTime(); diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/CalendarBuilder.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/CalendarBuilder.java new file mode 100644 index 0000000000..d1a1aedd8e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/CalendarBuilder.java @@ -0,0 +1,174 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time; + +import java.util.Calendar; +import java.util.TimeZone; + +import com.raytheon.uf.common.time.util.TimeUtil; + +/** + * Build {@link Calendar} objects. Note: Defaults to the GMT timezone since that + * is most often used. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1453       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class CalendarBuilder { + + private static final int UNSET = -1; + + private int year = UNSET; + + private int month = UNSET; + + private int dayOfMonth = UNSET; + + private int hourOfDay = UNSET; + + private int minute = UNSET; + + private int second = UNSET; + + private int millisecond = UNSET; + + private TimeZone timeZone = TimeZone.getTimeZone("GMT"); + + /** + * @param timeZone + * the timeZone to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + return this; + } + + /** + * @param year + * the year to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withYear(int year) { + this.year = year; + return this; + } + + /** + * @param month + * the month to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withMonth(int month) { + this.month = month; + return this; + } + + /** + * @param dayOfMonth + * the dayOfMonth to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withDayOfMonth(int dayOfMonth) { + this.dayOfMonth = dayOfMonth; + return this; + } + + /** + * @param hourOfDay + * the hourOfDay to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withHourOfDay(int hour) { + this.hourOfDay = hour; + return this; + } + + /** + * @param minute + * the minute to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withMinute(int minute) { + this.minute = minute; + return this; + } + + /** + * @param second + * the second to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withSecond(int second) { + this.second = second; + return this; + } + + /** + * @param millisecond + * the millisecond to set + * @return a {@link CalendarBuilder} to keep building with + */ + public CalendarBuilder withMillisecond(int millisecond) { + this.millisecond = millisecond; + return this; + } + + public Calendar build() { + Calendar calendar = TimeUtil.newCalendar(timeZone); + + setIfRequired(Calendar.YEAR, year, calendar); + setIfRequired(Calendar.MONTH, month, calendar); + setIfRequired(Calendar.DAY_OF_MONTH, dayOfMonth, calendar); + setIfRequired(Calendar.HOUR_OF_DAY, hourOfDay, calendar); + setIfRequired(Calendar.MINUTE, minute, calendar); + setIfRequired(Calendar.SECOND, second, calendar); + setIfRequired(Calendar.MILLISECOND, millisecond, calendar); + + return calendar; + } + + /** + * Set the {@link Calendar} field if required. + * + * @param field + * the calendar field constant, example: {@link Calendar#YEAR}. + * @param value + * the int value + * @param calendar + * the calendar instance + */ + private void setIfRequired(int field, int value, Calendar calendar) { + if (value != UNSET) { + calendar.set(field, value); + } + } + +} diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionTest.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionTest.java index 2fed4a035b..e8a12ba175 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionTest.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionTest.java @@ -33,6 +33,7 @@ import org.junit.Before; import org.junit.Test; import com.raytheon.uf.common.datadelivery.registry.Utils.SubscriptionStatus; +import com.raytheon.uf.common.time.CalendarBuilder; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.time.util.TimeUtilTest; @@ -46,7 +47,8 @@ import com.raytheon.uf.common.time.util.TimeUtilTest; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Aug 27, 2012 0743 djohnson Initial creation - * Jan 02, 2012 1345 djohnson Fix broken assertion that id matches copied object. + * Jan 02, 2013 1345 djohnson Fix broken assertion that id matches copied object. + * Jan 11, 2013 1453 djohnson Add test for active period crossing year boundary. * * * @@ -176,4 +178,23 @@ public class SubscriptionTest { assertThat(subscription.getStatus(), is(equalTo(SubscriptionStatus.INACTIVE.toString()))); } + + @Test + public void testGetStatusReturnsActiveForSubscriptionWithinActiveWindowCrossingYearBoundary() { + CalendarBuilder calBuilder = new CalendarBuilder() + .withMonth(Calendar.JANUARY).withDayOfMonth(10).withYear(1970); + + Calendar cal = calBuilder.build(); + final Date januaryTenth = cal.getTime(); + + final Date januaryFirst = calBuilder.withDayOfMonth(1).build() + .getTime(); + + Subscription subscription = new SubscriptionBuilder() + .withActivePeriodStart(januaryTenth) + .withActivePeriodEnd(januaryFirst).build(); + + assertThat(subscription.getStatus(), + is(equalTo(SubscriptionStatus.ACTIVE.toString()))); + } } diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionPresenterTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionPresenterTest.java index 8b155b539a..f6cb6600ff 100644 --- a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionPresenterTest.java +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionPresenterTest.java @@ -46,6 +46,7 @@ import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.SubscriptionBuilder; import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; +import com.raytheon.uf.common.time.CalendarBuilder; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.time.util.TimeUtilTest; import com.raytheon.uf.viz.core.SameThreadGuiTaskExecutor; @@ -69,6 +70,7 @@ import com.raytheon.uf.viz.datadelivery.subscription.view.ICreateSubscriptionDlg * Nov 20, 2012 1286 djohnson {@link ISubscriptionService} now takes the view. * Jan 02, 2012 1345 djohnson Remove obsolete test. * Jan 04, 2013 1453 djohnson Add tests for setting the active period. + * Jan 11, 2013 1453 djohnson Add test from failed test scenario. * * * @@ -305,7 +307,6 @@ public class CreateSubscriptionPresenterTest { @Test public void testActivePeriodEndCrossingYearBoundary() throws ParseException { - Calendar cal = TimeUtil.newGmtCalendar(); cal.set(Calendar.MONTH, Calendar.DECEMBER); cal.set(Calendar.DAY_OF_MONTH, 30); @@ -349,14 +350,68 @@ public class CreateSubscriptionPresenterTest { argThat(yyyyMmDdMatches(expectedEndCalendar.getTime()))); } + /** + * Taken from the following tester comments:
+ * When creating a subscription, if the Active Period End date is set to a + * month/day that is earlier than the month/day of the Active Period Start + * date (e.g., Active Period Start date = 01/10/2013 and Active Period End + * date = 01/01/2014), the subscription will go through successfully. Then, + * when editing the subscription and clicking on the Select Date for both + * the Active Period Start and End dates, the Active Period Start date + * (01/10/2014) is after the Active Period End date (01/01/2014). A check + * needs to be added such that if the Start date is after the End date, the + * year for the End date needs to increase by 1 (year + 1). While the year + * has no affect on the Active Period Start and End dates (and associated + * functionality), there may be confusion with the end user. + * + * @throws ParseException + */ + @Test + public void testActivePeriodWhereStartIsDayOfYearAfterEnd() + throws ParseException { + Calendar cal = new CalendarBuilder().withMonth(Calendar.JANUARY) + .withDayOfMonth(10).withYear(2013).build(); + + final Date januaryTenth = cal.getTime(); + + cal.set(Calendar.YEAR, 1970); + final Date startDate = cal.getTime(); + + Calendar cal2 = new CalendarBuilder().withMonth(Calendar.JANUARY) + .withDayOfMonth(1).withYear(2014).build(); + final Date januaryFirstYearLater = cal2.getTime(); + + cal2.set(Calendar.YEAR, 1970); + final Date endDate = cal2.getTime(); + + Subscription subscription = new SubscriptionBuilder() + .withActivePeriodStart(startDate).withActivePeriodEnd(endDate) + .build(); + + // freeze time at start date plus a minute + TimeUtilTest.freezeTime(januaryTenth.getTime() + + TimeUtil.MILLIS_PER_MINUTE); + + CreateSubscriptionDlgPresenter presenter = new CreateSubscriptionDlgPresenter( + view, dataSet, true, new SameThreadGuiTaskExecutor()); + presenter.setSubscriptionData(subscription); + presenter.init(); + + verify(view).setActiveStartDate(argThat(yyyyMmDdMatches(januaryTenth))); + verify(view).setActiveEndDate( + argThat(yyyyMmDdMatches(januaryFirstYearLater))); + } + @Test public void verifySubscriptionSetToView() { + presenter.open(); verify(view).setSubscription(presenter.getSubscription()); } @Test public void verifyCycleTimesSetToView() { - verify(view).setCycleTimes(presenter.cycleTimes); + presenter.open(); + verify(view).setCycleTimes(dataSet.getCycles()); } }