diff --git a/pom.xml b/pom.xml index a8c0be6..5a2ae7a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 de.srsoftware web4rail - 0.7.6 + 0.7.7 Web4Rail jar Java Model Railway Control diff --git a/src/main/java/de/srsoftware/web4rail/Application.java b/src/main/java/de/srsoftware/web4rail/Application.java index 070ae61..2a9e5e9 100644 --- a/src/main/java/de/srsoftware/web4rail/Application.java +++ b/src/main/java/de/srsoftware/web4rail/Application.java @@ -25,6 +25,7 @@ import com.sun.net.httpserver.HttpServer; import de.keawe.localconfig.Configuration; import de.keawe.tools.translations.Translation; import de.srsoftware.tools.Tag; +import de.srsoftware.web4rail.conditions.Condition; import de.srsoftware.web4rail.moving.Car; import de.srsoftware.web4rail.moving.Locomotive; import de.srsoftware.web4rail.moving.Train; @@ -63,6 +64,8 @@ public class Application implements Constants{ switch (realm) { case REALM_CAR: return Car.action(params); + case REALM_CONDITION: + return Condition.action(params); case REALM_CU: return plan.controlUnit().process(params); case REALM_LOCO: diff --git a/src/main/java/de/srsoftware/web4rail/Constants.java b/src/main/java/de/srsoftware/web4rail/Constants.java index 661f9f0..6128559 100644 --- a/src/main/java/de/srsoftware/web4rail/Constants.java +++ b/src/main/java/de/srsoftware/web4rail/Constants.java @@ -29,13 +29,14 @@ public interface Constants { public static final String ACTION_TURN = "turn"; public static final String ACTION_UPDATE = "update"; - public static final String REALM = "realm"; - public static final String REALM_CAR = "car"; - public static final String REALM_CU = "cu"; - public static final String REALM_LOCO = "loco"; - public static final String REALM_ROUTE = "route"; - public static final String REALM_PLAN = "plan"; - public static final String REALM_TRAIN = "train"; + public static final String REALM = "realm"; + public static final String REALM_CAR = "car"; + public static final String REALM_CONDITION = "condition"; + public static final String REALM_CU = "cu"; + public static final String REALM_LOCO = "loco"; + public static final String REALM_ROUTE = "route"; + public static final String REALM_PLAN = "plan"; + public static final String REALM_TRAIN = "train"; public static final String ID = "id"; public static final String PORT = "port"; @@ -43,5 +44,4 @@ public interface Constants { public static final String CONTACT = "contact"; public static final String TYPE = "type"; public static final String NBSP = " "; - } diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java index 5ff3cca..ec09a3c 100644 --- a/src/main/java/de/srsoftware/web4rail/Route.java +++ b/src/main/java/de/srsoftware/web4rail/Route.java @@ -26,6 +26,7 @@ import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.actions.Action; import de.srsoftware.web4rail.actions.Action.Context; import de.srsoftware.web4rail.actions.ActivateRoute; +import de.srsoftware.web4rail.actions.ConditionalAction; import de.srsoftware.web4rail.actions.FinishRoute; import de.srsoftware.web4rail.actions.SetSignalsToStop; import de.srsoftware.web4rail.actions.SpeedReduction; @@ -82,7 +83,8 @@ public class Route implements Constants{ SpeedReduction.class, SetSignalsToStop.class, FinishRoute.class, - TurnTrain.class); + TurnTrain.class, + ConditionalAction.class); for (Class clazz : classes) select.addOption(clazz.getSimpleName()); select.addTo(new Label("Action type:")).addTo(typeForm); return new Button(t("Create action"),"return submitForm('"+formId+"');").addTo(typeForm); @@ -127,13 +129,14 @@ public class Route implements Constants{ Tile tag = plan.get(contactId, false); if (!(tag instanceof Contact)) return t("No contact id passed to request!"); Contact contact = (Contact) tag; + String type = params.get(TYPE); Window win = new Window("add-action-form", t("Add action to contact on route")); new Tag("div").content("Route: "+this).addTo(win); new Tag("div").content("Contact: "+contact).addTo(win); - - String type = params.get(TYPE); if (type == null) return (actionTypeForm(contact).addTo(win)); switch (type) { + case "ConditionalAction": + return ConditionalAction.propForm(params,this,contact); case "FinishRoute": addAction(contact.trigger(),new FinishRoute(id())); break; @@ -184,7 +187,7 @@ public class Route implements Constants{ Tag ul = new Tag("ul"); boolean first = true; for (Action action : actions) { - props.put(ACTION_ID, action.toString()); + props.put(ACTION_ID, action.id()); Tag act = new Tag("li").content(action.toString()); if (!first) { @@ -469,8 +472,10 @@ public class Route implements Constants{ } public Object moveAction(HashMap params) { - String action_id = params.get(ACTION_ID); - if (action_id == null) return t("No action id passed to request!"); + if (!params.containsKey(ACTION_ID)) return t("No action id passed to request!"); + + int action_id = Integer.parseInt(params.get(ACTION_ID)); + String contactId = params.get(CONTACT); Tile tag = plan.get(contactId, false); if (!(tag instanceof Contact)) return t("No contact id passed to request!"); @@ -478,7 +483,7 @@ public class Route implements Constants{ Vector actions = triggers.get(contact.trigger()); for (int i=1; i conditions = new Vector(); + private Vector actions = new Vector(); + + private ConditionalAction addCondition(Condition condition) { + conditions.add(new TrainSelect()); + return this; + } + + private static void addToContact(Route route, Contact contact, String conditionType) { + Condition condition = null; + switch (conditionType) { + case "TrainSelect": + condition = new TrainSelect(); + break; + default: return; + } + route.addAction(contact.trigger(), new ConditionalAction().addCondition(condition)); + } + + @Override + public boolean fire(Context context) throws IOException { + for (Condition condition : conditions) { + if (condition.fulfilledBy(context)) return fireActions(context); + } + return false; + } + + private boolean fireActions(Context context) { + for (Action action : actions) try { + action.fire(context); + } catch (IOException e) { + LOG.warn("Was not able to fire {}",action); + } + return true; + } + + public static Window propForm(HashMap params, Route route, Contact contact) { + String condition = params.get(REALM_CONDITION); + if (condition != null) { + addToContact(route,contact,condition); + return route.properties(); + } + Window win = Action.propForm(params); + String formId = "add-action-to-contact-"+contact.id(); + Tag form = new Form(formId); + new Tag("div").content(t("Add Action {} to contact {} on route {}:",ConditionalAction.class.getSimpleName(),contact,route)).addTo(win); + new Input(REALM, REALM_ROUTE).hideIn(form); + new Input(ID,route.id()).hideIn(form); + new Input(ACTION,ACTION_ADD_ACTION).hideIn(form); + new Input(CONTACT,contact.id()).hideIn(form); + new Input(TYPE,ConditionalAction.class.getSimpleName()).hideIn(form); + Select select = new Select(REALM_CONDITION); + List> conditionTypes = List.of(TrainSelect.class); + for (Class clazz : conditionTypes) select.addOption(clazz.getSimpleName()); + select.addTo(form); + new Button(t("Create action"),"return submitForm('"+formId+"');").addTo(form).addTo(win); + return win; + } + + @Override + public String toString() { + if (conditions.isEmpty()) return t("Invalid condition"); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i maxSpeed) context.train.setSpeed(maxSpeed); + public boolean fire(Context context) { + if (context.train != null && context.train.speed > maxSpeed) { + context.train.setSpeed(maxSpeed); + return true; + } + return false; } @Override diff --git a/src/main/java/de/srsoftware/web4rail/actions/TurnTrain.java b/src/main/java/de/srsoftware/web4rail/actions/TurnTrain.java index 241fc1f..d472bf7 100644 --- a/src/main/java/de/srsoftware/web4rail/actions/TurnTrain.java +++ b/src/main/java/de/srsoftware/web4rail/actions/TurnTrain.java @@ -9,7 +9,11 @@ public class TurnTrain extends RouteAction implements Constants{ } @Override - public void fire(Context context) { - if (context.train != null) context.train.turn(); + public boolean fire(Context context) { + if (context.train != null) { + context.train.turn(); + return true; + } + return false; } } diff --git a/src/main/java/de/srsoftware/web4rail/conditions/Condition.java b/src/main/java/de/srsoftware/web4rail/conditions/Condition.java new file mode 100644 index 0000000..a523ad3 --- /dev/null +++ b/src/main/java/de/srsoftware/web4rail/conditions/Condition.java @@ -0,0 +1,69 @@ +package de.srsoftware.web4rail.conditions; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONObject; + +import de.keawe.tools.translations.Translation; +import de.srsoftware.tools.Tag; +import de.srsoftware.web4rail.Application; +import de.srsoftware.web4rail.Constants; +import de.srsoftware.web4rail.Window; +import de.srsoftware.web4rail.actions.Action.Context; + +public abstract class Condition implements Constants { + + private static HashMap conditions = new HashMap(); + + public abstract boolean fulfilledBy(Context context); + protected int id; + + public static Object action(HashMap params) { + if (!params.containsKey(ID)) return t("No id passed to Condition.action!"); + int cid = Integer.parseInt(params.get(ID)); + Condition condition = conditions.get(cid); + if (condition == null) return t("No condition with id {}!",cid); + + String action = params.get(ACTION); + if (action == null) return t("No action passed to Condition.action!"); + + switch (action) { + case ACTION_PROPS: + return condition.properties(); + case ACTION_UPDATE: + return condition.update(params); + } + return t("Unknown action: {}",action); + } + + protected abstract Window properties(); + + + public Condition() { + this(new Date().hashCode()); + } + + public Condition(int id) { + this.id = id; + conditions.put(id, this); + } + + public Tag link(String tagClass) { + String json = new JSONObject(Map.of(REALM,REALM_CONDITION,ID,id,ACTION,ACTION_PROPS)).toString().replace("\"", "'"); + return new Tag(tagClass).clazz("link").attr("onclick","request("+json+")").content(toString()); + } + + + @Override + public String toString() { + return t("invalid condition"); + } + + public static String t(String text, Object...fills) { + return Translation.get(Application.class, text, fills); + } + + protected abstract Object update(HashMap params); +} diff --git a/src/main/java/de/srsoftware/web4rail/conditions/TrainSelect.java b/src/main/java/de/srsoftware/web4rail/conditions/TrainSelect.java new file mode 100644 index 0000000..f83e52d --- /dev/null +++ b/src/main/java/de/srsoftware/web4rail/conditions/TrainSelect.java @@ -0,0 +1,52 @@ +package de.srsoftware.web4rail.conditions; + +import java.util.HashMap; + +import de.srsoftware.web4rail.Window; +import de.srsoftware.web4rail.actions.Action.Context; +import de.srsoftware.web4rail.moving.Train; +import de.srsoftware.web4rail.tags.Button; +import de.srsoftware.web4rail.tags.Form; +import de.srsoftware.web4rail.tags.Input; +import de.srsoftware.web4rail.tags.Label; + +public class TrainSelect extends Condition { + + private static final Object TRAIN = Train.class.getSimpleName(); + private Train train; + + @Override + public boolean fulfilledBy(Context context) { + // TODO Auto-generated method stub + return false; + } + + @Override + protected Window properties() { + Window win = new Window("condition-props", t("Properties of {}",getClass().getSimpleName())); + String formId = "conditional-props-"+id; + Form form = new Form(formId); + new Input(REALM,REALM_CONDITION).hideIn(form); + new Input(ACTION,ACTION_UPDATE).hideIn(form); + new Input(ID,id).hideIn(form); + Train.selector(train, null).addTo(new Label(t("Select train:")+NBSP)).addTo(form); + new Button(t("Save")).addTo(form).addTo(win); + return win; + } + + @Override + public String toString() { + if (train == null) return super.toString(); + return t("Train = {}",train); + } + + @Override + protected Object update(HashMap params) { + if (!params.containsKey(TRAIN)) return t("No train id passed to TrainSelect.update()!"); + int tid = Integer.parseInt(params.get(TRAIN)); + Train train = Train.get(tid); + if (train == null) return t("No train with id {} found!",tid); + this.train = train; + return t("Updated condition"); + } +} diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index f0666a5..a64abad 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java @@ -39,10 +39,10 @@ import de.srsoftware.web4rail.tiles.Signal; public class Train implements Constants { private static final Logger LOG = LoggerFactory.getLogger(Train.class); - private static final HashMap trains = new HashMap<>(); + private static final HashMap trains = new HashMap<>(); public static final String ID = "id"; - public long id; + public int id; private static final String NAME = "name"; private String name = null; @@ -98,8 +98,8 @@ public class Train implements Constants { this(loco,null); } - public Train(Locomotive loco, Long id) { - if (id == null) id = new Date().getTime(); + public Train(Locomotive loco, Integer id) { + if (id == null) id = new Date().hashCode(); this.id = id; add(loco); trains.put(id, this); @@ -117,7 +117,7 @@ public class Train implements Constants { } return t("No train id passed!"); } - long id = Long.parseLong(params.get(Train.ID)); + int id = Integer.parseInt(params.get(Train.ID)); Train train = trains.get(id); if (train == null) return(t("No train with id {}!",id)); switch (action) { @@ -189,7 +189,7 @@ public class Train implements Constants { this.block = block; } - public static Train get(long id) { + public static Train get(int id) { return trains.get(id); } @@ -237,7 +237,7 @@ public class Train implements Constants { while (line != null) { JSONObject json = new JSONObject(line); - long id = json.getLong(ID); + int id = json.getInt(ID); Train train = new Train(null,id); train.load(json).plan(plan); @@ -378,12 +378,24 @@ public class Train implements Constants { public static void saveAll(String filename) throws IOException { BufferedWriter file = new BufferedWriter(new FileWriter(filename)); - for (Entry entry:trains.entrySet()) { + for (Entry entry:trains.entrySet()) { Train train = entry.getValue(); file.write(train.json()+"\n"); } file.close(); } + + public static Select selector(Train preselected,Collection exclude) { + if (exclude == null) exclude = new Vector(); + Select select = new Select(Train.class.getSimpleName()); + new Tag("option").attr("value","0").content(t("unset")).addTo(select); + for (Train train : Train.list()) { + if (exclude.contains(train)) continue; + Tag opt = select.addOption(train.id, train); + if (train == preselected) opt.attr("selected", "selected"); + } + return select; + } public void setSpeed(int v) { LOG.debug("Setting speed to {} kmh.",v); diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java index fca4d5c..a0ef631 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java @@ -14,6 +14,7 @@ import de.srsoftware.web4rail.tags.Button; import de.srsoftware.web4rail.tags.Checkbox; import de.srsoftware.web4rail.tags.Input; import de.srsoftware.web4rail.tags.Label; +import de.srsoftware.web4rail.tags.Select; public abstract class Block extends StretchableTile{ private static final String NAME = "name"; @@ -22,7 +23,7 @@ public abstract class Block extends StretchableTile{ private static final String ALLOW_TURN = "allowTurn"; public boolean turnAllowed = false; - private static final String TRAIN = "train"; + private static final String TRAIN = Train.class.getSimpleName(); @Override public JSONObject config() { @@ -51,7 +52,7 @@ public abstract class Block extends StretchableTile{ name = json.has(NAME) ? json.getString(NAME) : "Block"; turnAllowed = json.has(ALLOW_TURN) && json.getBoolean(ALLOW_TURN); if (json.has(TRAIN)) { - Train tr = Train.get(json.getLong(TRAIN)); + Train tr = Train.get(json.getInt(TRAIN)); train(tr); } return this; @@ -65,13 +66,7 @@ public abstract class Block extends StretchableTile{ new Checkbox(ALLOW_TURN,t("Turn allowed"),turnAllowed).addTo(new Tag("p")).addTo(form); - Tag select = new Tag("select").attr("name", TRAIN); - new Tag("option").attr("value","0").content(t("unset")).addTo(select); - for (Train train : Train.list()) { - Tag opt = new Tag("option").attr("value", ""+train.id); - if (this.train == train) opt.attr("selected", "selected"); - opt.content(train.toString()).addTo(select); - } + Select select = Train.selector(train, null); select.addTo(new Label(t("Trains:")+" ")).addTo(new Tag("p")).addTo(form); return form; @@ -118,7 +113,7 @@ public abstract class Block extends StretchableTile{ super.update(params); if (params.containsKey(NAME)) name=params.get(NAME); if (params.containsKey(TRAIN)) { - long trainId = Long.parseLong(params.get(TRAIN)); + int trainId = Integer.parseInt(params.get(TRAIN)); Train t = Train.get(trainId); if (t != null) { Block oldBlock = t.block();