/* * ALMA - Atacama Large Millimiter Array * Copyright (c) European Southern Observatory, 2011 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package alma.acs.monitoring.blobber; import java.util.ListIterator; import java.util.NoSuchElementException; import org.apache.commons.collections.list.CursorableLinkedList; import alma.MonitorArchiver.CollectorListStatus; /** * This class encapsulates a <code>{@link CursorableLinkedList}<{@link CollectorData}></code>, * which holds all monitor collector references together with their data that got harvested by a blobber. * It allows calls to {@link #add(CollectorData)} and {@link #remove(CollectorData)} while iterating * over the list of CollectorData objects using methods {@link #next()} or {@link #hasNext()}. * <p> * The only added value compared to using the <code>CursorableLinkedList</code> directly is * the synchronization of concurrent calls and the type casts (CursorableLinkedList does not support generics). */ public class CollectorList { /** * CursorableLinkedList allows concurrent modifications and iteration, * so that we can use a simple iterator instead of taking care of list indices ourselves. */ private final CursorableLinkedList myList = new CursorableLinkedList(); /** * Smart list iterator, that takes account of list insertions and removals * in between the calls to next(), as long as the list methods * are not called concurrently. * @TOOD Use generics once the apache commons lists support them. */ private ListIterator myListIterator; public CollectorList() { resetIterator(); } /** * Creates and adds a CollectorData object for the given collector ID. * @see #add(CollectorData) */ public CollectorListStatus add(String inCollectorName) { return add(new CollectorData(inCollectorName)); } /** * @param inData The object that identifies a collector. * @return ADDED if the CollectorData object was added to this list, or KNOWN if it was already in the list. */ public CollectorListStatus add(CollectorData inData) { CollectorListStatus outValue = CollectorListStatus.KNOWN; synchronized (myList) { if (!this.myList.contains(inData)) { this.myList.add(inData); outValue = CollectorListStatus.ADDED; } } return outValue; } /** * @param inCollectorName The ID of the collector for which we check the list. * @return KNOWN if the given collector is already in this list, or UNKNOWN otherwise. */ public CollectorListStatus contains(String inCollectorName) { return contains(new CollectorData(inCollectorName)); } /** * This method is currently used only from {@link #contains(String)}. * Make it public if it should be used from outside. */ protected CollectorListStatus contains(CollectorData inData) { CollectorListStatus outValue = CollectorListStatus.UNKNOWN; synchronized (myList) { if (this.myList.contains(inData)) { outValue = CollectorListStatus.KNOWN; } } return outValue; } /** * * @param inCollectorName * @return REMOVED if the given collector was in this list and got removed, or UNKNOWN otherwise. */ public CollectorListStatus remove(String inCollectorName) { return remove(new CollectorData(inCollectorName)); } /** * This method is currently used only from {@link #remove(String)}. * Make it public if it should be used from outside. */ protected synchronized CollectorListStatus remove(CollectorData inData) { boolean removedIt; synchronized (myList) { removedIt = myList.remove(inData); } return ( removedIt ? CollectorListStatus.REMOVED : CollectorListStatus.UNKNOWN ); } /** * @return The number of monitor collectors in this list. */ public int size() { synchronized (myList) { return this.myList.size(); } } /** * @return The next CollectorData from the list. * @throws NoSuchElementException if we are at the end of the list. * Should have checked with {@link #hasNext()}, and called {@link #resetIterator()}. */ public CollectorData next() { synchronized (myList) { return (CollectorData) myListIterator.next(); } } /** * @return <code>true</code> if a subsequent call to {@link #next()} * will return another CollectorData object from the current iteration; * <code>false</code> otherwise. */ public boolean hasNext() { synchronized (myList) { return myListIterator.hasNext(); } } public void resetIterator() { synchronized (myList) { myListIterator = myList.listIterator(); } } /** * This class encapsulates meta data for a monitor collector: the Collector-ID, and the last successful access time * for that collector. * <p> * The collector-ID is the name of the collector component deployed in the container from whose components we want * to collect monitoring data. */ protected static class CollectorData { private final String collectorId; public CollectorData(String inCollectorId) { if (inCollectorId == null) { throw new IllegalArgumentException("inCollectorId cannot be null."); } this.collectorId = inCollectorId; } /** * @return The collector ID for a given container, which is the name of the collector component deployed in that * container. */ public String getCollectorId() { return this.collectorId; } @Override public boolean equals(Object inObject) { if (inObject == null || !(inObject instanceof CollectorData)) { return false; } return (collectorId.equals(((CollectorData) inObject).collectorId)); } /** * Must be consistent with equals(), based only on collectorId. */ @Override public int hashCode() { return collectorId.hashCode(); } /** * Timestamp of the last successful data retrieval from this monitor collector. * <p> * Currently no-op, but could be useful to store this data in the future. */ void setLastSuccessfulAccessTime(long currentTimeMillis) { } } }