/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2013, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.catalog; import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.Set; import org.helios.apmrouter.collections.ConcurrentLongSortedSet; import org.helios.apmrouter.dataservice.json.catalog.MetricURISubscriptionType; import org.helios.apmrouter.util.BitMaskedEnum; /** * <p>Title: EntryStatus</p> * <p>Description: The status of an entry with respect to the Up/Down state of the metric</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.destination.chronicletimeseries.EntryStatus</code></p> */ public enum EntryStatus { /** The entry is active and has had recent inserts */ ACTIVE((byte)1), /** The entry is stale and has not seen inserts within the stale window */ STALE((byte)2), /** The entry is offline and has not seen inserts within one time series tier */ OFFLINE((byte)4); /** A decode map for ByteMask -> EntryStatus */ public static final Map<Byte, EntryStatus> MASK2ENUM = BitMaskedEnum.Support.generateByteMap(EntryStatus.values()); private EntryStatus(byte mask) { this.mask = mask; } private final byte mask; /** A bit mask of all statuses turned on */ public static final byte ALL_STATUS_MASK; static { byte stat = 0; for(EntryStatus es: EntryStatus.values()) { stat = (byte)(stat | es.mask); } ALL_STATUS_MASK = stat; } /** * Returns the byte ordinal for this EntryStatus * @return the byte ordinal */ public byte byteOrdinal() { return (byte)ordinal(); } public static void main(String[] args) { for(EntryStatus e: EntryStatus.values()) { System.out.println(e.name() + ":" + e.byteOrdinal()); } } /** * Returns the bit mask representing each of the entry state ordinals passed * @param ordinals the oridnals to mask * @return the mask */ public static byte getMaskFor(byte[] ordinals) { if(ordinals==null || ordinals.length==0) return 0; byte m = 0; for(byte o: ordinals) { m = (byte) (m | EntryStatus.forByte(o).mask); } return m; } /** * Returns the EntryStatus with the specified byte ordinal * @param b The byte ordinal to get an EntryStatus for * @return an EntryStatus */ public static EntryStatus forByte(byte b) { switch(b) { case 0: return ACTIVE; case 1: return STALE; case 2: return OFFLINE; default: throw new IllegalArgumentException("Invalid byte [" + b + "]", new Throwable()); } } /** * Returns an array of the EntryStatuses enabled for the passed byte mask * @param mask The mask to render * @return an array of the EntryStatuses enabled for the passed byte mask */ public static EntryStatus[] getEnabledFor(byte mask) { if(mask<0) throw new IllegalArgumentException("Invalid mask value [" + mask + "]", new Throwable()); Set<EntryStatus> enabled = EnumSet.noneOf(EntryStatus.class); for(EntryStatus to: values()) { if(to.isEnabled(mask)) { enabled.add(to); } } return enabled.toArray(new EntryStatus[enabled.size()]); } /** * Determines if this EntryStatus is enabled in the passed mask * @param mask the mask to test * @return if this EntryStatus is enabled in the passed mask, false otherwise */ public boolean isEnabled(byte mask) { return mask == (mask | this.mask); } /** * Decodes the passed int to an EntryStatus name * @param code the into to decode * @return the status name */ public static String decode(int code) { try { return EntryStatus.forByte((byte)code).name(); } catch (Exception ex) { return "INVALID CODE:" + code; } } /** * Renders a state change summary from a change map * @param changeMap the change map to render * @return a string */ public static String renderStatusCounts(Map<EntryStatus, EntryStatusChange> changeMap) { StringBuilder b = new StringBuilder("State Change Summary:"); for(Map.Entry<EntryStatus, EntryStatusChange> entry: changeMap.entrySet()) { b.append("\n\t").append(entry.getKey().name()).append(":").append(entry.getValue().getMetricIds().size()); } return b.toString(); } /** * <p>Title: EntryChange</p> * <p>Description: Represents an entry state being changed to, a timestamp and an array of metric ids that changed state.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.catalog.EntryStatusChange</code></p> */ public static class EntryStatusChange { private final EntryStatus toStatus; private final long timestamp; private final ConcurrentLongSortedSet metricIds; /** * Creates a new map of EntryStatusChanges keyed by the entry status * @param timestamp the timestamp that the changes to be added were effective as of * @return an EntryStatusChange map */ public static Map<EntryStatus, EntryStatusChange> getChangeMap(long timestamp) { return getChangeMap(timestamp, 2048); } /** * Creates a new map of EntryStatusChanges keyed by the entry status * @param timestamp the timestamp that the changes to be added were effective as of * @param sizeEstimate the initial size of the metric id array * @return an EntryStatusChange map */ public static Map<EntryStatus, EntryStatusChange> getChangeMap(long timestamp, int sizeEstimate) { Map<EntryStatus, EntryStatusChange> map = new EnumMap<EntryStatus, EntryStatusChange>(EntryStatus.class); for(EntryStatus es: EntryStatus.values()) { map.put(es, new EntryStatusChange(es, timestamp, sizeEstimate)); } return map; } /** * Creates a change map for a single state change * @param timestamp The timestamp of the change * @param metricId The metric id * @param status the new status * @return a singleton change map */ public static Map<EntryStatus, EntryStatusChange> getChangeMap(long timestamp, long metricId, EntryStatus status) { return new EnumMap<EntryStatus, EntryStatusChange>(Collections.singletonMap(status, new EntryStatusChange(status, timestamp, 1).appendMetricIds(metricId))); } /** * Creates a new EntryStatusChange * @param toStatus the status being transitioned to * @param timestamp the timestamp of the transition in a UTC long. */ private EntryStatusChange(EntryStatus toStatus, long timestamp) { this(toStatus, timestamp, 2048); } /** * Creates a new EntryStatusChange * @param toStatus the status being transitioned to * @param timestamp the timestamp of the transition in a UTC long. * @param sizeEstimate the initial size of the metric id array */ private EntryStatusChange(EntryStatus toStatus, long timestamp, int sizeEstimate) { this.toStatus = toStatus; this.timestamp = timestamp; metricIds = new ConcurrentLongSortedSet(false, sizeEstimate); } /** * Appends metric Ids to this state change * @param metricIds The metric ids to append * @return this state change */ public EntryStatusChange appendMetricIds(long...metricIds) { this.metricIds.add(metricIds); return this; } /** * Returns the status being transitioned to * @return the status being transitioned to */ public EntryStatus getToStatus() { return toStatus; } /** * Returns the time of the state change * @return the time of the state change */ public long getTimestamp() { return timestamp; } /** * Returns the metricIds that changed state * @return the metricIds that changed state */ public ConcurrentLongSortedSet getMetricIds() { return metricIds; } /** * Adds an array of metric ids to this state change * @param metricIds an array of metric ids. */ public void addMetricIds(long...metricIds) { this.metricIds.add(metricIds); } } /** * Returns the mask for this status * @return the mask for this status */ public byte getMask() { return mask; } }