package com.ibm.nmon.interval; import org.slf4j.Logger; import java.util.List; import java.util.Set; import java.util.Date; import java.util.regex.Pattern; import java.text.ParseException; import java.io.File; import java.io.LineNumberReader; import java.io.FileWriter; import java.io.IOException; import com.ibm.nmon.util.DataHelper; import com.ibm.nmon.util.TimeFormatCache; import com.ibm.nmon.util.TimeHelper; /** * A manager implementation for {@link Interval intervals}. Maintains a list of multiple intervals * along with a 'current' interval that is being analyzed. On changes, the manager will fire * {@link IntervalListener} events. */ public final class IntervalManager { private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(IntervalManager.class); private final Set<Interval> intervals; private Interval currentInterval; private List<IntervalListener> listeners = new java.util.concurrent.CopyOnWriteArrayList<IntervalListener>(); public IntervalManager() { intervals = new java.util.TreeSet<Interval>(); currentInterval = Interval.DEFAULT; } public Interval getCurrentInterval() { return currentInterval; } public void setCurrentInterval(Interval interval) { if (intervals.contains(interval)) { if (!currentInterval.equals(interval)) { LOGGER.debug("setting current interval to {}", TimeFormatCache.formatInterval(interval)); currentInterval = interval; for (IntervalListener listener : listeners) { listener.currentIntervalChanged(interval); } } } else if (Interval.DEFAULT.equals(interval)) { // call the listeners even if the current interval is already Interval.DEFAULT // this is needed in case data is added that redefines what the default interval time // span actually is // see com.ibm.nmon.NMONVisualizerApp.recalculateMinAndMaxSystemTime() LOGGER.debug("setting current interval to {}", "DEFAULT"); currentInterval = Interval.DEFAULT; for (IntervalListener listener : listeners) { listener.currentIntervalChanged(interval); } } } public Iterable<Interval> getIntervals() { return java.util.Collections.unmodifiableSet(intervals); } public int getIntervalCount() { return intervals.size(); } public boolean addInterval(Interval interval) { if (Interval.DEFAULT.equals(interval)) { LOGGER.trace("not adding DEFAULT interval"); return false; } else if (intervals.add(interval)) { LOGGER.debug("added " + "interval {}", TimeFormatCache.formatInterval(interval)); for (IntervalListener listener : listeners) { listener.intervalAdded(interval); } return true; } else { LOGGER.trace("interval {}" + " already present", TimeFormatCache.formatInterval(interval)); return false; } } public boolean removeInterval(Interval interval) { if (intervals.remove(interval)) { LOGGER.debug("removed " + "interval {}", TimeFormatCache.formatInterval(interval)); for (IntervalListener listener : listeners) { listener.intervalRemoved(interval); } if (currentInterval.equals(interval)) { LOGGER.trace("setting current interval to {}", "DEFAULT"); setCurrentInterval(Interval.DEFAULT); } return true; } else { return false; } } public void clearIntervals() { intervals.clear(); LOGGER.debug("intervals cleared"); for (IntervalListener listener : listeners) { listener.intervalsCleared(); } setCurrentInterval(Interval.DEFAULT); } public void renameInterval(Interval interval, String newName) { if (intervals.contains(interval)) { if (newName == null) { newName = ""; } if (!interval.getName().equals(newName)) { interval.setName(newName); TimeFormatCache.renameInterval(interval); for (IntervalListener listener : listeners) { listener.intervalRenamed(interval); } } } } public void addListener(IntervalListener listener) { if (listener != null) { listeners.add(listener); } } public void removeListener(IntervalListener listener) { listeners.remove(listener); } private static final Pattern DATA_SPLITTER = Pattern.compile("\"?,\"?"); public void loadFromFile(File file, long offset) throws IOException { LineNumberReader reader = null; try { reader = new LineNumberReader(new java.io.FileReader(file)); String line = null; Interval interval = null; while ((line = reader.readLine()) != null) { String[] data = DATA_SPLITTER.split(line); String name = ""; String start = ""; String end = ""; switch (data.length) { case 0: { LOGGER.trace("skipping empty interval data at line {}", reader.getLineNumber()); continue; } case 1: { LOGGER.trace("skipping empty interval data at line {}", reader.getLineNumber()); continue; } case 2: { start = data[0]; end = data[1]; break; } case 3: { name = DataHelper.newString(data[0]); start = data[1]; end = data[2]; break; } default: continue; } long startTime = 0; long endTime = 0; try { startTime = TimeHelper.TIMESTAMP_FORMAT_ISO.parse(start).getTime(); } catch (ParseException pe) { try { startTime = Long.parseLong(start) + offset; } catch (NumberFormatException nfe) { LOGGER.warn("cannot parse time {} at line {}", startTime, reader.getLineNumber()); continue; } } if (LOGGER.isDebugEnabled()) { LOGGER.debug("line {}: {}={}", new Object[] { reader.getLineNumber(), startTime, start }); } try { endTime = TimeHelper.TIMESTAMP_FORMAT_ISO.parse(end).getTime(); } catch (ParseException pe) { try { endTime = Long.parseLong(end) + offset; } catch (NumberFormatException nfe) { LOGGER.warn("cannot parse time {} at line {}", startTime, reader.getLineNumber()); continue; } } if (LOGGER.isDebugEnabled()) { LOGGER.debug("line {}: {}={}", new Object[] { reader.getLineNumber(), endTime, end }); } interval = new Interval(startTime, endTime); interval.setName(name); addInterval(interval); } if (interval != null) { setCurrentInterval(interval); } } finally { if (reader != null) { try { reader.close(); } catch (IOException ioe2) { // ignore } } } } public void saveToFile(File file, long offset) throws IOException { FileWriter writer = null; try { writer = new FileWriter(file); for (Interval interval : getIntervals()) { long start = interval.getStart() - offset; long end = interval.getEnd() - offset; writer.write(interval.getName()); writer.write(','); if (offset == 0) { // absolute time writer.write(TimeHelper.TIMESTAMP_FORMAT_ISO.format(new Date(start))); writer.write(','); writer.write(TimeHelper.TIMESTAMP_FORMAT_ISO.format(new Date(end))); } else { // relative time writer.write(Long.toString(start)); writer.write(','); writer.write(Long.toString(end)); } writer.write('\n'); } } catch (IOException ioe) { ioe.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException ioe2) { // ignore } } } } }