/* * RHQ Management Platform * Copyright (C) 2005-2014 Red Hat, Inc. * All rights reserved. * * 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 version 2 of the License. * * 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 */ package org.rhq.core.pc.drift; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.PriorityQueue; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.drift.DriftDefinition; import org.rhq.core.domain.drift.DriftDefinitionComparator; public class ScheduleQueueImpl implements ScheduleQueue { private static final Log log = LogFactory.getLog(ScheduleQueueImpl.class); private static final Runnable NO_OP = new Runnable() { @Override public void run() { } }; private PriorityQueue<DriftDetectionSchedule> queue; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private DriftDetectionSchedule activeSchedule; private Runnable deactivationTask; public ScheduleQueueImpl() { queue = new PriorityQueue<DriftDetectionSchedule>(10, new DriftDetectionScheduleQueueComparator()); } @Override public DriftDetectionSchedule getNextSchedule() { try { lock.writeLock().lock(); if (activeSchedule != null) { throw new IllegalStateException("There is already an active schedule that must be deactivated " + "before getting the next schedule."); } activeSchedule = queue.poll(); return activeSchedule == null ? null : activeSchedule.copy(); } finally { lock.writeLock().unlock(); } } private boolean isActiveSchedule(int resourceId, String defName) { try { lock.readLock().lock(); return activeSchedule != null && activeSchedule.getResourceId() == resourceId && activeSchedule.getDriftDefinition().getName().equals(defName); } finally { lock.readLock().unlock(); } } private boolean isActiveSchedule(int resourceId, DriftDefinition driftDef, DriftDefinitionComparator comparator) { try { lock.readLock().lock(); return activeSchedule != null && activeSchedule.getResourceId() == resourceId && comparator.compare(activeSchedule.getDriftDefinition(), driftDef) == 0; } finally { lock.readLock().unlock(); } } @Override public void deactivateSchedule(boolean updateSchedule) { try { lock.writeLock().lock(); if (deactivationTask != null) { deactivationTask.run(); } if (activeSchedule == null) { return; } if (updateSchedule) { activeSchedule.updateShedule(); } if (log.isDebugEnabled()) { SimpleDateFormat formatter = new SimpleDateFormat(); formatter.applyPattern("hh:mm:ss:SSS a"); log.debug("The next drift detection run for " + activeSchedule + " is set for " + formatter.format(new Date(activeSchedule.getNextScan()))); } queue.offer(activeSchedule); activeSchedule = null; } finally { deactivationTask = null; lock.writeLock().unlock(); } } @Override public boolean addSchedule(DriftDetectionSchedule schedule) { boolean inserted = false; try { lock.writeLock().lock(); inserted = queue.offer(schedule); } finally { lock.writeLock().unlock(); } return inserted; } @Override public boolean contains(int resourceId, DriftDefinition driftDef) { return find(resourceId, driftDef.getName()) != null; } @Override public boolean contains(int resourceId, DriftDefinition driftDef, DriftDefinitionComparator comparator) { if (isActiveSchedule(resourceId, driftDef, comparator)) { return true; } try { lock.readLock().lock(); for (DriftDetectionSchedule schedule : queue) { if (schedule.getResourceId() == resourceId && comparator.compare(schedule.getDriftDefinition(), driftDef) == 0) { return true; } } return false; } finally { lock.readLock().unlock(); } } @Override public DriftDetectionSchedule find(int resourceId, String defName) { if (isActiveSchedule(resourceId, defName)) { return activeSchedule.copy(); } try { lock.readLock().lock(); for (DriftDetectionSchedule schedule : queue) { if (schedule.getResourceId() == resourceId && schedule.getDriftDefinition().getName().equals(defName)) { return schedule.copy(); } } return null; } finally { lock.readLock().unlock(); } } @Override public DriftDetectionSchedule remove(int resourceId, DriftDefinition driftDef) { return remove(resourceId, driftDef.getName()); } @Override public DriftDetectionSchedule remove(int resourceId, String defName) { return removeAndExecute(resourceId, defName, NO_OP); } @Override public DriftDetectionSchedule removeAndExecute(int resourceId, DriftDefinition driftDef, Runnable task) { return removeAndExecute(resourceId, driftDef.getName(), task); } @Override public DriftDetectionSchedule removeAndExecute(int resourceId, String defName, Runnable task) { try { lock.writeLock().lock(); if (isActiveSchedule(resourceId, defName)) { deactivationTask = task; DriftDetectionSchedule removedSchedule = activeSchedule; activeSchedule = null; return removedSchedule; } Iterator<DriftDetectionSchedule> iterator = queue.iterator(); while (iterator.hasNext()) { DriftDetectionSchedule schedule = iterator.next(); if (schedule.getResourceId() == resourceId && schedule.getDriftDefinition().getName().equals(defName)) { iterator.remove(); task.run(); return schedule; } } return null; } finally { lock.writeLock().unlock(); } } @Override public DriftDetectionSchedule update(int resourceId, DriftDefinition driftDef) { DriftDetectionSchedule schedule = remove(resourceId, driftDef); if (schedule == null) { return null; } update(schedule, driftDef); try { lock.writeLock().lock(); if (queue.offer(schedule)) { return schedule.copy(); } return null; } finally { lock.writeLock().unlock(); } } private void update(DriftDetectionSchedule schedule, DriftDefinition driftDef) { schedule.getDriftDefinition().setEnabled(driftDef.isEnabled()); schedule.getDriftDefinition().setInterval(driftDef.getInterval()); schedule.getDriftDefinition().setDriftHandlingMode(driftDef.getDriftHandlingMode()); schedule.getDriftDefinition().setPinned(driftDef.isPinned()); schedule.getDriftDefinition().setComplianceStatus(driftDef.getComplianceStatus()); } @Override public void clear() { try { lock.writeLock().lock(); activeSchedule = null; queue.clear(); } finally { lock.writeLock().unlock(); } } /** * Generates a string representation of the schedules in the queue. The schedules that * appear in the string are in sorted order. If there is an active schedule it will * appear first. This method can be useful for debugging since it shows the contents of * the queue in sorted order. Use it cautiously however as writes to the queue are * blocked until this method returns. * * @return A string representation of the queue with the schedules appearing in sorted * order. */ @Override public String toString() { try { lock.readLock().lock(); if (activeSchedule == null && queue.isEmpty()) { return "ScheduleQueue[]"; } DriftDetectionSchedule[] schedules = toArray(); Arrays.sort(schedules); List<DriftDetectionSchedule> list = new ArrayList<DriftDetectionSchedule>(schedules.length + 1); if (activeSchedule != null) { list.add(activeSchedule); } list.addAll(Arrays.asList(schedules)); StringBuilder buffer = new StringBuilder("ScheduleQueue["); for (DriftDetectionSchedule schedule : list) { buffer.append(schedule).append(", "); } int end = buffer.length(); buffer.delete(end - 2, end); buffer.append("]"); return buffer.toString(); } finally { lock.readLock().unlock(); } } @Override public DriftDetectionSchedule[] toArray() { try { lock.readLock().lock(); return queue.toArray(new DriftDetectionSchedule[queue.size()]); } finally { lock.readLock().unlock(); } } }