Commit e2b5d7e1 authored by René Schöne's avatar René Schöne
Browse files

WIP: Adding test pipeline.

parent e750904f
apply plugin: 'java'
apply plugin: 'jastadd'
apply plugin: 'application'
apply plugin: "idea"
sourceCompatibility = 1.8
......@@ -20,14 +17,11 @@ buildscript {
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.0'
testCompile 'org.assertj:assertj-core:3.12.1'
compile 'com.fasterxml.jackson.core:jackson-core:2.9.8'
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
compile 'org.jastadd:jastadd:2.3.4'
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
// api 'org.jastadd:jastadd:2.3.4'
runtime 'org.jastadd:jastadd:2.3.4'
compile group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
}
sourceSets {
......@@ -163,3 +157,5 @@ jastadd {
}
generateAst.dependsOn relast
apply from: 'test.build.gradle'
//import java.util.Set;
//import java.util.TreeSet;
//import java.util.LinkedList;
//
//
//
//
//aspect ErrorMessage {
// public class ErrorMessage implements Comparable<ErrorMessage> {
// private final ASTNode node;
// private final String filename;
// private final int line;
// private final int col;
// private final String message;
//
// public ErrorMessage(ASTNode node, String message) {
// this.node = node;
// this.filename = node.containedFile().getFileName();
// this.line = node.getStartLine();
// this.col = node.getStartColumn();
// this.message = message;
// }
//
// public ASTNode getNode() {
// return node;
// }
// public int getLine() {
// return line;
// }
// public int getCol() {
// return col;
// }
// public String getMessage() {
// return message;
// }
//
// public String toString() {
// return filename + " Line " + line + ", column " + col + ": " + message;
// }
//
// @Override
// public int compareTo(ErrorMessage err) {
// int n = filename.compareTo(err.filename);
// if (n != 0) {
// return n;
// }
//
// n = line - err.line;
// if (n != 0) {
// return n;
// }
//
// n = col-err.col;
// if (n != 0) {
// return n;
// }
//
// return message.compareTo(err.message);
// }
// }
//
// protected ErrorMessage ASTNode.error(String message) {
// return new ErrorMessage(this, message);
// }
//}
import java.util.Set;
import java.util.TreeSet;
import java.util.LinkedList;
aspect Errors {
coll Set<ErrorMessage> Ros2Rag.errors()
[new TreeSet<ErrorMessage>()]
root Ros2Rag;
// TypeUse contributes error("Type '" + getID() + "' not found")
// when decl() == null && !isToken()
// to Program.errors();
UpdateDefinition contributes error("")
when true
to Ros2Rag.errors();
}
aspect ErrorMessage {
public class ErrorMessage implements Comparable<ErrorMessage> {
private final ASTNode node;
private final String filename;
private final int line;
private final int col;
private final String message;
public ErrorMessage(ASTNode node, String message) {
this.node = node;
this.filename = node.containedFile().getFileName();
this.line = node.getStartLine();
this.col = node.getStartColumn();
this.message = message;
}
public ASTNode getNode() {
return node;
}
public int getLine() {
return line;
}
public int getCol() {
return col;
}
public String getMessage() {
return message;
}
public String toString() {
return filename + " Line " + line + ", column " + col + ": " + message;
}
@Override
public int compareTo(ErrorMessage err) {
int n = filename.compareTo(err.filename);
if (n != 0) {
return n;
}
n = line - err.line;
if (n != 0) {
return n;
}
n = col-err.col;
if (n != 0) {
return n;
}
return message.compareTo(err.message);
}
}
protected ErrorMessage ASTNode.error(String message) {
return new ErrorMessage(this, message);
}
}
......@@ -90,7 +90,7 @@ aspect AspectGeneration {
}
public void Ros2Rag.generateGrammarExtension(StringBuilder sb) {
sb.append("aspect ros2rag.GrammarExtension {\n");
sb.append("aspect ROS2RAG {\n");
for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb);
......@@ -144,7 +144,7 @@ aspect AspectGeneration {
sb.append(ind(2)).append(mqttUpdaterAttribute()).append("().newConnection(topic, message -> {\n");
String lastResult = generateMappingApplication(sb, 3, "message");
sb.append(ind(3)).append("set").append(getToken().getName()).append("(").append(lastResult).append(");\n");
sb.append(ind(2)).append("}\n");
sb.append(ind(2)).append("});\n");
sb.append(ind(1)).append("}\n\n");
}
......@@ -168,7 +168,7 @@ aspect AspectGeneration {
sb.append(ind(1)).append("}\n\n");
// update method
sb.append(ind(1)).append("protected boolean").append(parentTypeName).append(".")
sb.append(ind(1)).append("protected boolean ").append(parentTypeName).append(".")
.append(updateMethod()).append("() {\n");
sb.append(ind(2)).append(tokenResetMethod()).append("();\n");
String lastResult = generateMappingApplication(sb, 2, "get" + getToken().getName() + "()");
......@@ -177,7 +177,7 @@ aspect AspectGeneration {
sb.append(ind(1)).append("}\n\n");
// write method
sb.append(ind(1)).append("protected void").append(parentTypeName).append(".")
sb.append(ind(1)).append("protected void ").append(parentTypeName).append(".")
.append(writeMethod()).append("() {\n");
// _mqttUpdater().publish(${writeTopic()}, ${lastValue()});
sb.append(ind(2)).append(mqttUpdaterAttribute()).append("().publish(")
......@@ -202,7 +202,7 @@ aspect AspectGeneration {
String sourceParentTypeName = getSource().containingTypeDecl().getName();
// dependency method
sb.append(ind(1)).append("public void").append(targetParentTypeName).append(".")
sb.append(ind(1)).append("public void ").append(targetParentTypeName).append(".")
.append(dependencyMethod()).append("(").append(sourceParentTypeName).append(" source) {\n");
sb.append(ind(2)).append("add").append(internalRelationPrefix()).append("Source(source);\n");
sb.append(ind(1)).append("}\n\n");
......
......@@ -4,6 +4,7 @@ import beaver.Parser;
import org.jastadd.ros2rag.ast.*;
import org.jastadd.ros2rag.compiler.options.CommandLine;
import org.jastadd.ros2rag.compiler.options.CommandLine.CommandLineException;
import org.jastadd.ros2rag.compiler.options.FlagOption;
import org.jastadd.ros2rag.compiler.options.Option;
import org.jastadd.ros2rag.compiler.options.StringOption;
import org.jastadd.ros2rag.parser.Ros2RagParser;
......@@ -22,6 +23,7 @@ public class Compiler {
private StringOption optionInputGrammar;
private StringOption optionRootNode;
private StringOption optionInputRos2Rag;
private FlagOption optionHelp;
private ArrayList<Option<?>> options;
private CommandLine commandLine;
......@@ -31,23 +33,34 @@ public class Compiler {
addOptions();
}
public int run(String[] args) throws CommandLineException, CompilerException {
public void run(String[] args) throws CommandLineException, CompilerException {
options = new ArrayList<>();
addOptions();
commandLine = new CommandLine(options);
commandLine.parse(args);
String outputDir = "gen"; // should not be used, but otherwise there is a compiler warning
if (optionHelp.isSet()) {
printUsage();
return;
}
String outputDir;
if (optionOutputDir.isSet()) {
outputDir = optionOutputDir.getValue();
} else {
outputDir = "gen";
System.out.println("No output output dir is set. Assuming '" + outputDir + "'.");
}
try {
Files.createDirectories(Paths.get(outputDir));
} catch (IOException e) {
throw new CompilerException("Error creating output dir " + outputDir, e);
}
printMessage("Running ROS2RAG Preprocessor");
printMessage("Running Ros2Rag Preprocessor");
if (anyRequiredOptionIsUnset()) {
return error("Aborting.");
throw new CompilerException("Aborting due to missing values for required options.");
}
List<String> otherArgs = commandLine.getArguments();
......@@ -59,15 +72,14 @@ public class Compiler {
printMessage("Writing output files");
// copy MqttUpdater into outputDir
try {
Files.copy(Paths.get("src", "main", "jastadd", "MqttUpdater.java_class"),
Paths.get(outputDir, "MqttUpdater.java"),
Files.copy(Paths.get("src", "main", "resources", "MqttUpdater.jadd"),
Paths.get(outputDir, "MqttUpdater.jadd"),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new CompilerException("Could not copy MqttUpdater.java", e);
}
writeToFile(outputDir + "/Grammar.relast", ros2Rag.getProgram().generateAbstractGrammar());
writeToFile(outputDir + "/ROS2RAG.jadd", ros2Rag.generateAspect(optionRootNode.getValue()));
return 0;
}
private boolean anyRequiredOptionIsUnset() {
......@@ -111,6 +123,7 @@ public class Compiler {
optionInputGrammar = addOption(new StringOption("inputGrammar", "base grammar."));
optionRootNode = addOption(new StringOption("rootNode", "root node in the base grammar."));
optionInputRos2Rag = addOption(new StringOption("inputRos2Rag", "ros2rag definition file."));
optionHelp = addOption(new FlagOption("help", "Print usage and exit."));
}
private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
......@@ -149,35 +162,18 @@ public class Compiler {
return ros2Rag;
}
private void parse(Program program, Reader reader, String file) {
Ros2RagScanner scanner = new Ros2RagScanner(reader);
Ros2RagParser parser = new Ros2RagParser();
try {
GrammarFile newFile = (GrammarFile) parser.parse(scanner);
program.addGrammarFile(newFile);
} catch (IOException e) {
error(e.getMessage());
} catch (Parser.Exception e) {
System.err.println("Parse error in file " + file);
System.err.println(e.getMessage());
System.exit(1);
}
}
protected int error(String message) {
System.err.println("Error: " + message);
System.err.println();
System.err.println("Usage: java -jar ros2rag.jar [--option1] [--option2=value] ... <filename1> <filename2> ... ");
System.err.println("Options:");
System.err.print(commandLine.printOptionHelp());
return 1;
protected void printUsage() {
System.out.println("Usage: java -jar ros2rag.jar [--option1] [--option2=value] ... <filename1> <filename2> ... ");
System.out.println("Options:");
System.out.print(commandLine.printOptionHelp());
}
public static class CompilerException extends Exception {
CompilerException(String message) {
super(message);
}
CompilerException(String message, Throwable cause) {
super(message, cause);
}
}
}
package org.jastadd.ros2rag.compiler.mqtt;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.*;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
/**
* Helper class to receive updates via MQTT and use callbacks to handle those messages.
*
......@@ -25,33 +5,33 @@ import java.util.function.Consumer;
*/
public class MqttUpdater {
private final Logger logger;
private final org.apache.logging.log4j.Logger logger;
private final String name;
/** The host running the MQTT broker. */
private URI host;
private java.net.URI host;
/** The connection to the MQTT broker. */
private CallbackConnection connection;
private org.fusesource.mqtt.client.CallbackConnection connection;
/** Whether we are subscribed to the topics yet */
private final Condition readyCondition;
private final Lock readyLock;
private final java.util.concurrent.locks.Condition readyCondition;
private final java.util.concurrent.locks.Lock readyLock;
private boolean ready;
private QoS qos;
private org.fusesource.mqtt.client.QoS qos;
/** Dispatch knowledge */
private final Map<String, Consumer<byte[]>> callbacks;
private final java.util.Map<String, java.util.function.Consumer<byte[]>> callbacks;
public MqttUpdater() {
this("Ros2Rag");
}
public MqttUpdater(String name) {
this.name = Objects.requireNonNull(name, "Name must be set");
this.logger = LogManager.getLogger(MqttUpdater.class);
this.callbacks = new HashMap<>();
this.readyLock = new ReentrantLock();
this.name = java.util.Objects.requireNonNull(name, "Name must be set");
this.logger = org.apache.logging.log4j.LogManager.getLogger(MqttUpdater.class);
this.callbacks = new java.util.HashMap<>();
this.readyLock = new java.util.concurrent.locks.ReentrantLock();
this.readyCondition = readyLock.newCondition();
this.ready = false;
this.qos = QoS.AT_LEAST_ONCE;
this.qos = org.fusesource.mqtt.client.QoS.AT_LEAST_ONCE;
}
/**
......@@ -59,18 +39,18 @@ public class MqttUpdater {
* @throws IOException if could not connect, or could not subscribe to a topic
* @return self
*/
public MqttUpdater setHost(String host, int port) throws IOException {
this.host = URI.create("tcp://" + host + ":" + port);
public MqttUpdater setHost(String host, int port) throws java.io.IOException {
this.host = java.net.URI.create("tcp://" + host + ":" + port);
logger.debug("Host for {} is {}", this.name, this.host);
Objects.requireNonNull(this.host, "Host need to be set!");
MQTT mqtt = new MQTT();
java.util.Objects.requireNonNull(this.host, "Host need to be set!");
org.fusesource.mqtt.client.MQTT mqtt = new org.fusesource.mqtt.client.MQTT();
mqtt.setHost(this.host);
connection = mqtt.callbackConnection();
AtomicReference<Throwable> error = new AtomicReference<>();
java.util.concurrent.atomic.AtomicReference<Throwable> error = new java.util.concurrent.atomic.AtomicReference<>();
// add the listener to dispatch messages later
connection.listener(new ExtendedListener() {
connection.listener(new org.fusesource.mqtt.client.ExtendedListener() {
public void onConnected() {
logger.debug("Connected");
}
......@@ -81,9 +61,9 @@ public class MqttUpdater {
}
@Override
public void onPublish(UTF8Buffer topic, Buffer body, Callback<Callback<Void>> ack) {
public void onPublish(org.fusesource.hawtbuf.UTF8Buffer topic, org.fusesource.hawtbuf.Buffer body, org.fusesource.mqtt.client.Callback<org.fusesource.mqtt.client.Callback<Void>> ack) {
String topicString = topic.toString();
Consumer<byte[]> callback = callbacks.get(topicString);
java.util.function.Consumer<byte[]> callback = callbacks.get(topicString);
if (callback == null) {
logger.debug("Got a message, but no callback to call. Forgot to unsubscribe?");
} else {
......@@ -95,7 +75,7 @@ public class MqttUpdater {
}
@Override
public void onPublish(UTF8Buffer topicBuffer, Buffer body, Runnable ack) {
public void onPublish(org.fusesource.hawtbuf.UTF8Buffer topicBuffer, org.fusesource.hawtbuf.Buffer body, Runnable ack) {
logger.warn("onPublish should not be called");
}
......@@ -108,10 +88,10 @@ public class MqttUpdater {
throwIf(error);
// actually establish the connection
connection.connect(new Callback<Void>() {
connection.connect(new org.fusesource.mqtt.client.Callback<Void>() {
@Override
public void onSuccess(Void value) {
connection.publish("components", (name + " is connected").getBytes(), QoS.AT_LEAST_ONCE, false, new Callback<Void>() {
connection.publish("components", (name + " is connected").getBytes(), org.fusesource.mqtt.client.QoS.AT_LEAST_ONCE, false, new org.fusesource.mqtt.client.Callback<Void>() {
@Override
public void onSuccess(Void value) {
logger.debug("success sending welcome message");
......@@ -141,21 +121,21 @@ public class MqttUpdater {
return this;
}
public URI getHost() {
public java.net.URI getHost() {
return host;
}
private void throwIf(AtomicReference<Throwable> error) throws IOException {
private void throwIf(java.util.concurrent.atomic.AtomicReference<Throwable> error) throws java.io.IOException {
if (error.get() != null) {
throw new IOException(error.get());
throw new java.io.IOException(error.get());
}
}
public void setQoSForSubscription(QoS qos) {
public void setQoSForSubscription(org.fusesource.mqtt.client.QoS qos) {
this.qos = qos;
}
public void newConnection(String topic, Consumer<byte[]> callback) {
public void newConnection(String topic, java.util.function.Consumer<byte[]> callback) {
if (!ready) {
// TODO should maybe be something more kind than throwing an exception here
throw new IllegalStateException("Updater not ready");
......@@ -165,7 +145,7 @@ public class MqttUpdater {
// subscribe at broker
Topic[] topicArray = { new Topic(topic, this.qos) };
connection.subscribe(topicArray, new Callback<byte[]>() {
connection.subscribe(topicArray, new org.fusesource.mqtt.client.Callback<byte[]>() {
@Override
public void onSuccess(byte[] qoses) {
logger.debug("Subscribed to {}, qoses: {}", topic, qoses);
......@@ -187,7 +167,7 @@ public class MqttUpdater {
* @param unit the time unit of the time argument
* @return whether this updater is ready
*/
public boolean waitUntilReady(long time, TimeUnit unit) {
public boolean waitUntilReady(long time, java.util.concurrent.TimeUnit unit) {
try {
readyLock.lock();
if (ready) {
......@@ -207,7 +187,7 @@ public class MqttUpdater {
logger.warn("Stopping without connection. Was setHost() called?");
return;
}
connection.disconnect(new Callback<Void>() {
connection.disconnect(new org.fusesource.mqtt.client.Callback<Void>() {
@Override
public void onSuccess(Void value) {
logger.info("Disconnected {} from {}", name, host);
......@@ -221,7 +201,7 @@ public class MqttUpdater {
}
public void publish(String topic, byte[] bytes) {
connection.publish(topic, bytes, qos, false, new Callback<Void>() {
connection.publish(topic, bytes, qos, false, new org.fusesource.mqtt.client.Callback<Void>() {
@Override
public void onSuccess(Void value) {
logger.debug("Published some bytes to {}", topic);
......
02-after-ros2rag/*
03-after-relast/*
java-gen/*
......@@ -6,7 +6,7 @@ Zone ::= Coordinate* ;
RobotArm ::= Joint* EndEffector <AttributeTestSource:int> /<AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ;
Joint ::= <Name> <CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition>
Joint ::= <Name:String> <CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition>
EndEffector : Joint;
......
syntax = "proto3";
package panda;
message PandaLinkState {
string name = 1;
message Position {
float positionX = 1;
float positionY = 2;
float positionZ = 3;
}
message Orientation {
float orientationX = 1;
float orientationY = 2;
float orientationZ = 3;
float orientationW = 4;
}
message TwistLinear {
float twistLinearX = 1;
float twistLinearY = 2;
float twistLinearZ = 3;
}
message TwistAngular {
float twistAngularX = 1;
float twistAngularY = 2;
float twistAngularZ = 3;
}
Position pos = 2;
Orientation orient = 3;
TwistLinear tl = 4;
TwistAngular ta = 5;
}
syntax = "proto3";
package config;
message RobotConfig {
double speed = 1;
bool loopTrajectory = 2;
enum PlanningMode {
FLUID = 0;
CARTESIAN = 1;
}
PlanningMode planningMode = 3;
}
package org.jastadd.ros2rag.tests;
import example.ast.*;
import org.junit.jupiter.api.Test;
/**
* Test case "example".
*
* @author rschoene - Initial contribution
*/
public class ExampleTest {
@Test
public void buildModel() {
Model model = new Model();
model.MqttSetHost("localhost");
ZoneModel zoneModel = new ZoneModel();
zoneModel.setSize(makePosition(1, 1, 1));