// This file is part of PleoCommand:
// Interactively control Pleo with psychobiological parameters
//
// Copyright (C) 2010 Oliver Hoffmann - Hoffmann_Oliver@gmx.de
//
// 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; either version 2
// of the License, or (at your option) any later version.
//
// 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, Boston, USA.
package pleocmd.pipe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import pleocmd.pipe.data.Data;
abstract class Feedback {
private long startTime;
private long stopTime;
private final List<Throwable> temporaryErrors;
private final List<Throwable> permanentErrors;
private int interruptionCount;
private int dropCount;
private int behindCountSignificant;
private long behindCount;
private long behindMax;
private long behindSum;
Feedback() {
startTime = 0;
temporaryErrors = new ArrayList<Throwable>();
permanentErrors = new ArrayList<Throwable>();
}
/**
* @return time at which the {@link Feedback} has been started
*/
public final synchronized long getStartTime() {
return startTime;
}
/**
* @return time at which the {@link Feedback} has been stopped or <b>0</b>
* if it is still running
*/
public final synchronized long getStopTime() {
return stopTime;
}
/**
* @return time which has elapsed since the {@link Feedback} has been
* started if it's currently running or the time it has run
* otherwise.
*/
public final synchronized long getElapsed() {
return (stopTime == 0 ? System.currentTimeMillis() : stopTime)
- startTime;
}
/**
* @return a list of all {@link Exception}s that have been thrown and which
* only caused temporary failure (i.e. affected only one
* {@link Data})
*/
public final synchronized List<Throwable> getTemporaryErrors() {
return Collections.unmodifiableList(temporaryErrors);
}
/**
* @return a list of all {@link Exception}s that have been thrown and which
* only caused permanent failure (i.e. possibly affected more than
* one {@link Data})
*/
public final synchronized List<Throwable> getPermanentErrors() {
return Collections.unmodifiableList(permanentErrors);
}
/**
* @return number of {@link Data} that have been interrupted because a
* {@link Data} with a higher priority has to be executed
*/
public final synchronized int getInterruptionCount() {
return interruptionCount;
}
/**
* @return number of {@link Data} that have been dropped because a
* {@link Data} with a higher priority is currently been executed or
* has been queued for execution
*/
public final synchronized int getDropCount() {
return dropCount;
}
public final synchronized long getSignificantBehindCount() {
return behindCountSignificant;
}
public final synchronized long getBehindCount() {
return behindCount;
}
public final synchronized long getBehindMax() {
return behindMax;
}
public final synchronized long getBehindSum() {
return behindSum;
}
public final synchronized long getBehindAverage() {
return behindCount == 0 ? 0 : behindSum / behindCount;
}
final synchronized void started() {
startTime = System.currentTimeMillis();
}
final synchronized void stopped() {
stopTime = System.currentTimeMillis();
((ArrayList<?>) temporaryErrors).trimToSize();
((ArrayList<?>) permanentErrors).trimToSize();
}
final synchronized void addError(final Throwable t, final boolean permanent) {
if (permanent)
permanentErrors.add(t);
else
temporaryErrors.add(t);
}
final synchronized void incInterruptionCount() {
++interruptionCount;
}
public final synchronized void incDropCount() {
++dropCount;
}
final synchronized void incDropCount(final int increment) {
dropCount += increment;
}
final synchronized void incBehindCount(final long behind,
final boolean significant) {
if (significant) ++behindCountSignificant;
++behindCount;
if (behindMax < behind) behindMax = behind;
behindSum += behind;
}
private String getCurrentRunningState() {
if (stopTime != 0)
return String.format("has run %d milliseconds", getElapsed());
if (startTime != 0)
return String.format("is running since %d milliseconds",
getElapsed());
return "has never been run";
}
@Override
public final synchronized String toString() {
// CS_IGNORE_BEGIN
if (startTime == 0 && stopTime == 0)
return String.format("Pipe %s", getCurrentRunningState());
return String.format("Pipe %s,%s encountered %d "
+ "temporary and %d permanent error(s), "
+ "output has been %d time(s) interrupted "
+ "due to high-priority data, "
+ "%d time(s) been dropped due to low-priority and "
+ "it was %d time(s) behind (average %d - max %d - sum %d).%s",
getCurrentRunningState(), getAdditionalString1(),
temporaryErrors.size(), permanentErrors.size(),
interruptionCount, dropCount, behindCountSignificant,
getBehindAverage(), behindMax, behindSum,
getAdditionalString2());
// CS_IGNORE_END
}
protected abstract String getAdditionalString1();
protected abstract String getAdditionalString2();
protected final <E> void appendToHTMLTable(final StringBuilder sb,
final String name, final E value) {
sb.append("<tr><td align=right>");
sb.append(name);
sb.append("</td><td align=left>");
sb.append(String.valueOf(value));
sb.append("</td></tr>");
}
public final synchronized String getHTMLTable() {
final StringBuilder sb = new StringBuilder("<table border=1>");
appendToHTMLTable(sb, "State", getCurrentRunningState());
addAdditionalHTMLTable1(sb);
appendToHTMLTable(sb, "Temporary errors", temporaryErrors.size());
appendToHTMLTable(sb, "Permanent errors", permanentErrors.size());
appendToHTMLTable(sb, "Interrupted output", getInterruptionCount());
appendToHTMLTable(sb, "Dropped output", getDropCount());
appendToHTMLTable(sb, "Significantly behind",
getSignificantBehindCount());
appendToHTMLTable(sb, "Behind stats", String.format(
"average %d - max %d - sum %d", getBehindAverage(),
getBehindMax(), getBehindSum()));
addAdditionalHTMLTable2(sb);
sb.append("</table>");
return sb.toString();
}
protected abstract void addAdditionalHTMLTable1(final StringBuilder sb);
protected abstract void addAdditionalHTMLTable2(final StringBuilder sb);
}