//
// 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.vm;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gov.nasa.jpf.Config;
/**
* A configuration file-driven attributor so that we can tailor JPF's
* attributor based on the application under test.
*
* The input file looks like:
* # This is a comment
* [atomic]
* <class regex> <method regex> (true|false)
* ...
* [relevance]
* <class regex> <method regex> (always|never|runnables|sync)
* ...
*
* @author Owen O'Malley
*/
public class ConfigAttributor extends DefaultAttributor {
public ConfigAttributor(Config conf) {
super(conf);
try {
parse("jpf-attributes");
} catch (FileNotFoundException e) {
// ignore
} catch (IOException e) {
System.err.println("IO exception reading attribute file: " + e);
System.err.println("Ignoring file");
relevance_rules.clear();
atomic_rules.clear();
}
}
public void setMethodInfoAttributes (MethodInfo mi) {
ClassInfo ci = mi.getClassInfo();
String cls = ci.getName();
String uniqueName = mi.getUniqueName();
super.setMethodInfoAttributes(mi);
for (NameRule rule : atomic_rules) {
if (rule.isMatch(cls, uniqueName)) {
mi.setAtomic(rule.getResult() == 1);
}
}
}
private void parse(String filename
) throws FileNotFoundException, IOException {
BufferedReader config_file = new BufferedReader(new FileReader(filename));
try {
System.out.println("Using JPF attributes from " + filename);
String line = config_file.readLine();
String current_section = null;
while (line != null) {
line = line.trim();
if (line.length() != 0 && line.charAt(0) != '#') {
if (line.charAt(0) == '[') {
current_section = parseSection(line);
} else if ("atomic".equals(current_section)) {
parseAtomicRule(line);
} else {
System.err.println("Rules found in section " + current_section +
", which is unknown.");
}
}
line = config_file.readLine();
}
} finally {
config_file.close();
}
}
private static final Pattern section_pattern =
Pattern.compile("\\[([a-zA-Z]+)\\]");
private String parseSection(String line) {
Matcher match = section_pattern.matcher(line);
if (match.matches()) {
return match.group(1);
}
System.err.println("Problem parsing section name " + line);
return null;
}
private static final Pattern atomic_rule_pattern =
Pattern.compile("([^ ]+) +([^ ]+) +(true|false)");
private void parseAtomicRule(String line) {
Matcher match = atomic_rule_pattern.matcher(line);
if (match.matches()) {
int result = 0;
String value = match.group(3);
if ("true".equals(value)) {
result = 1;
} else if ("false".equals(value)) {
result = 0;
} else {
System.err.println("Unknown atomic value: " + value);
return;
}
atomic_rules.add(new NameRule(match.group(1), match.group(2), result));
} else {
System.err.println("Atomic rule parse error on line: " + line);
}
}
/**
* A rule that contains two regular expressions that will take two strings
* and report if they match the rule.
* It also stores the result that needs to be returned if this rule matches.
*/
private static class NameRule {
NameRule(String class_pattern_string,
String method_pattern_string,
int value) {
class_pattern = Pattern.compile(class_pattern_string);
method_pattern = Pattern.compile(method_pattern_string);
result = value;
}
boolean isMatch(String class_name, String method_name) {
Matcher class_match = class_pattern.matcher(class_name);
if (class_match.matches()) {
return method_pattern.matcher(method_name).matches();
}
return false;
}
int getResult() {
return result;
}
Pattern class_pattern;
Pattern method_pattern;
int result;
}
private List<NameRule> relevance_rules = new ArrayList<NameRule>();
private List<NameRule> atomic_rules = new ArrayList<NameRule>();
}