2 * ============LICENSE_START==============================================
3 * Copyright (c) 2019 AT&T Intellectual Property.
4 * =======================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain a
7 * copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 * or implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 * ============LICENSE_END=================================================
20 package org.onap.optf.cmso.optimizer.availability.timewindows;
22 import com.google.ical.compat.jodatime.DateTimeIterator;
23 import com.google.ical.compat.jodatime.DateTimeIteratorFactory;
24 import java.text.ParseException;
25 import java.time.Instant;
26 import java.time.LocalDate;
27 import java.time.LocalDateTime;
28 import java.time.LocalTime;
29 import java.time.OffsetDateTime;
30 import java.time.OffsetTime;
31 import java.time.ZoneOffset;
32 import java.time.ZonedDateTime;
33 import java.time.temporal.ChronoUnit;
34 import java.util.ArrayList;
35 import java.util.Date;
36 import java.util.HashSet;
37 import java.util.List;
39 import org.joda.time.DateTime;
40 import org.joda.time.DateTimeZone;
41 import org.onap.observations.Observation;
42 import org.onap.optf.cmso.optimizer.availability.policies.model.AllowedPeriodicTime;
43 import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology;
44 import org.onap.optf.cmso.optimizer.availability.policies.model.TimeRange;
45 import org.onap.optf.cmso.optimizer.common.LogMessages;
46 import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow;
49 * The Class RecurringWindows.
51 public class RecurringWindows {
54 * Gets the availability windows for policies.
56 * @param policies the policies
57 * @param changeWindow the change window
58 * @return the availability windows for policies
60 public static List<ChangeWindow> getAvailabilityWindowsForPolicies(List<TimeLimitAndVerticalTopology> policies,
61 ChangeWindow changeWindow) {
62 List<ChangeWindow> availableList = new ArrayList<>();
63 for (TimeLimitAndVerticalTopology policy : policies) {
64 if (policy.getTimeSchedule() != null && policy.getTimeSchedule().getAllowedPeriodicTime() != null) {
65 for (AllowedPeriodicTime available : policy.getTimeSchedule().getAllowedPeriodicTime()) {
66 getAvailableWindowsForApt(available, changeWindow, availableList);
70 // Collapse all duplicate and overlapping availabity windows into minimum
72 availableList = collapseWindows(availableList);
78 private static List<ChangeWindow> collapseWindows(List<ChangeWindow> availableList) {
79 List<ChangeWindow> collapsed = new ArrayList<>();
80 Set<ChangeWindow> consumed = new HashSet<>();
81 for (ChangeWindow win : availableList) {
82 if (!consumed.contains(win)) {
83 // Find all windows that can collapse into this one
85 boolean allUnique = false;
88 for (ChangeWindow test : availableList) {
89 // if availability windows overlap
90 if (!consumed.contains(test)) {
91 if (win.absorbIfOverlapping(test)) {
104 // "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
105 private static void getAvailableWindowsForApt(AllowedPeriodicTime available, ChangeWindow changeWindow,
106 List<ChangeWindow> availableList) {
108 if (available.getDay() != null) {
109 switch (available.getDay()) {
112 getAvailableWindowsForAptDay(available, changeWindow, availableList);
118 availableList.add(changeWindow);
119 Observation.report(LogMessages.UNSUPPORTED_PERIODIC_TIME, available.toString());
123 // "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
125 private static void getAvailableWindowsForAptDay(AllowedPeriodicTime available, ChangeWindow changeWindow,
126 List<ChangeWindow> availableList) {
128 List<TimeRange> ranges = available.getTimeRange();
129 if (ranges.size() == 0) {
130 TimeRange range = new TimeRange();
131 range.setStart_time("00:00:00+00:00");
132 range.setStart_time("23:59:59+00:00");
135 StringBuilder rdata = new StringBuilder();
136 rdata.append(available.getDay().getRrule()).append("\n");
137 for (TimeRange range : ranges) {
138 processRange(range, changeWindow, availableList, rdata);
140 } catch (Exception e) {
141 Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage());
146 private static void processRange(TimeRange range, ChangeWindow changeWindow, List<ChangeWindow> availableList,
147 StringBuilder rdata) throws ParseException {
149 Instant cwStartInstant = changeWindow.getStartTime().toInstant();
150 Instant cwEndInstant = changeWindow.getEndTime().toInstant();
152 List<DateTime> startList = getRecurringList(range.getStart_time(), cwStartInstant, rdata, cwEndInstant);
153 List<DateTime> endList = getRecurringList(range.getEnd_time(), cwStartInstant, rdata, cwEndInstant);
154 // Pair them up to make change windows
155 // Everything should be UTC time
156 for (int i = 0; i < startList.size(); i++) {
157 DateTime startDt = startList.get(i);
158 if (i < endList.size()) {
159 DateTime endDt = endList.get(i);
160 if (endDt.isAfter(startDt)) {
161 ChangeWindow cw = new ChangeWindow();
162 cw.setStartTime(startDt.toDate());
163 cw.setEndTime(endDt.toDate());
164 availableList.add(cw);
173 private static List<DateTime> getRecurringList(String rangeTime, Instant cwStartInstant, StringBuilder rdata,
174 Instant cwEndInstant) throws ParseException {
176 Instant startInstant = getInstanceFromTime(rangeTime, cwStartInstant);
177 DateTime start = new DateTime(startInstant.toEpochMilli());
178 DateTimeIterator recur =
179 DateTimeIteratorFactory.createDateTimeIterator(rdata.toString(), start, DateTimeZone.UTC, true);
180 List<DateTime> list = new ArrayList<>();
181 while (recur.hasNext()) {
182 DateTime next = recur.next();
183 // System.out.println(next.toString());
184 if (next.isAfter(cwEndInstant.toEpochMilli())) {
194 // The policies with 'Day' enumeration only have time with no day so we add the
195 // date portion of the change window to the dtstart
197 private static Instant getInstanceFromTime(String timeIn, Instant cwStartInstant) {
198 Instant instant = null;
199 Instant date = cwStartInstant.truncatedTo(ChronoUnit.DAYS);
200 LocalDate epoch = LocalDate.ofEpochDay(0);
202 OffsetTime offset = OffsetTime.parse(timeIn);
203 OffsetDateTime odt = offset.atDate(epoch);
204 ZonedDateTime startTime = odt.atZoneSameInstant(ZoneOffset.UTC.normalized());
205 instant = Instant.from(startTime);
206 } catch (Exception e) {
207 LocalTime local = LocalTime.parse(timeIn);
208 LocalDateTime ldt = local.atDate(epoch);
209 ZonedDateTime startTime = ldt.atZone(ZoneOffset.UTC.normalized());
210 instant = Instant.from(startTime);
212 return instant.plus(date.toEpochMilli(), ChronoUnit.MILLIS);