001package org.javasimon.callback.timeline;
002
003import org.javasimon.Simon;
004import org.javasimon.Split;
005import org.javasimon.Stopwatch;
006import org.javasimon.StopwatchSample;
007import org.javasimon.callback.CallbackSkeleton;
008
009/**
010 * Timeline callback aims at keeping simon data for the last N minutes.
011 * A "timeline" object is stored in each Simon, it's fixed size ring buffer
012 * of "time ranges". A "time range" aggregates Simon data for a fixed duration.
013 * <p/>
014 * Example: a timeline containing 6 time ranges of 10 minutes each can be used to
015 * see evolution for an hour.
016 *
017 * @author gerald
018 */
019public class TimelineCallback extends CallbackSkeleton {
020
021        /** Default attribute name for storing timelines. */
022        public static final String TIMELINE_ATTRIBUTE_NAME = "timeline";
023
024        /** Attribute name for storing timeline in Simons. */
025        private final String timelineAttributeName;
026        /** Number of time ranges to keep in the timeline. */
027        private final int timelineCapacity;
028        /** Width in milliseconds of the time ranges. */
029        private final long timeRangeWidth;
030
031        /**
032         * Main constructor.
033         *
034         * @param timelineAttributeName Simon attribute name used for storing Timeline
035         * @param timelineCapacity Timeline capacity (number of time ranges)
036         * @param timeRangeWidth Time range width (in milliseconds)
037         */
038        public TimelineCallback(String timelineAttributeName, int timelineCapacity, long timeRangeWidth) {
039                this.timelineAttributeName = timelineAttributeName;
040                this.timelineCapacity = timelineCapacity;
041                this.timeRangeWidth = timeRangeWidth;
042        }
043
044        /**
045         * Constructor using default attribute name.
046         *
047         * @param timelineCapacity Timeline capacity (number of time ranges)
048         * @param timeRangeWidth Time range width (in milliseconds)
049         */
050        public TimelineCallback(int timelineCapacity, long timeRangeWidth) {
051                this(TIMELINE_ATTRIBUTE_NAME, timelineCapacity, timeRangeWidth);
052        }
053
054        /**
055         * Constructor using default attribute name, default timeline capacity of 6
056         * and default timeline width of 10 minutes. Timeline stores an hour of data.
057         */
058        public TimelineCallback() {
059                this(6, 1000L * 60L * 6L);
060        }
061
062        /**
063         * Returns timeline for given Stopwatch.
064         *
065         * @param stopwatch Stopwatch
066         * @return Stopwatch timeline
067         */
068        private StopwatchTimeline getStopwatchTimeline(Stopwatch stopwatch) {
069                return (StopwatchTimeline) stopwatch.getAttribute(timelineAttributeName);
070        }
071
072        /**
073         * On simon creation a timeline attribute is added (for Stopwatches only).
074         *
075         * @param simon created simon
076         */
077        @Override
078        public void onSimonCreated(Simon simon) {
079                if (simon instanceof Stopwatch) {
080                        simon.setAttribute(timelineAttributeName, new StopwatchTimeline(timelineCapacity, timeRangeWidth));
081                }
082        }
083
084        @Override
085        public void onStopwatchAdd(Stopwatch stopwatch, Split split, StopwatchSample sample) {
086                StopwatchTimeline timeline = getStopwatchTimeline(stopwatch);
087                if (timeline != null) {
088                        timeline.addSplit(split);
089                }
090        }
091
092        @Override
093        public void onStopwatchStop(Split split, StopwatchSample sample) {
094                StopwatchTimeline timeline = getStopwatchTimeline(split.getStopwatch());
095                if (timeline != null) {
096                        timeline.addSplit(split);
097                }
098        }
099}