//
// 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.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import gov.nasa.jpf.Config;
import gov.nasa.jpf.Error;
import gov.nasa.jpf.JPF;
import gov.nasa.jpf.JPFListener;
import gov.nasa.jpf.search.Search;
import gov.nasa.jpf.search.SearchListenerAdapter;
import gov.nasa.jpf.vm.Path;
import gov.nasa.jpf.vm.VM;
/**
* this is our default report generator, which is heavily configurable
* via our standard properties. Note this gets instantiated and
* registered automatically via JPF.addListeners(), so you don't
* have to add it explicitly
*/
public class Reporter extends SearchListenerAdapter {
public static Logger log = JPF.getLogger("report");
protected Config conf;
protected JPF jpf;
protected Search search;
protected VM vm;
protected Date started, finished;
protected Statistics stat; // the object that collects statistics
protected List<Publisher> publishers = new ArrayList<Publisher>();
protected Thread probeTimer;
public Reporter (Config conf, JPF jpf) {
this.conf = conf;
this.jpf = jpf;
search = jpf.getSearch();
vm = jpf.getVM();
boolean reportStats = conf.getBoolean("report.statistics", false);
started = new Date();
addConfiguredPublishers(conf);
for (Publisher publisher : publishers) {
if (reportStats || publisher.hasToReportStatistics()) {
reportStats = true;
}
if (publisher instanceof JPFListener) {
jpf.addListener((JPFListener)publisher);
}
}
if (reportStats){
getRegisteredStatistics();
}
int probeInterval = conf.getInt("report.probe_interval");
if (probeInterval > 0){
probeTimer = createProbeIntervalTimer(probeInterval);
}
}
protected Thread createProbeIntervalTimer (final int probeInterval){
Thread timer = new Thread( new Runnable(){
public void run(){
log.info("probe timer running");
while (!search.isDone()){
try {
Thread.sleep( probeInterval * 1000);
search.probeSearch(); // this is only a request
} catch (InterruptedException ix) {
// nothing
}
}
log.info("probe timer terminating");
}
}, "probe-timer");
timer.setDaemon(true);
// we don't start before the Search is started
return timer;
}
/**
* called after the JPF run is finished. Shouldn't be public, but is called by JPF
*/
public void cleanUp(){
// nothing yet
}
public Statistics getRegisteredStatistics(){
if (stat == null){ // none yet, initialize
// first, check if somebody registered one explicitly
stat = vm.getNextListenerOfType(Statistics.class, null);
if (stat == null){
stat = conf.getInstance("report.statistics.class@stat", Statistics.class);
if (stat == null) {
stat = new Statistics();
}
jpf.addListener(stat);
}
}
return stat;
}
void addConfiguredPublishers (Config conf) {
String[] def = { "console" };
Class<?>[] argTypes = { Config.class, Reporter.class };
Object[] args = { conf, this };
for (String id : conf.getStringArray("report.publisher", def)){
Publisher p = conf.getInstance("report." + id + ".class",
Publisher.class, argTypes, args);
if (p != null){
publishers.add(p);
} else {
log.warning("could not instantiate publisher class: " + id);
}
}
}
public void addPublisher( Publisher newPublisher){
publishers.add(newPublisher);
}
public List<Publisher> getPublishers() {
return publishers;
}
public boolean hasToReportTrace() {
for (Publisher p : publishers) {
if (p.hasTopic("trace")) {
return true;
}
}
return false;
}
public boolean hasToReportOutput() {
for (Publisher p : publishers) {
if (p.hasTopic("output")) {
return true;
}
}
return false;
}
public <T extends Publisher> boolean addPublisherExtension (Class<T> publisherCls, PublisherExtension e) {
boolean added = false;
for (Publisher p : publishers) {
Class<?> pCls = p.getClass();
if (publisherCls.isAssignableFrom(pCls)) {
p.addExtension(e);
added = true;
}
}
return added;
}
public <T extends Publisher> void setPublisherItems (Class<T> publisherCls,
int category, String[] topics){
for (Publisher p : publishers) {
if (publisherCls.isInstance(p)) {
p.setItems(category,topics);
return;
}
}
}
boolean contains (String key, String[] list) {
for (String s : list) {
if (s.equalsIgnoreCase(key)){
return true;
}
}
return false;
}
//--- the publishing phases
protected void publishStart() {
for (Publisher publisher : publishers) {
publisher.openChannel();
publisher.publishProlog();
publisher.publishStart();
}
}
protected void publishTransition() {
for (Publisher publisher : publishers) {
publisher.publishTransition();
}
}
protected void publishPropertyViolation() {
for (Publisher publisher : publishers) {
publisher.publishPropertyViolation();
}
}
protected void publishConstraintHit() {
for (Publisher publisher : publishers) {
publisher.publishConstraintHit();
}
}
protected void publishFinished() {
for (Publisher publisher : publishers) {
publisher.publishFinished();
publisher.publishEpilog();
publisher.closeChannel();
}
}
protected void publishProbe(){
for (Publisher publisher : publishers) {
publisher.publishProbe();
}
}
//--- the listener interface that drives report generation
public void searchStarted (Search search){
publishStart();
if (probeTimer != null){
probeTimer.start();
}
}
public void stateAdvanced (Search search) {
publishTransition();
}
public void searchConstraintHit(Search search) {
publishConstraintHit();
}
public void searchProbed (Search search){
publishProbe();
}
public void propertyViolated (Search search) {
publishPropertyViolation();
}
public void searchFinished (Search search){
finished = new Date();
publishFinished();
if (probeTimer != null){
// we could interrupt, but it's a daemon anyways
probeTimer = null;
}
}
//--- various getters
public Date getStartDate() {
return started;
}
public Date getFinishedDate () {
return finished;
}
public VM getVM() {
return vm;
}
public Search getSearch() {
return search;
}
public List<Error> getErrors () {
return search.getErrors();
}
public Error getCurrentError () {
return search.getCurrentError();
}
public String getLastSearchConstraint () {
return search.getLastSearchConstraint();
}
public String getCurrentErrorId () {
Error e = getCurrentError();
if (e != null) {
return "#" + e.getId();
} else {
return "";
}
}
public int getNumberOfErrors() {
return search.getErrors().size();
}
public Statistics getStatistics() {
return stat;
}
public Statistics getStatisticsSnapshot () {
return stat.clone();
}
/**
* in ms
*/
public long getElapsedTime () {
Date d = (finished != null) ? finished : new Date();
long t = d.getTime() - started.getTime();
return t;
}
public Path getPath (){
return vm.getClonedPath();
}
public String getJPFBanner () {
StringBuilder sb = new StringBuilder();
sb.append("JavaPathfinder v");
sb.append(JPF.VERSION);
String rev = getRevision();
if (rev != null){
sb.append(" (rev ");
sb.append(rev);
sb.append(')');
}
sb.append(" - (C) RIACS/NASA Ames Research Center");
if (conf.getBoolean("report.show_repository", false)) {
String repInfo = getRepositoryInfo();
if (repInfo != null) {
sb.append( repInfo);
}
}
return sb.toString();
}
protected String getRevision() {
try {
InputStream is = JPF.class.getResourceAsStream(".version");
if (is != null){
int len = is.available();
byte[] data = new byte[len];
is.read(data);
is.close();
return new String(data).trim();
} else {
return null;
}
} catch (Throwable t){
return null;
}
}
protected String getRepositoryInfo() {
try {
InputStream is = JPF.class.getResourceAsStream("build.properties");
if (is != null){
Properties revInfo = new Properties();
revInfo.load(is);
// StringBuffer sb = new StringBuffer();
String date = revInfo.getProperty("date");
String author = revInfo.getProperty("author");
String rev = revInfo.getProperty("rev");
String machine = revInfo.getProperty("hostname");
String loc = revInfo.getProperty("location");
// String upstream = revInfo.getProperty("upstream");
return String.format("%s %s %s %s %s", date,author,rev,machine,loc);
}
} catch (IOException iox) {
return null;
}
return null;
}
public String getHostName () {
try {
InetAddress in = InetAddress.getLocalHost();
String hostName = in.getHostName();
return hostName;
} catch (Throwable t) {
return "localhost";
}
}
public String getUser() {
return System.getProperty("user.name");
}
public String getSuT() {
return vm.getSUTDescription();
}
public String getJava (){
String vendor = System.getProperty("java.vendor");
String version = System.getProperty("java.version");
return vendor + "/" + version;
}
public String getArch () {
String arch = System.getProperty("os.arch");
Runtime rt = Runtime.getRuntime();
String type = arch + "/" + rt.availableProcessors();
return type;
}
public String getOS () {
String name = System.getProperty("os.name");
String version = System.getProperty("os.version");
return name + "/" + version;
}
}