//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.report;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import gov.nasa.jpf.Config;
/**
* abstract base for all format specific publishers. Note that this interface
* also has to work for non-stream based reporting, i.e. within Eclipse
* (we don't want to re-parse from text reports there)
*/
public abstract class Publisher {
// output phases
public static final int START = 1;
public static final int TRANSITION = 2;
public static final int PROBE = 3;
public static final int CONSTRAINT = 4;
public static final int PROPERTY_VIOLATION = 5;
public static final int FINISHED = 6;
protected Config conf;
protected Reporter reporter; // our master
protected String[] startItems = {};
protected String[] transitionItems = {};
protected String[] propertyViolationItems = {};
protected String[] constraintItems = {};
protected String[] finishedItems = {};
protected String[] probeItems = {};
DateFormat dtgFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
ArrayList<PublisherExtension> extensions;
/**
* to be initialized in openChannel
* NOTE - not all publishers need to have one
*/
protected PrintWriter out;
public PrintWriter getOut () {
return out;
}
protected Publisher (Config conf, Reporter reporter){
this.conf = conf;
this.reporter = reporter;
setTopicItems();
}
public void setItems (int category, String[] newTopics){
switch (category){
case START:
startItems = newTopics; break;
case PROBE:
probeItems = newTopics; break;
case TRANSITION:
transitionItems = newTopics; break;
case CONSTRAINT:
constraintItems = newTopics; break;
case PROPERTY_VIOLATION:
propertyViolationItems = newTopics; break;
case FINISHED:
finishedItems = newTopics; break;
default:
Reporter.log.warning("unknown publisher topic: " + category);
}
}
public abstract String getName();
protected void setTopicItems () {
setTopicItems(getName());
}
protected void setTopicItems (String name) {
String prefix = "report." + name;
startItems = conf.getStringArray(prefix + ".start", startItems);
transitionItems = conf.getStringArray(prefix + ".transition", transitionItems);
probeItems = conf.getStringArray(prefix + ".probe", transitionItems);
propertyViolationItems = conf.getStringArray(prefix + ".property_violation", propertyViolationItems);
constraintItems = conf.getStringArray(prefix + ".constraint", constraintItems);
finishedItems = conf.getStringArray(prefix + ".finished", finishedItems);
}
public void addExtension (PublisherExtension ext) {
if (extensions == null) {
extensions = new ArrayList<PublisherExtension>();
}
extensions.add(ext);
}
// <2do> should not be a list we can add to
private static final List<PublisherExtension> EMPTY_LIST = new ArrayList<PublisherExtension>(0);
public List<PublisherExtension> getExtensions(){
if (extensions != null){
return extensions;
} else {
return EMPTY_LIST; // make life easier for callers
}
}
public String getLastErrorId() {
return reporter.getCurrentErrorId();
}
public boolean hasTopic (String topic) {
for (String s : startItems) {
if (s.equalsIgnoreCase(topic)){
return true;
}
}
for (String s : transitionItems) {
if (s.equalsIgnoreCase(topic)){
return true;
}
}
for (String s : constraintItems) {
if (s.equalsIgnoreCase(topic)){
return true;
}
}
for (String s : propertyViolationItems) {
if (s.equalsIgnoreCase(topic)){
return true;
}
}
for (String s : finishedItems) {
if (s.equalsIgnoreCase(topic)){
return true;
}
}
return false;
}
public String formatDTG (Date date) {
return dtgFormatter.format(date);
}
/**
static public String _formatHMS (long t) {
t /= 1000; // convert to sec
long s = t % 60;
long h = t / 3600;
long m = (t % 3600) / 60;
StringBuilder sb = new StringBuilder();
sb.append(h);
sb.append(':');
if (m < 10){
sb.append('0');
}
sb.append(m);
sb.append(':');
if (s < 10){
sb.append('0');
}
sb.append(s);
return sb.toString();
}
**/
static char[] tBuf = { '0', '0', ':', '0', '0', ':', '0', '0' };
static synchronized public String formatHMS (long t) {
int h = (int) (t / 3600000);
int m = (int) ((t / 60000) % 60);
int s = (int) ((t / 1000) % 60);
tBuf[0] = (char) ('0' + (h / 10));
tBuf[1] = (char) ('0' + (h % 10));
tBuf[3] = (char) ('0' + (m / 10));
tBuf[4] = (char) ('0' + (m % 10));
tBuf[6] = (char) ('0' + (s / 10));
tBuf[7] = (char) ('0' + (s % 10));
return new String(tBuf);
}
public String getReportFileName (String key) {
String fname = conf.getString(key);
if (fname == null){
fname = conf.getString("report.file");
if (fname == null) {
fname = "report";
}
}
return fname;
}
public void publishTopicStart (String topic) {
// to be done by subclasses
}
public void publishTopicEnd (String topic) {
// to be done by subclasses
}
public boolean hasToReportStatistics() {
for (String s : finishedItems) {
if ("statistics".equalsIgnoreCase(s)){
return true;
}
}
return false;
}
//--- open/close streams etc
protected void openChannel(){}
protected void closeChannel(){}
//--- if you have different preferences about when to report things, override those
public void publishStart() {
for (String item : startItems) {
if ("jpf".equalsIgnoreCase(item)){
publishJPF();
} else if ("platform".equalsIgnoreCase(item)){
publishPlatform();
} else if ("user".equalsIgnoreCase(item)) {
} else if ("dtg".equalsIgnoreCase(item)) {
publishDTG();
} else if ("config".equalsIgnoreCase(item)){
publishJPFConfig();
} else if ("sut".equalsIgnoreCase(item)){
publishSuT();
}
}
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishStart(this);
}
}
}
public void publishTransition() {
for (String topic : transitionItems) {
if ("statistics".equalsIgnoreCase(topic)){
publishStatistics();
}
}
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishTransition(this);
}
}
}
public void publishConstraintHit() {
for (String item : constraintItems) {
if ("constraint".equalsIgnoreCase(item)) {
publishConstraint();
} else if ("trace".equalsIgnoreCase(item)){
publishTrace();
} else if ("snapshot".equalsIgnoreCase(item)){
publishSnapshot();
} else if ("output".equalsIgnoreCase(item)){
publishOutput();
} else if ("statistics".equalsIgnoreCase(item)){
publishStatistics(); // not sure if that is good for anything
}
}
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishConstraintHit(this);
}
}
}
public void publishProbe(){
for (String topic : probeItems) {
if ("statistics".equalsIgnoreCase(topic)){
publishStatistics();
}
}
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishProbe(this);
}
}
}
public void publishPropertyViolation() {
for (String topic : propertyViolationItems) {
if ("error".equalsIgnoreCase(topic)) {
publishError();
} else if ("trace".equalsIgnoreCase(topic)){
publishTrace();
} else if ("snapshot".equalsIgnoreCase(topic)){
publishSnapshot();
} else if ("output".equalsIgnoreCase(topic)){
publishOutput();
} else if ("statistics".equalsIgnoreCase(topic)){
publishStatistics(); // not sure if that is good for anything
}
}
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishPropertyViolation(this);
}
}
}
public void publishFinished() {
if (extensions != null) {
for (PublisherExtension e : extensions) {
e.publishFinished(this);
}
}
for (String topic : finishedItems) {
if ("result".equalsIgnoreCase(topic)){
publishResult();
} else if ("statistics".equalsIgnoreCase(topic)){
publishStatistics();
}
}
}
protected void publishProlog() {} // XML headers etc
protected void publishEpilog() {} // likewise at the end
//--- our standard topics (only placeholders here)
protected void publishJPF() {}
protected void publishJPFConfig() {}
protected void publishPlatform() {}
protected void publishUser() {}
protected void publishDTG() {}
protected void publishJava() {}
protected void publishSuT() {}
protected void publishResult() {}
protected void publishError() {}
protected void publishConstraint() {}
protected void publishTrace() {}
protected void publishOutput() {}
protected void publishSnapshot() {}
protected void publishStatistics() {}
//--- internal helpers
}