/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package util; import static util.BourneUtil.getCatalogClient; import java.net.URI; import java.util.Calendar; import java.util.Collection; import java.util.List; import controllers.util.Models; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import org.joda.time.DateTimeZone; import play.Logger; import com.emc.storageos.model.NamedRelatedResourceRep; import com.emc.storageos.model.RelatedResourceRep; import com.emc.vipr.client.ViPRCatalogClient2; import com.emc.vipr.model.catalog.ExecutionWindowCreateParam; import com.emc.vipr.model.catalog.ExecutionWindowRestRep; import com.emc.vipr.model.catalog.ExecutionWindowUpdateParam; import com.google.common.collect.Lists; public class ExecutionWindowUtils { public static final int MAX_EVENTS = 25; public static final int TIME_RANGE_PADDING_IN_HOURS = 2; public static boolean isAnyExecutionWindowActive() { List<ExecutionWindowRestRep> windows = getExecutionWindows(); for (ExecutionWindowRestRep window : windows) { if (isExecutionWindowActive(window)) { return true; } } return false; } public static boolean isExecutionWindowActive(ExecutionWindowRestRep executionWindow) { if (executionWindow != null) { executionWindow.isActive(Calendar.getInstance()); } return false; } public static ExecutionWindowRestRep getActiveOrNextExecutionWindow() { return getActiveOrNextExecutionWindow(Calendar.getInstance()); } public static ExecutionWindowRestRep getActiveOrNextExecutionWindow(Calendar time) { List<ExecutionWindowRestRep> windows = ExecutionWindowUtils.getExecutionWindows(); // Check active windows ExecutionWindowRestRep activeWindow = getActiveExecutionWindow(windows, time); if (activeWindow != null) { return activeWindow; } else { // Check for next window return getNextExecutionWindow(windows, time); } } public static ExecutionWindowRestRep getNextExecutionWindow(Calendar time) { return getNextExecutionWindow(ExecutionWindowUtils.getExecutionWindows( URI.create(Models.currentAdminTenant()) ), time); } public static ExecutionWindowRestRep getActiveExecutionWindow(Collection<ExecutionWindowRestRep> windows, Calendar time) { for (ExecutionWindowRestRep window : windows) { if (window.isActive(time)) { return window; } } return null; } public static ExecutionWindowRestRep getNextExecutionWindow(Collection<ExecutionWindowRestRep> windows, Calendar time) { Calendar nextWindowTime = null; ExecutionWindowRestRep nextWindow = null; for (ExecutionWindowRestRep window : windows) { Calendar windowTime = calculateNextWindowTime(time, window); if (nextWindowTime == null || nextWindowTime.after(windowTime)) { nextWindowTime = windowTime; nextWindow = window; } } return nextWindow; } public static Calendar calculateNextWindowTime(ExecutionWindowRestRep window) { return calculateNextWindowTime(Calendar.getInstance(), window); } public static Calendar calculateNextWindowTime(Calendar time, ExecutionWindowRestRep window) { return window.calculateNext(time); } public static boolean isOverlapping(ExecutionWindowRestRep newExecutionWindow) { DateTimeZone tz = DateTimeZone.UTC; List<ExecutionWindowRestRep> executionWindows = ExecutionWindowUtils.getExecutionWindows(); DateTime startOfWeek = getStartOfWeek(tz); DateTime endDateTime = startOfWeek.plusDays(31); List<Event> events = asEvents(executionWindows, startOfWeek, endDateTime, tz); List<Event> newEvents = asEvents(newExecutionWindow, startOfWeek, endDateTime, tz, 365); for (Event event : events) { for (Event newEvent : newEvents) { if (isOverlapping(event, newEvent)) { if (Logger.isDebugEnabled()) { Logger.debug("Overlapping events: " + event + " and " + event); } return true; } } } return false; } private static boolean isOverlapping(Event left, Event right) { return (StringUtils.equals(left.id, right.id) == false) && (left.startMillis < right.endMillis) && (right.startMillis < left.endMillis); } public static DateTime getStartOfWeek(DateTimeZone tz) { DateTime startOfWeek = new DateTime(tz); startOfWeek = startOfWeek.withDayOfWeek(DateTimeConstants.MONDAY); startOfWeek = startOfWeek.withMillisOfDay(0); startOfWeek = startOfWeek.withZone(DateTimeZone.UTC); return startOfWeek; } public static List<Event> asEvents(List<ExecutionWindowRestRep> executionWindows, DateTime start, DateTime end, DateTimeZone tz) { return asEvents(executionWindows, start, end, tz, MAX_EVENTS); } public static List<Event> asEvents(List<ExecutionWindowRestRep> executionWindows, DateTime start, DateTime end, DateTimeZone tz, long maxNumberOfEvents) { List<Event> events = Lists.newArrayList(); if (executionWindows != null) { for (ExecutionWindowRestRep executionWindow : executionWindows) { events.addAll(asEvents(executionWindow, start, end, tz, maxNumberOfEvents)); } } return events; } private static List<Event> asEvents(ExecutionWindowRestRep executionWindow, DateTime start, DateTime end, DateTimeZone tz, long maxNumberOfEvents) { long lengthInMillis = TimeUtils .toMillis(executionWindow.getExecutionWindowLength(), executionWindow.getExecutionWindowLengthType()); List<Event> events = Lists.newArrayList(); DateTime indexDate = start.withZone(DateTimeZone.UTC).minusHours(TIME_RANGE_PADDING_IN_HOURS); DateTime paddedEnd = end.withZone(DateTimeZone.UTC).plusHours(TIME_RANGE_PADDING_IN_HOURS); while (indexDate.isBefore(paddedEnd.getMillis())) { // Potentially some CRON expressions could fire a LOT. Max out // after a certain number of events per job if (events.size() > maxNumberOfEvents) { break; } if (isScheduled(indexDate, executionWindow)) { int hourOfDay = executionWindow.getHourOfDayInUTC(); int minute = 0; if (executionWindow.getMinuteOfHourInUTC() != null) { minute = executionWindow.getMinuteOfHourInUTC(); } DateTime nextDate = indexDate.withHourOfDay(hourOfDay); nextDate = nextDate.withMinuteOfHour(minute); nextDate = nextDate.withSecondOfMinute(0); nextDate = nextDate.withMillisOfSecond(0); DateTime nextEndDate = nextDate.plusMillis((int) lengthInMillis); String id = null; if (executionWindow.getId() != null) { id = executionWindow.getId().toString(); } events.add(new Event(id, executionWindow.getName(), nextDate, nextEndDate, tz)); } indexDate = indexDate.plusDays(1); } return events; } private static boolean isScheduled(DateTime indexDate, ExecutionWindowRestRep executionWindow) { if (indexDate != null && executionWindow != null) { if (ExecutionWindowRestRep.DAILY.equals(executionWindow.getExecutionWindowType())) { return true; } else if (ExecutionWindowRestRep.WEEKLY.equals(executionWindow.getExecutionWindowType())) { Integer dayOfWeek = executionWindow.getDayOfWeek(); if (dayOfWeek != null && indexDate.getDayOfWeek() == dayOfWeek) { return true; } } else if (ExecutionWindowRestRep.MONTHLY.equals(executionWindow.getExecutionWindowType())) { Integer dayOfMonth = executionWindow.getDayOfMonth(); Boolean lastDayOfMonth = executionWindow.getLastDayOfMonth(); if (lastDayOfMonth != null && lastDayOfMonth.booleanValue() == true) { if (isLastDayOfMonth(indexDate.getDayOfMonth(), indexDate)) { return true; } } else if (dayOfMonth != null && indexDate.getDayOfMonth() == dayOfMonth) { return true; } else if (isLastDayOfMonth(dayOfMonth, indexDate)) { return true; } } } return false; } private static boolean isLastDayOfMonth(Integer dayOfMonth, DateTime date) { if (dayOfMonth != null && date != null) { // Is last day of month? if (date.dayOfMonth().get() == date.dayOfMonth().getMaximumValue()) { // Is value store for day of month greater than or equal to current day if (dayOfMonth >= date.dayOfMonth().getMaximumValue()) { return true; } } } return false; } public static ExecutionWindowRestRep getExecutionWindow(RelatedResourceRep rep) { ViPRCatalogClient2 catalog = getCatalogClient(); return catalog.executionWindows().get(rep); } public static ExecutionWindowRestRep getExecutionWindow(String name, URI tenantId) { ViPRCatalogClient2 catalog = getCatalogClient(); List<ExecutionWindowRestRep> executionWindows = catalog.executionWindows().getByTenant(tenantId); for (ExecutionWindowRestRep executionWindow : executionWindows) { if (name.equals(executionWindow.getName())) { return executionWindow; } } return null; } public static ExecutionWindowRestRep getExecutionWindow(URI executionWindowId) { ViPRCatalogClient2 catalog = getCatalogClient(); return catalog.executionWindows().get(executionWindowId); } public static List<ExecutionWindowRestRep> getExecutionWindows(URI tenantId) { ViPRCatalogClient2 catalog = getCatalogClient(); return catalog.executionWindows().getByTenant(tenantId); } public static List<ExecutionWindowRestRep> getExecutionWindows() { ViPRCatalogClient2 catalog = getCatalogClient(); List<NamedRelatedResourceRep> reps = catalog.executionWindows().listByUserTenant(); return catalog.executionWindows().getByRefs(reps); } public static void deleteExecutionWindow(ExecutionWindowRestRep executionWindow) { if (executionWindow != null) { ViPRCatalogClient2 catalog = getCatalogClient(); catalog.executionWindows().deactivate(executionWindow.getId()); } } public static ExecutionWindowRestRep createExecutionWindow(ExecutionWindowCreateParam createParam) { ViPRCatalogClient2 catalog = getCatalogClient(); return catalog.executionWindows().create(createParam); } public static ExecutionWindowRestRep updateExecutionWindow(URI id, ExecutionWindowUpdateParam updateParam) { ViPRCatalogClient2 catalog = getCatalogClient(); return catalog.executionWindows().update(id, updateParam); } }