package pebl.xsd;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import pebl.benchmark.feature.Capability;
import pebl.benchmark.feature.Feature;
import pebl.benchmark.feature.HasMetrics;
import pebl.benchmark.feature.Metric;
import pebl.benchmark.feature.MetricType;
import pebl.benchmark.test.Test;
import pebl.result.engine.Engine;
import pebl.result.feature.AggregatedResult;
import pebl.result.test.TestResult;
@XmlRootElement
public class PEBL {
public static PEBL from(Path path) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(PEBL.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
PEBL pebl;
if(path.endsWith(".json")) {
unmarshaller.setProperty("eclipselink.media-type", "application/json");
unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
pebl = (PEBL) unmarshaller.unmarshal(path.toFile());
} else {
pebl = (PEBL) unmarshaller.unmarshal(path.toFile());
}
pebl.makeFilesAbsolute(path.toAbsolutePath().getParent());
//TODO reenable link assertion
//pebl.assertLinksWork();
return pebl;
}
private void toJson(Path path) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(PEBL.class);
Marshaller m4json = jc.createMarshaller();
m4json.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m4json.setProperty("eclipselink.media-type", "application/json");
m4json.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
m4json.marshal(this, path.toFile());
}
private void toXml(Path path) throws IOException {
JAXB.marshal(this, path.toFile());
}
public void assertLinksWork() {
List<Path> unlinked = new LinkedList<>();
Predicate<Path> relative = f -> !f.toAbsolutePath().toString().equals(f.toString());
Predicate<Path> missing = f -> !Files.exists(f);
benchmark.tests.forEach(e -> {
e.getFiles().stream().filter(missing.or(relative)).forEach(unlinked::add);
Optional.of(e.getProcess()).filter(missing.or(relative)).ifPresent(unlinked::add);
});
result.testResults.forEach(e -> {
e.getFiles().stream().filter(missing.or(relative)).forEach(unlinked::add);
e.getLogs().stream().filter(missing.or(relative)).forEach(unlinked::add);
});
if(unlinked.size() > 0) {
throw new IllegalStateException("Unlinked files: " + unlinked);
}
}
public void writeTo(Path workingDirectory) {
try {
Files.createDirectories(workingDirectory);
} catch (IOException e) {
throw new RuntimeException(e);
}
makeFilesRelative(workingDirectory.toAbsolutePath());
try {
toJson(workingDirectory.resolve("pebl.json"));
toXml(workingDirectory.resolve("pebl.xml"));
} catch (IOException | JAXBException e) {
throw new RuntimeException(e);
}
}
private void makeFilesAbsolute(Path workingDirectory) {
benchmark.tests.forEach(e -> {
final List<Path> files = e.getFiles()
.stream()
.map(workingDirectory::resolve)
.map(Path::toAbsolutePath)
.collect(Collectors.toList());
e.getFiles().clear();
e.getFiles().addAll(files);
e.setProcess(workingDirectory.resolve(e.getProcess()).toAbsolutePath());
});
result.testResults.forEach(e -> {
final List<Path> files = e.getFiles()
.stream()
.map(workingDirectory::resolve)
.map(Path::toAbsolutePath)
.collect(Collectors.toList());
e.getFiles().clear();
e.getFiles().addAll(files);
final List<Path> logFiles = e.getLogs()
.stream()
.map(workingDirectory::resolve)
.map(Path::toAbsolutePath)
.collect(Collectors.toList());
e.getLogs().clear();
e.getLogs().addAll(logFiles);
});
}
public void makeFilesRelative(Path workingDirectory) {
benchmark.tests.forEach(e -> {
final List<Path> files = new LinkedList<>();
for(Path file : e.getFiles()) {
// requires file to be absolute
Path relativeFile = workingDirectory.relativize(file.toAbsolutePath());
files.add(relativeFile);
}
e.getFiles().clear();
e.getFiles().addAll(files);
e.setProcess(workingDirectory.relativize(e.getProcess().toAbsolutePath()));
});
result.testResults.forEach(e -> {
final List<Path> files = e.getFiles()
.stream()
.map(Path::toAbsolutePath)
.map(workingDirectory::relativize)
.collect(Collectors.toList());
e.getFiles().clear();
e.getFiles().addAll(files);
final List<Path> logFiles = e.getLogs()
.stream()
.map(Path::toAbsolutePath)
.map(workingDirectory::relativize)
.collect(Collectors.toList());
e.getLogs().clear();
e.getLogs().addAll(logFiles);
});
}
public static class Benchmark {
@XmlElement(name = "capability")
@XmlElementWrapper(name = "capabilities")
public List<Capability> capabilities = new LinkedList<>();
@XmlElement(name = "test")
@XmlElementWrapper(name = "tests")
public List<Test> tests = new LinkedList<>();
@XmlElement(name = "metricType")
@XmlElementWrapper(name = "metricTypes")
public List<MetricType> metricTypes = new LinkedList<>();
}
public static class Result {
@XmlElement(name = "engine")
@XmlElementWrapper(name = "engines")
public List<Engine> engines = new LinkedList<>();
@XmlElement(name = "testResult")
@XmlElementWrapper(name = "testResults")
public List<TestResult> testResults = new LinkedList<>();
@XmlElement(name = "aggregatedResult")
@XmlElementWrapper(name = "aggregatedResults")
public List<AggregatedResult> aggregatedResults = new LinkedList<>();
}
@XmlElement(required = true)
public Benchmark benchmark = new Benchmark();
@XmlElement(required = true)
public Result result = new Result();
public Engine getEngine(String id) {
return this.result.engines.stream()
.filter(e -> e.getId().equals(id))
.findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
public Test getTest(String id) {
return this.benchmark.tests.stream().filter(e -> e.getId().equals(id)).findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
public Capability getCapability(String id) {
return this.benchmark.capabilities.stream().filter(e -> e.getId().equals(id)).findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
public MetricType getMetricType(String id) {
return this.benchmark.metricTypes.stream()
.filter(e -> e.getId().equals(id)).findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
public Metric getMetric(String id) {
List<HasMetrics> list = new LinkedList<>();
this.benchmark.capabilities.stream()
.peek(list::add)
.flatMap(c -> c.getLanguages().stream())
.peek(list::add)
.flatMap(l -> l.getGroups().stream())
.peek(list::add)
.flatMap(g -> g.getFeatureSets().stream())
.peek(list::add)
.flatMap(fs -> fs.getFeatures().stream())
.peek(list::add)
.count();
this.benchmark.tests.forEach(list::add);
return list.stream()
.flatMap(e -> e.getMetrics().stream())
.filter(m -> m.getId().equals(id))
.findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
public Feature getFeature(String id) {
return this.benchmark.capabilities.stream()
.flatMap(c -> c.getLanguages().stream())
.flatMap(l -> l.getGroups().stream())
.flatMap(g -> g.getFeatureSets().stream())
.flatMap(fs -> fs.getFeatures().stream())
.filter(e -> e.getId().equals(id)).findFirst()
.orElseThrow(() -> new IllegalStateException(id));
}
}