Skip to content
Snippets Groups Projects
Commit a33d6995 authored by René Schöne's avatar René Schöne
Browse files

Harmonize Main classes

parent 2d43f40d
No related branches found
No related tags found
1 merge request!1Multiple scenes, multiple robots and more
Pipeline #9763 passed
package de.tudresden.inf.st.ros3rag.common;
import de.tudresden.inf.st.ceti.Scene;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* Shared parts of both main classes.
*
* @author rschoene - Initial contribution
*/
public abstract class SharedMainParts<MqttHandler extends SharedMainParts.MqttHandlerWrapper<MqttHandler>,
WorldModel extends SharedMainParts.WorldModelWrapper> {
protected final Logger logger = LogManager.getLogger(this.getClass());
private final String TOPIC_MODEL;
private final String TOPIC_STATUS;
private final String TOPIC_REWIND;
private final String TOPIC_EXIT;
private final String TOPIC_SCENE_INIT;
protected MqttHandler mainHandler;
protected WorldModel model;
protected Configuration config;
protected final String cellName;
protected final Path pathToConfig;
public SharedMainParts(String cellName, Path pathToConfig) {
this.cellName = cellName;
this.pathToConfig = pathToConfig;
this.TOPIC_MODEL = cellName + "/model";
this.TOPIC_STATUS = cellName + "/status";
this.TOPIC_REWIND = cellName + "/rewind";
this.TOPIC_EXIT = cellName + "/exit";
this.TOPIC_SCENE_INIT = cellName + "/scene/init";
}
protected abstract MqttHandler createMqttHandler();
private Map<String, String> channelDescriptions() {
return new LinkedHashMap<>() {{
put(TOPIC_MODEL, "Print current model (detailed if message starts with 'detail");
put(TOPIC_REWIND, "Rewind app to start");
put(TOPIC_EXIT, "Exit app");
}};
}
public void run() throws Exception {
config = Util.parseConfig(pathToConfig.toFile());
/// Prepare main handler
mainHandler = createMqttHandler().dontSendWelcomeMessage();
mainHandler.setHost(config.mqttHost);
mainHandler.waitUntilReady(2, TimeUnit.SECONDS);
CountDownLatch exitCondition = new CountDownLatch(1);
mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown());
mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes)));
mainHandler.newConnection(TOPIC_REWIND, bytes ->
{
try {
rewind("rewind");
} catch (Exception e) {
logger.catching(e);
}
}
);
createSpecificMainHandlerConnections();
logger.info("Supported commands: {}", channelDescriptions());
rewind("Start");
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
exitCondition.await();
}
protected abstract void createSpecificMainHandlerConnections();
private void rewind(String statusMessage) throws Exception {
model = createWorldModel();
Scene scene = readSceneAndRobots();
/// Setup model connection
model.ragconnectCheckIncremental();
model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
connectEndpoints();
logStatus(statusMessage);
mainHandler.publish(TOPIC_SCENE_INIT, scene.toByteArray());
}
protected abstract Scene readSceneAndRobots() throws Exception;
protected abstract void connectEndpoints() throws IOException;
protected abstract WorldModel createWorldModel();
protected abstract String getModelInfos(WorldModel model, boolean detailed);
private void logStatus(String message) {
logger.info(message);
String content = getModelInfos(model, message.equals("Start") || message.startsWith("detail"));
logger.info("WorldModelB\n{}", content);
if (mainHandler != null) {
mainHandler.publish(TOPIC_STATUS, content.getBytes(StandardCharsets.UTF_8));
}
}
private void close() {
logger.info("Exiting ...");
mainHandler.close();
model.ragconnectCloseConnections();
}
public interface MqttHandlerWrapper<SELF> {
SELF dontSendWelcomeMessage();
boolean newConnection(String topic, Consumer<byte[]> callback);
void publish(String topic, byte[] payload);
void close();
SELF setHost(String host) throws java.io.IOException;
boolean waitUntilReady(long value, TimeUnit unit);
}
public interface WorldModelWrapper {
void ragconnectCheckIncremental();
void ragconnectSetupMqttWaitUntilReady(long value, TimeUnit unit);
void ragconnectCloseConnections();
}
}
......@@ -237,3 +237,7 @@ aspect ConvenienceMethods {
return new Size(length, width, height);
}
}
aspect Glue {
class MqttHandler implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.MqttHandlerWrapper<MqttHandler> {}
}
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
aspect Resolving {
inh ObjectOfInterest Robot.resolveObjectOfInterest(String name);
eq WorldModelA.getRobot().resolveObjectOfInterest(String name) {
......@@ -10,24 +5,6 @@ aspect Resolving {
}
}
aspect Computation {
// syn LogicalScene WorldModelA.getLogicalScene() {
// LogicalScene result = new LogicalScene();
// Map<MovableObject, LogicalMovableObject> objects = new HashMap<>();
// for (DropOffLocation location : getScene().getDropOffLocationList()) {
// var logicalLocation = new LogicalDropOffLocation();
// logicalLocation.setName(location.getName());
// for (MovableObject movableObject : getScene().getMovableObjectList()) {
// if (movableObject.isLocatedAt(location)) {
// LogicalMovableObject logicalMovableObject = objects.computeIfAbsent(movableObject, k -> {
// var newLogicalMovableObject = new LogicalMovableObject();
// newLogicalMovableObject.setName(k.getName());
// return newLogicalMovableObject;
// });
// logicalLocation.addContainedObjects(logicalMovableObject);
// }
// }
// }
// return result;
// }
aspect Glue {
class WorldModelA implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.WorldModelWrapper {}
}
......@@ -4,16 +4,10 @@ import de.tudresden.inf.st.placeA.ast.MqttHandler;
import de.tudresden.inf.st.placeA.ast.Robot;
import de.tudresden.inf.st.placeA.ast.Scene;
import de.tudresden.inf.st.placeA.ast.WorldModelA;
import de.tudresden.inf.st.ros3rag.common.Configuration;
import de.tudresden.inf.st.ros3rag.common.SharedMainParts;
import de.tudresden.inf.st.ros3rag.common.Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.io.IOException;
import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri;
import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
......@@ -23,78 +17,39 @@ import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
*
* @author rschoene - Initial contribution
*/
public class MainA {
private static final Logger logger = LogManager.getLogger(MainA.class);
public class MainA extends SharedMainParts<MqttHandler, WorldModelA> {
private final String TOPIC_SCENE_UPDATE_FROM_ROS;
private final String TOPIC_SCENE_UPDATE_TO_PLACE_B;
private final static String TOPIC_MODEL = "place-a/model";
private final static String TOPIC_STATUS = "place-a/status";
private final static String TOPIC_REWIND = "place-a/rewind";
private final static String TOPIC_EXIT = "place-a/exit";
private final String TOPIC_DEMO_MOVE_objectRed1_BLUE;
private final String TOPIC_DEMO_MOVE_objectRed1_RED;
private final static String TOPIC_SCENE_INIT = "place-a/scene/init";
private final static String TOPIC_SCENE_UPDATE_FROM_ROS = "place-a/scene/update";
private final static String TOPIC_SCENE_UPDATE_TO_PLACE_B = "place-a/logical/update";
MainA(String configFile) {
super("place-a", UtilA.pathToDirectoryOfPlaceA().resolve(configFile));
this.TOPIC_SCENE_UPDATE_FROM_ROS = cellName + "/scene/update";
this.TOPIC_SCENE_UPDATE_TO_PLACE_B = cellName + "/logical/update";
private final static String TOPIC_DEMO_MOVE_objectRed1_BLUE = "place-a/demo/move/objectRed1/blue";
private final static String TOPIC_DEMO_MOVE_objectRed1_RED = "place-a/demo/move/objectRed1/red";
private MqttHandler mainHandler;
private WorldModelA model;
private Configuration config;
private static final Map<String, String> channelDescriptions = new LinkedHashMap<>() {{
put(TOPIC_MODEL, "Print current model (detailed if message starts with 'detail");
put(TOPIC_REWIND, "Rewind app to start");
put(TOPIC_EXIT, "Exit app");
}};
public static void main(String[] args) throws Exception {
new MainA().run(args);
this.TOPIC_DEMO_MOVE_objectRed1_BLUE = cellName + "/demo/move/objectRed1/blue";
this.TOPIC_DEMO_MOVE_objectRed1_RED = cellName + "/demo/move/objectRed1/red";
}
private void run(String[] args) throws Exception {
public static void main(String[] args) throws Exception {
String configFile = args.length == 0 ? "src/main/resources/config-a.yaml" : args[0];
// --- No configuration below this line ---
config = Util.parseConfig(UtilA.pathToDirectoryOfPlaceA().resolve(configFile).toFile());
/// Prepare main handler
mainHandler = new MqttHandler("mainHandler").dontSendWelcomeMessage();
mainHandler.setHost(config.mqttHost);
CountDownLatch exitCondition = new CountDownLatch(1);
mainHandler.waitUntilReady(2, TimeUnit.SECONDS);
mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown());
mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes)));
mainHandler.newConnection(TOPIC_REWIND, bytes ->
{
try {
rewind("rewind");
} catch (Exception e) {
logger.catching(e);
}
new MainA(configFile).run();
}
);
@Override
protected void createSpecificMainHandlerConnections() {
mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_BLUE, bytes ->
UtilA.updatePositionOfObjectToLocation(model.getScene(), "objectRed1", "binBlue")
);
mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_RED, bytes ->
UtilA.updatePositionOfObjectToLocation(model.getScene(), "objectRed1", "binRed")
);
logger.info("Supported commands: {}", channelDescriptions);
rewind("Start");
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
exitCondition.await();
}
private void rewind(String statusMessage) throws Exception {
model = new WorldModelA();
@Override
protected de.tudresden.inf.st.ceti.Scene readSceneAndRobots() throws Exception {
/// Reading scene and robot
de.tudresden.inf.st.ceti.Scene scene = readScene(
UtilA.pathToDirectoryOfPlaceA().resolve(config.filenameInitialScene)
......@@ -103,40 +58,34 @@ public class MainA {
model.setScene(myScene);
// if multiple robots are specified, then error message will be displayed
Util.extractRobotNames(scene).forEach(this::setRobot);
Util.extractRobotNames(scene).forEach(name -> {
if (model.getRobot() != null) {
logger.error("Robot already set. Overriding with newly found name.");
}
model.setRobot(new Robot().setName(name));
});
/// Setup model connection
model.ragconnectCheckIncremental();
model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
return scene;
}
/// Connect endpoints
@Override
protected void connectEndpoints() throws IOException {
model.connectScene(mqttUri(TOPIC_SCENE_UPDATE_FROM_ROS, config));
model.getScene().connectLogicalScene(mqttUri(TOPIC_SCENE_UPDATE_TO_PLACE_B, config), true);
logStatus(statusMessage);
mainHandler.publish(TOPIC_SCENE_INIT, scene.toByteArray());
}
private void setRobot(String name) {
if (model.getRobot() != null) {
logger.error("Robot already set. Overriding with newly found name.");
}
model.setRobot(new Robot().setName(name));
@Override
protected MqttHandler createMqttHandler() {
return new MqttHandler("mainHandlerA");
}
private void logStatus(String message) {
logger.info(message);
String content = UtilA.getModelInfos(model, message.equals("Start") || message.startsWith("detail"));
logger.info("WorldModelA\n{}", content);
if (mainHandler != null) {
mainHandler.publish(TOPIC_STATUS, content.getBytes(StandardCharsets.UTF_8));
}
@Override
protected WorldModelA createWorldModel() {
return new WorldModelA();
}
private void close() {
logger.info("Exiting ...");
mainHandler.close();
model.ragconnectCloseConnections();
@Override
protected String getModelInfos(WorldModelA worldModelA, boolean detailed) {
return UtilA.getModelInfos(model, detailed);
}
}
......@@ -182,6 +182,8 @@ aspect GlueForShared {
// uncache Difference.resolveLogicalObjectOfInterest
inh LogicalObjectOfInterest Difference.resolveLogicalObjectOfInterest(String name);
eq WorldModelB.diffScenes().resolveLogicalObjectOfInterest(String name) = getMyScene().getLogicalScene().resolveLogicalObjectOfInterest(name);
class WorldModelB implements de.tudresden.inf.st.ros3rag.common.SharedMainParts.WorldModelWrapper {}
}
aspect Printing {
......
......@@ -3,18 +3,12 @@ package de.tudresden.inf.st.placeB;
import de.tudresden.inf.st.ceti.Reachability;
import de.tudresden.inf.st.placeB.ast.*;
import de.tudresden.inf.st.ros3rag.common.Configuration;
import de.tudresden.inf.st.ros3rag.common.SharedMainParts;
import de.tudresden.inf.st.ros3rag.common.Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri;
import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
......@@ -24,77 +18,38 @@ import static de.tudresden.inf.st.ros3rag.common.Util.readScene;
*
* @author rschoene - Initial contribution
*/
public class MainB {
private static final Logger logger = LogManager.getLogger(MainB.class);
private final static String TOPIC_MODEL = "place-b/model";
private final static String TOPIC_STATUS = "place-b/status";
private final static String TOPIC_REWIND = "place-b/rewind";
private final static String TOPIC_EXIT = "place-b/exit";
private final static String TOPIC_MY_SCENE_INIT = "place-b/scene/init";
private final static String TOPIC_ROBOT_REACHABILITY = "place-b/reachability/%s";
private final static String TOPIC_MY_SCENE_UPDATE_FROM_ROS = "place-b/scene/update";
private final static String TOPIC_COMMAND = "place-b/command";
private final static String TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A = "place-a/logical/update";
private final static String TOPIC_DEMO_MOVE_objectRed1_RED = "place-b/demo/move/objectRed1/red";
private MqttHandler mainHandler;
private WorldModelB model;
private Configuration config;
private static final Map<String, String> channelDescriptions = new LinkedHashMap<>() {{
put(TOPIC_MODEL, "Print current model (detailed if message starts with 'detail");
put(TOPIC_REWIND, "Rewind app to start");
put(TOPIC_EXIT, "Exit app");
}};
public static void main(String[] args) throws Exception {
new MainB().run(args);
public class MainB extends SharedMainParts<MqttHandler, WorldModelB> {
private final String TOPIC_ROBOT_REACHABILITY;
private final String TOPIC_MY_SCENE_UPDATE_FROM_ROS;
private final String TOPIC_COMMAND;
private final String TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A;
private final String TOPIC_DEMO_MOVE_objectRed1_RED;
MainB(String configFile) {
super("place-b", UtilB.pathToDirectoryOfPlaceB().resolve(configFile));
this.TOPIC_ROBOT_REACHABILITY = cellName + "/reachability/%s";
this.TOPIC_MY_SCENE_UPDATE_FROM_ROS = cellName + "/scene/update";
this.TOPIC_COMMAND = cellName + "/command";
this.TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A = "place-a/logical/update";
this.TOPIC_DEMO_MOVE_objectRed1_RED = cellName + "/demo/move/objectRed1/red";
}
private void run(String[] args) throws Exception {
public static void main(String[] args) throws Exception {
String configFile = args.length == 0 ? "src/main/resources/config-b.yaml" : args[0];
// --- No configuration below this line ---
config = Util.parseConfig(UtilB.pathToDirectoryOfPlaceB().resolve(configFile).toFile());
/// Prepare main handler
mainHandler = new MqttHandler("mainHandler").dontSendWelcomeMessage();
mainHandler.setHost(config.mqttHost);
mainHandler.waitUntilReady(2, TimeUnit.SECONDS);
CountDownLatch exitCondition = new CountDownLatch(1);
mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown());
mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes)));
mainHandler.newConnection(TOPIC_REWIND, bytes ->
{
try {
rewind("rewind");
} catch (Exception e) {
logger.catching(e);
}
new MainB(configFile).run();
}
);
@Override
protected void createSpecificMainHandlerConnections() {
mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_RED, bytes ->
UtilB.updatePositionOfObjectToLocation(model.getMyScene(), "objectRed1", "binRed")
);
logger.info("Supported commands: {}", channelDescriptions);
rewind("Start");
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
exitCondition.await();
}
private void rewind(String statusMessage) throws Exception {
model = new WorldModelB();
@Override
protected de.tudresden.inf.st.ceti.Scene readSceneAndRobots() throws Exception {
/// Reading scene and robots
de.tudresden.inf.st.ceti.Scene scene = readScene(
UtilB.pathToDirectoryOfPlaceB().resolve(config.filenameInitialScene)
......@@ -121,33 +76,29 @@ public class MainB {
}
}
/// Setup model connection
model.ragconnectCheckIncremental();
model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
return scene;
}
/// Connect endpoints
@Override
protected void connectEndpoints() throws IOException {
model.connectMyScene(mqttUri(TOPIC_MY_SCENE_UPDATE_FROM_ROS, config));
model.connectOtherScene(mqttUri(TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A, config));
model.connectNextOperation(mqttUri(TOPIC_COMMAND, config), false);
logStatus(statusMessage);
mainHandler.publish(TOPIC_MY_SCENE_INIT, scene.toByteArray());
}
private void logStatus(String message) {
logger.info(message);
String content = UtilB.getModelInfos(model, message.equals("Start") || message.startsWith("detail"));
logger.info("WorldModelB\n{}", content);
if (mainHandler != null) {
mainHandler.publish(TOPIC_STATUS, content.getBytes(StandardCharsets.UTF_8));
@Override
protected MqttHandler createMqttHandler() {
return new MqttHandler("mainHandlerB");
}
@Override
protected WorldModelB createWorldModel() {
return new WorldModelB();
}
private void close() {
logger.info("Exiting ...");
mainHandler.close();
model.ragconnectCloseConnections();
@Override
protected String getModelInfos(WorldModelB worldModelB, boolean detailed) {
return UtilB.getModelInfos(model, detailed);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment